Compare commits

...
230 Commits
Author SHA1 Message Date
Simba 856df5ebe3 change user search text. 2021-01-05 23:12:16 +08:00
Simba 82f5b016e5 transform class arrow function to class method function. 2021-01-05 22:53:30 +08:00
Simba 9e0cdfd167 transform matter pages class arrow function to class method function. 2021-01-04 23:08:16 +08:00
Simba 2c835ea42f v3.1.2 2021-01-04 22:08:36 +08:00
Simba 666783e11e upload cancel. 2021-01-04 22:06:27 +08:00
lishuang 2894434ae8 Refine the variable scope. 2021-01-04 22:06:27 +08:00
lishuang 2b28317a8f Fix the large file upload bug. 2021-01-04 22:06:27 +08:00
lishuang 31ce6dca15 Fix the upload bug. 2021-01-04 22:06:27 +08:00
Simba c9a5fee48a upload matters. 2021-01-04 22:06:27 +08:00
lishuang b31cd37109 Fix the sort bug. 2021-01-04 22:06:27 +08:00
Simba 8786e2b427 matter list sort. 2021-01-04 22:06:27 +08:00
Simba 87cce788a5 preference recycle bin zero keep-day setting. 2021-01-04 22:06:27 +08:00
Simba 8165c13128 change soft del and hard del order. 2021-01-04 22:06:27 +08:00
Simba b7f4d87236 add scan immediately. 2021-01-04 22:06:27 +08:00
Simba 91ffc11b90 a little optimization. 2021-01-04 22:06:27 +08:00
Simba e2ad3d1caf matter list delete option soft or hard. 2021-01-04 22:06:27 +08:00
Simba 9bd725fc8e upload matter promote to global. 2021-01-02 14:37:13 +08:00
Simba affd0d0325 all-files menu navigate to all files index. 2021-01-02 14:05:21 +08:00
Simba b9402649c6 user role can not update sizeLimit and totalSizeLimit by self. 2021-01-02 13:47:56 +08:00
Simba 02298f9361 remove js-cookie. 2020-12-09 23:41:01 +08:00
Simba f698bdd6b0 mobile initial hide menu. 2020-11-26 23:24:43 +08:00
Simba ef85fda048 change version 2020-09-16 09:13:37 +08:00
Simba 27816d9303 release 3.1.1 2020-09-08 00:22:26 +08:00
Simba 52189867ea del useless component 2020-09-08 00:11:53 +08:00
Simba c127440207 declare dom file type 2020-09-08 00:03:52 +08:00
Simba d856e81c5f del upload directory tooltip 2020-09-07 23:55:46 +08:00
lishuang 36d4c81dd5 Rm the testing lib. 2020-09-07 23:52:31 +08:00
Simba 254bde20b9 change file type 2020-09-07 23:23:38 +08:00
Simba 153270fe9a fix share detail page refresh login 2020-09-06 15:32:19 +08:00
Simba 9fa6462bcd fix unlogin user open share file 2020-09-06 14:30:57 +08:00
Simba bb16ed3b21 support upload directory 2020-09-06 01:41:35 +08:00
Simba 32c881a875 update share detail responsive 2020-07-27 22:35:56 +08:00
Simba 5859dd5113 feat: share matter login not required 2020-07-26 21:45:24 +08:00
eyeblue 214b34ed28 Update SideLayout.tsx
Rm a import.
2020-07-21 10:40:54 +08:00
eyeblue ab7c915140 Update package.json
Fix the antd version.
2020-07-21 10:40:07 +08:00
Simba 0e8c223cfa add readme 2020-07-18 16:29:47 +08:00
lishuang e1838a5fac Fix the display for url. 2020-07-18 15:16:06 +08:00
Simba 813e9c9ae3 preference previewEngine default url 2020-07-18 15:14:04 +08:00
Simba 7bddd1e1c8 matter recovery 2020-07-18 15:04:48 +08:00
lishuang 392fd860f2 Fix the useless console log feature. 2020-07-18 14:52:39 +08:00
Simba 17a674d956 change bin list 2020-07-18 14:42:25 +08:00
lishuang 71bc7ebe8e Fix some style for about modal. 2020-07-18 14:40:17 +08:00
lishuang 18db3f5cae Fix some details. 2020-07-16 02:00:52 +08:00
Simba 9901920bc7 add recovery matter 2020-07-15 09:22:32 +08:00
Simba 0296d2f345 add recycle bin list 2020-07-14 23:08:31 +08:00
lishuang d880fc0487 Fix the share root uuid. 2020-07-12 23:32:31 +08:00
lishuang 058498093a Change the dashboard color. 2020-07-12 23:13:53 +08:00
lishuang 2ac3e24e7a Fix the response feature. 2020-07-12 23:10:59 +08:00
Simba f7f0351505 fix share detail preview and download problem 2020-07-12 23:09:53 +08:00
lishuang 8b9b6f6bd4 Fix the preview engine. 2020-07-12 22:08:55 +08:00
lishuang 4bcc3555ca Fix the share empty hint. 2020-07-12 21:49:49 +08:00
Simba e003175a02 preference add deletedKeepDays 2020-07-12 18:33:01 +08:00
Simba 46db40780a add default preview engines 2020-07-12 17:39:18 +08:00
lishuang 5b5f0d05c4 Fix the data error for dashboard. 2020-07-12 16:31:21 +08:00
Simba 93691bdb4f fix scan edit problem 2020-07-12 15:26:32 +08:00
Simba 00429b1f73 preference scan edit complete 2020-07-12 01:59:32 +08:00
lishuang b0029661e0 No longer need eslint. 2020-07-12 00:08:32 +08:00
lishuang 5325637deb Remove the service worker. 2020-07-12 00:06:15 +08:00
lishuang aee4a75428 Remove the service worker. 2020-07-12 00:02:47 +08:00
lishuang 820801af20 Add a field into matter. 2020-07-11 23:59:13 +08:00
lishuang e60cbd853f Finish the dashboard feature. 2020-07-11 22:16:10 +08:00
lishuang e61ff77284 Fix the lang time. 2020-07-11 21:58:51 +08:00
lishuang 4ec3c9f9ab Change some styles for the matter detail page. 2020-07-11 21:16:09 +08:00
Simba 202f6e54b7 preview engine 2020-07-11 21:07:13 +08:00
lishuang c3c5adffd7 Add etl feature. 2020-07-11 21:05:32 +08:00
Simba 7ff2e70853 fix user detail style problem 2020-07-11 18:06:33 +08:00
Simba 9981b2f56d Merge branch 'master' of github.com:eyebluecn/tank-front 2020-07-11 17:42:19 +08:00
Simba cbc1cbe9f4 add mobile user list 2020-07-11 17:42:08 +08:00
lishuang 99eca5420e Add the physic. 2020-07-11 17:38:56 +08:00
Simba eb072dc5a9 matter list refresh code upgrade 2020-07-02 18:51:37 +08:00
Simba 14bf34fbc6 use template string instead of common string 2020-07-01 17:38:44 +08:00
Simba 5d6d11aa7d add webpack theme change and dynamic antd style import 2020-07-01 15:16:26 +08:00
Simba ec90f66d94 add polyfill 2020-06-30 15:35:42 +08:00
Simba 7d8e245e14 fix a breadcrumb bug 2020-06-24 00:49:37 +08:00
Simba 65456dfccc some internationalization 2020-06-24 00:08:29 +08:00
Simba 7bfc98a0ff add about modal 2020-06-23 23:58:57 +08:00
Simba 061ade451a fix a share bug 2020-06-21 21:39:53 +08:00
Simba 85810b5767 preference engines style 2020-06-21 21:23:12 +08:00
Simba 7bb3d6fe3b preference engines internationalization 2020-06-21 20:46:22 +08:00
Simba 3b7da44cc7 preference index engines 2020-06-21 19:34:16 +08:00
lishuang 9d8d3d35da Remove some useless things. 2020-06-21 18:06:18 +08:00
lishuang 62466ff1d4 Add the url remark. 2020-06-21 17:38:03 +08:00
lishuang 8e9ee8df71 Finish the preview. 2020-06-21 17:32:11 +08:00
lishuang 08f5a9f186 Finish the preview. 2020-06-21 17:21:14 +08:00
Simba 49413436c1 batch move style 2020-06-21 16:10:59 +08:00
Simba 6afbc93199 add infoCell 2020-06-21 15:01:41 +08:00
Simba 41b5b44403 add some icon 2020-06-21 14:09:25 +08:00
lishuang b34f66ad8c Finish the Rough preview engine feature. 2020-06-21 03:33:27 +08:00
lishuang 1d8eb74ba7 Ready to reuse the Form.Item. 2020-06-21 03:13:04 +08:00
Simba 0dc139c087 matter and share tooltips 2020-06-21 02:51:24 +08:00
lishuang 92eb82e207 Add the preview config and engine model. 2020-06-21 02:41:36 +08:00
Simba 2f76483d05 matter and share internationalization 2020-06-21 02:20:48 +08:00
Simba 3ae906b07e drag matter complete 2020-06-21 01:02:59 +08:00
lishuang e41ae5e5b5 Finish the System cleanup feature. 2020-06-21 00:12:29 +08:00
lishuang 43ab1290f5 Finish the user delete feature. 2020-06-21 00:04:43 +08:00
lishuang 13a3020633 Finish the Breadcrumb panel. 2020-06-20 21:26:43 +08:00
Simba 9e505f2003 matter image 2020-06-20 21:25:38 +08:00
lishuang 7803fd0dba Finish the Breadcrumb feature for all files. 2020-06-20 21:10:01 +08:00
lishuang 7f9425fc61 Reformat the matter List view. 2020-06-20 20:27:05 +08:00
lishuang dc377984ff Finish the I18N work for install module. 2020-06-20 18:13:35 +08:00
lishuang 057feb28e2 Refine the Lang module. 2020-06-20 17:40:46 +08:00
lishuang 5681238cd0 Ready to migrate lang from Moon to Lang. 2020-06-20 17:35:21 +08:00
lishuang 43f3712f54 Finish the i18n for user model. 2020-06-20 17:28:28 +08:00
Simba 736d0120b7 share detail complete 2020-06-20 17:13:12 +08:00
lishuang 5483b99376 Finish the i18n work for preference and dashboard. 2020-06-20 16:18:31 +08:00
lishuang f13543c54e Add the i18n frame. 2020-06-20 15:17:47 +08:00
lishuang 00a9e71de9 Ready to refine the global i18n feature. 2020-06-20 14:11:22 +08:00
lishuang f058642d69 Fix the copyright and record feature. 2020-06-20 13:46:40 +08:00
lishuang 7fd650024e Fix the responsive feature for the Layout. 2020-06-20 01:52:19 +08:00
lishuang edc6c9c562 Finish the rough frame layout. 2020-06-20 01:37:42 +08:00
lishuang 65b8de8db0 Finish the main layout. 2020-06-20 01:10:24 +08:00
lishuang eada6b5005 Ready to refine the whole frame. 2020-06-20 00:30:16 +08:00
lishuang bb397d0639 Fix the log and favicon feature. 2020-06-20 00:05:31 +08:00
Simba 86852f6714 matter list share 2020-06-19 23:35:39 +08:00
Simba 7b1af51fe6 share operation alpha 2020-06-19 17:59:52 +08:00
simba 61746f5ebf test github account 2020-06-19 10:08:44 +08:00
Simba 231d89ae5c complete share list 2020-06-18 23:58:13 +08:00
Simba a1fb2f9ba5 use sun global router 2020-06-18 22:42:27 +08:00
simba 9782fd929a share components begin 2020-06-18 18:39:49 +08:00
simba d0dab0894c mobile matter detail cache handles expanding 2020-06-17 11:57:25 +08:00
Simba 422f716d36 use velocity-react instead of cssTransitionGroup and velocity-animate 2020-06-17 09:28:19 +08:00
simba 1fa200e0fd mobile matter list handles expanding 2020-06-16 18:19:21 +08:00
Simba c83edd2209 matter list mobile handles visible without transition 2020-06-16 00:10:50 +08:00
Simba 328946944d download token 2020-06-15 21:32:29 +08:00
simba 700a2eff60 share model 2020-06-15 18:18:02 +08:00
Simba 8871c7873d matter detail 2020-06-14 18:29:18 +08:00
Simba 47faafa27d complete file page 2020-06-13 21:06:07 +08:00
Simba f0aac156a2 search file 2020-06-13 16:53:04 +08:00
Simba 148a0052e3 complete move batch 2020-06-13 16:33:42 +08:00
Simba 68d6fa0176 alpha move batch 2020-06-13 01:06:17 +08:00
lishuang cc8d2c8729 Finis the preview feature. 2020-06-13 00:44:56 +08:00
lishuang 34ef6e4ec9 Finish the pdf preview. 2020-06-13 00:35:34 +08:00
Simba 3c97f38c5e prepare batchMove 2020-06-12 08:56:09 +08:00
simba 750478036c change native button to Button 2020-06-11 18:15:24 +08:00
simba 9a0f787484 use launchUpload with reactComponent 2020-06-10 17:06:26 +08:00
Simba 9e99a5f30a complete file upload progress 2020-06-10 00:17:46 +08:00
Simba f471691292 complete file upload 2020-06-08 23:07:35 +08:00
lishuang dd20af4c19 Finish all the work for installing. 2020-06-07 22:16:31 +08:00
lishuang 3902a657ee Finish the Install UI. 2020-06-07 21:58:53 +08:00
lishuang 84cfc03d29 Add a line. 2020-06-07 21:37:46 +08:00
lishuang af41bbe7a3 Finish the first install pipeline work. 2020-06-07 21:29:18 +08:00
Simba ea4c9428a1 Merge remote-tracking branch 'origin/react-refine' into react-refine 2020-06-07 21:28:24 +08:00
Simba 328bc4c712 matter list some function complete 2020-06-07 21:28:00 +08:00
lishuang 17b4dbb191 Finish the separate work for SetAdmin panel. 2020-06-07 21:02:18 +08:00
lishuang 7569ca9c87 Finish all the feature of CreateTablePanel. 2020-06-07 20:14:12 +08:00
lishuang 754c86a7c5 Finish the MysqlPanel. 2020-06-07 19:36:20 +08:00
lishuang 023bb4a3a1 Add tabs for install. 2020-06-07 17:56:42 +08:00
lishuang 16adebaebf Add the frame for install. 2020-06-07 17:43:02 +08:00
lishuang 7ae8dd128f Refine the MessageBox usage. 2020-06-07 17:20:47 +08:00
lishuang e9863403fe Ready to do the install work. 2020-06-07 17:00:31 +08:00
Simba 260462465e matter goto directory 2020-06-07 16:55:39 +08:00
lishuang de63f1e3d4 Add the dashboard hint. 2020-06-07 16:36:59 +08:00
lishuang 33b48e0e2d Finish all the dashboard view. 2020-06-07 16:33:29 +08:00
lishuang d62192fa39 Finish the card and line charts. 2020-06-07 16:19:48 +08:00
lishuang 62c183470a Import the echarts. Ready to combine the dashboard data. 2020-06-07 16:00:19 +08:00
lishuang 3819c8e24e Add the card dashboard feature. 2020-06-07 15:37:58 +08:00
lishuang cca1a55647 Add placeholder of Dashboard. Add ImagePreviewer. 2020-06-07 15:19:58 +08:00
lishuang a4ae20f458 Finish all the UserList feature. 2020-06-07 14:33:04 +08:00
lishuang 7009d94648 Finish the ImagePreviewer module. 2020-06-07 00:54:59 +08:00
lishuang d227d231db Fix the user/detail page. Add the Authentication login method. 2020-06-07 00:46:39 +08:00
Simba b8cd2e5d4d matter simple handle complete 2020-06-07 00:24:17 +08:00
lishuang 422b5bda20 Finish the transfiguration feature. 2020-06-07 00:23:15 +08:00
lishuang 5f0455c676 Add the change password and reset password feature. 2020-06-07 00:11:50 +08:00
Simba e4b9e58a41 add rename matter 2020-06-06 23:43:04 +08:00
lishuang 8babfa9d67 Add the User Detail page. 2020-06-06 21:59:18 +08:00
lishuang 30b2a5ba09 Finish the Image Resize feature. 2020-06-06 21:31:33 +08:00
Simba 290eab243b feat: axios return promise 2020-06-06 21:18:46 +08:00
lishuang 9bab8765c4 Try to use the old html. 2020-06-06 21:13:27 +08:00
Simba e3d34dde82 some matter change 2020-06-06 19:22:21 +08:00
lishuang 3e9533a624 Ready to add the UserDetail page. 2020-06-06 19:04:11 +08:00
lishuang 41df6e08ed Finish the create feature of user. 2020-06-06 18:54:53 +08:00
lishuang 3e0fe86a4b Add the Edit. 2020-06-06 18:22:41 +08:00
lishuang 469d3d93f9 Finish the rough feature of PreferenceForm. 2020-06-06 17:13:06 +08:00
lishuang d07a7d229c Refine the form of Preference. 2020-06-06 17:04:35 +08:00
Simba 2eddd832e8 add matter model 2020-06-06 15:08:08 +08:00
lishuang c7ffa53463 Change the images. 2020-06-06 14:52:14 +08:00
lishuang be436f6679 Add the UserList. 2020-06-06 14:39:12 +08:00
lishuang 8e17ad1c5f Finish the Preference Index and Edit page. 2020-06-06 14:26:35 +08:00
lishuang 622b8129fb Finish the Preference index page. 2020-06-06 14:06:28 +08:00
lishuang b8599d15d0 Fix the crash error. 2020-06-06 12:20:41 +08:00
Simba 2fa3fca071 fix some problems 2020-06-06 12:17:05 +08:00
lishuang a67e0e1e23 Refine some golbal. 2020-06-06 12:07:46 +08:00
Simba 67ace29f28 add some utils 2020-06-06 12:06:07 +08:00
lishuang 31011d65ed Change Bamboo to Tank. 2020-06-06 11:57:14 +08:00
lishuang f9ed88b84f Add the placeholder for preference. 2020-06-06 11:49:44 +08:00
lishuang 7bf0fc6c77 Finish the login page. 2020-06-06 01:07:59 +08:00
lishuang 5b7d29de4d Finish the Login page. 2020-06-06 00:51:11 +08:00
lishuang bc01b42182 Use TankComponent. 2020-06-06 00:33:45 +08:00
lishuang 9ca77eb501 Find reactComponent back. 2020-06-06 00:33:13 +08:00
lishuang 36a890ceb4 Add the feature. 2020-06-06 00:24:22 +08:00
lishuang 232c63af60 Remove the reactComponent. 2020-06-06 00:20:11 +08:00
Simba 686ff1dcde transfer some dependency to devDenpendency 2020-06-06 00:18:20 +08:00
lishuang 7bad1db7e6 Commit the matter. 2020-06-06 00:05:24 +08:00
lishuang 3a2a5bab2a Add the main frame. 2020-06-06 00:04:03 +08:00
lishuang ddbc94e854 Change the port. 2020-06-05 23:45:01 +08:00
lishuang 7332a1807d add the bamboo demo 2020-06-05 23:26:14 +08:00
lishuang 03bb3f4881 Finish the first version of tank from bamboo. 2020-06-05 23:21:18 +08:00
lishuang 397cc7af58 Remove the jest tests. Add the support for less. Keep the class name. Add antd. 2020-06-05 22:47:36 +08:00
lishuang 2afa8c6f0f run eject 2020-06-05 22:31:58 +08:00
lishuang 9894b3196f Let's refine tank by react+antd. 2020-06-05 22:26:59 +08:00
lishuang 094d6961e2 Add the custom api for office preview. 2020-05-09 02:20:49 +08:00
lishuang 4e5796159f Finish the charset for mysql. 2020-05-06 02:21:29 +08:00
zicla 2409817980 Remove the package-lock.json 2020-03-11 00:52:42 +08:00
eyeblue 641830255f Merge pull request #20 from eyebluecn/dependabot/npm_and_yarn/mixin-deep-1.3.2
Bump mixin-deep from 1.3.1 to 1.3.2
2020-03-11 00:46:50 +08:00
eyeblue 347598abac Merge pull request #21 from eyebluecn/dependabot/npm_and_yarn/lodash.defaultsdeep-4.6.1
Bump lodash.defaultsdeep from 4.6.0 to 4.6.1
2020-03-11 00:46:32 +08:00
dependabot[bot] f010f8a709 Bump lodash.defaultsdeep from 4.6.0 to 4.6.1
Bumps [lodash.defaultsdeep](https://github.com/lodash/lodash) from 4.6.0 to 4.6.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.6.0...4.6.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-10 16:46:14 +00:00
eyeblue 26f6e00d15 Merge pull request #22 from eyebluecn/dependabot/npm_and_yarn/lodash-4.17.15
Bump lodash from 4.17.11 to 4.17.15
2020-03-11 00:45:10 +08:00
dependabot[bot] 8720c172b0 Bump lodash from 4.17.11 to 4.17.15
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.15.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.15)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-10 16:44:36 +00:00
dependabot[bot] 4922ba1082 Bump mixin-deep from 1.3.1 to 1.3.2
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-10 16:44:18 +00:00
zicla 24d91ae7cc Merge remote-tracking branch 'origin/feat-compress-code' 2020-03-11 00:44:00 +08:00
eyeblue 3f6fcd408e Merge pull request #17 from eyebluecn/dependabot/npm_and_yarn/eslint-utils-1.4.3
Bump eslint-utils from 1.3.1 to 1.4.3
2020-03-11 00:41:21 +08:00
simba 643bd8ee80 feat: compress build code. 2019-11-19 18:20:20 +08:00
eyeblue d8195aede5 Merge pull request #16 from eyebluecn/fix-search
fix: some search problems.
2019-11-18 21:20:26 +08:00
simba 88a7f64510 feat: add web folder copy link. 2019-11-18 21:14:18 +08:00
dependabot[bot] 4884b953ce Bump eslint-utils from 1.3.1 to 1.4.3
Bumps [eslint-utils](https://github.com/mysticatea/eslint-utils) from 1.3.1 to 1.4.3.
- [Release notes](https://github.com/mysticatea/eslint-utils/releases)
- [Commits](https://github.com/mysticatea/eslint-utils/compare/v1.3.1...v1.4.3)

Signed-off-by: dependabot[bot] <support@github.com>
2019-11-02 22:37:29 +00:00
simba d85dd443e0 fix: some search problems. 2019-10-18 22:35:42 +08:00
zicla 76255dc098 Release 3.0.6 2019-10-13 16:59:03 +08:00
simba aab1d1b48d fix: keyword search. 2019-10-11 22:15:05 +08:00
simba a6b8643941 feat: delete useless code. 2019-09-04 22:50:17 +08:00
simba dd99108afd feat: update drag file icon. 2019-09-04 22:13:56 +08:00
eyeblue 23f7c50106 Merge pull request #14 from eyebluecn/feat-drop-exquiste
Accept.
2019-08-31 22:53:19 +08:00
simba 55da380795 feat: add drag file background. 2019-08-31 21:44:50 +08:00
eyeblue 912536c620 Merge pull request #13 from eyebluecn/feat-drag-file
Accept. This feature will release on 3.1.0
2019-08-29 00:08:00 +08:00
simba 73e4670f8b feat: format code. 2019-08-28 23:50:36 +08:00
simba 9e7c2cbf5a feat: add drop file without format. 2019-08-28 09:12:34 +08:00
simba 9dbb8d4001 feat: update category. 2019-08-24 22:24:08 +08:00
simba 56b39b698d feat: adjust views. 2019-08-24 18:25:47 +08:00
eyeblue 2f545a343f Merge pull request #10 from eyebluecn/feat-update-category
Accept feat: adjust category and views
2019-08-24 17:53:16 +08:00
simba 28eb0a01bd feat: adjust views. 2019-08-24 17:22:12 +08:00
simba ebe2651ce8 feat: adjust category. 2019-08-24 16:58:37 +08:00
390 changed files with 21411 additions and 35881 deletions
-8
View File
@@ -1,8 +0,0 @@
/build/
/config/
/dist/
/static/
/*.js
src/common/fork/*
-67
View File
@@ -1,67 +0,0 @@
// https://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
env: {
browser: true,
},
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
extends: 'standard',
// required to lint *.vue files
plugins: [
'html'
],
// add your custom rules here
'rules': {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
//ignore the paren check before function.
'space-before-function-paren': [0, 'always'],
//ignore the space before block.
'space-before-blocks': [0, 'always'],
//ignore the empty line check.
'no-multiple-empty-lines': [0, {'max': 2}],
//semicolon or no semicolon is ok.
'semi': [0, 'always'],
//ignore the space before or after =>
'arrow-spacing': 0,
//the type of quotes
'quotes': [0, 'single'],
//block can be padded by blank lines
'padded-blocks': 0,
//comma spacing before or after.
'comma-spacing': 0,
//key spacing.
'key-spacing': [0, {'beforeColon': false, 'afterColon': true}],
//trailing spaces
'no-trailing-spaces': 0,
//spaced comment
'spaced-comment': 0,
//keyword-spacing
'keyword-spacing': 0,
'space-in-parens': 0,
'no-extend-native': 0,
'no-useless-escape': 0,
'no-unused-vars': 0,
'no-undef': 0,
'no-tabs': 0,
'indent': 0,
'no-multi-spaces': 0,
'eol-last': 0,
'no-template-curly-in-string': 0,
'no-mixed-spaces-and-tabs': 0,
'handle-callback-err': 0,
"import/no-webpack-loader-syntax": "off",
'object-curly-spacing': 0,
'comma-dangle': 0
}
}
+24 -2
View File
@@ -1,9 +1,27 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
node_modules/
/dist/
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
yarn.lock
# Editor directories and files
.idea
@@ -12,3 +30,7 @@ yarn-error.log*
*.ntvs*
*.njsproj
*.sln
draft.html
report.*.json
draft.txt
-27
View File
@@ -1,27 +0,0 @@
# 蓝眼云盘
2018-04-12
tank-1.0.3
1. 添加了多文件同时上传的功能.
2. 开发情况下有可能上传的文件路径没有权限,添加了更多提示.
2018-01-19
tank-1.0.2
1. 修复了下载时无法估算文件大小的bug,header头重添加了Content-Type. [#2](https://github.com/eyebluecn/tank/issues/2)
2. 修复了移动端样式混乱的问题.[#3](https://github.com/eyebluecn/tank/issues/3)
3. 修复了文夹层数无上限的bug. [#4](https://github.com/eyebluecn/tank/issues/4)
4. 修复了文件夹自己移动到自己后就全部消失的bug. [#8](https://github.com/eyebluecn/tank/issues/8)
5. 统一不能删除用户,但是可以禁用或者启用用户. [#9](https://github.com/eyebluecn/tank/issues/9)
2018-01-12
tank-1.0.1
1. 修复面包屑回退的bug [#1](https://github.com/eyebluecn/tank/issues/1)
2. 修复移动文件时,可能移到其他人的文件夹下的bug
3. 新增404页面
4. 移除掉一些没用的代码
2018-01-01
tank-1.0.0
完成基本核心功能
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 蓝眼
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+34 -53
View File
@@ -1,70 +1,51 @@
![蓝眼云盘logo](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/logo.png)
[![蓝眼云盘logo](./doc/img/logo.png)](https://github.com/eyebluecn/tank)
# 蓝眼云盘前端
[English Version](https://tank-doc.eyeblue.cn/en)
##### [在线Demo](http://tank.eyeblue.cn) (体验账号: demo 密码:123456)
# 蓝眼云盘(3.1.2)
[在线Demo](https://tank.eyeblue.cn) (体验账号: demo 密码:123456)
##### [配套后端tank](https://github.com/eyebluecn/tank)
蓝眼云盘是蓝眼开源系列代表作品之一,致力于打造精致,优雅,简约的云盘。核心功能如下:
1. 文件列表
2. 文件/文件夹上传 + 拖拽上传
3. 文件分享
4. 文件监控统计
5. 回收站
6. 多用户
7. [WebDav](https://tank-doc.eyeblue.cn/advance/webdav.html)
8. [扫描磁盘任务](https://tank-doc.eyeblue.cn/advance/scan.html)
9. [在线预览及自定义配置预览引擎](https://tank-doc.eyeblue.cn/advance/preview.html)
### 简介
蓝眼云盘是前后端彻底分离的项目,本项目主要为后端提供静态资源文件。更多关于蓝眼云盘的介绍,请参考[蓝眼云盘后端](https://github.com/eyebluecn/tank)
[更多内容请移步至文档](https://tank-doc.eyeblue.cn/)
如果您觉得蓝眼云盘对您有帮助,请不要吝惜您的star :smile:
### 技术栈
vue2.0 + vue-router + vuex + vue-resource + webpack + es6 + less
### 运行
```
npm install
npm run serve
```
### 打包
```
npm run build
```
打包的结果在`dist`文件夹下,将该文件夹下的内容放置在[后端tank](https://github.com/eyebluecn/tank)的`build/html`文件夹下即可。
### 配套后端
此项目有配套后端项目,对golang感兴趣的同学可以猛戳 [配套后端tank](https://github.com/eyebluecn/tank)
### 总结
1、 蓝眼的宗旨是专注于开源精致而优雅的软件,所以在代码的构建过程中我们不停地思考与迭代,追求最优质的代码。
2、 蓝眼云盘前端代码的构建完全面向对象,可扩展能力强,涉及多用户,多权限功能。
3、 蓝眼云盘后端采用了更贴近底层golang语言,更加适用于文件传输类的软件,速度更快,用户体验更好。
### Contribution
感谢所有蓝眼云盘的贡献者 [@zicla](https://github.com/zicla),[@seaheart](https://github.com/seaheart),@heying,[@hxsherry](https://github.com/hxsherry)
如果您也想参与进来,请尽情的fork, star, post issue, pull requests
前端技术栈:Typescript + React + Ant Design 4.0 + OOP
### 软件截图
#### PC端截图
![](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/tank0.png)
![](./doc/img/tank0.png)
![](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/tank1.png)
![](./doc/img/tank1.png)
![](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/tank2.png)
![](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/tank3.png)
![](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/tank4.png)
![](./doc/img/tank2.png)
#### 手机端截图
![](https://raw.githubusercontent.com/eyebluecn/tank/master/build/doc/img/mobile.png)
![](./doc/img/mobile.png)
## [安装文档](https://tank-doc.eyeblue.cn/basic/install.html)
### Contribution
感谢所有蓝眼云盘的贡献者 [@zicla](https://github.com/zicla),[@seaheart](https://github.com/seaheart),[@yemuhe](https://github.com/yemuhe),[@hxsherry](https://github.com/hxsherry)
如果您也想参与进来,请尽情的fork, star, post issue, pull requests
当然你可以加入钉钉群一起直接交流,在钉钉群中可以获取最新beta版本。
![](./doc/img/dingding.jpg)
群号:23156361
### License
-5
View File
@@ -1,5 +0,0 @@
module.exports = {
presets: [
'@vue/app'
]
}
+101
View File
@@ -0,0 +1,101 @@
'use strict';
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
// Make sure that including paths.js after env.js will read .env variables.
delete require.cache[require.resolve('./paths')];
const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
throw new Error(
'The NODE_ENV environment variable is required but was not specified.'
);
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
const dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
`${paths.dotenv}.${NODE_ENV}`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
paths.dotenv,
].filter(Boolean);
// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
require('dotenv-expand')(
require('dotenv').config({
path: dotenvFile,
})
);
}
});
// We support resolving modules according to `NODE_PATH`.
// This lets you use absolute paths in imports inside large monorepos:
// https://github.com/facebook/create-react-app/issues/253.
// It works similar to `NODE_PATH` in Node itself:
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
.filter(folder => folder && !path.isAbsolute(folder))
.map(folder => path.resolve(appDirectory, folder))
.join(path.delimiter);
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
// injected into the application via DefinePlugin in webpack configuration.
const REACT_APP = /^REACT_APP_/i;
function getClientEnvironment(publicUrl) {
const raw = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
return env;
},
{
// Useful for determining whether we’re running in production mode.
// Most importantly, it switches React into the correct mode.
NODE_ENV: process.env.NODE_ENV || 'development',
// Useful for resolving the correct path to static assets in `public`.
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// This should only be used as an escape hatch. Normally you would put
// images into the `src` and `import` them in code to get their paths.
PUBLIC_URL: publicUrl,
// We support configuring the sockjs pathname during development.
// These settings let a developer run multiple simultaneous projects.
// They are used as the connection `hostname`, `pathname` and `port`
// in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
// and `sockPort` options in webpack-dev-server.
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
}
);
// Stringify all values so we can feed into webpack DefinePlugin
const stringified = {
'process.env': Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
return env;
}, {}),
};
return { raw, stringified };
}
module.exports = getClientEnvironment;
+66
View File
@@ -0,0 +1,66 @@
'use strict';
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const chalk = require('react-dev-utils/chalk');
const paths = require('./paths');
// Ensure the certificate and key provided are valid and if not
// throw an easy to debug error
function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
let encrypted;
try {
// publicEncrypt will throw an error with an invalid cert
encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
} catch (err) {
throw new Error(
`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
);
}
try {
// privateDecrypt will throw an error with an invalid key
crypto.privateDecrypt(key, encrypted);
} catch (err) {
throw new Error(
`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
err.message
}`
);
}
}
// Read file and throw an error if it doesn't exist
function readEnvFile(file, type) {
if (!fs.existsSync(file)) {
throw new Error(
`You specified ${chalk.cyan(
type
)} in your env, but the file "${chalk.yellow(file)}" can't be found.`
);
}
return fs.readFileSync(file);
}
// Get the https config
// Return cert files if provided in env, otherwise just true or false
function getHttpsConfig() {
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
const isHttps = HTTPS === 'true';
if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
const config = {
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
};
validateKeyAndCerts({ ...config, keyFile, crtFile });
return config;
}
return isHttps;
}
module.exports = getHttpsConfig;
+14
View File
@@ -0,0 +1,14 @@
'use strict';
// This is a custom Jest transformer turning style imports into empty objects.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process() {
return 'module.exports = {};';
},
getCacheKey() {
// The output is always the same.
return 'cssTransform';
},
};
+40
View File
@@ -0,0 +1,40 @@
'use strict';
const path = require('path');
const camelcase = require('camelcase');
// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process(src, filename) {
const assetFilename = JSON.stringify(path.basename(filename));
if (filename.match(/\.svg$/)) {
// Based on how SVGR generates a component name:
// https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
const pascalCaseFilename = camelcase(path.parse(filename).name, {
pascalCase: true,
});
const componentName = `Svg${pascalCaseFilename}`;
return `const React = require('react');
module.exports = {
__esModule: true,
default: ${assetFilename},
ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
return {
$$typeof: Symbol.for('react.element'),
type: 'svg',
ref: ref,
key: null,
props: Object.assign({}, props, {
children: ${assetFilename}
})
};
}),
};`;
}
return `module.exports = ${assetFilename};`;
},
};
+141
View File
@@ -0,0 +1,141 @@
'use strict';
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
const chalk = require('react-dev-utils/chalk');
const resolve = require('resolve');
/**
* Get additional module paths based on the baseUrl of a compilerOptions object.
*
* @param {Object} options
*/
function getAdditionalModulePaths(options = {}) {
const baseUrl = options.baseUrl;
// We need to explicitly check for null and undefined (and not a falsy value) because
// TypeScript treats an empty string as `.`.
if (baseUrl == null) {
// If there's no baseUrl set we respect NODE_PATH
// Note that NODE_PATH is deprecated and will be removed
// in the next major release of create-react-app.
const nodePath = process.env.NODE_PATH || '';
return nodePath.split(path.delimiter).filter(Boolean);
}
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
// We don't need to do anything if `baseUrl` is set to `node_modules`. This is
// the default behavior.
if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
return null;
}
// Allow the user set the `baseUrl` to `appSrc`.
if (path.relative(paths.appSrc, baseUrlResolved) === '') {
return [paths.appSrc];
}
// If the path is equal to the root directory we ignore it here.
// We don't want to allow importing from the root directly as source files are
// not transpiled outside of `src`. We do allow importing them with the
// absolute path (e.g. `src/Components/Button.js`) but we set that up with
// an alias.
if (path.relative(paths.appPath, baseUrlResolved) === '') {
return null;
}
// Otherwise, throw an error.
throw new Error(
chalk.red.bold(
"Your project's `baseUrl` can only be set to `src` or `node_modules`." +
' Create React App does not support other values at this time.'
)
);
}
/**
* Get webpack aliases based on the baseUrl of a compilerOptions object.
*
* @param {*} options
*/
function getWebpackAliases(options = {}) {
const baseUrl = options.baseUrl;
if (!baseUrl) {
return {};
}
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
if (path.relative(paths.appPath, baseUrlResolved) === '') {
return {
src: paths.appSrc,
};
}
}
/**
* Get jest aliases based on the baseUrl of a compilerOptions object.
*
* @param {*} options
*/
function getJestAliases(options = {}) {
const baseUrl = options.baseUrl;
if (!baseUrl) {
return {};
}
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
if (path.relative(paths.appPath, baseUrlResolved) === '') {
return {
'^src/(.*)$': '<rootDir>/src/$1',
};
}
}
function getModules() {
// Check if TypeScript is setup
const hasTsConfig = fs.existsSync(paths.appTsConfig);
const hasJsConfig = fs.existsSync(paths.appJsConfig);
if (hasTsConfig && hasJsConfig) {
throw new Error(
'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
);
}
let config;
// If there's a tsconfig.json we assume it's a
// TypeScript project and set up the config
// based on tsconfig.json
if (hasTsConfig) {
const ts = require(resolve.sync('typescript', {
basedir: paths.appNodeModules,
}));
config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
// Otherwise we'll check if there is jsconfig.json
// for non TS projects.
} else if (hasJsConfig) {
config = require(paths.appJsConfig);
}
config = config || {};
const options = config.compilerOptions || {};
const additionalModulePaths = getAdditionalModulePaths(options);
return {
additionalModulePaths: additionalModulePaths,
webpackAliases: getWebpackAliases(options),
jestAliases: getJestAliases(options),
hasTsConfig,
};
}
module.exports = getModules();
+72
View File
@@ -0,0 +1,72 @@
'use strict';
const path = require('path');
const fs = require('fs');
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebook/create-react-app/issues/637
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
// "public path" at which the app is served.
// webpack needs to know it to put the right <script> hrefs into HTML even in
// single-page apps that may serve index.html for nested URLs like /todos/42.
// We can't use a relative path in HTML because we don't want to load something
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
const publicUrlOrPath = getPublicUrlOrPath(
process.env.NODE_ENV === 'development',
require(resolveApp('package.json')).homepage,
process.env.PUBLIC_URL
);
const moduleFileExtensions = [
'web.mjs',
'mjs',
'web.js',
'js',
'web.ts',
'ts',
'web.tsx',
'tsx',
'json',
'web.jsx',
'jsx',
];
// Resolve file paths in the same order as webpack
const resolveModule = (resolveFn, filePath) => {
const extension = moduleFileExtensions.find(extension =>
fs.existsSync(resolveFn(`${filePath}.${extension}`))
);
if (extension) {
return resolveFn(`${filePath}.${extension}`);
}
return resolveFn(`${filePath}.js`);
};
// config after eject: we're in ./config/
module.exports = {
dotenv: resolveApp('.env'),
appPath: resolveApp('.'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveModule(resolveApp, 'src/index'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
appJsConfig: resolveApp('jsconfig.json'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
proxySetup: resolveApp('config/setupProxy.js'),
appNodeModules: resolveApp('node_modules'),
publicUrlOrPath,
};
module.exports.moduleFileExtensions = moduleFileExtensions;
+35
View File
@@ -0,0 +1,35 @@
'use strict';
const { resolveModuleName } = require('ts-pnp');
exports.resolveModuleName = (
typescript,
moduleName,
containingFile,
compilerOptions,
resolutionHost
) => {
return resolveModuleName(
moduleName,
containingFile,
compilerOptions,
resolutionHost,
typescript.resolveModuleName
);
};
exports.resolveTypeReferenceDirective = (
typescript,
moduleName,
containingFile,
compilerOptions,
resolutionHost
) => {
return resolveModuleName(
moduleName,
containingFile,
compilerOptions,
resolutionHost,
typescript.resolveTypeReferenceDirective
);
};
+17
View File
@@ -0,0 +1,17 @@
const proxy = require('http-proxy-middleware');
module.exports = function (app) {
//为了解决前端开发时跨域问题,配置后台接口代理。
app.use(proxy(
'/api',
{
target: 'http://localhost:6010',
changeOrigin: true,
pathRewrite: {
'^/api': '/api'
}
}
));
};
+691
View File
@@ -0,0 +1,691 @@
"use strict";
const fs = require("fs");
const path = require("path");
const webpack = require("webpack");
const resolve = require("resolve");
const PnpWebpackPlugin = require("pnp-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CaseSensitivePathsPlugin = require("case-sensitive-paths-webpack-plugin");
const InlineChunkHtmlPlugin = require("react-dev-utils/InlineChunkHtmlPlugin");
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const safePostCssParser = require("postcss-safe-parser");
const ManifestPlugin = require("webpack-manifest-plugin");
const InterpolateHtmlPlugin = require("react-dev-utils/InterpolateHtmlPlugin");
const WatchMissingNodeModulesPlugin = require("react-dev-utils/WatchMissingNodeModulesPlugin");
const ModuleScopePlugin = require("react-dev-utils/ModuleScopePlugin");
const getCSSModuleLocalIdent = require("react-dev-utils/getCSSModuleLocalIdent");
const paths = require("./paths");
const modules = require("./modules");
const getClientEnvironment = require("./env");
const ModuleNotFoundPlugin = require("react-dev-utils/ModuleNotFoundPlugin");
const ForkTsCheckerWebpackPlugin = require("react-dev-utils/ForkTsCheckerWebpackPlugin");
const typescriptFormatter = require("react-dev-utils/typescriptFormatter");
const postcssNormalize = require("postcss-normalize");
const appPackageJson = require(paths.appPackageJson);
// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
// Some apps do not need the benefits of saving a web request, so not inlining the chunk
// makes for a smoother build process.
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== "false";
const imageInlineSizeLimit = parseInt(
process.env.IMAGE_INLINE_SIZE_LIMIT || "10000"
);
// Check if TypeScript is setup
const useTypeScript = fs.existsSync(paths.appTsConfig);
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;
// This is the production and development configuration.
// It is focused on developer experience, fast rebuilds, and a minimal bundle.
module.exports = function (webpackEnv) {
const isEnvDevelopment = webpackEnv === "development";
const isEnvProduction = webpackEnv === "production";
// Variable used for enabling profiling in Production
// passed into alias object. Uses a flag if passed into the build command
const isEnvProductionProfile =
isEnvProduction && process.argv.includes("--profile");
// We will provide `paths.publicUrlOrPath` to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
// Get environment variables to inject into our app.
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
// common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [
isEnvDevelopment && require.resolve("style-loader"),
isEnvProduction && {
loader: MiniCssExtractPlugin.loader,
// css is located in `static/css`, use '../../' to locate index.html folder
// in production `paths.publicUrlOrPath` can be a relative path
options: paths.publicUrlOrPath.startsWith(".")
? { publicPath: "../../" }
: {},
},
{
loader: require.resolve("css-loader"),
options: cssOptions,
},
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve("postcss-loader"),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: "postcss",
plugins: () => [
require("postcss-flexbugs-fixes"),
require("postcss-preset-env")({
autoprefixer: {
flexbox: "no-2009",
},
stage: 3,
}),
// Adds PostCSS Normalize as the reset css with default options,
// so that it honors browserslist config in package.json
// which in turn let's users customize the target behavior as per their needs.
postcssNormalize(),
],
sourceMap: isEnvProduction && shouldUseSourceMap,
},
},
].filter(Boolean);
if (preProcessor) {
loaders.push(
{
loader: require.resolve("resolve-url-loader"),
options: {
sourceMap: isEnvProduction && shouldUseSourceMap,
},
},
preProcessor
);
}
return loaders;
};
return {
mode: isEnvProduction ? "production" : isEnvDevelopment && "development",
// Stop compilation early in production
bail: isEnvProduction,
devtool: isEnvProduction
? shouldUseSourceMap
? "source-map"
: false
: isEnvDevelopment && "cheap-module-source-map",
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
entry: [
// Include an alternative client for WebpackDevServer. A client's job is to
// connect to WebpackDevServer by a socket and get notified about changes.
// When you save a file, the client will either apply hot updates (in case
// of CSS changes), or refresh the page (in case of JS changes). When you
// make a syntax error, this client will display a syntax error overlay.
// Note: instead of the default WebpackDevServer client, we use a custom one
// to bring better experience for Create React App users. You can replace
// the line below with these two lines if you prefer the stock client:
// require.resolve('webpack-dev-server/client') + '?/',
// require.resolve('webpack/hot/dev-server'),
isEnvDevelopment &&
require.resolve("react-dev-utils/webpackHotDevClient"),
// Finally, this is your app's code:
paths.appIndexJs,
// We include the app code last so that if there is a runtime error during
// initialization, it doesn't blow up the WebpackDevServer client, and
// changing JS code would still trigger a refresh.
].filter(Boolean),
output: {
// The build folder.
path: isEnvProduction ? paths.appBuild : undefined,
// Add /* filename */ comments to generated require()s in the output.
pathinfo: isEnvDevelopment,
// There will be one main bundle, and one file per asynchronous chunk.
// In development, it does not produce real files.
filename: isEnvProduction
? "static/js/[name].[contenthash:8].js"
: isEnvDevelopment && "static/js/bundle.js",
// TODO: remove this when upgrading to webpack 5
futureEmitAssets: true,
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
? "static/js/[name].[contenthash:8].chunk.js"
: isEnvDevelopment && "static/js/[name].chunk.js",
// webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path.
// We inferred the "public path" (such as / or /my-project) from homepage.
publicPath: paths.publicUrlOrPath,
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: isEnvProduction
? (info) =>
path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, "/")
: isEnvDevelopment &&
((info) =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, "/")),
// Prevents conflicts when multiple webpack runtimes (from different apps)
// are used on the same page.
jsonpFunction: `webpackJsonp${appPackageJson.name}`,
// this defaults to 'window', but by setting it to 'this' then
// module chunks which are built will work in web workers as well.
globalObject: "this",
},
optimization: {
minimize: isEnvProduction,
minimizer: [
// This is only used in production mode
new TerserPlugin({
terserOptions: {
parse: {
// We want terser to parse ecma 8 code. However, we don't want it
// to apply any minification steps that turns valid ecma 5 code
// into invalid ecma 5 code. This is why the 'compress' and 'output'
// sections only apply transformations that are ecma 5 safe
// https://github.com/facebook/create-react-app/pull/4234
ecma: 8,
},
compress: {
ecma: 5,
warnings: false,
// Disabled because of an issue with Uglify breaking seemingly valid code:
// https://github.com/facebook/create-react-app/issues/2376
// Pending further investigation:
// https://github.com/mishoo/UglifyJS2/issues/2011
comparisons: false,
// Disabled because of an issue with Terser breaking valid code:
// https://github.com/facebook/create-react-app/issues/5250
// Pending further investigation:
// https://github.com/terser-js/terser/issues/120
inline: 2,
//保持类名 by zicla
keep_fnames: true,
},
mangle: {
safari10: true,
//保持类名 by zicla
keep_fnames: true,
},
// Added for profiling in devtools
keep_classnames: isEnvProductionProfile,
keep_fnames: isEnvProductionProfile,
output: {
ecma: 5,
comments: false,
// Turned on because emoji and regex is not minified properly using default
// https://github.com/facebook/create-react-app/issues/2488
ascii_only: true,
},
},
sourceMap: shouldUseSourceMap,
}),
// This is only used in production mode
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
parser: safePostCssParser,
map: shouldUseSourceMap
? {
// `inline: false` forces the sourcemap to be output into a
// separate file
inline: false,
// `annotation: true` appends the sourceMappingURL to the end of
// the css file, helping the browser find the sourcemap
annotation: true,
}
: false,
},
cssProcessorPluginOptions: {
preset: ["default", { minifyFontValues: { removeQuotes: false } }],
},
}),
],
// Automatically split vendor and commons
// https://twitter.com/wSokra/status/969633336732905474
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
splitChunks: {
chunks: "all",
name: false,
},
// Keep the runtime chunk separated to enable long term caching
// https://twitter.com/wSokra/status/969679223278505985
// https://github.com/facebook/create-react-app/issues/5358
runtimeChunk: {
name: (entrypoint) => `runtime-${entrypoint.name}`,
},
},
resolve: {
// This allows you to set a fallback for where webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
// if there are any conflicts. This matches Node resolution mechanism.
// https://github.com/facebook/create-react-app/issues/253
modules: ["node_modules", paths.appNodeModules].concat(
modules.additionalModulePaths || []
),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebook/create-react-app/issues/290
// `web` extension prefixes have been added for better support
// for React Native Web.
extensions: paths.moduleFileExtensions
.map((ext) => `.${ext}`)
.filter((ext) => useTypeScript || !ext.includes("ts")),
alias: {
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
"react-native": "react-native-web",
// Allows for better profiling with ReactDevTools
...(isEnvProductionProfile && {
"react-dom$": "react-dom/profiling",
"scheduler/tracing": "scheduler/tracing-profiling",
}),
...(modules.webpackAliases || {}),
},
plugins: [
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
// guards against forgotten dependencies and such.
PnpWebpackPlugin,
// Prevents users from importing files from outside of src/ (or node_modules/).
// This often causes confusion because we only process files within src/ with babel.
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
// please link the files into your node_modules/ and let module-resolution kick in.
// Make sure your source files are compiled, as they will not be processed in any way.
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
],
},
resolveLoader: {
plugins: [
// Also related to Plug'n'Play, but this time it tells webpack to load its loaders
// from the current package.
PnpWebpackPlugin.moduleLoader(module),
],
},
module: {
strictExportPresence: true,
rules: [
// Disable require.ensure as it's not a standard language feature.
{ parser: { requireEnsure: false } },
{
// "oneOf" will traverse all following loaders until one will
// match the requirements. When no loader matches it will fall
// back to the "file" loader at the end of the loader list.
oneOf: [
// "url" loader works like "file" loader except that it embeds assets
// smaller than specified limit in bytes as data URLs to avoid requests.
// A missing `test` is equivalent to a match.
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve("url-loader"),
options: {
limit: imageInlineSizeLimit,
name: "static/media/[name].[hash:8].[ext]",
},
},
// Process application JS with Babel.
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve("babel-loader"),
options: {
customize: require.resolve(
"babel-preset-react-app/webpack-overrides"
),
plugins: [
[
require.resolve("babel-plugin-named-asset-import"),
{
loaderMap: {
svg: {
ReactComponent:
"@svgr/webpack?-svgo,+titleProp,+ref![path]",
},
},
},
],
],
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
// See #6846 for context on why cacheCompression is disabled
cacheCompression: false,
compact: isEnvProduction,
},
},
// Process any JS outside of the app with Babel.
// Unlike the application JS, we only compile the standard ES features.
{
test: /\.(js|mjs)$/,
exclude: /@babel(?:\/|\\{1,2})runtime/,
loader: require.resolve("babel-loader"),
options: {
babelrc: false,
configFile: false,
compact: false,
presets: [
[
require.resolve("babel-preset-react-app/dependencies"),
{ helpers: true },
],
],
cacheDirectory: true,
// See #6846 for context on why cacheCompression is disabled
cacheCompression: false,
// Babel sourcemaps are needed for debugging into node_modules
// code. Without the options below, debuggers like VSCode
// show incorrect code and set breakpoints on the wrong lines.
sourceMaps: shouldUseSourceMap,
inputSourceMap: shouldUseSourceMap,
},
},
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use MiniCSSExtractPlugin to extract that CSS
// to a file, but in development "style" loader enables hot editing
// of CSS.
// By default we support CSS Modules with the extension .module.css
{
test: cssRegex,
exclude: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap,
}),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true,
},
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
// using the extension .module.css
{
test: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap,
modules: {
getLocalIdent: getCSSModuleLocalIdent,
},
}),
},
// Opt-in support for SASS (using .scss or .sass extensions).
// By default we support SASS Modules with the
// extensions .module.scss or .module.sass
{
test: sassRegex,
exclude: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction && shouldUseSourceMap,
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
}
),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true,
},
// Adds support for CSS Modules, but using SASS
// using the extension .module.scss or .module.sass
{
test: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction && shouldUseSourceMap,
modules: {
getLocalIdent: getCSSModuleLocalIdent,
},
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
}
),
},
// less-loader by zicla
{
test: lessRegex,
exclude: lessModuleRegex,
use: getStyleLoaders(
{
importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap,
},
{
loader: "less-loader",
options: {
sourceMap: true,
lessOptions: {
modifyVars: {
'primary-color': '#215891',
},
javascriptEnabled: true,
}
},
}
),
sideEffects: true,
},
// less-loader by zicla
{
test: lessModuleRegex,
use: getStyleLoaders(
{
importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap,
modules: true,
getLocalIdent: getCSSModuleLocalIdent,
},
{
loader: "less-loader",
options: {
sourceMap: true,
lessOptions: {
modifyVars: {
'primary-color': '#215891',
},
javascriptEnabled: true,
}
},
}
),
},
// "file" loader makes sure those assets get served by WebpackDevServer.
// When you `import` an asset, you get its (virtual) filename.
// In production, they would get copied to the `build` folder.
// This loader doesn't use a "test" so it will catch all modules
// that fall through the other loaders.
{
loader: require.resolve("file-loader"),
// Exclude `js` files to keep "css" loader working as it injects
// its runtime that would otherwise be processed through "file" loader.
// Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders.
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
options: {
name: "static/media/[name].[hash:8].[ext]",
},
},
// ** STOP ** Are you adding a new loader?
// Make sure to add the new loader(s) before the "file" loader.
],
},
],
},
plugins: [
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appHtml,
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
),
// Inlines the webpack runtime script. This script is too small to warrant
// a network request.
// https://github.com/facebook/create-react-app/issues/5358
isEnvProduction &&
shouldInlineRuntimeChunk &&
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
// It will be an empty string unless you specify "homepage"
// in `package.json`, in which case it will be the pathname of that URL.
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
// This gives some necessary context to module not found errors, such as
// the requesting resource.
new ModuleNotFoundPlugin(paths.appPath),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
// It is absolutely essential that NODE_ENV is set to production
// during a production build.
// Otherwise React will be compiled in the very slow development mode.
new webpack.DefinePlugin(env.stringified),
// This is necessary to emit hot updates (currently CSS only):
isEnvDevelopment && new webpack.HotModuleReplacementPlugin(),
// Watcher doesn't work well if you mistype casing in a path so we use
// a plugin that prints an error when you attempt to do this.
// See https://github.com/facebook/create-react-app/issues/240
isEnvDevelopment && new CaseSensitivePathsPlugin(),
// If you require a missing module and then `npm install` it, you still have
// to restart the development server for webpack to discover it. This plugin
// makes the discovery automatic so you don't have to restart.
// See https://github.com/facebook/create-react-app/issues/186
isEnvDevelopment &&
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
isEnvProduction &&
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "static/css/[name].[contenthash:8].css",
chunkFilename: "static/css/[name].[contenthash:8].chunk.css",
}),
// Generate an asset manifest file with the following content:
// - "files" key: Mapping of all asset filenames to their corresponding
// output file so that tools can pick it up without having to parse
// `index.html`
// - "entrypoints" key: Array of files which are included in `index.html`,
// can be used to reconstruct the HTML if necessary
new ManifestPlugin({
fileName: "asset-manifest.json",
publicPath: paths.publicUrlOrPath,
generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => {
manifest[file.name] = file.path;
return manifest;
}, seed);
const entrypointFiles = entrypoints.main.filter(
(fileName) => !fileName.endsWith(".map")
);
return {
files: manifestFiles,
entrypoints: entrypointFiles,
};
},
}),
// Moment.js is an extremely popular library that bundles large locale files
// by default due to how webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales.
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// TypeScript type checking
useTypeScript &&
new ForkTsCheckerWebpackPlugin({
typescript: resolve.sync("typescript", {
basedir: paths.appNodeModules,
}),
async: isEnvDevelopment,
useTypescriptIncrementalApi: true,
checkSyntacticErrors: true,
resolveModuleNameModule: process.versions.pnp
? `${__dirname}/pnpTs.js`
: undefined,
resolveTypeReferenceDirectiveModule: process.versions.pnp
? `${__dirname}/pnpTs.js`
: undefined,
tsconfig: paths.appTsConfig,
reportFiles: [
"**",
"!**/__tests__/**",
"!**/?(*.)(spec|test).*",
"!**/src/setupProxy.*",
"!**/src/setupTests.*",
],
silent: true,
// The formatter is invoked directly in WebpackDevServerUtils during development
formatter: isEnvProduction ? typescriptFormatter : undefined,
}),
].filter(Boolean),
// Some libraries import Node modules but don't use them in the browser.
// Tell webpack to provide empty mocks for them so importing them works.
node: {
module: "empty",
dgram: "empty",
dns: "mock",
fs: "empty",
http2: "empty",
net: "empty",
tls: "empty",
child_process: "empty",
},
// Turn off performance processing because we utilize
// our own hints via the FileSizeReporter
performance: false,
};
};
+130
View File
@@ -0,0 +1,130 @@
'use strict';
const fs = require('fs');
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
const ignoredFiles = require('react-dev-utils/ignoredFiles');
const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
const paths = require('./paths');
const getHttpsConfig = require('./getHttpsConfig');
const host = process.env.HOST || '0.0.0.0';
const sockHost = process.env.WDS_SOCKET_HOST;
const sockPath = process.env.WDS_SOCKET_PATH; // default: '/sockjs-node'
const sockPort = process.env.WDS_SOCKET_PORT;
module.exports = function(proxy, allowedHost) {
return {
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
// websites from potentially accessing local content through DNS rebinding:
// https://github.com/webpack/webpack-dev-server/issues/887
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
// However, it made several existing use cases such as development in cloud
// environment or subdomains in development significantly more complicated:
// https://github.com/facebook/create-react-app/issues/2271
// https://github.com/facebook/create-react-app/issues/2233
// While we're investigating better solutions, for now we will take a
// compromise. Since our WDS configuration only serves files in the `public`
// folder we won't consider accessing them a vulnerability. However, if you
// use the `proxy` feature, it gets more dangerous because it can expose
// remote code execution vulnerabilities in backends like Django and Rails.
// So we will disable the host check normally, but enable it if you have
// specified the `proxy` setting. Finally, we let you override it if you
// really know what you're doing with a special environment variable.
disableHostCheck:
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true',
// Enable gzip compression of generated files.
compress: true,
// Silence WebpackDevServer's own logs since they're generally not useful.
// It will still show compile warnings and errors with this setting.
clientLogLevel: 'none',
// By default WebpackDevServer serves physical files from current directory
// in addition to all the virtual build products that it serves from memory.
// This is confusing because those files won’t automatically be available in
// production build folder unless we copy them. However, copying the whole
// project directory is dangerous because we may expose sensitive files.
// Instead, we establish a convention that only files in `public` directory
// get served. Our build script will copy `public` into the `build` folder.
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
// Note that we only recommend to use `public` folder as an escape hatch
// for files like `favicon.ico`, `manifest.json`, and libraries that are
// for some reason broken when imported through webpack. If you just want to
// use an image, put it in `src` and `import` it from JavaScript instead.
contentBase: paths.appPublic,
contentBasePublicPath: paths.publicUrlOrPath,
// By default files from `contentBase` will not trigger a page reload.
watchContentBase: true,
// Enable hot reloading server. It will provide WDS_SOCKET_PATH endpoint
// for the WebpackDevServer client so it can learn when the files were
// updated. The WebpackDevServer client is included as an entry point
// in the webpack development configuration. Note that only changes
// to CSS are currently hot reloaded. JS changes will refresh the browser.
hot: true,
// Use 'ws' instead of 'sockjs-node' on server since we're using native
// websockets in `webpackHotDevClient`.
transportMode: 'ws',
// Prevent a WS client from getting injected as we're already including
// `webpackHotDevClient`.
injectClient: false,
// Enable custom sockjs pathname for websocket connection to hot reloading server.
// Enable custom sockjs hostname, pathname and port for websocket connection
// to hot reloading server.
sockHost,
sockPath,
sockPort,
// It is important to tell WebpackDevServer to use the same "publicPath" path as
// we specified in the webpack config. When homepage is '.', default to serving
// from the root.
// remove last slash so user can land on `/test` instead of `/test/`
publicPath: paths.publicUrlOrPath.slice(0, -1),
// WebpackDevServer is noisy by default so we emit custom message instead
// by listening to the compiler events with `compiler.hooks[...].tap` calls above.
quiet: true,
// Reportedly, this avoids CPU overload on some systems.
// https://github.com/facebook/create-react-app/issues/293
// src/node_modules is not ignored to support absolute imports
// https://github.com/facebook/create-react-app/issues/1065
watchOptions: {
ignored: ignoredFiles(paths.appSrc),
},
https: getHttpsConfig(),
host,
overlay: false,
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebook/create-react-app/issues/387.
disableDotRule: true,
index: paths.publicUrlOrPath,
},
public: allowedHost,
// `proxy` is run between `before` and `after` `webpack-dev-server` hooks
proxy,
before(app, server) {
// Keep `evalSourceMapMiddleware` and `errorOverlayMiddleware`
// middlewares before `redirectServedPath` otherwise will not have any effect
// This lets us fetch source contents from webpack for the error overlay
app.use(evalSourceMapMiddleware(server));
// This lets us open files from the runtime error overlay.
app.use(errorOverlayMiddleware());
if (fs.existsSync(paths.proxySetup)) {
// This registers user provided middleware for proxy reasons
require(paths.proxySetup)(app);
}
},
after(app) {
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match
app.use(redirectServedPath(paths.publicUrlOrPath));
// This service worker file is effectively a 'no-op' that will reset any
// previous service worker registered for the same host:port combination.
// We do this in development to avoid hitting the production cache if
// it used the same host and port.
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath));
},
};
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

-33
View File
@@ -1,33 +0,0 @@
## change default port to 6015
create file `vue.config.js` next to `package.json`
```js
module.exports = {
devServer: {
port: 6015
}
}
```
## Add less support
npm install -D less-loader less
## Add http proxy
```
module.exports = {
devServer: {
proxy: {
'/api': {
//target: 'https://tank.eyeblue.cn',
target: 'http://127.0.0.1:6010',
changeOrigin: true,
pathRewrite: {
'^/api': '/api'
}
}
}
}
}
```
-12310
View File
File diff suppressed because it is too large Load Diff
+96 -73
View File
@@ -1,79 +1,102 @@
{
"name": "EyeblueTank",
"version": "0.1.0",
"name": "tank-front",
"version": "3.1.2",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"animate.css": "^3.7.0",
"babel-polyfill": "^6.26.0",
"bootstrap": "^3.4.1",
"clipboard": "^2.0.4",
"core-js": "^2.6.5",
"echarts": "^4.2.1",
"element-ui": "^2.8.2",
"enquire.js": "^2.1.6",
"font-awesome": "^4.7.0",
"icheck": "^1.0.2",
"jquery": "^3.4.1",
"js-cookie": "^2.2.0",
"perfect-scrollbar": "^1.4.0",
"swiper": "^4.5.0",
"velocity-animate": "^1.5.2",
"vue": "^2.6.10",
"vue-echarts": "^4.0.2",
"vue-i18n": "^8.11.2",
"vue-multiselect": "^2.1.6",
"vue-nprogress": "^0.1.5",
"vue-resource": "^1.5.1",
"vue-router": "^3.0.6",
"vuex": "^3.1.1",
"vuex-router-sync": "^5.0.0",
"x-photoswipe": "^4.1.3-rc.1"
"@ant-design/icons": "4.2.1",
"pretty-format": "25.5.0",
"@types/echarts": "^4.6.1",
"@types/photoswipe": "^4.1.0",
"antd": "4.4.3",
"axios": "^0.19.2",
"camelcase": "^5.3.1",
"comma-separated-values": "^3.6.4",
"dotenv": "8.2.0",
"dotenv-expand": "5.1.0",
"echarts": "^4.8.0",
"echarts-for-react": "^2.0.16",
"fs-extra": "^8.1.0",
"identity-obj-proxy": "3.0.0",
"photoswipe": "^4.1.3",
"qs": "^6.9.4",
"react": "^16.13.1",
"react-app-polyfill": "^1.0.6",
"react-dev-utils": "^10.2.1",
"react-dom": "^16.13.1",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"semver": "6.3.0",
"ts-pnp": "1.1.6",
"velocity-react": "^1.4.3"
},
"scripts": {
"start": "node scripts/start.js",
"build": "node scripts/build.js"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"babel": {
"presets": [
"react-app"
],
"plugins": [
[
"import",
{
"libraryName": "antd",
"style": true
},
"antd"
]
]
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.7.0",
"@vue/cli-plugin-eslint": "^3.7.0",
"@vue/cli-service": "^3.7.0",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.16.0",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-html": "^5.0.5",
"eslint-plugin-import": "^2.17.2",
"eslint-plugin-node": "^9.0.1",
"eslint-plugin-promise": "^4.1.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^5.0.0",
"less": "^3.9.0",
"less-loader": "^5.0.0",
"vue-template-compiler": "^2.5.21"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended",
"@vue/standard"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions"
]
"@babel/core": "7.9.0",
"@svgr/webpack": "4.3.3",
"@types/node": "^12.0.0",
"@types/qs": "^6.9.3",
"@types/react": "^16.9.0",
"@types/react-dom": "^16.9.0",
"@types/react-router-dom": "^5.1.5",
"@types/react-transition-group": "^4.4.0",
"babel-loader": "8.1.0",
"babel-plugin-import": "^1.13.0",
"babel-plugin-named-asset-import": "^0.3.6",
"babel-preset-react-app": "^9.1.2",
"case-sensitive-paths-webpack-plugin": "2.3.0",
"css-loader": "3.4.2",
"file-loader": "4.3.0",
"html-webpack-plugin": "4.0.0-beta.11",
"less": "^3.11.2",
"less-loader": "^6.1.0",
"mini-css-extract-plugin": "0.9.0",
"optimize-css-assets-webpack-plugin": "5.0.3",
"pnp-webpack-plugin": "1.6.4",
"postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0",
"postcss-normalize": "8.0.1",
"postcss-preset-env": "6.7.0",
"postcss-safe-parser": "4.0.1",
"prettier": "^2.0.5",
"resolve": "1.15.0",
"resolve-url-loader": "3.1.1",
"sass-loader": "8.0.2",
"style-loader": "0.23.1",
"terser-webpack-plugin": "2.3.5",
"typescript": "~3.7.2",
"url-loader": "2.3.0",
"webpack": "4.42.0",
"webpack-dev-server": "3.10.3",
"webpack-manifest-plugin": "2.2.0"
}
}
+10 -9
View File
@@ -1,17 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="eyeblue tank"
/>
<title>EyeblueTank</title>
</head>
<body>
<noscript>
<strong>We're sorry but tank-front-tmp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<noscript>You need to enable JavaScript to run EyeblueTank.</noscript>
<div id="root"></div>
</body>
</html>
+211
View File
@@ -0,0 +1,211 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const path = require('path');
const chalk = require('react-dev-utils/chalk');
const fs = require('fs-extra');
const webpack = require('webpack');
const configFactory = require('../config/webpack.config');
const paths = require('../config/paths');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
const printBuildError = require('react-dev-utils/printBuildError');
const measureFileSizesBeforeBuild =
FileSizeReporter.measureFileSizesBeforeBuild;
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
const useYarn = fs.existsSync(paths.yarnLockFile);
// These sizes are pretty large. We'll warn for bundles exceeding them.
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Generate configuration
const config = configFactory('production');
// We require that you explicitly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// First, read the current file sizes in build directory.
// This lets us display how much they changed later.
return measureFileSizesBeforeBuild(paths.appBuild);
})
.then(previousFileSizes => {
// Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash
fs.emptyDirSync(paths.appBuild);
// Merge with the public folder
copyPublicFolder();
// Start the webpack build
return build(previousFileSizes);
})
.then(
({ stats, previousFileSizes, warnings }) => {
if (warnings.length) {
console.log(chalk.yellow('Compiled with warnings.\n'));
console.log(warnings.join('\n\n'));
console.log(
'\nSearch for the ' +
chalk.underline(chalk.yellow('keywords')) +
' to learn more about each warning.'
);
console.log(
'To ignore, add ' +
chalk.cyan('// eslint-disable-next-line') +
' to the line before.\n'
);
} else {
console.log(chalk.green('Compiled successfully.\n'));
}
console.log('File sizes after gzip:\n');
printFileSizesAfterBuild(
stats,
previousFileSizes,
paths.appBuild,
WARN_AFTER_BUNDLE_GZIP_SIZE,
WARN_AFTER_CHUNK_GZIP_SIZE
);
console.log();
const appPackage = require(paths.appPackageJson);
const publicUrl = paths.publicUrlOrPath;
const publicPath = config.output.publicPath;
const buildFolder = path.relative(process.cwd(), paths.appBuild);
printHostingInstructions(
appPackage,
publicUrl,
publicPath,
buildFolder,
useYarn
);
},
err => {
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
if (tscCompileOnError) {
console.log(
chalk.yellow(
'Compiled with the following type errors (you may want to check these before deploying your app):\n'
)
);
printBuildError(err);
} else {
console.log(chalk.red('Failed to compile.\n'));
printBuildError(err);
process.exit(1);
}
}
)
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
// Create the production build and print the deployment instructions.
function build(previousFileSizes) {
// We used to support resolving modules according to `NODE_PATH`.
// This now has been deprecated in favor of jsconfig/tsconfig.json
// This lets you use absolute paths in imports inside large monorepos:
if (process.env.NODE_PATH) {
console.log(
chalk.yellow(
'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.'
)
);
console.log();
}
console.log('Creating an optimized production build...');
const compiler = webpack(config);
return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
let messages;
if (err) {
if (!err.message) {
return reject(err);
}
let errMessage = err.message;
// Add additional information for postcss errors
if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
errMessage +=
'\nCompileError: Begins at CSS selector ' +
err['postcssNode'].selector;
}
messages = formatWebpackMessages({
errors: [errMessage],
warnings: [],
});
} else {
messages = formatWebpackMessages(
stats.toJson({ all: false, warnings: true, errors: true })
);
}
if (messages.errors.length) {
// Only keep the first error. Others are often indicative
// of the same problem, but confuse the reader with noise.
if (messages.errors.length > 1) {
messages.errors.length = 1;
}
return reject(new Error(messages.errors.join('\n\n')));
}
if (
process.env.CI &&
(typeof process.env.CI !== 'string' ||
process.env.CI.toLowerCase() !== 'false') &&
messages.warnings.length
) {
console.log(
chalk.yellow(
'\nTreating warnings as errors because process.env.CI = true.\n' +
'Most CI servers set it automatically.\n'
)
);
return reject(new Error(messages.warnings.join('\n\n')));
}
return resolve({
stats,
previousFileSizes,
warnings: messages.warnings,
});
});
});
}
function copyPublicFolder() {
fs.copySync(paths.appPublic, paths.appBuild, {
dereference: true,
filter: file => file !== paths.appHtml,
});
}
+166
View File
@@ -0,0 +1,166 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const fs = require('fs');
const chalk = require('react-dev-utils/chalk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const {
choosePort,
createCompiler,
prepareProxy,
prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const paths = require('../config/paths');
const configFactory = require('../config/webpack.config');
const createDevServerConfig = require('../config/webpackDevServer.config');
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 6015;
const HOST = process.env.HOST || '0.0.0.0';
if (process.env.HOST) {
console.log(
chalk.cyan(
`Attempting to bind to HOST environment variable: ${chalk.yellow(
chalk.bold(process.env.HOST)
)}`
)
);
console.log(
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
);
console.log(
`Learn more here: ${chalk.yellow('https://bit.ly/CRA-advanced-config')}`
);
console.log();
}
// We require that you explicitly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `choosePort()` Promise resolves to the next free port.
return choosePort(HOST, DEFAULT_PORT);
})
.then(port => {
if (port == null) {
// We have not found a port.
return;
}
const config = configFactory('development');
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const useTypeScript = fs.existsSync(paths.appTsConfig);
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
const urls = prepareUrls(
protocol,
HOST,
port,
paths.publicUrlOrPath.slice(0, -1)
);
const devSocket = {
warnings: warnings =>
devServer.sockWrite(devServer.sockets, 'warnings', warnings),
errors: errors =>
devServer.sockWrite(devServer.sockets, 'errors', errors),
};
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler({
appName,
config,
devSocket,
urls,
useYarn,
useTypeScript,
tscCompileOnError,
webpack,
});
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
const proxyConfig = prepareProxy(
proxySetting,
paths.appPublic,
paths.publicUrlOrPath
);
// Serve webpack assets generated by the compiler over a web server.
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
const devServer = new WebpackDevServer(compiler, serverConfig);
// Launch WebpackDevServer.
devServer.listen(port, HOST, err => {
if (err) {
return console.log(err);
}
if (isInteractive) {
clearConsole();
}
// We used to support resolving modules according to `NODE_PATH`.
// This now has been deprecated in favor of jsconfig/tsconfig.json
// This lets you use absolute paths in imports inside large monorepos:
if (process.env.NODE_PATH) {
console.log(
chalk.yellow(
'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.'
)
);
console.log();
}
console.log(chalk.cyan('Starting the development server...\n'));
openBrowser(urls.localUrlForBrowser);
});
['SIGINT', 'SIGTERM'].forEach(function(sig) {
process.on(sig, function() {
devServer.close();
process.exit();
});
});
if (isInteractive || process.env.CI !== 'true') {
// Gracefully exit when stdin ends
process.stdin.on('end', function() {
devServer.close();
process.exit();
});
process.stdin.resume();
}
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
+53
View File
@@ -0,0 +1,53 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const jest = require('jest');
const execSync = require('child_process').execSync;
let argv = process.argv.slice(2);
function isInGitRepository() {
try {
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
function isInMercurialRepository() {
try {
execSync('hg --cwd . root', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
// Watch unless on CI or explicitly running all tests
if (
!process.env.CI &&
argv.indexOf('--watchAll') === -1 &&
argv.indexOf('--watchAll=false') === -1
) {
// https://github.com/facebook/create-react-app/issues/5210
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
argv.push(hasSourceControl ? '--watch' : '--watchAll');
}
jest.run(argv);
+2
View File
@@ -0,0 +1,2 @@
//import global style.
@import './assets/css/index.less';
+20
View File
@@ -0,0 +1,20 @@
import React from 'react';
import {BrowserRouter as Router} from "react-router-dom";
import {ConfigProvider} from 'antd';
import Frame from "./pages/Frame";
import en_US from 'antd/es/locale/en_US';
// global less 须放在Frame组件之后,不然会出现按需加载的less文件覆盖样式问题
import './App.less';
function App() {
return (
<Router>
<ConfigProvider locale={en_US}>
<Frame/>
</ConfigProvider>
</Router>
);
}
export default App;
-97
View File
@@ -1,97 +0,0 @@
<template>
<div class="nb-app">
<NprogressContainer/>
<router-view/>
</div>
</template>
<script>
import NprogressContainer from 'vue-nprogress/src/NprogressContainer'
export default {
data() {
return {
preference: this.$store.state.preference
}
},
computed: {},
components: {
NprogressContainer
},
mounted() {
let that = this
this.preference.httpFetch()
}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "~font-awesome/css/font-awesome.css";
@import "./assets/css/app.less";
.nb-app {
height: 100%;
.nprogress-container {
position: fixed !important;
width: 100%;
height: 150px;
z-index: 2048;
pointer-events: none;
#nprogress {
//@color: #48e79a;
@color: #1ab394;
.bar {
background: @color;
}
.peg {
box-shadow: 0 0 10px @color, 0 0 5px @color;
}
.spinner-icon {
border-top-color: @color;
border-left-color: @color;
}
}
}
//所有的滚动条样式
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track-piece {
background-color: #eee;
margin: -2px;
}
::-webkit-scrollbar-thumb {
background: #aaa;
min-height: 150px;
min-width: 150px;
border-radius: 10px;
}
::-webkit-scrollbar-thumb:vertical:hover {
background: #555555
}
::-webkit-scrollbar-thumb:horizontal:hover {
background: #555555
}
}
</style>
-169
View File
@@ -1,169 +0,0 @@
//global css.
//Include font-awesome
//Include what we need in bootstrap.
@import "bootstrap/bootstrap.less";
@import "inspinia/style.less";
//Animated
@import "~animate.css/animate.min.css";
//element-ui
@import "~element-ui/lib/theme-chalk/index.css";
//使用自定义的主题
@import "global/border.less";
@import "global/button.less";
@import "global/color.less";
@import "global/font.less";
@import "global/layout.less";
@import "global/miscellaneous.less";
@import "global/responsive.less";
//h2被污染了
.el-notification__title {
margin-top: 0;
}
.el-dialog__wrapper {
.el-dialog__body {
padding: 0 20px 20px 20px;
}
}
//手机端的弹出框太大了
@media (max-width: 768px) {
.el-message-box__wrapper {
.el-message-box {
width: 90%;
}
}
.el-dialog__wrapper {
.el-dialog {
width: 90%;
}
}
}
html, body {
font-family: "微软雅黑", Microsoft YaHei, "Helvetica Neue", Helvetica, Arial, sans-serif, "open sans";
font-size: 13px;
color: @text-color;
background-color: white;
img {
max-width: 100%;
}
}
//列表单元格的样式。
.nb-app {
//media-body下的p字体大小
.media-body {
p {
font-size: 13px;
}
}
.cell-title {
font-size: 17px;
color: @app-color-title;
.one-line;
a {
font-size: 17px;
color: @app-color-title;
&:hover {
color: @brand-primary;
}
}
}
.cell-content {
font-size: 12px;
color: @app-color-title;
letter-spacing: 0;
line-height: 18px;
}
.cell-description {
font-size: 12px;
color: @app-color-content;
letter-spacing: 0;
line-height: 24px;
}
}
//超链接颜色.
a {
color: @brand-primary;
&:hover, &:focus {
color: @brand-info;
}
}
//段落统一样式
p {
color: #333;
font-size: 15px;
padding: 0;
}
//每个页面导航处样式
.pedia-navigation {
margin-bottom: 10px;
border-bottom: 1px solid #E6E6E6;
position: relative;
.item {
font-size: 16px;
color: #778195;
margin-top: 15px;
margin-right: 20px;
display: inline-block;
box-sizing: content-box;
line-height: 30px;
&:hover, &.is-link-active, &.active {
color: @brand-primary;
border-bottom: 2px solid @brand-primary;
}
}
.tool {
position: absolute;
right: 0;
bottom: 5px;
display: inline-block;
}
}
//markdown中默认图片剧中
p {
> img {
text-align: center;
}
}
//列表页中展开的标准样式
.form-info {
margin-bottom: 10px;
> span:first-child:not(.label) {
width: 150px;
color: #99a9bf;
font-size: 15px;
font-weight: bold;
}
> span:last-child:not(.label) {
font-size: 15px;
}
}
-54
View File
@@ -1,54 +0,0 @@
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
// Core variables and mixins
@import "../global/variables.less";
@import "~bootstrap/less/mixins.less";
// Reset and dependencies
@import "~bootstrap/less/normalize.less";
@import "~bootstrap/less/print.less";
//We DO NOT use bootstrap's icon. We use font-awesome
//@import "~bootstrap/less/glyphicons.less";
// Core CSS
@import "~bootstrap/less/scaffolding.less";
@import "~bootstrap/less/type.less";
@import "~bootstrap/less/code.less";
@import "~bootstrap/less/grid.less";
@import "~bootstrap/less/tables.less";
@import "~bootstrap/less/forms.less";
@import "~bootstrap/less/buttons.less";
// Components
@import "~bootstrap/less/component-animations.less";
@import "~bootstrap/less/dropdowns.less";
@import "~bootstrap/less/button-groups.less";
@import "~bootstrap/less/input-groups.less";
@import "~bootstrap/less/navs.less";
@import "~bootstrap/less/navbar.less";
@import "~bootstrap/less/breadcrumbs.less";
@import "~bootstrap/less/pagination.less";
@import "~bootstrap/less/pager.less";
@import "~bootstrap/less/labels.less";
@import "~bootstrap/less/badges.less";
@import "~bootstrap/less/jumbotron.less";
@import "~bootstrap/less/thumbnails.less";
@import "~bootstrap/less/alerts.less";
@import "~bootstrap/less/progress-bars.less";
@import "~bootstrap/less/media.less";
@import "~bootstrap/less/list-group.less";
@import "~bootstrap/less/panels.less";
@import "~bootstrap/less/responsive-embed.less";
@import "~bootstrap/less/wells.less";
@import "~bootstrap/less/close.less";
// Components w/ JavaScript
@import "~bootstrap/less/modals.less";
@import "~bootstrap/less/tooltip.less";
@import "~bootstrap/less/popovers.less";
@import "~bootstrap/less/carousel.less";
// Utility classes
@import "~bootstrap/less/utilities.less";
@import "~bootstrap/less/responsive-utilities.less";
+15 -19
View File
@@ -14,14 +14,11 @@
@gray-light: lighten(@gray-base, 46.7%); // #777
@gray-lighter: lighten(@gray-base, 93.5%); // #eee
//zhengxianqian Theme.
@brand-primary: #23B7E5;
@brand-success: #1ab394;
@brand-info: #5EC1C5;
@brand-warning: #FEC62E;
@brand-danger: #FE8768;
@brand-gray: #c2c2c2;
@brand-laxative: #B3EE3A;
@brand-primary: darken(#428bca, 6.5%); // #337ab7
@brand-success: #5cb85c;
@brand-info: #5bc0de;
@brand-warning: #f0ad4e;
@brand-danger: #d9534f;
//== Scaffolding
@@ -109,9 +106,9 @@
@border-radius-large: 6px;
@border-radius-small: 3px;
//** Global color for active items (e.g., navs or dropdowns).
//** Global color for active pendants (e.g., navs or dropdowns).
@component-active-color: #fff;
//** Global background color for active items (e.g., navs or dropdowns).
//** Global background color for active pendants (e.g., navs or dropdowns).
@component-active-bg: @brand-primary;
//** Width of the `border` for generating carets that indicate dropdowns.
@@ -193,7 +190,6 @@
//** `<input>` border color
@input-border: #ccc;
// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4
//** Default `.form-control` border radius
// This has no effect on `<select>`s in some browsers, due to the limited stylability of `<select>`s in CSS.
@input-border-radius: @border-radius-base;
@@ -240,7 +236,7 @@
@dropdown-border: rgba(0,0,0,.15);
//** Dropdown menu `border-color` **for IE8**.
@dropdown-fallback-border: #ccc;
//** Divider color for between dropdown items.
//** Divider color for between dropdown pendants.
@dropdown-divider-bg: #e5e5e5;
//** Dropdown link text color.
@@ -678,22 +674,22 @@
//** List group border radius
@list-group-border-radius: @border-radius-base;
//** Background color of single list items on hover
//** Background color of single list pendants on hover
@list-group-hover-bg: #f5f5f5;
//** Text color of active list items
//** Text color of active list pendants
@list-group-active-color: @component-active-color;
//** Background color of active list items
//** Background color of active list pendants
@list-group-active-bg: @component-active-bg;
//** Border color of active list elements
@list-group-active-border: @list-group-active-bg;
//** Text color for content within active list items
//** Text color for content within active list pendants
@list-group-active-text-color: lighten(@list-group-active-bg, 40%);
//** Text color of disabled list items
//** Text color of disabled list pendants
@list-group-disabled-color: @gray-light;
//** Background color of disabled list items
//** Background color of disabled list pendants
@list-group-disabled-bg: @gray-lighter;
//** Text color for content within disabled list items
//** Text color for content within disabled list pendants
@list-group-disabled-text-color: @list-group-disabled-color;
@list-group-link-color: #555;
+1 -1
View File
@@ -36,6 +36,6 @@
}
.border-bottom {
border-bottom: 1px solid #eee;
border-bottom: 1px solid #F9F9F9;
}
+72 -20
View File
@@ -1,31 +1,83 @@
@import "variables";
.btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
white-space: nowrap;
vertical-align: middle;
-ms-touch-action: manipulation;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.btn-action {
margin: 0 3px;
display: inline-block;
opacity: 0.85;
-webkit-transition: all 0.1s;
-o-transition: all 0.1s;
transition: all 0.1s;
cursor: pointer;
margin: 0 3px;
display: inline-block;
opacity: 0.85;
-webkit-transition: all 0.1s;
-o-transition: all 0.1s;
transition: all 0.1s;
cursor: pointer;
outline: none;
&:hover {
text-decoration: none;
opacity: 1;
-moz-transform: scale(1.2);
-webkit-transform: scale(1.2);
-o-transform: scale(1.2);
-ms-transform: scale(1.2);
transform: scale(1.2);
}
&:hover {
text-decoration: none;
opacity: 1;
-moz-transform: scale(1.2);
-webkit-transform: scale(1.2);
-o-transform: scale(1.2);
-ms-transform: scale(1.2);
transform: scale(1.2);
}
&:focus {
outline: none;
}
}
.btn-primary {
color: #fff;
background-color: #337ab7;
border-color: #2e6da4;
}
.btn-primary:focus,
.btn-primary.focus {
color: #fff;
background-color: #286090;
border-color: #122b40;
}
.btn-primary:hover {
color: #fff;
background-color: #286090;
border-color: #204d74;
}
.btn-sm {
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
//编辑区域按钮,鼠标一上去按钮变大
.action-buttons {
a {
.btn-action;
}
a {
.btn-action;
}
}
.cursor {
cursor: pointer;
cursor: pointer;
}
+94 -339
View File
@@ -1,358 +1,113 @@
@import "./variables.less";
.bg-primary {
background-color: @brand-primary;
color: white;
}
.bg-primary{ background-color: @brand-primary; color: white;}
.bg-success{ background-color: @brand-success; color: white; }
.bg-info{ background-color: @brand-info; color: white; }
.bg-warning{ background-color: @brand-warning; color: white; }
.bg-danger{ background-color: @brand-danger; color: white; }
.bg-gray{ background-color: @brand-gray; color: white; }
.bg-laxative{ background-color: @brand-laxative; color: white; }
.bg-success {
background-color: @brand-success;
color: white;
}
.bg-info {
background-color: @brand-info;
color: white;
}
.bg-warning {
background-color: @brand-warning;
color: white;
}
.bg-danger {
background-color: @brand-danger;
color: white;
}
.bg-gray {
background-color: @brand-gray;
color: white;
}
.bg-laxative {
background-color: @brand-laxative;
color: white;
}
.text-primary {
color: @brand-primary;
}
.bg-navy {
background-color: #001F3F;
}
.bg-blue {
background-color: #0074D9;
}
.bg-aqua {
background-color: #7FDBFF;
}
.bg-aliceblue {
background-color: aliceblue;
}
.bg-pink {
background-color: pink;
}
.bg-azure {
background-color: azure;
}
.bg-teal {
background-color: #39CCCC;
}
.bg-olive {
background-color: #3D9970;
}
.bg-green {
background-color: #2ECC40;
}
.bg-lime {
background-color: #01FF70;
}
.bg-yellow {
background-color: #FFDC00;
}
.bg-pink {
color: pink;
}
.bg-orange {
background-color: #FF851B;
}
.bg-red {
background-color: #FF4136;
}
.bg-fuchsia {
background-color: #F012BE;
}
.bg-purple {
background-color: #B10DC9;
}
.bg-maroon {
background-color: #85144B;
}
.bg-white {
background-color: #FFFFFF;
}
.bg-gray {
background-color: #AAAAAA;
}
.bg-silver {
background-color: #DDDDDD;
}
.text-primary{ color: @brand-primary;}
.text-success{ color: @brand-success; }
.text-info{ color: @brand-info; }
.text-warning{ color: @brand-warning; }
.text-danger{ color: @brand-danger; }
.text-gray{ color: @brand-gray; }
.text-laxative{ color: @brand-laxative; }
.text-theme { color: @primary-color; }
.bg-navy { background-color: #001F3F;}
.bg-blue { background-color: #0074D9;}
.bg-aqua { background-color: #7FDBFF;}
.bg-aliceblue { background-color: aliceblue;}
.bg-pink { background-color: pink;}
.bg-azure { background-color: azure;}
.bg-teal { background-color: #39CCCC;}
.bg-olive { background-color: #3D9970;}
.bg-green { background-color: #2ECC40;}
.bg-lime { background-color: #01FF70;}
.bg-yellow { background-color: #FFDC00;}
.bg-pink { color: pink; }
.bg-orange { background-color: #FF851B;}
.bg-red { background-color: #FF4136;}
.bg-fuchsia { background-color: #F012BE;}
.bg-purple { background-color: #B10DC9;}
.bg-maroon { background-color: #85144B;}
.bg-white { background-color: #FFFFFF;}
.bg-gray { background-color: #AAAAAA;}
.bg-silver { background-color: #DDDDDD;}
.bg-silver-white {
background-color: #EEEEEE;
background-color: #EEEEEE;
}
.bg-black { background-color: #111111;}
.bg-black {
background-color: #111111;
}
.bg-111{ background-color:#111 }
.bg-222{ background-color:#222 }
.bg-333{ background-color:#333 }
.bg-444{ background-color:#444 }
.bg-555{ background-color:#555 }
.bg-666{ background-color:#666 }
.bg-777{ background-color:#777 }
.bg-888{ background-color:#888 }
.bg-999{ background-color:#999 }
.bg-aaa{ background-color:#aaa }
.bg-bbb{ background-color:#bbb }
.bg-ccc{ background-color:#ccc }
.bg-ddd{ background-color:#ddd }
.bg-eee{ background-color:#eee }
.bg-111 {
background-color: #111
}
.bg-222 {
background-color: #222
}
.bg-333 {
background-color: #333
}
.bg-444 {
background-color: #444
}
.bg-555 {
background-color: #555
}
.bg-666 {
background-color: #666
}
.bg-777 {
background-color: #777
}
.bg-888 {
background-color: #888
}
.bg-999 {
background-color: #999
}
.bg-aaa {
background-color: #aaa
}
.bg-bbb {
background-color: #bbb
}
.bg-ccc {
background-color: #ccc
}
.bg-ddd {
background-color: #ddd
}
.bg-eee {
background-color: #eee
}
/* Colors */
.navy {
color: #001F3F;
}
.navy { color: #001F3F;}
.blue { color: #0074D9;}
.aqua { color: #7FDBFF;}
.teal { color: #39CCCC;}
.olive { color: #3D9970;}
.green { color: #2ECC40;}
.lime { color: #01FF70;}
.yellow { color: #FFDC00;}
.pink { color: pink; }
.orange { color: #FF851B;}
.red { color: #FF4136;}
.fuchsia { color: #F012BE;}
.purple { color: #B10DC9;}
.maroon { color: #85144B;}
.white { color: #FFFFFF;}
.silver { color: #DDDDDD;}
.gray { color: #AAAAAA;}
.black { color: #111111;}
.blue {
color: #0074D9;
}
.aqua {
color: #7FDBFF;
}
.color-111{color:#111}
.color-222{color:#222}
.color-333{color:#333}
.color-444{color:#444}
.color-555{color:#555}
.color-666{color:#666}
.color-777{color:#777}
.color-888{color:#888}
.color-999{color:#999}
.color-aaa{color:#aaa}
.color-bbb{color:#bbb}
.color-ccc{color:#ccc}
.color-ddd{color:#ddd}
.color-eee{color:#eee}
.teal {
color: #39CCCC;
}
.olive {
color: #3D9970;
}
.color-text { color: #660E7A;}
.color-doc { color: #295496;}
.color-xls { color: #1E6C41;}
.color-ppt { color: #D04324;}
.color-pdf { color: #E40B0B;}
.color-audio { color: #5bc0de;}
.color-video { color: #5cb85c;}
.color-image { color: #0074D9;}
.color-archive { color: #4437f2;}
.green {
color: #2ECC40;
}
.color-light-active{ color: #ffc60c;}
.color-light-inactive{ color:#ccc;}
.lime {
color: #01FF70;
}
.yellow {
color: #FFDC00;
}
.pink {
color: pink;
}
.orange {
color: #FF851B;
}
.red {
color: #FF4136;
}
.fuchsia {
color: #F012BE;
}
.purple {
color: #B10DC9;
}
.maroon {
color: #85144B;
}
.white {
color: #FFFFFF;
}
.silver {
color: #DDDDDD;
}
.gray {
color: #AAAAAA;
}
.black {
color: #111111;
}
.color-111 {
color: #111
}
.color-222 {
color: #222
}
.color-333 {
color: #333
}
.color-444 {
color: #444
}
.color-555 {
color: #555
}
.color-666 {
color: #666
}
.color-777 {
color: #777
}
.color-888 {
color: #888
}
.color-999 {
color: #999
}
.color-aaa {
color: #aaa
}
.color-bbb {
color: #bbb
}
.color-ccc {
color: #ccc
}
.color-ddd {
color: #ddd
}
.color-eee {
color: #eee
}
.color-text {
color: #660E7A;
}
.color-doc {
color: #295496;
}
.color-xls {
color: #1E6C41;
}
.color-ppt {
color: #D04324;
}
.color-pdf {
color: #E40B0B;
}
.color-audio {
color: #5bc0de;
}
.color-video {
color: #5cb85c;
}
.color-image {
color: #0074D9;
}
.color-archive {
color: #4437f2;
}
.color-light-active {
color: #ffc60c;
}
.color-light-inactive {
color: #ccc;
}
+87 -76
View File
@@ -1,132 +1,143 @@
#layout{
.margin(@from,@end,@step){
.mX(@f,@e,@s) when (@e >= @f){
.m@{e}{
margin:@e*1px;
/**
全局常用样式定义
使用ml、pt等缩写表示常用的布局方式,数字表示像素值
比如ml10表示margin-left:10px;
*/
#layout {
.margin(@from,@end,@step) {
.mX(@f,@e,@s) when (@e >= @f) {
.m@{e} {
margin: @e*1px;
}
.mt@{e}{
margin-top:@e*1px;
.mt@{e} {
margin-top: @e*1px;
}
.mr@{e}{
margin-right:@e*1px;
.mr@{e} {
margin-right: @e*1px;
}
.mb@{e}{
.mb@{e} {
margin-bottom: @e*1px;
}
.ml@{e}{
.ml@{e} {
margin-left: @e*1px;
}
.mv@{e}{
.mv@{e} {
margin-top: @e*1px;
margin-bottom: @e*1px;
}
.mh@{e}{
.mh@{e} {
margin-left: @e*1px;
margin-right: @e*1px*1px;
}
.mX(@f,@e - @s,@s);
.mX(@f, @e - @s, @s);
}
.mX(@from,@end,@step);
.mX(@from, @end, @step);
}
.padding(@from,@end,@step){
.pX(@f,@e,@s) when (@e >= @f){
.p@{e}{
padding:@e*1px;
.padding(@from,@end,@step) {
.pX(@f,@e,@s) when (@e >= @f) {
.p@{e} {
padding: @e*1px;
}
.pt@{e}{
padding-top:@e*1px;
.pt@{e} {
padding-top: @e*1px;
}
.pr@{e}{
padding-right:@e*1px;
.pr@{e} {
padding-right: @e*1px;
}
.pb@{e}{
.pb@{e} {
padding-bottom: @e*1px;
}
.pl@{e}{
.pl@{e} {
padding-left: @e*1px;
}
.pv@{e}{
.pv@{e} {
padding-top: @e*1px;
padding-bottom: @e*1px;
}
.ph@{e}{
.ph@{e} {
padding-left: @e*1px;
padding-right: @e*1px;
}
.pX(@f,@e - @s,@s);
.pX(@f, @e - @s, @s);
}
.pX(@from,@end,@step);
.pX(@from, @end, @step);
}
.width(@from,@end,@step){
.wX(@f,@e,@s) when (@e >= @f){
.w@{e}{
width:@e*1px;
.width(@from,@end,@step) {
.wX(@f,@e,@s) when (@e >= @f) {
.w@{e} {
width: @e*1px;
}
.w@{e}m{
max-width:@e*1px;
.w@{e}m {
max-width: @e*1px;
}
.w@{e}n{
min-width:@e*1px;
.w@{e}n {
min-width: @e*1px;
}
.w@{e}i{
width:@e*1px!important;
.w@{e}i {
width: @e*1px !important;
}
.wX(@f,@e - @s,@s);
.wX(@f, @e - @s, @s);
}
.wX(@from,@end,@step);
.wX(@from, @end, @step);
}
.height(@from,@end,@step){
.hX(@f,@e,@s) when (@e >= @f){
.h@{e}{
height:@e*1px;
.height(@from,@end,@step) {
.hX(@f,@e,@s) when (@e >= @f) {
.h@{e} {
height: @e*1px;
}
.lh@{e}{
line-height:@e*1px;
.lh@{e} {
line-height: @e*1px;
}
.h@{e}m{
max-height:@e*1px;
.h@{e}m {
max-height: @e*1px;
}
.h@{e}n{
min-height:@e*1px;
.h@{e}n {
min-height: @e*1px;
}
.h@{e}i{
height:@e*1px!important;
.h@{e}i {
height: @e*1px !important;
}
.hX(@f,@e - @s,@s);
.hX(@f, @e - @s, @s);
}
.hX(@from,@end,@step);
.hX(@from, @end, @step);
}
}
.wp20{
width:20%;
.wp20 {
width: 20%;
}
.wp25{
width:25%;
.wp25 {
width: 25%;
}
.wp33{
width:33%;
.wp33 {
width: 33%;
}
.wp100{
width:100%;
.wp100 {
width: 100%;
}
.wp50{
width:50%;
.wp50 {
width: 50%;
}
.hp100{
height:100%;
.hp100 {
height: 100%;
}
.hp50{
.hp50 {
height: 50%;
}
#layout > .margin(20,200,5);
#layout > .margin(0,19,1);
#layout > .padding(20,200,5);
#layout > .padding(0,19,1);
#layout > .width(20,400,10);
#layout > .width(0,19,1);
#layout > .height(20,400,10);
#layout > .height(0,19,1);
#layout > .margin(20, 200, 5);
#layout > .margin(0, 19, 1);
#layout > .padding(20, 200, 5);
#layout > .padding(0, 19, 1);
#layout > .width(20, 400, 5);
#layout > .width(0, 19, 1);
#layout > .height(20, 400, 5);
#layout > .height(0, 19, 1);
+99 -24
View File
@@ -1,3 +1,5 @@
@import "variables";
.compulsory {
&:before {
content: "*";
@@ -21,27 +23,8 @@
}
.btn-file {
overflow: hidden;
position: relative;
vertical-align: middle;
cursor: pointer;
> input {
position: absolute;
top: 0;
right: 0;
margin: 0;
opacity: 0;
filter: alpha(opacity=0);
font-size: 23px;
height: 100%;
width: 100%;
direction: ltr;
cursor: pointer;
}
}
//超出三行使用点点点
.list-text-restriction {
display: -webkit-box;
-webkit-box-orient: vertical;
@@ -67,9 +50,101 @@
overflow: hidden;
}
.tank-box {
//讨厌的outline
a {
outline: none;
&:focus, &:hover, &:active {
outline: none;
}
}
//制造一个手机容器
.mobile-container {
max-width: 400px;
border: 1px solid #eee;
padding: 10px;
margin: 10px auto;
display: block;
background-color: white;
box-shadow: 0 0 5px rgba(0, 0, 0, .2);
border-radius: 5px;
padding: 20px 15px 10px 15px;
}
//按照字母来wrap,不然有些老长老长
.wrap-word {
word-wrap: break-word;
}
.text-left {
text-align: left;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
.display-none {
display: none !important;
}
.pull-right {
float: right !important;
}
.pull-left {
float: left !important;
}
//超链接导航样式
.link {
color: #1890ff;
text-decoration: none;
background-color: transparent;
outline: none;
cursor: pointer;
transition: color 0.3s;
text-decoration-skip: objects;
}
//头像
.avatar-large {
border-radius: 50%;
width: 120px;
height: 120px;
cursor: pointer;
}
.avatar-middle {
border-radius: 50%;
width: 80px;
height: 80px;
cursor: pointer;
}
.avatar-small {
border-radius: 50%;
width: 60px;
height: 60px;
cursor: pointer;
}
.relative {
position: relative;
}
.hot-area {
position: relative;
&:after {
position: absolute;
top: -10px;
right: -10px;
bottom: -10px;
left: -10px;
content: '';
}
}
+11
View File
@@ -0,0 +1,11 @@
//超出三行使用点点点
.line-ellipsis(@rows,@line-height) {
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
position: relative;
line-height: @line-height;
max-height: @line-height * @rows;
-webkit-line-clamp: @rows;
text-overflow: ellipsis;
}
+20 -13
View File
@@ -19,18 +19,25 @@
}
//浏览器滚动条样式
.thin-scrollbar {
::-webkit-scrollbar {
width: 3px;
height: 3px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.3);
}
//滚动条样式
::-webkit-scrollbar {
width: 10px;
height: 10px
}
::-webkit-scrollbar-thumb {
transition: all .3s ease;
border-color: transparent;
background-color: rgba(0, 0, 0, .1);
z-index: 40
}
::-webkit-scrollbar-thumb:hover {
transition: all .3s ease;
background-color: rgba(0, 0, 0, .15)
}
::-webkit-scrollbar-corner {
background-color: #eaeaeb
}
+11 -87
View File
@@ -1,98 +1,22 @@
@import "../bootstrap/variables.less";
//Bootstrap Theme.
//@brand-primary: darken(#428bca, 6.5%); // #337ab7
//@brand-success: #5cb85c;
//@brand-info: #5bc0de;
//@brand-warning: #f0ad4e;
//@brand-danger: #d9534f;
//@brand-gray: #c2c2c2;
//Angulr Theme.
//@brand-primary: #7266ba;
//@brand-info: #23b7e5;
//@brand-success: #27c24c;
//@brand-warning: #fad733;
//@brand-danger: #f05050;
//@brand-light: #edf1f2;
//@brand-dark: #3a3f51;
//@brand-black: #1c2b36;
//@brand-gray: #c2c2c2;
//@brand-laxative: #B3EE3A;
//Inspina Theme.
//@brand-primary: #1ab394;
//@brand-success: #1c84c6;
//@brand-info: #23c6c8;
//@brand-warning: #f8ac59;
//@brand-danger: #ED5565;
//@brand-gray: #c2c2c2;
//@brand-laxative: #B3EE3A;
//zhengxianqian Theme.
//@brand-primary: #23B7E5;
@brand-primary: #006699;
@brand-success: #1ab394;
@brand-info: #5EC1C5;
@brand-warning: #FEC62E;
@brand-danger: #FE8768;
//custom basic color
@brand-primary: #215891;
@brand-success: #67C23A;
@brand-info: #2DB7F5;
@brand-warning: #E6A23C;
@brand-danger: #FF756F;
@brand-gray: #c2c2c2;
@brand-laxative: #B3EE3A;
//主题默认颜色
@primary-color: @brand-primary;
@navy: @brand-primary; // Primary color
@dark-gray: @brand-gray; // Default color
@blue: @brand-success; // Success color
@lazur: @brand-info; // Info color
@yellow: @brand-warning; // Warrning color
@red: @brand-danger; // Danger color
@green: @brand-laxative; // Danger color
@gray-base: #000;
@gray-darker: lighten(@gray-base, 13.5%); // #222
@gray-dark: lighten(@gray-base, 20%); // #333
@gray: lighten(@gray-base, 33.5%); // #555
@gray-light: lighten(@gray-base, 46.7%); // #777
@gray-lighter: lighten(@gray-base, 93.5%); // #eee
// Various colors
@text-color: #676a6c; // Body text
@gray: #f3f3f4; // Background wrapper color
@light-gray: #D1DADE; // Default label, badget
@label-badget-color: #5E5E5E;
@light-blue: #f3f6fb;
// Spiner color and margin
@spin-color: @navy;
@spin-margin: 0 auto;
// IBOX colors ( default panel colors)
@border-color: #e7eaec; // IBox border
@ibox-title-bg: #ffffff; // IBox Background header
@ibox-content-bg: #ffffff; // IBox Background content
//Sidebar width
@sidebar-width: 170px;
// Boxed layout width
@boxed-width: 1200px;
//Border radius for buttons
@btn-border-radius: 3px;
//Navigation
@nav-bg: #2F4050;
@nav-text-color: #a7b1c2;
//左侧菜单宽度
@sidebar-width: 200px;
//顶部导航栏宽度
@top-navigation-height: 45px;
@app-color-title: #474747;
@app-color-content: #8A8A8A;
//上方导航栏高度
@frame-header-height: 80px;
//下方蓝眼云盘高度
@power-footer-height: 40px;
+17
View File
@@ -0,0 +1,17 @@
//使用自定义的主题
@import "global/animation";
@import "global/border";
@import "global/button";
@import "global/color";
@import "global/font";
@import "global/layout";
@import "global/miscellaneous";
@import "global/responsive";
html, body {
font-family: "微软雅黑", Microsoft YaHei, "Helvetica Neue", Helvetica, Arial, sans-serif, "open sans";
font-size: 13px;
color: @text-color;
}
@@ -1,72 +0,0 @@
.label {
background-color: @light-gray;
color: @label-badget-color;
font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 10px;
font-weight: 600;
padding: 3px 8px;
text-shadow: none;
}
.badge {
background-color: @light-gray;
color: @label-badget-color;
font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 11px;
font-weight: 600;
padding-bottom: 4px;
padding-left: 6px;
padding-right: 6px;
text-shadow: none;
}
.label-primary, .badge-primary {
background-color: @navy;
color: #FFFFFF;
}
.label-success, .badge-success {
background-color: @blue;
color: #FFFFFF;
}
.label-warning, .badge-warning {
background-color: @yellow;
color: #FFFFFF;
}
.label-warning-light, .badge-warning-light {
background-color: @yellow;
color: #ffffff;
}
.label-danger, .badge-danger {
background-color: @red;
color: #FFFFFF;
}
.label-info, .badge-info {
background-color: @lazur;
color: #FFFFFF;
}
.label-inverse, .badge-inverse {
background-color: #262626;
color: #FFFFFF;
}
.label-laxative, .badge-laxative {
background-color: @green;
color: #FFFFFF;
}
.label-white, .badge-white {
background-color: #FFFFFF;
color: #5E5E5E;
}
.label-white, .badge-disable {
background-color: #2A2E36;
color: #8B91A0;
}
File diff suppressed because it is too large Load Diff
-309
View File
@@ -1,309 +0,0 @@
.btn {
border-radius: @btn-border-radius;
}
.float-e-margins .btn {
margin-bottom: 5px;
}
.btn-w-m {
min-width: 120px;
}
.btn-primary.btn-outline {
color: @navy;
}
.btn-success.btn-outline {
color: @blue;
}
.btn-info.btn-outline {
color: @lazur;
}
.btn-warning.btn-outline {
color: @yellow;
}
.btn-danger.btn-outline {
color: @red;
}
.btn-primary.btn-outline:hover,
.btn-success.btn-outline:hover,
.btn-info.btn-outline:hover,
.btn-warning.btn-outline:hover,
.btn-danger.btn-outline:hover {
color: #fff;
}
.btn-primary {
background-color: @navy;
border-color: @navy;
color: #FFFFFF;
}
.btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, .open .dropdown-toggle.btn-primary, .btn-primary:active:focus, .btn-primary:active:hover, .btn-primary.active:hover, .btn-primary.active:focus {
background-color: darken(@navy, 3%);
border-color: darken(@navy, 3%);
color: #FFFFFF;
}
.btn-primary:active, .btn-primary.active, .open .dropdown-toggle.btn-primary {
background-image: none;
}
.btn-primary.disabled, .btn-primary.disabled:hover, .btn-primary.disabled:focus, .btn-primary.disabled:active, .btn-primary.disabled.active, .btn-primary[disabled], .btn-primary[disabled]:hover, .btn-primary[disabled]:focus, .btn-primary[disabled]:active, .btn-primary.active[disabled], fieldset[disabled] .btn-primary, fieldset[disabled] .btn-primary:hover, fieldset[disabled] .btn-primary:focus, fieldset[disabled] .btn-primary:active, fieldset[disabled] .btn-primary.active {
background-color: lighten(@navy, 4%);
border-color: lighten(@navy, 4%);
}
.btn-success {
background-color: @blue;
border-color: @blue;
color: #FFFFFF;
}
.btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success.active, .open .dropdown-toggle.btn-success, .btn-success:active:focus, .btn-success:active:hover, .btn-success.active:hover, .btn-success.active:focus {
background-color: darken(@blue, 3%);
border-color: darken(@blue, 3%);
color: #FFFFFF;
}
.btn-success:active, .btn-success.active, .open .dropdown-toggle.btn-success {
background-image: none;
}
.btn-success.disabled, .btn-success.disabled:hover, .btn-success.disabled:focus, .btn-success.disabled:active, .btn-success.disabled.active, .btn-success[disabled], .btn-success[disabled]:hover, .btn-success[disabled]:focus, .btn-success[disabled]:active, .btn-success.active[disabled], fieldset[disabled] .btn-success, fieldset[disabled] .btn-success:hover, fieldset[disabled] .btn-success:focus, fieldset[disabled] .btn-success:active, fieldset[disabled] .btn-success.active {
background-color: lighten(@blue, 4%);
border-color: lighten(@blue, 4%);
}
.btn-info {
background-color: @lazur;
border-color: @lazur;
color: #FFFFFF;
}
.btn-info:hover, .btn-info:focus, .btn-info:active, .btn-info.active, .open .dropdown-toggle.btn-info, .btn-info:active:focus, .btn-info:active:hover, .btn-info.active:hover, .btn-info.active:focus {
background-color: darken(@lazur, 3%);
border-color: darken(@lazur, 3%);
color: #FFFFFF;
}
.btn-info:active, .btn-info.active, .open .dropdown-toggle.btn-info {
background-image: none;
}
.btn-info.disabled, .btn-info.disabled:hover, .btn-info.disabled:focus, .btn-info.disabled:active, .btn-info.disabled.active, .btn-info[disabled], .btn-info[disabled]:hover, .btn-info[disabled]:focus, .btn-info[disabled]:active, .btn-info.active[disabled], fieldset[disabled] .btn-info, fieldset[disabled] .btn-info:hover, fieldset[disabled] .btn-info:focus, fieldset[disabled] .btn-info:active, fieldset[disabled] .btn-info.active {
background-color: lighten(@lazur, 4%);
border-color: lighten(@lazur, 4%);
}
.btn-default {
color: inherit;
background: white;
border: 1px solid @border-color;
}
.btn-default:hover, .btn-default:focus, .btn-default:active, .btn-default.active, .open .dropdown-toggle.btn-default, .btn-default:active:focus, .btn-default:active:hover, .btn-default.active:hover, .btn-default.active:focus {
color: inherit;
border: 1px solid #d2d2d2;
}
.btn-default:active, .btn-default.active, .open .dropdown-toggle.btn-default {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15) inset;
}
.btn-default.disabled, .btn-default.disabled:hover, .btn-default.disabled:focus, .btn-default.disabled:active, .btn-default.disabled.active, .btn-default[disabled], .btn-default[disabled]:hover, .btn-default[disabled]:focus, .btn-default[disabled]:active, .btn-default.active[disabled], fieldset[disabled] .btn-default, fieldset[disabled] .btn-default:hover, fieldset[disabled] .btn-default:focus, fieldset[disabled] .btn-default:active, fieldset[disabled] .btn-default.active {
color: #cacaca;
}
.btn-warning {
background-color: @yellow;
border-color: @yellow;
color: #FFFFFF;
}
.btn-warning:hover, .btn-warning:focus, .btn-warning:active, .btn-warning.active, .open .dropdown-toggle.btn-warning, .btn-warning:active:focus, .btn-warning:active:hover, .btn-warning.active:hover, .btn-warning.active:focus {
background-color: darken(@yellow, 3%);
border-color: darken(@yellow, 3%);
color: #FFFFFF;
}
.btn-warning:active, .btn-warning.active, .open .dropdown-toggle.btn-warning {
background-image: none;
}
.btn-warning.disabled, .btn-warning.disabled:hover, .btn-warning.disabled:focus, .btn-warning.disabled:active, .btn-warning.disabled.active, .btn-warning[disabled], .btn-warning[disabled]:hover, .btn-warning[disabled]:focus, .btn-warning[disabled]:active, .btn-warning.active[disabled], fieldset[disabled] .btn-warning, fieldset[disabled] .btn-warning:hover, fieldset[disabled] .btn-warning:focus, fieldset[disabled] .btn-warning:active, fieldset[disabled] .btn-warning.active {
background-color: lighten(@yellow, 4%);
border-color: lighten(@yellow, 4%);
}
.btn-danger {
background-color: @red;
border-color: @red;
color: #FFFFFF;
}
.btn-danger:hover, .btn-danger:focus, .btn-danger:active, .btn-danger.active, .open .dropdown-toggle.btn-danger, .btn-danger:active:focus, .btn-danger:active:hover, .btn-danger.active:hover, .btn-danger.active:focus {
background-color: darken(@red, 3%);
border-color: darken(@red, 3%);
color: #FFFFFF;
}
.btn-danger:active, .btn-danger.active, .open .dropdown-toggle.btn-danger {
background-image: none;
}
.btn-danger.disabled, .btn-danger.disabled:hover, .btn-danger.disabled:focus, .btn-danger.disabled:active, .btn-danger.disabled.active, .btn-danger[disabled], .btn-danger[disabled]:hover, .btn-danger[disabled]:focus, .btn-danger[disabled]:active, .btn-danger.active[disabled], fieldset[disabled] .btn-danger, fieldset[disabled] .btn-danger:hover, fieldset[disabled] .btn-danger:focus, fieldset[disabled] .btn-danger:active, fieldset[disabled] .btn-danger.active {
background-color: lighten(@red, 4%);
border-color: lighten(@red, 4%);
}
.btn-link {
color: inherit;
}
.btn-link:hover, .btn-link:focus, .btn-link:active, .btn-link.active, .open .dropdown-toggle.btn-link {
color: @navy;
text-decoration: none;
}
.btn-link:active, .btn-link.active, .open .dropdown-toggle.btn-link {
background-image: none;
}
.btn-link.disabled, .btn-link.disabled:hover, .btn-link.disabled:focus, .btn-link.disabled:active, .btn-link.disabled.active, .btn-link[disabled], .btn-link[disabled]:hover, .btn-link[disabled]:focus, .btn-link[disabled]:active, .btn-link.active[disabled], fieldset[disabled] .btn-link, fieldset[disabled] .btn-link:hover, fieldset[disabled] .btn-link:focus, fieldset[disabled] .btn-link:active, fieldset[disabled] .btn-link.active {
color: #cacaca;
}
.btn-white {
color: inherit;
background: white;
border: 1px solid @border-color;
}
.btn-white:hover, .btn-white:focus, .btn-white:active, .btn-white.active, .open .dropdown-toggle.btn-white, .btn-white:active:focus, .btn-white:active:hover, .btn-white.active:hover, .btn-white.active:focus {
color: inherit;
border: 1px solid #d2d2d2;
}
.btn-white:active, .btn-white.active {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15) inset;
}
.btn-white:active, .btn-white.active, .open .dropdown-toggle.btn-white {
background-image: none;
}
.btn-white.disabled, .btn-white.disabled:hover, .btn-white.disabled:focus, .btn-white.disabled:active, .btn-white.disabled.active, .btn-white[disabled], .btn-white[disabled]:hover, .btn-white[disabled]:focus, .btn-white[disabled]:active, .btn-white.active[disabled], fieldset[disabled] .btn-white, fieldset[disabled] .btn-white:hover, fieldset[disabled] .btn-white:focus, fieldset[disabled] .btn-white:active, fieldset[disabled] .btn-white.active {
color: #cacaca;
}
.form-control, .form-control:focus, .has-error .form-control:focus, .has-success .form-control:focus, .has-warning .form-control:focus, .navbar-collapse, .navbar-form, .navbar-form-custom .form-control:focus, .navbar-form-custom .form-control:hover, .open .btn.dropdown-toggle, .panel, .popover, .progress, .progress-bar {
box-shadow: none;
}
.btn-outline {
color: inherit;
background-color: transparent;
transition: all .5s;
}
.btn-rounded {
border-radius: 50px;
}
.btn-large-dim {
width: 90px;
height: 90px;
font-size: 42px;
}
button.dim {
display: inline-block;
text-decoration: none;
text-transform: uppercase;
text-align: center;
padding-top: 6px;
margin-right: 10px;
position: relative;
cursor: pointer;
border-radius: 5px;
font-weight: 600;
margin-bottom: 20px !important;
}
button.dim:active {
top: 3px;
}
button.btn-primary.dim {
box-shadow: inset 0 0 0 darken(@navy, 6%), 0 5px 0 0 darken(@navy, 6%), 0 10px 5px #999;
}
button.btn-primary.dim:active {
box-shadow: inset 0 0 0 darken(@navy, 6%), 0 2px 0 0 darken(@navy, 6%), 0 5px 3px #999;
}
button.btn-default.dim {
box-shadow: inset 0 0 0 darken(@dark-gray, 6%), 0 5px 0 0 darken(@dark-gray, 6%), 0 10px 5px #999;
}
button.btn-default.dim:active {
box-shadow: inset 0 0 0 darken(@dark-gray, 6%), 0 2px 0 0 darken(@dark-gray, 6%), 0 5px 3px #999;
}
button.btn-warning.dim {
box-shadow: inset 0 0 0 darken(@yellow, 6%), 0 5px 0 0 darken(@yellow, 6%), 0 10px 5px #999;
}
button.btn-warning.dim:active {
box-shadow: inset 0 0 0 darken(@yellow, 6%), 0 2px 0 0 darken(@yellow, 6%), 0 5px 3px #999;
}
button.btn-info.dim {
box-shadow: inset 0 0 0 darken(@lazur, 6%), 0 5px 0 0 darken(@lazur, 6%), 0 10px 5px #999;
}
button.btn-info.dim:active {
box-shadow: inset 0 0 0 darken(@lazur, 6%), 0 2px 0 0 darken(@lazur, 6%), 0 5px 3px #999;
}
button.btn-success.dim {
box-shadow: inset 0 0 0 darken(@blue, 6%), 0 5px 0 0 darken(@blue, 6%), 0 10px 5px #999;
}
button.btn-success.dim:active {
box-shadow: inset 0 0 0 darken(@blue, 6%), 0 2px 0 0 darken(@blue, 6%), 0 5px 3px #999;
}
button.btn-danger.dim {
box-shadow: inset 0 0 0 darken(@red, 6%), 0 5px 0 0 darken(@red, 6%), 0 10px 5px #999;
}
button.btn-danger.dim:active {
box-shadow: inset 0 0 0 darken(@red, 6%), 0 2px 0 0 darken(@red, 6%), 0 5px 3px #999;
}
button.dim:before {
font-size: 50px;
line-height: 1em;
font-weight: normal;
color: #fff;
display: block;
padding-top: 10px;
}
button.dim:active:before {
top: 7px;
font-size: 50px;
}
.btn:focus {
outline: none !important;
}
-119
View File
@@ -1,119 +0,0 @@
#small-chat {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 100;
}
#small-chat .badge {
position: absolute;
top: -3px;
right: -4px;
}
.open-small-chat {
height: 38px;
width: 38px;
display: block;
background: #1ab394;
padding: 9px 8px;
text-align: center;
color: #fff;
border-radius: 50%;
}
.open-small-chat:hover {
color: white;
background: #1ab394;
}
.small-chat-box {
display: none;
position: fixed;
bottom: 20px;
right: 75px;
background: #fff;
border: 1px solid @border-color;
width: 230px;
height: 320px;
border-radius: 4px;
}
.small-chat-box.ng-small-chat {
display: block;
}
.small-chat-box.active {
display: block;
}
.small-chat-box {
.heading {
background: @nav-bg;
padding: 8px 15px;
font-weight: bold;
color: #fff;
}
.chat-date {
opacity: 0.6;
font-size: 10px;
font-weight: normal;
}
.content {
padding: 15px 15px;
.author-name {
font-weight: bold;
margin-bottom: 3px;
font-size: 11px;
}
> div {
padding-bottom: 20px;
}
.chat-message {
padding: 5px 10px;
border-radius: 6px;
font-size: 11px;
line-height: 14px;
max-width: 80%;
background: #f3f3f4;
margin-bottom: 10px;
}
.chat-message.active {
background: #1ab394;
color: #fff;
}
.left {
text-align: left;
clear: both;
.chat-message {
float: left;
}
}
.right {
text-align: right;
clear: both;
.chat-message {
float: right;
}
}
}
.form-chat {
padding: 10px 10px;
}
}
File diff suppressed because it is too large Load Diff
-15
View File
@@ -1,15 +0,0 @@
.border-radius (@radius: 3px) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
-moz-background-clip: padding;
-webkit-background-clip: padding-box;
background-clip: padding-box;
}
.opacity (@opacity: 0.5) {
-webkit-opacity: @opacity;
-moz-opacity: @opacity;
opacity: @opacity;
}
File diff suppressed because it is too large Load Diff
-191
View File
@@ -1,191 +0,0 @@
.sidebard-panel {
width: 220px;
background: darken(@gray, 3%);
padding: 10px 20px;
position: absolute;
right: 0;
}
.sidebard-panel .feed-element img.img-circle {
width: 32px;
height: 32px;
}
.sidebard-panel .feed-element, .media-body, .sidebard-panel p {
font-size: 12px;
}
.sidebard-panel .feed-element {
margin-top: 20px;
padding-bottom: 0;
}
.sidebard-panel .list-group {
margin-bottom: 10px;
}
.sidebard-panel .list-group .list-group-item {
padding: 5px 0;
font-size: 12px;
border: 0;
}
.sidebar-content .wrapper, .wrapper.sidebar-content {
padding-right: 230px !important;
}
// Right sidebar
#right-sidebar {
background-color: #fff;
border-left: 1px solid #e7eaec;
border-top: 1px solid #e7eaec;
overflow: hidden;
position: fixed;
top: 60px;
width: 260px !important;
z-index: 1009;
bottom: 0;
right: -260px;
}
#right-sidebar.sidebar-open {
right: 0;
}
#right-sidebar.sidebar-open.sidebar-top {
top: 0;
border-top: none;
}
.sidebar-container {
ul.nav-tabs {
border: none;
}
ul.nav-tabs.navs-4 li {
width: 25%;
}
ul.nav-tabs.navs-3 li {
width: 33.3333%;
}
ul.nav-tabs.navs-2 li {
width: 50%;
}
ul.nav-tabs li {
border: none;
}
ul.nav-tabs li a {
border: none;
padding: 12px 10px;
margin: 0;
border-radius: 0;
background: @nav-bg;
color: #fff;
text-align: center;
border-right: 1px solid lighten(@nav-bg, 2%);
}
ul.nav-tabs li.active a {
border: none;
background: #f9f9f9;
color: @text-color;
font-weight: bold;
}
.nav-tabs > li.active > a:hover,
.nav-tabs > li.active > a:focus {
border: none;
}
ul.sidebar-list {
margin: 0;
padding: 0;
}
ul.sidebar-list li {
border-bottom: 1px solid @border-color;
padding: 15px 20px;
list-style: none;
font-size: 12px;
}
ul.sidebar-list li:nth-child(2n+2) {
// background: #f9f9f9;
}
.sidebar-message:nth-child(2n+2) {
background: #f9f9f9;
}
ul.sidebar-list li a {
text-decoration: none;
color: inherit;
}
.sidebar-content {
padding: 15px 20px;
font-size: 12px;
}
.date-item {
}
.sidebar-title {
background: #f9f9f9;
padding: 20px;
border-bottom: 1px solid @border-color;
h3 {
margin-bottom: 3px;
padding-left: 2px;
}
}
.tab-content {
h4 {
margin-bottom: 5px;
}
}
.sidebar-message > a > .pull-left {
margin-right: 10px;
}
.sidebar-message > a {
text-decoration: none;
color: inherit;
}
.sidebar-message {
padding: 15px 20px;
}
.sidebar-message:hover {
// background: #f9f9f9;
}
.sidebar-message .message-avatar {
height: 38px;
width: 38px;
border-radius: 50%;
}
.setings-item {
padding: 15px 20px;
border-bottom: 1px solid @border-color;
}
}
-997
View File
@@ -1,997 +0,0 @@
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-rotating-plane"></div>
*
*/
.sk-spinner-rotating-plane.sk-spinner {
width: 30px;
height: 30px;
background-color: @spin-color;
margin: @spin-margin;
-webkit-animation: sk-rotatePlane 1.2s infinite ease-in-out;
animation: sk-rotatePlane 1.2s infinite ease-in-out;
}
@-webkit-keyframes sk-rotatePlane {
0% {
-webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
}
50% {
-webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
}
100% {
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
}
}
@keyframes sk-rotatePlane {
0% {
-webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
}
50% {
-webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
}
100% {
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
}
}
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-double-bounce">
* <div class="sk-double-bounce1"></div>
* <div class="sk-double-bounce2"></div>
* </div>
*
*/
.sk-spinner-double-bounce.sk-spinner {
width: 40px;
height: 40px;
position: relative;
margin: @spin-margin;
}
.sk-spinner-double-bounce .sk-double-bounce1, .sk-spinner-double-bounce .sk-double-bounce2 {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: @spin-color;
opacity: 0.6;
position: absolute;
top: 0;
left: 0;
-webkit-animation: sk-doubleBounce 2s infinite ease-in-out;
animation: sk-doubleBounce 2s infinite ease-in-out;
}
.sk-spinner-double-bounce .sk-double-bounce2 {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
@-webkit-keyframes sk-doubleBounce {
0%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
50% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes sk-doubleBounce {
0%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
50% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-wave">
* <div class="sk-rect1"></div>
* <div class="sk-rect2"></div>
* <div class="sk-rect3"></div>
* <div class="sk-rect4"></div>
* <div class="sk-rect5"></div>
* </div>
*
*/
.sk-spinner-wave.sk-spinner {
margin: @spin-margin;
width: 50px;
height: 30px;
text-align: center;
font-size: 10px;
}
.sk-spinner-wave div {
background-color: @spin-color;
height: 100%;
width: 6px;
display: inline-block;
-webkit-animation: sk-waveStretchDelay 1.2s infinite ease-in-out;
animation: sk-waveStretchDelay 1.2s infinite ease-in-out;
}
.sk-spinner-wave .sk-rect2 {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}
.sk-spinner-wave .sk-rect3 {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
.sk-spinner-wave .sk-rect4 {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}
.sk-spinner-wave .sk-rect5 {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s;
}
@-webkit-keyframes sk-waveStretchDelay {
0%, 40%, 100% {
-webkit-transform: scaleY(0.4);
transform: scaleY(0.4);
}
20% {
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
}
@keyframes sk-waveStretchDelay {
0%, 40%, 100% {
-webkit-transform: scaleY(0.4);
transform: scaleY(0.4);
}
20% {
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
}
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-wandering-cubes">
* <div class="sk-cube1"></div>
* <div class="sk-cube2"></div>
* </div>
*
*/
.sk-spinner-wandering-cubes.sk-spinner {
margin: @spin-margin;
width: 32px;
height: 32px;
position: relative;
}
.sk-spinner-wandering-cubes .sk-cube1, .sk-spinner-wandering-cubes .sk-cube2 {
background-color: @spin-color;
width: 10px;
height: 10px;
position: absolute;
top: 0;
left: 0;
-webkit-animation: sk-wanderingCubeMove 1.8s infinite ease-in-out;
animation: sk-wanderingCubeMove 1.8s infinite ease-in-out;
}
.sk-spinner-wandering-cubes .sk-cube2 {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}
@-webkit-keyframes sk-wanderingCubeMove {
25% {
-webkit-transform: translateX(42px) rotate(-90deg) scale(0.5);
transform: translateX(42px) rotate(-90deg) scale(0.5);
}
50% {
/* Hack to make FF rotate in the right direction */
-webkit-transform: translateX(42px) translateY(42px) rotate(-179deg);
transform: translateX(42px) translateY(42px) rotate(-179deg);
}
50.1% {
-webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);
transform: translateX(42px) translateY(42px) rotate(-180deg);
}
75% {
-webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);
transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);
}
100% {
-webkit-transform: rotate(-360deg);
transform: rotate(-360deg);
}
}
@keyframes sk-wanderingCubeMove {
25% {
-webkit-transform: translateX(42px) rotate(-90deg) scale(0.5);
transform: translateX(42px) rotate(-90deg) scale(0.5);
}
50% {
/* Hack to make FF rotate in the right direction */
-webkit-transform: translateX(42px) translateY(42px) rotate(-179deg);
transform: translateX(42px) translateY(42px) rotate(-179deg);
}
50.1% {
-webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);
transform: translateX(42px) translateY(42px) rotate(-180deg);
}
75% {
-webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);
transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);
}
100% {
-webkit-transform: rotate(-360deg);
transform: rotate(-360deg);
}
}
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-pulse"></div>
*
*/
.sk-spinner-pulse.sk-spinner {
width: 40px;
height: 40px;
margin: @spin-margin;
background-color: @spin-color;
border-radius: 100%;
-webkit-animation: sk-pulseScaleOut 1s infinite ease-in-out;
animation: sk-pulseScaleOut 1s infinite ease-in-out;
}
@-webkit-keyframes sk-pulseScaleOut {
0% {
-webkit-transform: scale(0);
transform: scale(0);
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 0;
}
}
@keyframes sk-pulseScaleOut {
0% {
-webkit-transform: scale(0);
transform: scale(0);
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 0;
}
}
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-chasing-dots">
* <div class="sk-dot1"></div>
* <div class="sk-dot2"></div>
* </div>
*
*/
.sk-spinner-chasing-dots.sk-spinner {
margin: @spin-margin;
width: 40px;
height: 40px;
position: relative;
text-align: center;
-webkit-animation: sk-chasingDotsRotate 2s infinite linear;
animation: sk-chasingDotsRotate 2s infinite linear;
}
.sk-spinner-chasing-dots .sk-dot1, .sk-spinner-chasing-dots .sk-dot2 {
width: 60%;
height: 60%;
display: inline-block;
position: absolute;
top: 0;
background-color: @spin-color;
border-radius: 100%;
-webkit-animation: sk-chasingDotsBounce 2s infinite ease-in-out;
animation: sk-chasingDotsBounce 2s infinite ease-in-out;
}
.sk-spinner-chasing-dots .sk-dot2 {
top: auto;
bottom: 0;
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
@-webkit-keyframes sk-chasingDotsRotate {
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes sk-chasingDotsRotate {
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@-webkit-keyframes sk-chasingDotsBounce {
0%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
50% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes sk-chasingDotsBounce {
0%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
50% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-three-bounce">
* <div class="sk-bounce1"></div>
* <div class="sk-bounce2"></div>
* <div class="sk-bounce3"></div>
* </div>
*
*/
.sk-spinner-three-bounce.sk-spinner {
margin: @spin-margin;
width: 70px;
text-align: center;
}
.sk-spinner-three-bounce div {
width: 18px;
height: 18px;
background-color: @spin-color;
border-radius: 100%;
display: inline-block;
-webkit-animation: sk-threeBounceDelay 1.4s infinite ease-in-out;
animation: sk-threeBounceDelay 1.4s infinite ease-in-out;
/* Prevent first frame from flickering when animation starts */
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.sk-spinner-three-bounce .sk-bounce1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
.sk-spinner-three-bounce .sk-bounce2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
@-webkit-keyframes sk-threeBounceDelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
40% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes sk-threeBounceDelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
40% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-circle">
* <div class="sk-circle1 sk-circle"></div>
* <div class="sk-circle2 sk-circle"></div>
* <div class="sk-circle3 sk-circle"></div>
* <div class="sk-circle4 sk-circle"></div>
* <div class="sk-circle5 sk-circle"></div>
* <div class="sk-circle6 sk-circle"></div>
* <div class="sk-circle7 sk-circle"></div>
* <div class="sk-circle8 sk-circle"></div>
* <div class="sk-circle9 sk-circle"></div>
* <div class="sk-circle10 sk-circle"></div>
* <div class="sk-circle11 sk-circle"></div>
* <div class="sk-circle12 sk-circle"></div>
* </div>
*
*/
.sk-spinner-circle.sk-spinner {
margin: @spin-margin;
width: 22px;
height: 22px;
position: relative;
}
.sk-spinner-circle .sk-circle {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.sk-spinner-circle .sk-circle:before {
content: '';
display: block;
margin: @spin-margin;
width: 20%;
height: 20%;
background-color: @spin-color;
border-radius: 100%;
-webkit-animation: sk-circleBounceDelay 1.2s infinite ease-in-out;
animation: sk-circleBounceDelay 1.2s infinite ease-in-out;
/* Prevent first frame from flickering when animation starts */
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.sk-spinner-circle .sk-circle2 {
-webkit-transform: rotate(30deg);
-ms-transform: rotate(30deg);
transform: rotate(30deg);
}
.sk-spinner-circle .sk-circle3 {
-webkit-transform: rotate(60deg);
-ms-transform: rotate(60deg);
transform: rotate(60deg);
}
.sk-spinner-circle .sk-circle4 {
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
}
.sk-spinner-circle .sk-circle5 {
-webkit-transform: rotate(120deg);
-ms-transform: rotate(120deg);
transform: rotate(120deg);
}
.sk-spinner-circle .sk-circle6 {
-webkit-transform: rotate(150deg);
-ms-transform: rotate(150deg);
transform: rotate(150deg);
}
.sk-spinner-circle .sk-circle7 {
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
transform: rotate(180deg);
}
.sk-spinner-circle .sk-circle8 {
-webkit-transform: rotate(210deg);
-ms-transform: rotate(210deg);
transform: rotate(210deg);
}
.sk-spinner-circle .sk-circle9 {
-webkit-transform: rotate(240deg);
-ms-transform: rotate(240deg);
transform: rotate(240deg);
}
.sk-spinner-circle .sk-circle10 {
-webkit-transform: rotate(270deg);
-ms-transform: rotate(270deg);
transform: rotate(270deg);
}
.sk-spinner-circle .sk-circle11 {
-webkit-transform: rotate(300deg);
-ms-transform: rotate(300deg);
transform: rotate(300deg);
}
.sk-spinner-circle .sk-circle12 {
-webkit-transform: rotate(330deg);
-ms-transform: rotate(330deg);
transform: rotate(330deg);
}
.sk-spinner-circle .sk-circle2:before {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}
.sk-spinner-circle .sk-circle3:before {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
.sk-spinner-circle .sk-circle4:before {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}
.sk-spinner-circle .sk-circle5:before {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s;
}
.sk-spinner-circle .sk-circle6:before {
-webkit-animation-delay: -0.7s;
animation-delay: -0.7s;
}
.sk-spinner-circle .sk-circle7:before {
-webkit-animation-delay: -0.6s;
animation-delay: -0.6s;
}
.sk-spinner-circle .sk-circle8:before {
-webkit-animation-delay: -0.5s;
animation-delay: -0.5s;
}
.sk-spinner-circle .sk-circle9:before {
-webkit-animation-delay: -0.4s;
animation-delay: -0.4s;
}
.sk-spinner-circle .sk-circle10:before {
-webkit-animation-delay: -0.3s;
animation-delay: -0.3s;
}
.sk-spinner-circle .sk-circle11:before {
-webkit-animation-delay: -0.2s;
animation-delay: -0.2s;
}
.sk-spinner-circle .sk-circle12:before {
-webkit-animation-delay: -0.1s;
animation-delay: -0.1s;
}
@-webkit-keyframes sk-circleBounceDelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
40% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes sk-circleBounceDelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
40% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-cube-grid">
* <div class="sk-cube"></div>
* <div class="sk-cube"></div>
* <div class="sk-cube"></div>
* <div class="sk-cube"></div>
* <div class="sk-cube"></div>
* <div class="sk-cube"></div>
* <div class="sk-cube"></div>
* <div class="sk-cube"></div>
* <div class="sk-cube"></div>
* </div>
*
*/
.sk-spinner-cube-grid {
/*
* Spinner positions
* 1 2 3
* 4 5 6
* 7 8 9
*/
}
.sk-spinner-cube-grid.sk-spinner {
width: 30px;
height: 30px;
margin: @spin-margin;
}
.sk-spinner-cube-grid .sk-cube {
width: 33%;
height: 33%;
background-color: @spin-color;
float: left;
-webkit-animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
}
.sk-spinner-cube-grid .sk-cube:nth-child(1) {
-webkit-animation-delay: 0.2s;
animation-delay: 0.2s;
}
.sk-spinner-cube-grid .sk-cube:nth-child(2) {
-webkit-animation-delay: 0.3s;
animation-delay: 0.3s;
}
.sk-spinner-cube-grid .sk-cube:nth-child(3) {
-webkit-animation-delay: 0.4s;
animation-delay: 0.4s;
}
.sk-spinner-cube-grid .sk-cube:nth-child(4) {
-webkit-animation-delay: 0.1s;
animation-delay: 0.1s;
}
.sk-spinner-cube-grid .sk-cube:nth-child(5) {
-webkit-animation-delay: 0.2s;
animation-delay: 0.2s;
}
.sk-spinner-cube-grid .sk-cube:nth-child(6) {
-webkit-animation-delay: 0.3s;
animation-delay: 0.3s;
}
.sk-spinner-cube-grid .sk-cube:nth-child(7) {
-webkit-animation-delay: 0s;
animation-delay: 0s;
}
.sk-spinner-cube-grid .sk-cube:nth-child(8) {
-webkit-animation-delay: 0.1s;
animation-delay: 0.1s;
}
.sk-spinner-cube-grid .sk-cube:nth-child(9) {
-webkit-animation-delay: 0.2s;
animation-delay: 0.2s;
}
@-webkit-keyframes sk-cubeGridScaleDelay {
0%, 70%, 100% {
-webkit-transform: scale3D(1, 1, 1);
transform: scale3D(1, 1, 1);
}
35% {
-webkit-transform: scale3D(0, 0, 1);
transform: scale3D(0, 0, 1);
}
}
@keyframes sk-cubeGridScaleDelay {
0%, 70%, 100% {
-webkit-transform: scale3D(1, 1, 1);
transform: scale3D(1, 1, 1);
}
35% {
-webkit-transform: scale3D(0, 0, 1);
transform: scale3D(0, 0, 1);
}
}
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-wordpress">
* <span class="sk-inner-circle"></span>
* </div>
*
*/
.sk-spinner-wordpress.sk-spinner {
background-color: @spin-color;
width: 30px;
height: 30px;
border-radius: 30px;
position: relative;
margin: @spin-margin;
-webkit-animation: sk-innerCircle 1s linear infinite;
animation: sk-innerCircle 1s linear infinite;
}
.sk-spinner-wordpress .sk-inner-circle {
display: block;
background-color: #fff;
width: 8px;
height: 8px;
position: absolute;
border-radius: 8px;
top: 5px;
left: 5px;
}
@-webkit-keyframes sk-innerCircle {
0% {
-webkit-transform: rotate(0);
transform: rotate(0);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes sk-innerCircle {
0% {
-webkit-transform: rotate(0);
transform: rotate(0);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
/*
* Usage:
*
* <div class="sk-spinner sk-spinner-fading-circle">
* <div class="sk-circle1 sk-circle"></div>
* <div class="sk-circle2 sk-circle"></div>
* <div class="sk-circle3 sk-circle"></div>
* <div class="sk-circle4 sk-circle"></div>
* <div class="sk-circle5 sk-circle"></div>
* <div class="sk-circle6 sk-circle"></div>
* <div class="sk-circle7 sk-circle"></div>
* <div class="sk-circle8 sk-circle"></div>
* <div class="sk-circle9 sk-circle"></div>
* <div class="sk-circle10 sk-circle"></div>
* <div class="sk-circle11 sk-circle"></div>
* <div class="sk-circle12 sk-circle"></div>
* </div>
*
*/
.sk-spinner-fading-circle.sk-spinner {
margin: @spin-margin;
width: 22px;
height: 22px;
position: relative;
}
.sk-spinner-fading-circle .sk-circle {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.sk-spinner-fading-circle .sk-circle:before {
content: '';
display: block;
margin: @spin-margin;
width: 18%;
height: 18%;
background-color: @spin-color;
border-radius: 100%;
-webkit-animation: sk-circleFadeDelay 1.2s infinite ease-in-out;
animation: sk-circleFadeDelay 1.2s infinite ease-in-out;
/* Prevent first frame from flickering when animation starts */
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.sk-spinner-fading-circle .sk-circle2 {
-webkit-transform: rotate(30deg);
-ms-transform: rotate(30deg);
transform: rotate(30deg);
}
.sk-spinner-fading-circle .sk-circle3 {
-webkit-transform: rotate(60deg);
-ms-transform: rotate(60deg);
transform: rotate(60deg);
}
.sk-spinner-fading-circle .sk-circle4 {
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
}
.sk-spinner-fading-circle .sk-circle5 {
-webkit-transform: rotate(120deg);
-ms-transform: rotate(120deg);
transform: rotate(120deg);
}
.sk-spinner-fading-circle .sk-circle6 {
-webkit-transform: rotate(150deg);
-ms-transform: rotate(150deg);
transform: rotate(150deg);
}
.sk-spinner-fading-circle .sk-circle7 {
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
transform: rotate(180deg);
}
.sk-spinner-fading-circle .sk-circle8 {
-webkit-transform: rotate(210deg);
-ms-transform: rotate(210deg);
transform: rotate(210deg);
}
.sk-spinner-fading-circle .sk-circle9 {
-webkit-transform: rotate(240deg);
-ms-transform: rotate(240deg);
transform: rotate(240deg);
}
.sk-spinner-fading-circle .sk-circle10 {
-webkit-transform: rotate(270deg);
-ms-transform: rotate(270deg);
transform: rotate(270deg);
}
.sk-spinner-fading-circle .sk-circle11 {
-webkit-transform: rotate(300deg);
-ms-transform: rotate(300deg);
transform: rotate(300deg);
}
.sk-spinner-fading-circle .sk-circle12 {
-webkit-transform: rotate(330deg);
-ms-transform: rotate(330deg);
transform: rotate(330deg);
}
.sk-spinner-fading-circle .sk-circle2:before {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}
.sk-spinner-fading-circle .sk-circle3:before {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
.sk-spinner-fading-circle .sk-circle4:before {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}
.sk-spinner-fading-circle .sk-circle5:before {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s;
}
.sk-spinner-fading-circle .sk-circle6:before {
-webkit-animation-delay: -0.7s;
animation-delay: -0.7s;
}
.sk-spinner-fading-circle .sk-circle7:before {
-webkit-animation-delay: -0.6s;
animation-delay: -0.6s;
}
.sk-spinner-fading-circle .sk-circle8:before {
-webkit-animation-delay: -0.5s;
animation-delay: -0.5s;
}
.sk-spinner-fading-circle .sk-circle9:before {
-webkit-animation-delay: -0.4s;
animation-delay: -0.4s;
}
.sk-spinner-fading-circle .sk-circle10:before {
-webkit-animation-delay: -0.3s;
animation-delay: -0.3s;
}
.sk-spinner-fading-circle .sk-circle11:before {
-webkit-animation-delay: -0.2s;
animation-delay: -0.2s;
}
.sk-spinner-fading-circle .sk-circle12:before {
-webkit-animation-delay: -0.1s;
animation-delay: -0.1s;
}
@-webkit-keyframes sk-circleFadeDelay {
0%, 39%, 100% {
opacity: 0;
}
40% {
opacity: 1;
}
}
@keyframes sk-circleFadeDelay {
0%, 39%, 100% {
opacity: 0;
}
40% {
opacity: 1;
}
}
-31
View File
@@ -1,31 +0,0 @@
/*
*
* INSPINIA - Responsive Admin Theme
* version 2.6.2
*
*/
// Variables, Mixins
@import "../global/variables.less";
@import "mixins.less";
// INSPINIA Theme Elements
@import "typography.less";
@import "buttons.less";
@import "badgets_labels.less";
@import "elements.less";
@import "sidebar.less";
@import "base.less";
@import "pages.less";
@import "chat.less";
@import "spinners.less";
-32
View File
@@ -1,32 +0,0 @@
h1, h2, h3, h4, h5, h6 {
font-weight: 100;
}
h1 {
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 16px;
}
h4 {
font-size: 14px;
}
h5 {
font-size: 12px;
}
h6 {
font-size: 10px;
}
h3, h4, h5 {
margin-top: 5px;
font-weight: 600;
}
-1
View File
@@ -1 +0,0 @@
@import "~bootstrap/less/variables.less";

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Before

Width:  |  Height:  |  Size: 943 B

After

Width:  |  Height:  |  Size: 943 B

Before

Width:  |  Height:  |  Size: 828 B

After

Width:  |  Height:  |  Size: 828 B

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before

Width:  |  Height:  |  Size: 943 B

After

Width:  |  Height:  |  Size: 943 B

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Before

Width:  |  Height:  |  Size: 743 B

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

-147
View File
@@ -1,147 +0,0 @@
<template>
<div id="body">
<div>
<SideNavigation/>
<div id="page-wrapper" :class="{'show-drawer':$store.state.config.showDrawer}" @click="blankClick">
<div>
<div class="mb10">
<router-link to="/" v-if="$store.state.breadcrumbs && $store.state.breadcrumbs.length">
<i class="fa fa-home f16"></i>
</router-link>
<span v-for="b in $store.state.breadcrumbs">
<span>/</span>
<router-link v-if="(b.name || b.path) && b.name !== $store.state.route.name" :to="b">
{{b.displayDirect?b.title:$t(b.title)}}
</router-link>
<span v-else>
{{b.displayDirect?b.title:$t(b.title)}}
</span>
</span>
</div>
<router-view></router-view>
</div>
</div>
<TopNavigation/>
<!--手机上不显示bottomNavigation,而采用弹出的形式-->
<BottomNavigation/>
</div>
</div>
</template>
<script>
import SideNavigation from './layout/SideNavigation.vue'
import TopNavigation from './layout/TopNavigation.vue'
import BottomNavigation from './layout/BottomNavigation.vue'
import enquire from 'enquire.js/dist/enquire'
export default {
data() {
return {
member: this.$store.state.member
}
},
computed: {
config() {
return this.$store.state.config
}
},
components: {
SideNavigation,
TopNavigation,
BottomNavigation
},
methods: {
blankClick() {
if (this.config.mobile) {
if (this.config.showDrawer) {
this.$store.state.config.showDrawer = false
}
}
},
listenResponsiveEvent() {
let that = this
enquire.register('(max-width: 768px)', {
match: function () {
that.$store.state.config.showDrawer = false
that.$store.state.config.mobile = true
},
unmatch: function () {
that.$store.state.config.showDrawer = true
that.$store.state.config.mobile = false
}
})
}
},
created() {
},
mounted() {
let that = this
this.$store.state.environment = 'backyard'
this.listenResponsiveEvent()
}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../assets/css/global/variables";
#page-wrapper {
position: fixed;
left: @sidebar-width;
top: @top-navigation-height;
right: 0;
bottom: @power-footer-height;
overflow-y: auto;
overflow-x: hidden;
z-index: 10;
padding: 10px;
-webkit-transition: all 0.4s;
-moz-transition: all 0.4s;
-o-transition: all 0.4s;
transition: all 0.4s;
background-color: #f3f3f4;
//大屏幕
@media (min-width: @screen-sm-min) {
left: @sidebar-width;
}
//小屏幕
@media (max-width: @screen-xs-max) {
left: 0;
bottom: 0;
}
&.show-drawer {
//大屏幕
@media (min-width: @screen-sm-min) {
left: @sidebar-width;
}
//小屏幕
@media (max-width: @screen-xs-max) {
left: 0;
bottom: 0;
}
}
}
</style>
-516
View File
@@ -1,516 +0,0 @@
<template>
<div class="dashboard-index">
<div class="row mt20">
<div class="col-lg-3 col-md-6 col-sm-12">
<div class="text-block">
<div class="upper">
<div class="indicator">{{ $t('dashboard.totalInvokeNum') }}</div>
<div class="amount">{{dashboard.totalInvokeNum}}</div>
<div>
<RatePanel :name="$t('dashboard.weekRate')" :standardValue="standardWeekInvokeNum"
:compareValue="compareWeekInvokeNum"/>
<RatePanel :name="$t('dashboard.dayRate')" :standardValue="standardDayInvokeNum"
:compareValue="compareDayInvokeNum"/>
</div>
</div>
<div class="lower">
{{ $t('dashboard.yesterdayInvoke') }}:{{dashboard.invokeNum}}
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 col-sm-12">
<div class="text-block">
<div class="upper">
<div class="indicator">{{ $t('dashboard.totalUV') }}</div>
<div class="amount">{{dashboard.totalUv}}</div>
<div>
<RatePanel :name="$t('dashboard.weekRate')" :standardValue="standardWeekUv"
:compareValue="compareWeekUv"/>
<RatePanel :name="$t('dashboard.dayRate')" :standardValue="standardDayUv" :compareValue="compareDayUv"/>
</div>
</div>
<div class="lower">
{{ $t('dashboard.yesterdayUV') }}:{{dashboard.uv}}
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 col-sm-12">
<div class="text-block">
<div class="upper">
<div class="indicator">{{ $t('dashboard.totalMatterNum') }}</div>
<div class="amount">{{dashboard.totalMatterNum}}</div>
<div>
<RatePanel :name="$t('dashboard.weekRate')" :standardValue="standardWeekMatterNum"
:compareValue="compareWeekMatterNum"/>
<RatePanel :name="$t('dashboard.dayRate')" :standardValue="standardDayMatterNum"
:compareValue="compareDayMatterNum"/>
</div>
</div>
<div class="lower">
{{ $t('dashboard.yesterdayMatterNum') }}:{{dashboard.matterNum}}
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 col-sm-12">
<div class="text-block">
<div class="upper">
<div class="indicator">{{ $t('dashboard.totalFileSize') }}</div>
<div class="amount">{{dashboard.totalFileSize | humanFileSize}}</div>
<div>
<RatePanel :name="$t('dashboard.weekRate')" :standardValue="standardWeekSize"
:compareValue="compareWeekSize"/>
<RatePanel :name="$t('dashboard.dayRate')" :standardValue="standardDaySize"
:compareValue="compareDaySize"/>
</div>
</div>
<div class="lower">
{{ $t('dashboard.yesterdayMatterSize') }}:{{dashboard.fileSize | humanFileSize}}
</div>
</div>
</div>
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="figure-block">
<div class="title">
{{ $t('dashboard.recentDayInvokeUV',[days]) }}
</div>
<figure>
<ECharts
ref="invokeListChart"
theme="ovilia-green"
:autoResize="true"
:initOptions="initOptions"
:options="invokeListOption"/>
</figure>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="figure-block">
<div class="title">
{{ $t('dashboard.downloadMatterTop10') }}
</div>
<div class="list-rank">
<ul>
<li v-for="(matter,index) in matterPager.data">
<span class="rank" :class="{top3:index<3}">{{index+1}}</span>
<router-link class="name" :to="'/matter/detail/'+matter.uuid">{{matter.name}}</router-link>
<span class="info">{{matter.times}}</span>
</li>
</ul>
</div>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="figure-block">
<div class="title">
{{ $t('dashboard.activeIpTop10') }}
</div>
<div class="list-rank">
<ul>
<li v-for="(item,index) in activeIpTop10">
<span class="rank" :class="{top3:index<3}">{{index+1}}</span>
<span class="name" :to="'/'">{{item.ip}}</span>
<span class="info">{{item.times}}</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import ECharts from 'vue-echarts/components/ECharts'
import 'echarts/lib/chart/bar'
import 'echarts/lib/chart/line'
import 'echarts/lib/chart/pie'
import 'echarts/lib/chart/map'
import 'echarts/lib/chart/radar'
import 'echarts/lib/chart/scatter'
import 'echarts/lib/chart/effectScatter'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/polar'
import 'echarts/lib/component/geo'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/title'
import 'echarts/lib/component/visualMap'
import 'echarts/lib/component/dataset'
import 'echarts/map/js/world'
import 'zrender/lib/svg/svg'
import theme from "./theme"
import Dashboard from "../../common/model/dashboard/Dashboard";
import Pager from "../../common/model/base/Pager";
import {SortDirection} from "../../common/model/base/SortDirection";
import {simpleDate} from "../../common/filter/time";
import RatePanel from "./widget/RatePanel"
import Matter from "../../common/model/matter/Matter";
//自定义主题
ECharts.registerTheme('ovilia-green', theme)
export default {
data: function () {
return {
days: 15,
//用来存放日期的,辅助x轴的生成
dateStrings: [],
//昨天的统计情况
dashboard: new Dashboard(),
//调用量周环比
standardWeekInvokeNum: 0,
compareWeekInvokeNum: 0,
//调用量日环比
standardDayInvokeNum: 0,
compareDayInvokeNum: 0,
//UV周环比
standardWeekUv: 0,
compareWeekUv: 0,
//UV日环比
standardDayUv: 0,
compareDayUv: 0,
//文件总数周环比
standardWeekMatterNum: 0,
compareWeekMatterNum: 0,
//文件总数日环比
standardDayMatterNum: 0,
compareDayMatterNum: 0,
//文件大小周环比
standardWeekSize: 0,
compareWeekSize: 0,
//文件大小日环比
standardDaySize: 0,
compareDaySize: 0,
pager: new Pager(Dashboard, 15),
matterPager: new Pager(Matter, 10),
activeIpTop10: [],
//图标加载中的样式
loadingOption: {
text: this.$t("dashboard.loading"),
color: '#006699',
maskColor: 'rgba(255, 255, 255, 0.4)'
},
initOptions: {
renderer: 'canvas'
},
invokeListOption: {
tooltip: {},
legend: {
data: ['PV', 'UV']
},
xAxis: {
name: this.$t("dashboard.date"),
data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
},
yAxis: {
name: this.$t("dashboard.num")
},
series: [{
name: 'PV',
type: 'bar',
data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}, {
name: 'UV',
type: 'line',
data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}]
}
}
},
components: {
ECharts,
RatePanel
},
methods: {
updateDateStrings() {
let that = this;
//更新横坐标 从昨天开始倒推
let arr = []
for (let d = that.days; d >= 1; d--) {
let thenDate = new Date((new Date()).getTime() - d * 24 * 60 * 60 * 1000)
arr.push(simpleDate(thenDate))
}
that.dateStrings = arr
},
//获取15日调用分时数据
refreshDashboardPager() {
let that = this;
this.pager.setFilterValue("orderDt", SortDirection.DESC)
that.$refs.invokeListChart.showLoading()
this.pager.httpFastPage(function (response) {
let list = that.pager.data
if (list.length > 0) {
that.dashboard.render(list[list.length - 1])
}
//数据转换成map,方便检索
let map = {}
for (let i = 0; i < list.length; i++) {
map[list[i].dt] = list[i]
}
let invokeNumData = []
let uvData = []
let matterNumData = []
let fileSizeData = []
for (let i = 0; i < that.days; i++) {
invokeNumData.push(0)
uvData.push(0)
matterNumData.push(0)
fileSizeData.push(0)
}
//按照日期对应。
for (let i = 0; i < that.dateStrings.length; i++) {
let item = map[that.dateStrings[i]];
if (item) {
invokeNumData[i] = item.invokeNum
uvData[i] = item.uv
matterNumData[i] = item.matterNum
fileSizeData[i] = item.fileSize
}
}
//同环比
that.standardWeekInvokeNum = 0
that.compareWeekInvokeNum = 0
//调用量日环比
that.standardDayInvokeNum = 0
that.compareDayInvokeNum = 0
//UV周环比
that.standardWeekUv = 0
that.compareWeekUv = 0
//UV日环比
that.standardDayUv = 0
that.compareDayUv = 0
//文件总数周环比
that.standardWeekMatterNum = 0
that.compareWeekMatterNum = 0
//文件总数日环比
that.standardDayMatterNum = 0
that.compareDayMatterNum = 0
//文件大小周环比
that.standardWeekSize = 0
that.compareWeekSize = 0
//文件大小日环比
that.standardDaySize = 0
that.compareDaySize = 0
for (let i = 0; i < that.days; i++) {
if (i >= 1 && i <= 7) {
that.standardWeekInvokeNum += invokeNumData[i]
that.standardWeekUv += uvData[i]
that.standardWeekMatterNum += matterNumData[i]
that.standardWeekSize += fileSizeData[i]
} else if (i >= 8 && i <= 14) {
that.compareWeekInvokeNum += invokeNumData[i]
that.compareWeekUv += uvData[i]
that.compareWeekMatterNum += matterNumData[i]
that.compareWeekSize += fileSizeData[i]
}
if (i === 13) {
that.standardDayInvokeNum = invokeNumData[i]
that.standardDayUv = uvData[i]
that.standardDayMatterNum = matterNumData[i]
that.standardDaySize = fileSizeData[i]
}
if (i === 14) {
that.compareDayInvokeNum = invokeNumData[i]
that.compareDayUv = uvData[i]
that.compareDayMatterNum = matterNumData[i]
that.compareDaySize = fileSizeData[i]
}
}
that.invokeListOption.xAxis.data = that.dateStrings.map((k) => k.substr(5))
that.invokeListOption.series[0].data = invokeNumData
that.invokeListOption.series[1].data = uvData
that.$refs.invokeListChart.hideLoading()
}, function () {
that.$refs.invokeListChart.hideLoading()
})
},
//获取下载前10的文件
refreshMatterPager() {
let that = this;
that.matterPager.setFilterValue("orderTimes", SortDirection.DESC)
that.matterPager.httpFastPage()
},
refreshActiveIpTop10() {
let that = this
that.dashboard.httpActiveIpTop10(function (response) {
that.activeIpTop10 = response.data.data
})
}
},
mounted() {
let that = this;
this.updateDateStrings()
this.refreshDashboardPager()
this.refreshMatterPager()
this.refreshActiveIpTop10()
}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../../assets/css/global/variables";
.dashboard-index {
figure {
.echarts {
width: 100%;
height: 300px;
}
}
.text-block {
background-color: white;
box-shadow: 0 0 5px rgba(0, 0, 0, .2);
border-radius: 5px;
padding: 20px 15px 10px 15px;
margin-bottom: 30px;
.upper {
.indicator {
color: rgba(0, 0, 0, .45);
font-size: 14px;
line-height: 22px;
height: 22px;
}
.amount {
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
white-space: nowrap;
color: rgba(0, 0, 0, .85);
margin-top: 4px;
margin-bottom: 20px;
font-size: 30px;
line-height: 38px;
height: 38px;
}
.rate {
margin-right: 15px;
}
}
.lower {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid #eee;
font-size: 14px;
}
}
.figure-block {
background-color: white;
box-shadow: 0 0 5px rgba(0, 0, 0, .2);
border-radius: 5px;
margin-bottom: 20px;
.title {
font-size: 18px;
padding: 15px 20px;
color: black;
margin-bottom: 10px;
border-bottom: 1px solid #eee;
}
}
.list-rank {
padding: 0 20px 10px 20px;
ul {
list-style: none;
padding: 0;
li {
zoom: 1;
margin-top: 16px;
display: flex;
align-items: center;
.rank {
border-radius: 20px;
display: inline-block;
font-size: 12px;
font-weight: 600;
margin-right: 16px;
height: 20px;
line-height: 20px;
width: 20px;
text-align: center;
margin-top: 1.5px;
background-color: #f5f5f5;
&.top3 {
background-color: #314659;
color: #fff;
}
}
.name {
color: rgba(0, 0, 0, .65);
font-size: 14px;
line-height: 22px;
flex: 1 1;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
margin-right: 8px;
&:hover {
color: @brand-primary;
}
}
.info {
color: rgba(0, 0, 0, .65);
font-size: 14px;
line-height: 22px;
}
}
}
}
}
</style>
@@ -1,79 +0,0 @@
<template>
<span class="widget-rate-panel">
<span class="name">{{name}}</span>
<span class="infinite" v-if="infinite">∞</span>
<span class="no-data" v-else-if="noData"> - </span>
<span v-else>{{value>0?'+':''}}{{value}}%</span>
<i class="fa fa-arrow-down text-success" v-if="!noData && value<0"></i>
<i class="fa fa-arrow-up text-danger" v-if="!noData && (infinite || value>=0)"></i>
</span>
</template>
<script>
export default {
data: function () {
return {}
},
computed: {
noData() {
return this.standardValue === 0 && this.compareValue === 0
},
infinite() {
return this.standardValue === 0 && this.compareValue > 0
},
value() {
if (this.standardValue === 0) {
if (this.compareValue === 0) {
return 0;
} else {
return 100;
}
} else {
let v1 = this.compareValue - this.standardValue
let v2 = v1 / this.standardValue
return (v2 * 100).toFixed(0)
}
}
},
props: {
name: {
type: String,
required: false,
'default': ""
},
standardValue: {
type: Number,
required: true,
'default': 0
},
compareValue: {
type: Number,
required: true,
'default': 0
}
},
components: {},
methods: {},
mounted() {
let that = this;
}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../../../assets/css/global/variables";
.widget-rate-panel {
margin-right: 5px;
.infinite {
}
.no-data {
}
}
</style>
-167
View File
@@ -1,167 +0,0 @@
<template>
<div class="widget-image-cache-list animated fadeIn">
<div class="row">
<div class="col-md-12 text-right pb10">
<button class="btn btn-primary btn-sm mr5" v-if="selectedImageCaches.length" @click.stop.prevent="deleteBatch">
<i class="fa fa-trash"></i>
{{ $t('delete') }}
</button>
<button class="btn btn-primary btn-sm mr5" v-if="selectedImageCaches.length !== pager.data.length"
@click.stop.prevent="checkAll">
<i class="fa fa-check-square"></i>
{{ $t('selectAll') }}
</button>
<button class="btn btn-primary btn-sm mr5"
v-if="pager.data.length && selectedImageCaches.length === pager.data.length"
@click.stop.prevent="checkNone">
<i class="fa fa-square-o"></i>
{{ $t('cancel') }}
</button>
</div>
<div class="col-md-12" v-for="(imageCache,index) in pager.data">
<ImageCachePanel
:imageCache="imageCache"
@deleteSuccess="refresh"
@checkImageCache="checkImageCache"
@previewImageCache="previewImageCache"
/>
</div>
<div class="col-md-12 mt20">
<NbPager :pager="pager" :callback="refresh"></NbPager>
</div>
</div>
</div>
</template>
<script>
import NbFilter from '../../../../common/widget/filter/NbFilter.vue'
import NbPager from '../../../../common/widget/NbPager.vue'
import Pager from '../../../../common/model/base/Pager'
import ImageCache from "../../../../common/model/image/cache/ImageCache";
import ImageCachePanel from "./ImageCachePanel"
import {MessageBox, Message} from "element-ui"
export default {
data() {
return {
pager: new Pager(ImageCache, Pager.MAX_PAGE_SIZE),
user: this.$store.state.user,
selectedImageCaches: []
}
},
props: {
initFilter: {
type: Object,
required: false
}
},
components: {
NbFilter,
NbPager,
ImageCachePanel
},
methods: {
search() {
this.pager.page = 0
this.refresh()
},
refresh() {
if (this.initFilter) {
for (let key in this.initFilter) {
if (this.initFilter.hasOwnProperty(key)) {
this.pager.setFilterValue(key, this.initFilter[key]);
}
}
}
this.pager.httpFastPage()
},
checkImageCache(imageCache) {
let that = this
//统计所有的勾选
this.selectedImageCaches.splice(0, this.selectedImageCaches.length)
this.pager.data.forEach(function (imageCache, index) {
if (imageCache.check) {
that.selectedImageCaches.push(imageCache)
}
})
},
//全选
checkAll() {
this.pager.data.forEach(function (i, index) {
i.check = true
})
this.checkImageCache()
},
//取消全选
checkNone() {
this.pager.data.forEach(function (i, index) {
i.check = false
})
this.checkImageCache()
},
previewImageCache(imageCache) {
let that = this;
//从matter开始预览图片
let imageArray = []
let startIndex = -1;
this.pager.data.forEach(function (item, index) {
imageArray.push(item.getResizeUrl())
if (item.uuid === imageCache.uuid) {
startIndex = imageArray.length - 1
}
})
that.$photoSwipePlugin.showPhotos(imageArray, startIndex)
},
deleteBatch() {
let that = this
MessageBox.confirm(that.$t("actionCanNotRevertConfirm"), that.$t("prompt"), {
confirmButtonText: that.$t("confirm"),
cancelButtonText: that.$t("cancel"),
type: 'warning',
callback: function (action, instance) {
if (action === 'confirm') {
let uuids = ""
that.selectedImageCaches.forEach(function (item, index) {
if (index === 0) {
uuids = item.uuid
} else {
uuids = uuids + "," + item.uuid
}
})
let imageCache = new ImageCache()
imageCache.httpDeleteBatch(uuids, function (response) {
Message.success(that.$t("operationSuccess"))
that.refresh()
})
}
}
})
}
},
mounted() {
this.pager.enableHistory()
this.refresh()
}
}
</script>
<style lang="less" rel="stylesheet/less">
.widget-image-cache-list {
}
</style>
-273
View File
@@ -1,273 +0,0 @@
<template>
<div class="widget-image-cache-panel">
<div @click.stop.prevent="clickRow">
<div class="media">
<div class="pull-left">
<div class="left-part">
<span class="basic-span">
<NbCheckbox v-model="imageCache.check"/>
</span>
<span class="basic-span">
<img class="image-cache-icon" :src="handleImageUrl(imageCache.getOriginUrl(),false,100,100)"/>
</span>
</div>
</div>
<!--在大屏下的操作栏-->
<div class="pull-right hidden-sm hidden-xs">
<div class="right-part" v-if="imageCache.uuid">
<span class="image-cache-operation">
<i class="fa fa-trash btn-action text-danger" :title="$t('delete')" @click.stop.prevent="deleteImageCache"></i>
</span>
<span class="image-cache-size">
{{imageCache.size | humanFileSize}}
</span>
<span class="image-cache-date">
{{imageCache.updateTime | simpleDateHourMinute}}
</span>
</div>
</div>
<!--在小屏幕下的操作栏-->
<div class="pull-right hidden-lg hidden-md">
<span class="more-btn" @click.stop.prevent="showMore = !showMore">
<i class="fa fa-ellipsis-h btn-action" :title="$t('showMore')"></i>
</span>
</div>
<div class="media-body">
<div class="middle-part">
<span class="image-cache-name">
{{imageCache.name}}
</span>
</div>
</div>
</div>
</div>
<NbExpanding>
<div class="hidden-lg hidden-md more-panel" v-if="showMore">
<div class="cell-btn" style="border: none">
<span>
{{imageCache.updateTime | simpleDateHourMinute}}
</span>
<span v-if="!imageCache.dir">
{{imageCache.size | humanFileSize}}
</span>
</div>
<div class="cell-btn text-danger" :title="$t('delete')" @click.stop.prevent="deleteImageCache">
<i class="fa fa-trash"></i>
</div>
</div>
</NbExpanding>
</div>
</template>
<script>
import ImageCache from '../../../../common/model/image/cache/ImageCache'
import NbCheckbox from '../../../../common/widget/NbCheckbox'
import NbExpanding from '../../../../common/widget/NbExpanding'
import {Message, MessageBox} from 'element-ui'
import {handleImageUrl} from "../../../../common/util/ImageUtil";
export default {
data() {
return {
//正在向服务器提交rename的请求
renamingLoading: false,
showMore: false
}
},
components: {
NbExpanding,
NbCheckbox
},
props: {
imageCache: {
type: ImageCache,
required: true
}
},
watch: {
'imageCache.check'(newVal, oldVal) {
this.$emit('checkImageCache', this.imageCache)
}
},
methods: {
handleImageUrl,
clickRow() {
let that = this
this.$emit('previewImageCache', this.imageCache)
},
deleteImageCache() {
let that = this
MessageBox.confirm(that.$t("actionCanNotRevertConfirm"), that.$t("prompt"), {
confirmButtonText: that.$t("confirm"),
cancelButtonText: that.$t("cancel"),
type: 'warning',
callback: function (action, instance) {
if (action === 'confirm') {
that.imageCache.httpDelete(function (response) {
Message.success(that.$t("operationSuccess"))
that.$emit('deleteSuccess', that.imageCache)
})
}
}
})
},
finishCreateDirectory() {
let that = this
that.imageCache.httpCreateDirectory(function () {
that.director.createMode = false
that.editMode = false
that.imageCache.render(new ImageCache())
that.$emit('createDirectorySuccess', that.imageCache)
}, function (errorMessage) {
that.director.createMode = false
that.editMode = false
Message.error(errorMessage)
})
}
},
created() {
},
mounted() {
}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../../../../assets/css/global/variables";
@base-height: 48px;
@inner-cell-height: 36px;
.basic-span {
display: inline-block;
vertical-align: middle;
line-height: @base-height;
margin-right: 5px;
}
.widget-image-cache-panel {
border-top: 1px solid #eee;
background-color: white;
.media {
> .pull-left {
padding-right: 1px;
}
}
.image-cache-icon {
width: 24px;
}
.left-part {
margin-left: 10px;
}
.middle-part {
height: @base-height;
overflow: hidden;
.image-cache-name-edit {
.basic-span;
width: 90%;
input {
width: 100%;
height: 26px;
display: inline-block;
padding: 6px;
}
}
.image-cache-name {
.basic-span;
width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
.right-part {
.image-cache-operation {
.basic-span;
display: none;
i {
font-size: 16px;
margin-right: 5px;
&:hover {
}
}
}
.image-cache-size {
.basic-span;
display: inline-block;
width: 80px;
text-align: left;
margin-left: 20px;
}
.image-cache-date {
.basic-span;
}
}
.more-btn {
display: inline-block;
vertical-align: middle;
line-height: @base-height;
padding: 0 15px;
}
&:hover {
background-color: aliceblue;
cursor: pointer;
.image-cache-operation {
display: inline-block;
}
}
.more-panel {
border-top: 1px solid #eee;
padding-left: 35px;
.info {
}
.cell-btn {
border-top: 1px solid #eee;
line-height: @inner-cell-height;
vertical-align: middle;
}
}
}
</style>
-481
View File
@@ -1,481 +0,0 @@
<template>
<div class="backyard-install">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane :label=" $t('install.configMysql')" name="first">
<div class="install-block">
<div class="row" v-validator="install.validatorSchema.mysqlHost.error">
<label class="col-md-2 control-label mt5 compulsory">MySQL Host</label>
<div class="col-md-10 validate">
<input type="text" class="form-control" v-model="install.mysqlHost">
</div>
</div>
<div class="row mt10" v-validator="install.validatorSchema.mysqlPort.error">
<label class="col-md-2 control-label mt5 compulsory">MySQL {{ $t('install.port') }}</label>
<div class="col-md-10 validate">
<input type="number" class="form-control" v-model="install.mysqlPort">
</div>
</div>
<div class="row mt10" v-validator="install.validatorSchema.mysqlSchema.error">
<label class="col-md-2 control-label mt5 compulsory">MySQL {{ $t('install.schema') }}</label>
<div class="col-md-10 validate">
<input type="text" class="form-control" v-model="install.mysqlSchema">
</div>
</div>
<div class="row mt10" v-validator="install.validatorSchema.mysqlUsername.error">
<label class="col-md-2 control-label mt5 compulsory">MySQL {{ $t('username') }}</label>
<div class="col-md-10 validate">
<input type="text" class="form-control" v-model="install.mysqlUsername">
</div>
</div>
<div class="row mt10" v-validator="install.validatorSchema.mysqlPassword.error">
<label class="col-md-2 control-label mt5 compulsory">MySQL {{ $t('password') }}</label>
<div class="col-md-10 validate">
<input type="password" class="form-control" :value="install.mysqlPassword" @input="mysqlPasswordChange">
</div>
</div>
<div class="row mt20">
<div class="col-md-12">
<div class="alert alert-info">
<div><i class="fa fa-bullhorn"></i> {{ $t('install.notice') }}</div>
<ol class="pl30 m0">
<li>{{ $t('install.mysqlNotice1') }}</li>
<li>{{ $t('install.mysqlNotice2') }}</li>
</ol>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-right">
<button class="btn btn-success btn-sm mr5" v-if="install.verified">
<i class="fa fa-link"></i>
{{ $t('install.mysqlConnectionPass') }}
</button>
<button class="btn btn-info btn-sm mr5" @click.stop.prevent="verify" v-if="!install.verified">
<i class="fa fa-unlink"></i>
{{ $t('install.testMysqlConnection') }}
</button>
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="goTo('second')">
<i class="fa fa-arrow-right"></i>
{{ $t('install.nextStep') }}
</button>
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane :label="$t('install.createTable')" name="second" :disabled="!install.verified">
<div class="install-block">
<div class="mb15 border-bottom" v-for="(tableInfo,index) in install.tableInfoList">
<div class="f16">
{{tableInfo.name}}
<span class="label label-success" v-if="tableInfo.tableExist && !tableInfo.missingFields.length">
{{ $t('install.installed') }}
</span>
<span class="label label-danger" v-if="tableInfo.tableExist && tableInfo.missingFields.length">
{{ $t('install.installedButMissing') }}
</span>
<span class="label label-warning" v-if="!tableInfo.tableExist">
{{ $t('install.toBeInstalled') }}
</span>
</div>
<div class="mt10">
{{ $t('install.allFields') }}: <span class="label label-default mr5 inline-block mb10"
v-for="field in tableInfo.allFields">{{field.DBName}}</span>
</div>
<div class="mt10" v-if="tableInfo.tableExist && tableInfo.missingFields.length">
{{ $t('install.missingFields') }}: <span class="label label-default mr5 inline-block mb10"
v-for="field in tableInfo.missingFields">{{field.DBName}}</span>
</div>
</div>
<div class="row mt20">
<div class="col-md-12">
<div class="alert alert-info">
<div><i class="fa fa-bullhorn"></i>{{ $t('install.tableNotice') }}</div>
<ol class="pl30 m0">
<li>{{ $t('install.tableNotice1') }}</li>
<li>{{ $t('install.tableNotice2') }}</li>
<li>{{ $t('install.tableNotice3') }}</li>
<li>{{ $t('install.tableNotice4') }}</li>
</ol>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-right">
<button class="btn btn-info btn-sm mr5" v-if="!install.tableCreated()" @click.stop.prevent="createTable()">
<i class="fa fa-gavel"></i>
{{ $t('install.oneKeyCreate') }}
</button>
<button class="btn btn-success btn-sm mr5" v-if="install.tableCreated()">
<i class="fa fa-check"></i>
{{ $t('install.oneKeyCreate') }}
</button>
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="goTo('first')">
<i class="fa fa-arrow-left"></i>
{{ $t('install.preStep') }}
</button>
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="goTo('third')">
<i class="fa fa-arrow-right"></i>
{{ $t('install.nextStep') }}
</button>
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane :label="$t('install.setAdministrator')" name="third" :disabled="!install.tableCreated()">
<div class="install-block">
<div class="text-center" v-show="phase===-1">
<i class="fa fa-spinner fa-spin fa-3x fa-fw"></i>
</div>
<NbExpanding>
<div v-show="phase===0">
<div>
{{ $t('install.detectAdministrator') }}
</div>
<div class="mv10 bold" v-for="admin in install.adminList">
{{admin.username}}
</div>
<div>
{{ $t('install.useOrCreateAdministrator') }}
</div>
<div>
<div class="text-right">
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="phase = 1">
<i class="fa fa-user-o"></i>
{{ $t('install.validateAdministrator') }}
</button>
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="phase = 2">
<i class="fa fa-user-plus"></i>
{{ $t('install.createAdministrator') }}
</button>
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="goTo('second')">
<i class="fa fa-arrow-left"></i>
{{ $t('install.preStep') }}
</button>
</div>
</div>
</div>
</NbExpanding>
<NbExpanding>
<div v-show="phase===1">
<div class="bold f20 text-center">
{{ $t('install.validateAdministrator') }}
</div>
<div class="row mt10" v-validator="install.adminValidatorSchema.adminUsername.error">
<label class="col-md-2 control-label mt5 compulsory">{{ $t('install.administratorUsername') }}</label>
<div class="col-md-10 validate">
<input type="text" class="form-control" v-model="install.adminUsername">
</div>
</div>
<div class="row mt10" v-validator="install.adminValidatorSchema.adminPassword.error">
<label class="col-md-2 control-label mt5 compulsory">{{ $t('install.administratorPassword') }}</label>
<div class="col-md-10 validate">
<input type="password" class="form-control" v-model="install.adminPassword">
</div>
</div>
<div class="row mt10">
<div class="col-md-12 text-right">
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="phase = 0">
<i class="fa fa-arrow-left"></i>
{{ $t('install.preStep') }}
</button>
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="validateAdmin()">
<i class="fa fa-send"></i>
{{ $t('submit') }}
</button>
</div>
</div>
</div>
</NbExpanding>
<NbExpanding>
<div v-show="phase===2">
<div class="bold f20 text-center">
{{ $t('install.createAdministrator') }}
</div>
<div class="row mt10" v-validator="install.adminValidatorSchema.adminUsername.error">
<label class="col-md-2 control-label mt5 compulsory">{{ $t('install.administratorUsername') }}</label>
<div class="col-md-10 validate">
<input type="text" class="form-control" v-model="install.adminUsername">
</div>
</div>
<div class="row mt10" v-validator="install.adminValidatorSchema.adminPassword.error">
<label class="col-md-2 control-label mt5 compulsory">{{ $t('install.administratorPassword') }}</label>
<div class="col-md-10 validate">
<input type="password" class="form-control" v-model="install.adminPassword">
</div>
</div>
<div class="row mt10" v-validator="install.adminValidatorSchema.adminRepassword.error">
<label class="col-md-2 control-label mt5 compulsory">{{ $t('install.administratorRePassword') }}</label>
<div class="col-md-10 validate">
<input type="password" class="form-control" v-model="install.adminRepassword">
</div>
</div>
<div class="row mt20">
<div class="col-md-12">
<div class="alert alert-info">
<div><i class="fa fa-bullhorn"></i> {{ $t('install.notice') }}</div>
<ol class="pl30 m0">
<li>{{ $t('install.usernameRule') }}</li>
</ol>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-right">
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="preStep">
<i class="fa fa-arrow-left"></i>
{{ $t('install.preStep') }}
</button>
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="createAdmin()">
<i class="fa fa-send"></i>
{{ $t('submit') }}
</button>
</div>
</div>
</div>
</NbExpanding>
</div>
</el-tab-pane>
<el-tab-pane :label="$t('finish') " name="forth" :disabled="!install.adminConfigured">
<div class="install-block">
<div class="text-center">
<img src="../../assets/img/success.svg" class="w50"/>
</div>
<div class="text-center mt10">
{{ $t('install.congratulationInstall') }}
</div>
<div class="text-center mv20">
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="finish">
<i class="fa fa-home">
{{ $t('install.enterHome') }}
</i>
</button>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import Install from "../../common/model/install/Install";
import NbExpanding from "../../common/widget/NbExpanding";
export default {
data() {
return {
//用来决定该如何验证管理员
phase: -1,
activeName: 'first',
install: new Install()
}
},
computed: {
mysqlUrl() {
return this.install.mysqlUsername + ":" + this.install.mysqlPassword + "@tcp(" + this.install.mysqlHost + ":" + this.install.mysqlPort + ")/" + this.install.mysqlSchema + "?charset=utf8&parseTime=True&loc=Local"
}
},
watch: {
mysqlUrl(newVal, oldVal) {
this.install.verified = false
}
},
components: {
NbExpanding
},
methods: {
mysqlPasswordChange(e) {
//这么做主要是为了防止浏览器自动填充
//只有在第一个tab的时候才能变化
if (this.activeName === "first") {
this.install.mysqlPassword = e.target.value
}
},
verify() {
let that = this;
this.install.httpVerify(function () {
that.install.verified = true
that.$message.success(that.$t("install.mysqlConnectionPass"))
})
},
fetchTableInfoList() {
let that = this;
this.install.httpTableInfoList()
},
handleClick(tab, event) {
let paneName = tab.paneName;
},
createTable() {
//开始建表
let that = this;
this.install.httpCreateTable(function (response) {
that.$message.success(that.$t("install.createTableSuccess"))
})
},
goTo(tabName) {
let that = this
if (tabName === "second") {
if (!this.install.verified) {
this.$message.error(that.$t("install.validateMysqlFirst"))
return
}
this.fetchTableInfoList();
} else if (tabName === "third") {
if (!this.install.tableCreated()) {
this.$message.error(that.$t("install.crateTableFirst"))
return
}
//获取管理员列表
this.adminList()
} else if (tabName === "forth") {
if (!this.install.adminConfigured) {
this.$message.error(that.$t("install.configAdminFirst"))
return
}
}
this.activeName = tabName
},
adminList() {
//开始创建管理员
let that = this;
this.install.httpAdminList(function (response) {
if (that.install.adminList.length) {
that.phase = 0
} else {
that.phase = 2
}
})
},
createAdmin() {
//开始创建管理员
let that = this;
this.install.httpCreateAdmin(function (response) {
that.$message.success(that.$t("install.createAdminSuccess"))
that.goTo("forth")
})
},
validateAdmin() {
//开始创建管理员
let that = this;
this.install.httpValidateAdmin(function (response) {
that.$message.success(that.$t("install.validateAdminSuccess"))
that.goTo("forth")
})
},
//创建管理员时的上一步
preStep() {
let that = this
if (that.install.adminList.length) {
that.phase = 0
} else {
that.goTo("second")
}
},
finish() {
let that = this;
that.install.httpFinish(function (response) {
that.$store.state.installed = true
that.$store.state.preference.httpFetch(function () {
that.$router.push("/")
})
})
}
},
mounted() {
}
}
</script>
<style lang="less" rel="stylesheet/less">
.backyard-install {
.install-block {
background-color: white;
box-shadow: 0 0 5px rgba(0, 0, 0, .2);
border-radius: 5px;
padding: 20px 15px 10px 15px;
margin-bottom: 30px;
}
}
</style>
-108
View File
@@ -1,108 +0,0 @@
<template>
<div class="bottom-navigation text-center">
<span class="item">
<span v-html="preference.copyright"></span>
</span>
<span class="item">
<span v-html="preference.record"></span>
</span>
<span class="item">
<a href="javascript:void(0)" @click.stop.prevent="changeLang">
{{Vue.store.state.lang==='zh'?'English':'中文'}}
</a>
</span>
<!-- 版本号:cn.eyeblue.tank:3.0.0 -->
<!-- 开源不易,请不要移除掉这里的代码,蓝眼云盘谢谢您 ^_^ -->
<span class="brand">
Powered by <a target="_blank" href="https://github.com/eyebluecn/tank">
<img class="w30" src="../../assets/img/logo.png"/>
{{ Vue.i18n.t("eyeblueTank") }}</a>
</span>
</div>
</template>
<script>
import Cookies from "js-cookie"
import Vue from "vue"
export default {
data() {
return {
Vue,
preference: Vue.store.state.preference
}
},
methods: {
changeLang() {
if (Vue.store.state.lang === 'zh') {
Vue.store.state.lang = 'en'
} else {
Vue.store.state.lang = 'zh'
}
Cookies.set('_lang', Vue.store.state.lang);
Vue.i18n.locale = Vue.store.state.lang
}
}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../../assets/css/global/variables";
.bottom-navigation {
//大屏幕
@media (min-width: @screen-sm-min) {
position: fixed;
height: @power-footer-height;
line-height: @power-footer-height;
background-color: white;
bottom: 0;
right: 0;
left: @sidebar-width;
padding: 0 20px;
border-top: 1px solid #eee;
.item {
margin-right: 10px;
}
}
//小屏幕
@media (max-width: @screen-xs-max) {
.item {
display: block;
}
}
&.show-drawer {
//大屏幕
@media (min-width: @screen-sm-min) {
position: fixed;
height: @power-footer-height;
line-height: @power-footer-height;
background-color: white;
bottom: 0;
right: 0;
left: @sidebar-width;
padding: 0 20px;
border-top: 1px solid #eee;
.item {
margin-right: 10px;
}
}
//小屏幕
@media (max-width: @screen-xs-max) {
.item {
display: block;
}
}
}
.brand {
}
}
</style>
-28
View File
@@ -1,28 +0,0 @@
<template>
<div class="not-found">
{{ $t('notFound') }}
</div>
</template>
<script>
export default {
data() {
return {}
},
computed: {},
watch: {},
components: {},
methods: {}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../../assets/css/global/variables";
.not-found {
font-size: 32px;
}
</style>
-310
View File
@@ -1,310 +0,0 @@
<template>
<nav ref="menuNav" class="side-navigation" :class="{'show-drawer':showDrawer}" @click.stop.prevent="eatClick">
<div class="sidebar-collapse">
<div class="menu-header" @click="goToProfile" v-if="$store.state.installed">
<div class="logo-area">
<img alt="image" class="img-circle w80"
:src="user.getAvatarUrl()"/>
</div>
<div class="text-area">
<div class="nickname">
{{user.role === 'GUEST' ? '请登录' : user.username}}
</div>
</div>
</div>
<ul class="nav mt20" v-if="$store.state.installed">
<li v-if="user.role === UserRole.GUEST">
<router-link to="/user/login">
<i class="w14 fa fa-user-circle-o"></i>
<span>{{ $t('login') }}</span>
</router-link>
</li>
<li v-if="user.role !== UserRole.GUEST">
<router-link to="/" :class="{'custom-active':isCustomActive('/')}">
<i class="w14 fa fa fa-th"></i>
<span>{{ $t('layout.allFiles') }}</span>
</router-link>
</li>
<li v-if="user.role !== UserRole.GUEST">
<router-link to="/share/list" :class="{'custom-active':isCustomActive('/share/list')}">
<i class="w14 fa fa fa-share-alt"></i>
<span>{{ $t('layout.myShare') }}</span>
</router-link>
</li>
<li v-if="user.role === UserRole.ADMINISTRATOR">
<router-link to="/preference" :class="{'custom-active':isCustomActive('/preference')}">
<i class="w14 fa fa-cog"></i>
<span>{{ $t('layout.setting') }}</span>
</router-link>
</li>
<li v-if="user.role === UserRole.ADMINISTRATOR">
<router-link to="/dashboard/index" :class="{'custom-active':isCustomActive('/dashboard/index')}">
<i class="w14 fa fa-dashboard"></i>
<span>{{ $t('layout.dashboard') }}</span>
</router-link>
</li>
<li v-if="user.role === UserRole.ADMINISTRATOR">
<router-link to="/user/list" :class="{'custom-active':isCustomActive('/user/list')}">
<i class="w14 fa fa-user"></i>
<span>{{ $t('layout.users') }}</span>
</router-link>
</li>
<li v-if="user.role !== UserRole.GUEST">
<router-link to="/user/login" :class="{'custom-active':isCustomActive('/user/login')}">
<i class="w14 fa fa-power-off"></i>
<span>{{ $t('layout.logout') }}</span>
</router-link>
</li>
<li class="about-menu">
<a href="javascript:void(0)" @click.stop.prevent="showAbout($createElement)">
<i class="w14 fa fa-info-circle"></i>
<span>{{ $t('layout.about') }}</span>
</a>
</li>
</ul>
<div class="menu-header" v-if="!$store.state.installed">
<div class="logo-area">
<img alt="image" class="img-circle w80" src="../../assets/img/logo.png"/>
</div>
</div>
<ul class="nav mt20" v-if="!$store.state.installed">
<li>
<router-link to="/install/index" :class="{'custom-active':isCustomActive('/install/index')}">
<i class="w14 fa fa-cogs"></i>
<span>{{ $t('layout.install') }}</span>
</router-link>
</li>
</ul>
</div>
</nav>
</template>
<script>
import {MessageBox} from 'element-ui'
import {UserRole} from "../../common/model/user/UserRole";
import {handleImageUrl} from "../../common/util/ImageUtil";
import BottomNavigation from "./BottomNavigation";
let logoPath = require("../../assets/img/logo.png")
export default {
data() {
return {
UserRole,
user: this.$store.state.user,
preference: this.$store.state.preference
}
},
computed: {
showDrawer() {
return this.$store.state.config.showDrawer;
},
mobile() {
return this.$store.state.config.mobile;
}
},
components: {},
methods: {
handleImageUrl,
isCustomActive(path) {
return this.$route.path === path
},
goToProfile() {
if (this.user.role === UserRole.GUEST) {
this.$router.push("/user/login");
} else {
this.$router.push("/user/detail/" + this.user.uuid);
}
},
eatClick() {
},
showAbout(createElement) {
let that = this
let targetMatterUuid = null
let dom = createElement(BottomNavigation, {
props: {
}
})
MessageBox({
title: that.$t('layout.about'),
message: dom,
confirmButtonText: that.$t("confirm"),
showCancelButton: false,
callback: (action, instance) => {
}
})
}
},
watch: {},
mounted() {
let that = this;
}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../../assets/css/global/variables";
@nav-bg: #3A3F51;
@nav-text-color: white;
@font-highlight-color: #ddd;
@left-border-color: @brand-primary;
//手机屏幕
@media (max-width: @screen-xs-max) {
}
//左侧菜单block.
.side-navigation {
//overflow: auto;
-webkit-transition: all 0.4s;
-moz-transition: all 0.4s;
-o-transition: all 0.4s;
transition: all 0.4s;
position: fixed;
width: @sidebar-width;
left: -@sidebar-width;
top: 0;
bottom: 0;
z-index: 1000;
background: darken(@nav-bg, 3%);
&.show-drawer {
left: 0;
}
.sidebar-collapse {
padding-bottom: 40px;
}
.app-name-box {
text-align: center;
vertical-align: middle;
display: table-cell;
width: @sidebar-width;
background-color: @brand-primary;
height: @top-navigation-height;
a {
font-size: 16px;
color: white;
}
}
//放头像和用户名的地方。
.menu-header {
cursor: pointer;
.logo-area {
text-align: center;
padding: 20px 0;
}
.text-area {
.nickname {
text-align: center;
color: @nav-text-color;
font-weight: bold;
}
.role {
text-align: center;
color: @nav-text-color;
}
}
}
//分割线
.separate-line {
margin-top: 20px;
padding-bottom: 5px;
border-bottom: 1px solid #666666;
span {
margin-left: 20px;
color: #777;
}
}
.nav {
li {
a {
color: @nav-text-color;
padding: 12px 20px;
&:hover, &:focus {
color: @font-highlight-color;
background-color: transparent;
outline: none;
}
i {
margin-right: 6px;
}
//为什么要用custom-active? 因为 is-link-exact-active 不能匹配 /user/list 和 /user/list?page=0
// is-link-active 会将 / 和 /preference 进行匹配。
//所以用 is-link-exact-active 的话就会出现刷新列表页面时不高亮
//用 is-link-active 时会两个高亮。
&.custom-active {
background-color: black;
}
}
}
}
.about-menu {
//大屏幕
@media (min-width: @screen-sm-min) {
display: none;
}
//手机屏幕
@media (max-width: @screen-xs-max) {
}
}
}
</style>
-177
View File
@@ -1,177 +0,0 @@
<template>
<div class="top-navigation-bar">
<nav class="navbar">
<div class="navbar-title">
<router-link to="/">
<img class="logo" :src="logoUrl"/>
<span class="title">{{preference.name?preference.name: $t('eyeblueTank') }}</span>
</router-link>
</div>
<button class="drawer-trigger btn btn-primary btn-sm mr5"
@click.stop.prevent="$store.state.config.showDrawer=!$store.state.config.showDrawer">
<i class="fa fa-bars"></i>
</button>
</nav>
</div>
</template>
<script>
let defaultLogoPath = require("../../assets/img/logo.png");
export default {
data() {
return {
preference: this.$store.state.preference,
user: this.$store.state.user
}
},
computed: {
//logo可以使用自定义的。
logoUrl() {
if (this.preference.logoUrl) {
return this.preference.logoUrl + "?ir=fill_" + 200 + "_" + 200
} else {
return defaultLogoPath
}
}
},
components: {},
methods: {}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../../assets/css/global/variables";
//上方的导航栏
.top-navigation-bar {
height: @top-navigation-height;
background-color: white;
border-bottom: 1px solid #eeeeee;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
padding-left: @sidebar-width;
.navbar {
border: none;
}
//手机屏幕
@media (max-width: @screen-xs-max) {
padding-left: 0;
}
.navbar-title {
float: left;
cursor: pointer;
margin-left: 10px;
.logo {
height: @top-navigation-height;
}
.title {
margin-left: 10px;
font-size: 18px;
color: black;
font-weight: bold;
display: inline-block;
line-height: @top-navigation-height;
vertical-align: middle;
}
}
.login-trigger {
float: right;
margin-right: 10px;
.login-span, .register-span {
color: #888;
cursor: pointer;
font-size: 14px;
line-height: 40px;
&:hover {
color: black;
text-decoration: underline;
}
}
}
.drawer-trigger {
float: right;
margin-top: 5px;
margin-right: 5px;
}
.navbar-right {
> li {
display: inline-block;
&:last-child {
margin-right: 5px;
}
a {
color: #999c9e;
font-size: 14px;
padding: 6px 12px;
}
}
@media (min-width: 768px) {
float: right !important;
margin-right: 0;
}
.message-info {
position: relative;
.label {
line-height: 12px;
padding: 2px 5px;
position: absolute;
left: 10%;
bottom: 50%;
}
}
}
//小屏幕
@media (min-width: @screen-sm-min) {
.drawer-trigger {
display: none;
}
}
//手机屏幕
@media (max-width: @screen-xs-max) {
.navbar-right {
display: none;
}
}
}
</style>
-204
View File
@@ -1,204 +0,0 @@
<template>
<div class="matter-detail">
<div class="matter-block">
<div class="title">
{{$t('matter.fileInfo')}}
</div>
<div class="row">
<div class="col-md-12 form-info">
<span>{{$t('matter.fileInfo')}}: </span>
<span class="bold">{{matter.name}}</span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('matter.path')}}: </span>
<span class="matter-breadcrumb">
<span v-for="m in parentList">
<span>/</span>
<router-link v-if="m.dir" :to="'/?puuid='+m.uuid">
{{m.name}}
</router-link>
<span v-else>
{{m.name}}
</span>
</span>
</span>
<a class="mr15" :title="$t('matter.path')"
@click.stop.prevent="copyPath">
<i class="fa fa-copy"></i>
</a>
</div>
<div class="col-md-12 form-info" v-if="!matter.dir">
<span>{{$t('matter.size')}}: </span>
<span class="bold">{{matter.size | humanFileSize}}</span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('matter.createTime')}}: </span>
<span class="bold">{{matter.createTime | simpleDateTime}}</span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('matter.updateTime')}}: </span>
<span class="bold">{{matter.updateTime | simpleDateTime}}</span>
</div>
<div class="col-md-12 form-info" v-if="!matter.dir">
<span>{{$t('matter.publicOrPrivate')}}: </span>
<span>{{matter.privacy?$t('matter.privateInfo'):$t('matter.publicInfo')}}</span>
</div>
<div class="col-md-12 form-info" v-if="!matter.dir">
<span>{{$t('matter.downloadTimes')}}: </span>
<span>{{matter.times}}</span>
</div>
<div class="col-md-12 form-info" v-if="!matter.dir">
<span>{{$t('matter.operations')}}: </span>
<span>
<a class="mr15" :title="$t('matter.download')" @click.stop.prevent="matter.download()" v-if="!matter.dir">
<i class="fa fa-download"></i>
{{$t('matter.download')}}
</a>
<a class="mr15" :title="$t('matter.preview')" @click.stop.prevent="matter.preview()" v-if="!matter.dir">
<i class="fa fa-eye"></i>
{{$t('matter.preview')}}
</a>
<a class="mr15" :title="$t('matter.oneTimeLinkInfo')"
@click.stop.prevent="copyLink" v-if="!matter.dir && matter.privacy">
<i class="fa fa-link"></i>
{{$t('matter.oneTimeLink')}}
</a>
<a class="mr15" :title="$t('matter.publicInfo')"
@click.stop.prevent="copyLink" v-if="!matter.dir && !matter.privacy">
<i class="fa fa-link"></i>
{{$t('matter.copyLink')}}
</a>
</span>
</div>
</div>
</div>
<div class="matter-block" v-if="!matter.dir && matter.uuid && matter.isImage()">
<div class="title">
{{$t('matter.imageCache')}}
</div>
<div class="ph5">
<ImageCacheList :initFilter="{matterUuid:matter.uuid}"/>
</div>
</div>
</div>
</template>
<script>
import Matter from "../../common/model/matter/Matter";
import ImageCacheList from "../image/cache/widget/ImageCacheList"
import DownloadToken from "../../common/model/download/token/DownloadToken";
import {Message} from "element-ui"
export default {
data() {
return {
matter: new Matter(),
//复制只能是同步进行,因此提前获取downloadToken
downloadToken: new DownloadToken(),
preference: this.$store.state.preference
}
},
computed: {
parentList() {
let that = this
let arr = []
let item = that.matter;
while (item) {
arr.unshift(item)
item = item.parent
}
return arr;
}
},
methods: {
copyLink() {
let that = this;
if (that.matter.privacy) {
let textToCopy = that.matter.getDownloadUrl(that.downloadToken.uuid);
that.$copyPlguin.copy(textToCopy, function () {
Message.success({
message: that.$t('operationSuccess'),
center: true
})
})
} else {
let textToCopy = that.matter.getDownloadUrl();
that.$copyPlguin.copy(textToCopy, function () {
Message.success({
message: that.$t('operationSuccess'),
center: true
})
})
}
},
copyPath() {
let that = this;
let textToCopy = that.matter.path;
that.$copyPlguin.copy(textToCopy, function () {
Message.success({
message: that.$t('operationSuccess'),
center: true
})
})
}
},
components: {
ImageCacheList
},
mounted() {
let that = this;
this.matter.uuid = this.$store.state.route.params.uuid
if (this.matter.uuid) {
this.matter.httpDetail(function () {
if (!that.matter.dir) {
that.downloadToken.httpFetchDownloadToken(that.matter.uuid)
}
})
}
}
}
</script>
<style lang="less" rel="stylesheet/less">
.matter-detail {
.matter-block {
background-color: white;
box-shadow: 0 0 5px rgba(0, 0, 0, .2);
border-radius: 5px;
padding: 20px 15px 10px 15px;
margin-bottom: 30px;
.title {
font-size: 16px;
padding: 0 0 15px 0;
color: black;
margin-bottom: 10px;
border-bottom: 1px solid #eee;
}
.matter-breadcrumb {
a {
font-weight: normal;
}
}
}
}
</style>
-544
View File
@@ -1,544 +0,0 @@
<template>
<div class="backyard-matter-list">
<div class="row">
<div class="col-md-8 mb10">
<button class="btn btn-primary btn-sm mr5 mb5" v-if="selectedMatters.length !== pager.data.length"
@click.stop.prevent="checkAll">
<i class="fa fa-check-square"></i>
{{ $t("selectAll") }}
</button>
<button class="btn btn-primary btn-sm mr5 mb5"
v-if="pager.data.length && selectedMatters.length === pager.data.length"
@click.stop.prevent="checkNone">
<i class="fa fa-square-o"></i>
{{ $t("cancel") }}
</button>
<button class="btn btn-primary btn-sm mr5 mb5" v-if="selectedMatters.length" @click.stop.prevent="deleteBatch">
<i class="fa fa-trash"></i>
{{ $t("delete") }}
</button>
<button class="btn btn-primary btn-sm mr5 mb5" v-if="selectedMatters.length" @click.stop.prevent="downloadZip">
<i class="fa fa-download"></i>
{{ $t("matter.download") }}
</button>
<button class="btn btn-primary btn-sm mr5 mb5" v-if="selectedMatters.length"
@click.stop.prevent="moveBatch($createElement)">
<i class="fa fa-arrows"></i>
{{ $t("matter.move") }}
</button>
<button class="btn btn-primary btn-sm mr5 mb5" v-if="selectedMatters.length"
@click.stop.prevent="shareDialogVisible = !shareDialogVisible">
<i class="fa fa-share-alt"></i>
{{ $t("matter.share") }}
</button>
<el-dialog
:title="$t('matter.share')"
:visible.sync="shareDialogVisible"
:append-to-body="true">
<SharePanel :matters="selectedMatters"
@close="shareDialogVisible = false"/>
</el-dialog>
<span class="btn btn-primary btn-sm btn-file mr5 mb5">
<slot name="button">
<i class="fa fa-cloud-upload"></i>
<span> {{ $t("matter.upload") }} </span>
</slot>
<input ref="refFile" type="file" multiple="multiple" @change.prevent.stop="triggerUpload"/>
</span>
<button class="btn btn-sm btn-primary mr5 mb5" @click.stop.prevent="createDirectory">
<i class="fa fa-folder"></i>
{{ $t("matter.create") }}
</button>
</div>
<div class="col-md-4 mb10">
<div class="input-group">
<input type="text" class="form-control" v-model="searchText" @keyup.enter="searchFile"
:placeholder="$t('matter.searchFile')">
<span class="input-group-btn">
<button type="button" class="btn btn-primary" @click.prevent.stop="searchFile">
<i class="fa fa-search"></i>
</button>
</span>
</div>
</div>
<div class="col-md-12">
<div v-for="m in uploadMatters">
<UploadMatterPanel :matter="m"/>
</div>
<div v-if="director.createMode">
<MatterPanel ref="newMatterPanel" @createDirectorySuccess="refresh()"
:matter="newMatter"
:director="director"/>
</div>
<div v-for="matter in pager.data">
<MatterPanel :key="matter.uuid"
@goToDirectory="goToDirectory"
@deleteSuccess="refresh()"
:matter="matter"
:director="director"
@checkMatter="checkMatter"
@previewImage="previewImage"
/>
</div>
<div>
<NbPager :pager="pager" :callback="refresh" :emptyHint="$t('matter.noContentYet')"/>
</div>
</div>
</div>
</div>
</template>
<script>
import MatterPanel from './widget/MatterPanel'
import UploadMatterPanel from './widget/UploadMatterPanel'
import MoveBatchPanel from './widget/MoveBatchPanel'
import SharePanel from './widget/ShareOperationPanel'
import NbSlidePanel from '../../common/widget/NbSlidePanel.vue'
import NbExpanding from '../../common/widget/NbExpanding.vue'
import NbCheckbox from '../../common/widget/NbCheckbox.vue'
import NbFilter from '../../common/widget/filter/NbFilter'
import NbPager from '../../common/widget/NbPager'
import Matter from '../../common/model/matter/Matter'
import Pager from '../../common/model/base/Pager'
import Director from './widget/Director'
import {Message, MessageBox} from 'element-ui'
import {UserRole} from "../../common/model/user/UserRole";
import {SortDirection} from "../../common/model/base/SortDirection";
import {humanFileSize} from "../../common/filter/str";
import Share from "../../common/model/share/Share";
export default {
data() {
return {
//当前文件夹信息。
matter: new Matter(),
//准备新建的文件。
newMatter: new Matter(),
//准备上传的一系列文件
uploadMatters: this.$store.state.uploadMatters,
//当前选中的文件
selectedMatters: [],
//搜索的文字
searchText: null,
pager: new Pager(Matter, 50),
//移动的目标文件夹
targetMatterUuid: null,
user: this.$store.state.user,
preference: this.$store.state.preference,
breadcrumbs: this.$store.state.breadcrumbs,
director: new Director(),
share: new Share(),
//分享的弹框
shareDialogVisible: false
}
},
components: {
MatterPanel,
UploadMatterPanel,
MoveBatchPanel,
SharePanel,
NbCheckbox,
NbFilter,
NbPager,
NbSlidePanel,
NbExpanding
},
methods: {
reset() {
this.pager.page = 0
this.pager.resetFilter()
this.pager.enableHistory()
},
search() {
this.pager.page = 0
this.refresh()
},
refresh() {
let puuid = this.$route.query.puuid
if (puuid) {
this.pager.setFilterValue('puuid', puuid)
} else {
this.pager.setFilterValue('puuid', 'root')
}
//如果所有的排序都没有设置,那么默认以时间降序。
this.pager.setFilterValue('orderCreateTime', SortDirection.DESC)
this.pager.setFilterValue("orderDir", SortDirection.DESC)
//如果没有设置用户的话,那么默认显示当前登录用户的资料
if (!this.pager.getFilterValue('userUuid')) {
this.pager.setFilterValue('userUuid', this.user.uuid)
}
this.pager.setFilterValue("name", null)
//刷新面包屑
this.refreshBreadcrumbs()
this.pager.httpFastPage()
},
goToDirectory(uuid) {
this.pager.setFilterValue('puuid', uuid)
this.pager.page = 0
let query = this.pager.getParams()
//采用router去管理路由,否则浏览器的回退按钮出现意想不到的问题。
this.$router.push({
path: '/',
query: query
})
},
refreshBreadcrumbs() {
let that = this
//清空暂存区
this.selectedMatters.splice(0, this.selectedMatters.length)
let uuid = that.pager.getFilterValue('puuid')
//根目录简单处理即可。
if (!uuid || uuid === 'root') {
this.matter.uuid = 'root'
that.breadcrumbs.splice(0, that.breadcrumbs.length)
that.breadcrumbs.push({
title: 'matter.allFiles'
})
} else {
this.matter.uuid = uuid
this.matter.httpDetail(function () {
let arr = []
let cur = that.matter.parent
while (cur) {
arr.push(cur)
cur = cur.parent
}
that.breadcrumbs.splice(0, that.breadcrumbs.length)
let query = that.pager.getParams()
query['puuid'] = 'root'
//添加一个随机数,防止watch $route失败
query['_t'] = new Date().getTime()
that.breadcrumbs.push({
title: 'matter.allFiles',
path: '/',
query: query
})
for (let i = arr.length - 1; i >= 0; i--) {
let m = arr[i]
let query = that.pager.getParams()
query['puuid'] = m.uuid
query['_t'] = new Date().getTime()
that.breadcrumbs.push({
title: m.name,
displayDirect: true,
path: '/',
query: query
})
}
//第一个文件
that.breadcrumbs.push({
title: that.matter.name,
displayDirect: true,
})
})
}
},
createDirectory() {
let that = this
that.newMatter.name = 'matter.allFiles'
that.newMatter.dir = true
that.newMatter.editMode = true
that.newMatter.puuid = that.matter.uuid
if (!that.newMatter.puuid) {
that.newMatter.puuid = 'root'
}
//指定为当前选择的用户。
//如果没有设置用户的话,那么默认显示当前登录用户的资料
if (!that.pager.getFilterValue('userUuid')) {
that.newMatter.userUuid = that.user.uuid
} else {
that.newMatter.userUuid = that.pager.getFilterValue('userUuid')
}
that.director.createMode = true
setTimeout(function () {
that.$refs.newMatterPanel.highLight()
}, 100)
},
triggerUpload() {
let that = this
let domFiles = that.$refs['refFile'].files;
if (!domFiles || !domFiles.length) {
that.$message.error(that.$t('matter.allFiles'))
return;
}
if (domFiles.length > 1000) {
that.$message.error(that.$t('matter.exceed1000'))
return;
}
for (let i = 0; i < domFiles.length; i++) {
let domFile = domFiles[i];
let m = new Matter()
m.dir = false
m.puuid = that.matter.uuid
//指定为当前选择的用户。
//如果没有设置用户的话,那么默认显示当前登录用户的资料
if (!that.pager.getFilterValue('userUuid')) {
m.userUuid = that.user.uuid
} else {
m.userUuid = that.pager.getFilterValue('userUuid')
}
//判断文件大小。
if (that.user.sizeLimit >= 0) {
if (domFile.size > that.user.sizeLimit) {
that.$message.error(that.$t('matter.sizeExceedLimit', humanFileSize(domFile.size), humanFileSize(that.user.sizeLimit)))
continue
}
}
m.file = domFile
m.httpUpload(function () {
that.$store.state.uploadListInstance.refresh()
})
that.uploadMatters.push(m)
}
},
previewImage(matter) {
let that = this;
//从matter开始预览图片
let imageArray = []
let startIndex = -1;
this.pager.data.forEach(function (item, index) {
if (item.isImage()) {
imageArray.push(item.getPreviewUrl())
if (item.uuid === matter.uuid) {
startIndex = imageArray.length - 1
}
}
})
that.$photoSwipePlugin.showPhotos(imageArray, startIndex)
},
//全选
checkAll() {
this.pager.data.forEach(function (i, index) {
i.check = true
})
this.checkMatter()
},
//取消全选
checkNone() {
this.pager.data.forEach(function (i, index) {
i.check = false
})
this.checkMatter()
},
//选择文件时放入暂存区等待操作
checkMatter(matter) {
let that = this
//统计所有的勾选
this.selectedMatters.splice(0, this.selectedMatters.length)
this.pager.data.forEach(function (matter, index) {
if (matter.check) {
that.selectedMatters.push(matter)
}
})
},
//批量删除
downloadZip() {
let that = this
let uuids = []
that.selectedMatters.forEach(function (item, index) {
uuids.push(item.uuid)
})
that.matter.downloadZip(uuids.toString())
},
//批量删除
deleteBatch() {
let that = this
MessageBox.confirm(that.$t("actionCanNotRevertConfirm"), that.$t("prompt"), {
confirmButtonText: that.$t("confirm"),
cancelButtonText: that.$t("cancel"),
type: 'warning',
callback: function (action, instance) {
if (action === 'confirm') {
let uuids = ""
that.selectedMatters.forEach(function (item, index) {
if (index === 0) {
uuids = item.uuid
} else {
uuids = uuids + "," + item.uuid
}
})
that.matter.httpDeleteBatch(uuids, function (response) {
Message.success(that.$t("operationSuccess"))
that.refresh()
})
}
}
})
},
//批量移动
moveBatch(createElement) {
let that = this
let dom = createElement(MoveBatchPanel, {
props: {
version: (new Date()).getTime(),
userUuid: that.selectedMatters[0].userUuid,
callback: function (matter) {
if (matter.uuid) {
that.targetMatterUuid = matter.uuid
} else {
that.targetMatterUuid = "root"
}
}
}
})
MessageBox({
title: '移动到',
message: dom,
customClass: 'wp50',
confirmButtonText: that.$t("confirm"),
showCancelButton: true,
cancelButtonText: '关闭',
callback: (action, instance) => {
if (action === 'confirm') {
let uuids = ""
that.selectedMatters.forEach(function (item, index) {
if (index === 0) {
uuids = item.uuid
} else {
uuids = uuids + "," + item.uuid
}
})
that.matter.httpMove(uuids, that.targetMatterUuid, function (response) {
Message.success('移动成功!')
that.refresh()
})
}
}
})
},
searchFile() {
let that = this;
if (that.searchText) {
//刷新面包屑
that.refreshBreadcrumbs()
that.pager.resetFilter()
that.pager.setFilterValue('puuid', null)
that.pager.setFilterValue("orderCreateTime", SortDirection.DESC)
that.pager.setFilterValue("name", that.searchText)
that.pager.httpFastPage()
} else {
that.refresh()
}
}
},
watch: {
'$route'(newVal, oldVal) {
this.refresh()
},
'searchText'(newVal, oldVal) {
if (oldVal && !newVal) {
this.refresh()
}
}
},
created() {
/*初始化inputSelection*/
if (this.user.role === UserRole.ADMINISTRATOR) {
this.pager.getFilter('userUuid').visible = true
} else {
this.pager.setFilterValue('userUuid', this.user.uuid)
}
},
mounted() {
let that = this
this.pager.enableHistory()
//更新vuex中List实例,主要解决大文件上传持有的功能。
this.$store.state.uploadListInstance = this
this.refresh()
}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../../assets/css/global/variables";
.backyard-matter-list {
}
</style>
-140
View File
@@ -1,140 +0,0 @@
<template>
<div class="folder-tree">
<div class="h50 cursor folder-block" :class="{'bg-silver-white': targetMatter.uuid === matter.uuid}"
@click.stop.prevent="clickItem">
<span class="fa fa-chevron-down mr5 w14" v-if="pager.data.length && showSubFolder"></span>
<span class="fa fa-chevron-right mr5 w14" v-if="pager.data.length && !showSubFolder"></span>
<span :class="{ 'ml23': !pager.data.length }">
<span v-if="matter.uuid">
<img :src="matter.getIcon()" class="mr5" :alt="Vue.i18n.t('matter.directory')" width="22"/>
<span>{{matter.name}}</span>
</span>
<span v-else>
<span>{{Vue.i18n.t('matter.root')}}</span>
</span>
</span>
</div>
<NbExpanding>
<div v-if="pager.data.length && showSubFolder" class="pl20">
<div v-for="(child, index) in pager.data">
<FolderTree :matter="child" :targetMatter="targetMatter" :userUuid="userUuid" :version="version"
:callback="callback" :showSubFolderInit="false"/>
</div>
</div>
</NbExpanding>
</div>
</template>
<script>
import NbExpanding from '../../../common/widget/NbExpanding'
import Pager from '../../../common/model/base/Pager'
import Matter from '../../../common/model/matter/Matter'
import Vue from "vue"
export default {
name: "FolderTree",
data() {
return {
Vue,
showSubFolder: false,
pager: new Pager(Matter)
}
},
props: {
targetMatter: {
type: Matter,
required: true
},
matter: {
type: Matter,
required: true
},
showSubFolderInit: {
type: Boolean,
required: false,
default: false
},
userUuid: {
type: String,
required: true
},
//为了让Tree在每次点开的时候都更新
version: {
type: Number,
required: true
},
//选择了一个文件夹后回掉,参数matter
callback: {
type: Function,
required: true
}
},
watch: {
//有可能外面世界的userUuid发生了变化
'userUuid'(newVal, oldVal) {
this.refresh()
},
//有可能外面世界的version发生了变化
'version'(newVal, oldVal) {
this.refresh()
}
},
methods: {
clickItem() {
this.showSubFolder = !this.showSubFolder
if (this.targetMatter.uuid !== this.matter.uuid) {
this.targetMatter.render(this.matter)
if (typeof this.callback === "function") {
this.callback(this.targetMatter)
}
}
},
refresh() {
this.showSubFolder = this.showSubFolderInit
if (!this.matter.uuid) {
this.pager.setFilterValue('puuid', 'root')
} else {
this.pager.setFilterValue('puuid', this.matter.uuid)
}
//限制选择的范围。文件和目标文件夹必须是同一主人
this.pager.setFilterValue('userUuid', this.userUuid)
this.pager.setFilterValue('dir', true)
this.pager.httpFastPage()
}
},
components: {
NbExpanding
},
mounted() {
this.refresh()
}
}
</script>
<style lang="less" rel="stylesheet/less">
.folder-tree {
.folder-block {
padding: 5px 10px;
line-height: 40px;
&:hover {
background: #eee;
}
}
.ml23 {
margin-left: 23px;
}
}
</style>
-145
View File
@@ -1,145 +0,0 @@
<template>
<div class="nb-matter-image">
<div class="tiny-block">
<div class="p10 mb10 bg-white br5 border" :style="'width:'+previewWidth+'px'" v-show="preview && value">
<img class="wp100 cursor" :src="value" @click="$photoSwipePlugin.showPhoto(value)"/>
</div>
</div>
<div>
<div class="input-group">
<input type="text"
class="form-control input-sm"
v-model="value"
v-if="manual"
:placeholder="$t('matter.fillInPicLink')">
<span class="form-control input-sm btn-file text-center pt3 pb0" v-show="!manual">
<slot name="button">
<i class="fa fa-cloud-upload"></i>
<span>{{value?$t('matter.rePick'):$t('matter.chooseImage')}}</span>
</slot>
<input ref="refFile" type="file" @change.prevent.stop="triggerUpload"/>
</span>
<span class="input-group-btn">
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="manual = !manual">
<i class="fa fa-pencil" v-if="!manual"></i>
<i class="fa fa-cloud-upload" v-if="manual"></i>
<span>{{manual?$t('matter.uploadMode'):$t('matter.fillMode')}}</span>
</button>
</span>
</div>
<div class="italic" v-if="uploadHint">
{{uploadHint}}
</div>
</div>
<div>
<UploadMatterPanel :matter="matter"/>
</div>
</div>
</template>
<script>
import Matter from '../../../common/model/matter/Matter'
import UploadMatterPanel from "./UploadMatterPanel"
import {humanFileSize} from "../../../common/filter/str";
export default {
data() {
return {
manual: false,
user: this.$store.state.user,
matter: new Matter()
}
},
components: {
UploadMatterPanel
},
props: {
preview: {
//上传的照片是否需要预览
type: Boolean,
required: false,
'default': true
},
previewWidth: {
type: Number,
required: false,
'default': 200
},
//图片的url.
value: {
type: String | null,
required: true
},
//filter.
filter: {
type: String,
required: false,
"default": "image"
},
uploadHint: {
type: String,
required: false,
"default": ""
}
},
methods: {
del() {
let that = this
that.matter.clear()
},
triggerUpload() {
let that = this
let matter = that.matter;
matter.puuid = "root"
matter.uploadHint = that.uploadHint
matter.filter = that.filter
matter.privacy = false
matter.dir = false
matter.alien = true
matter.userUuid = that.user.uuid
let value = that.$refs['refFile'].value
if (!value) {
return
}
matter.file = that.$refs['refFile'].files[0]
//判断文件大小。
if (that.user.sizeLimit >= 0) {
if (matter.file.size > that.user.sizeLimit) {
that.$message.error(this.$t('matter.sizeExceedLimit', humanFileSize(matter.file.size), humanFileSize(that.user.sizeLimit)))
return;
}
}
matter.httpUpload(function () {
that.$emit("input", matter.getPreviewUrl())
})
}
},
created() {
},
mounted() {
}
}
</script>
<style lang="less" rel="stylesheet/less">
.nb-matter-image {
}
</style>
-449
View File
@@ -1,449 +0,0 @@
<template>
<div class="widget-matter-panel">
<div @click.stop.prevent="clickRow">
<div class="media">
<div class="pull-left">
<div class="left-part">
<span class="basic-span">
<NbCheckbox v-model="matter.check"/>
</span>
<span class="basic-span">
<img class="matter-icon" :src="matter.getIcon()"/>
</span>
</div>
</div>
<!--在大屏下的操作栏-->
<div class="pull-right hidden-sm hidden-xs">
<div class="right-part" v-if="matter.uuid">
<span class="matter-operation">
<i class="fa fa-lock btn-action text-primary" v-if="!matter.dir && matter.privacy"
:title="$t('matter.setPublic')"
@click.stop.prevent="matter.httpChangePrivacy(false)"></i>
<i class="fa fa-unlock btn-action text-primary" v-if="!matter.dir && !matter.privacy"
:title="$t('matter.setPrivate')"
@click.stop.prevent="matter.httpChangePrivacy(true)"></i>
<i class="fa fa-info-circle btn-action text-primary" :title="$t('matter.file')"
@click.stop.prevent="$router.push('/matter/detail/'+matter.uuid)"></i>
<i class="fa fa-font btn-action text-primary" :title="$t('matter.rename')"
@click.stop.prevent="prepareRename"></i>
<i class="fa fa-link btn-action text-primary" :title="$t('matter.copyLink')" v-if="!matter.dir"
@click.stop.prevent="clipboard"></i>
<i class="fa fa-download btn-action text-primary" :title="$t('matter.download')"
@click.stop.prevent="matter.download()"></i>
<i class="fa fa-trash btn-action text-danger" :title="$t('matter.delete')"
@click.stop.prevent="deleteMatter"></i>
</span>
<span class="matter-size">
{{matter.size | humanFileSize}}
</span>
<span class="matter-date">
{{matter.updateTime | simpleDateHourMinute}}
</span>
</div>
</div>
<!--在小屏幕下的操作栏-->
<div class="pull-right hidden-lg hidden-md">
<span class="more-btn" @click.stop.prevent="showMore = !showMore">
<i class="fa fa-ellipsis-h btn-action" :title="$t('matter.more')"></i>
</span>
</div>
<div class="media-body">
<div class="middle-part">
<span class="matter-name-edit" v-if="matter.editMode">
<input ref="editInput" class="form-control"
:class="matter.uuid"
v-model="renameMatterName"
:placeholder="$t('matter.enterName')"
@blur="blurTrigger()"
v-on:keyup.13="enterTrigger()"/>
</span>
<span class="matter-name"
:title="matter.name" v-else>
{{matter.name}} <i class="fa fa-unlock" v-if="!matter.dir && !matter.privacy"
:title="$t('matter.publicFileEveryoneCanVisit')"></i>
</span>
</div>
</div>
</div>
</div>
<NbExpanding>
<div class="hidden-lg hidden-md more-panel" v-if="showMore">
<div class="cell-btn" style="border: none">
<span>
{{matter.updateTime | simpleDateHourMinute}}
</span>
<span v-if="!matter.dir">
{{matter.size | humanFileSize}}
</span>
</div>
<div class="cell-btn" v-if="!matter.dir && matter.privacy" :title="$t('matter.setPublic')"
@click.stop.prevent="matter.httpChangePrivacy(false)">
<i class="fa fa-lock"></i>
{{$t('matter.setPublic')}}
</div>
<div class="cell-btn" v-if="!matter.dir && !matter.privacy" :title="$t('matter.setPrivate')"
@click.stop.prevent="matter.httpChangePrivacy(true)">
<i class="fa fa-unlock"></i>
{{$t('matter.setPrivate')}}
</div>
<div class="cell-btn" :title="$t('matter.fileDetail')"
@click.stop.prevent="$router.push('/matter/detail/'+matter.uuid)">
<i class="fa fa-info-circle"></i>
{{$t('matter.fileDetail')}}
</div>
<div class="cell-btn" :title="$t('matter.rename')" @click.stop.prevent="prepareRename">
<i class="fa fa-pencil"></i>
{{$t('matter.rename')}}
</div>
<div class="cell-btn" :title="$t('matter.copyLink')"
@click.stop.prevent="clipboard">
<i class="fa fa-link"></i>
{{$t('matter.copyLink')}}
</div>
<div class="cell-btn" :title="$t('matter.download')"
@click.stop.prevent="matter.download()">
<i class="fa fa-download"></i>
{{$t('matter.download')}}
</div>
<div class="cell-btn text-danger" :title="$t('matter.delete')" @click.stop.prevent="deleteMatter">
<i class="fa fa-trash"></i>
{{$t('matter.delete')}}
</div>
</div>
</NbExpanding>
</div>
</template>
<script>
import Matter from '../../../common/model/matter/Matter'
import NbCheckbox from '../../../common/widget/NbCheckbox'
import NbExpanding from '../../../common/widget/NbExpanding'
import $ from 'jquery'
import Director from './Director'
import {Message, MessageBox} from 'element-ui'
import {currentHost, setInputSelection} from '../../../common/util/Utils'
export default {
data() {
return {
//正在向服务器提交rename的请求
renamingLoading: false,
showMore: false,
//正在重命名的临时字段
renameMatterName: null
}
},
components: {
NbExpanding,
NbCheckbox
},
props: {
matter: {
type: Matter,
required: true
},
director: {
type: Director,
required: true
}
},
watch: {
'matter.check'(newVal, oldVal) {
this.$emit('checkMatter', this.matter)
}
},
methods: {
clickRow() {
let that = this
if (this.director.isEditing()) {
console.error('导演正忙着,不予执行')
return
}
if (this.matter.dir) {
this.$emit('goToDirectory', that.matter.uuid)
} else {
//图片进行预览操作
if (that.matter.isImage()) {
this.$emit("previewImage", that.matter)
} else {
that.matter.preview()
}
}
},
deleteMatter() {
let that = this
MessageBox.confirm(that.$t('actionCanNotRevertConfirm'), that.$t('prompt'), {
confirmButtonText: that.$t("confirm"),
cancelButtonText: that.$t("cancel"),
type: 'warning',
callback: function (action, instance) {
if (action === 'confirm') {
that.matter.httpDelete(function (response) {
Message.success(that.$t('operationSuccess'))
that.$emit('deleteSuccess', that.matter)
})
}
}
})
},
prepareRename() {
let that = this
if (this.director.isEditing()) {
console.error('导演正忙着,不予执行')
return
}
//告诉导演,自己正在编辑
this.director.renameMode = true
this.matter.editMode = true
this.renameMatterName = this.matter.name
//稍作延迟,vue的组件才能加载出来
setTimeout(function () {
//如果是文件夹,全选中
let dotIndex = that.matter.name.lastIndexOf('.')
if (dotIndex === -1) {
setInputSelection(that.$refs.editInput, 0, that.renameMatterName.length)
} else {
setInputSelection(that.$refs.editInput, 0, dotIndex)
}
}, 100)
},
finishRename() {
let that = this
//有可能按enter的时候和blur同时了。
if (that.renamingLoading) {
return
}
that.renamingLoading = true
this.matter.httpRename(that.renameMatterName, function () {
that.renamingLoading = false
Message.success(that.$t('operationSuccess'))
//告诉导演,自己编辑完毕
that.director.renameMode = false
that.matter.editMode = false
}, function (errorMessage) {
that.renamingLoading = false
Message.error(errorMessage)
//告诉导演,自己编辑完毕
that.director.renameMode = false
that.matter.editMode = false
})
},
finishCreateDirectory() {
let that = this
that.matter.name = that.renameMatterName
that.matter.httpCreateDirectory(function () {
that.director.createMode = false
that.editMode = false
that.matter.render(new Matter())
that.$emit('createDirectorySuccess', that.matter)
}, function (errorMessage) {
that.director.createMode = false
that.editMode = false
Message.error(errorMessage)
})
},
blurTrigger() {
let that = this
if (that.matter.editMode) {
if (that.director.createMode) {
that.finishCreateDirectory()
} else if (that.director.renameMode) {
that.finishRename()
}
}
},
enterTrigger() {
$(this.$refs.editInput).blur()
},
highLight() {
$(this.$refs.editInput).select()
},
clipboard() {
let that = this
let textToCopy = this.matter.getDownloadUrl();
this.$copyPlguin.copy(textToCopy, function () {
Message.success({
message: that.$t('operationSuccess'),
center: true
})
})
}
},
created() {
},
mounted() {
}
}
</script>
<style lang="less" rel="stylesheet/less">
@import "../../../assets/css/global/variables";
@base-height: 48px;
@inner-cell-height: 36px;
.basic-span {
display: inline-block;
vertical-align: middle;
line-height: @base-height;
margin-right: 5px;
}
.widget-matter-panel {
border-top: 1px solid #eee;
background-color: white;
.media {
> .pull-left {
padding-right: 1px;
}
}
.matter-icon {
width: 24px;
}
.left-part {
margin-left: 10px;
}
.middle-part {
height: @base-height;
overflow: hidden;
.matter-name-edit {
.basic-span;
width: 90%;
input {
width: 100%;
height: 26px;
display: inline-block;
padding: 6px;
}
}
.matter-name {
.basic-span;
width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
.right-part {
.matter-operation {
.basic-span;
display: none;
i {
font-size: 16px;
margin-right: 5px;
&:hover {
}
}
}
.matter-size {
.basic-span;
display: inline-block;
width: 80px;
text-align: left;
margin-left: 20px;
}
.matter-date {
.basic-span;
}
}
.more-btn {
display: inline-block;
vertical-align: middle;
line-height: @base-height;
padding: 0 15px;
}
&:hover {
background-color: aliceblue;
cursor: pointer;
.matter-operation {
display: inline-block;
}
}
.more-panel {
border-top: 1px solid #eee;
padding-left: 35px;
.info {
}
.cell-btn {
border-top: 1px solid #eee;
line-height: @inner-cell-height;
vertical-align: middle;
}
}
}
</style>
@@ -1,53 +0,0 @@
<template>
<div class="move-batch-panel h300">
<FolderTree ref="folderTree" :matter="matter" :targetMatter="targetMatter" :userUuid="userUuid" :version="version"
:callback="callback"
:showSubFolderInit="true"/>
</div>
</template>
<script>
import FolderTree from '../widget/FolderTree'
import Matter from '../../../common/model/matter/Matter'
export default {
data() {
return {
//当前matter,这一级为 root.
matter: new Matter(),
//最终选择的那个matter
targetMatter: new Matter()
}
},
watch: {},
props: {
//寻找该用户的合适文件夹
userUuid: {
type: String,
required: true
},
//为了让Tree在每次点开的时候都更新
version: {
type: Number,
required: true
},
//选择了一个文件夹后回掉,参数matter
callback: {
type: Function,
required: true
}
},
components: {
FolderTree
},
mounted() {
}
}
</script>
<style lang="less" rel="stylesheet/less">
.move-batch-panel {
overflow-y: scroll;
}
</style>
@@ -1,120 +0,0 @@
<template>
<div class="widget-share-panel">
<div class="row" v-if="!share.uuid">
<label class="col-md-4 control-label mt5">{{$t('matter.expire')}}</label>
<div class="col-md-8">
<select class="form-control" v-model="share.expireOption">
<option v-for="item in ShareExpireOptionList" :value="item.value">{{$t(item.name)}}</option>
</select>
</div>
</div>
<div v-if="share.uuid">
<ShareDialogPanel :share="share" :showSuccessHint="true"/>
</div>
<div class="text-right mt10">
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="share.copyLinkAndCode()" v-if="share.uuid">
{{$t('matter.copyLinkAndCode')}}
</button>
<button class="btn btn-primary btn-sm mr5" @click.stop.prevent="submit" v-if="!share.uuid">
{{$t('matter.share')}}
</button>
<button class="btn btn-default btn-sm mr5" @click.stop.prevent="close">
{{$t('matter.close')}}
</button>
</div>
</div>
</template>
<script>
import {ShareExpireOptionList} from "../../../common/model/share/ShareExpireOption";
import Share from "../../../common/model/share/Share";
import {currentHost} from "../../../common/util/Utils";
import ShareDialogPanel from "../../share/widget/ShareDialogPanel"
export default {
data() {
return {
ShareExpireOptionList,
share: new Share()
}
},
watch: {
matters(newVal, oldVal) {
this.share.render(new Share())
}
},
props: {
matters: {
type: Array,
required: true
}
},
components: {
ShareDialogPanel
},
methods: {
currentHost,
submit() {
let that = this
let uuids = []
that.matters.forEach(function (item, index) {
uuids.push(item.uuid)
})
that.share.httpCreate(uuids, function (response) {
}, function (errorMessage, response) {
that.$message.error(errorMessage)
})
},
copyText(text) {
let that = this;
that.$copyPlguin.copy(text, function () {
that.$message.success({
message: that.$t('operationSuccess'),
center: true
})
})
},
close() {
this.$emit("close")
}
},
mounted() {
}
}
</script>
<style lang="less" rel="stylesheet/less">
.widget-share-panel {
.share-block {
.share-icon {
width: 30px;
height: 30px;
}
.name {
font-size: 18px;
margin-left: 10px;
line-height: 30px;
}
}
}
</style>
@@ -1,90 +0,0 @@
<template>
<div class="upload-matter-panel">
<NbExpanding>
<div class="huge-block clearfix"
v-if="matter.loading">
<div class="media">
<div class="pull-right">
<i class="btn-action f16 fa fa-trash text-danger" v-if="false" @click.stop.prevent="del()"></i>
</div>
<div class="media-body">{{matter.file.name}}</div>
</div>
<div class="progress" :class="{'progress-striped active' : matter.loading}">
<div :style="'width: '+(matter.progress*100)+'%'" class="progress-bar progress-bar-primary">
<span>{{$t('matter.uploaded')}} {{(matter.progress * 100).toFixed(1)}}%</span>
</div>
</div>
<div>
{{$t('matter.uploaded')}}:{{ (matter.file.size * matter.progress).toFixed(0) | humanFileSize }}/{{ matter.file.size |
humanFileSize}}
{{$t('matter.speed')}}:{{matter.speed | humanFileSize}}/s
</div>
</div>
</NbExpanding>
</div>
</template>
<script>
import Matter from '../../../common/model/matter/Matter'
import NbExpanding from "../../../common/widget/NbExpanding"
export default {
data() {
return {}
},
components: {
NbExpanding
},
props: {
matter: {
type: Matter,
required: true
}
},
methods: {
del() {
let that = this
that.matter.clear()
}
},
created() {
},
mounted() {
}
}
</script>
<style lang="less" rel="stylesheet/less">
.upload-matter-panel {
.huge-block {
background-color: white;
border-radius: 5px;
padding: 10px;
border: 1px solid #eeeeee;
margin-bottom: 10px;
.progress {
margin-bottom: 10px;
}
.media {
margin-bottom: 5px;
.media-body {
cursor: pointer;
color: #555;
font-size: 15px;
font-weight: bold;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
}
</style>
-157
View File
@@ -1,157 +0,0 @@
<template>
<div class="backyard-preference-edit animated fadeIn">
<div class="tank-box bg-white br4 p20 mt10">
<div class="row" v-validator="preference.validatorSchema.name.error">
<label class="col-md-2 control-label mt5 compulsory">
{{$t('preference.websiteName')}}
</label>
<div class="col-md-10 validate">
<input type="text" class="form-control" v-model="preference.name">
</div>
</div>
<div class="row mt10">
<label class="col-md-2 control-label mt5">
{{$t('preference.logo')}}
</label>
<div class="col-md-10">
<MatterImage v-model="preference.logoUrl" :uploadHint="$t('preference.logoSquare')"/>
</div>
</div>
<div class="row mt10">
<label class="col-md-2 control-label mt5">favicon</label>
<div class="col-md-10">
<MatterImage v-model="preference.faviconUrl" filter=".ico"
:uploadHint="$t('preference.onlyAllowIco')"
:previewWidth="60"/>
</div>
</div>
<div class="row mt10">
<label class="col-md-2 control-label mt5">{{$t('preference.copyright')}}</label>
<div class="col-md-10">
<input type="text" class="form-control" v-model="preference.copyright">
</div>
</div>
<div class="row mt10">
<label class="col-md-2 control-label mt5">{{$t('preference.extraInfo')}}</label>
<div class="col-md-10">
<input type="text" class="form-control" v-model="preference.record">
</div>
</div>
<div class="row mt10">
<label class="col-md-2 control-label mt5">{{$t('preference.zipMaxNumLimit')}}</label>
<div class="col-md-10">
<input type="text" class="form-control" v-model="preference.downloadDirMaxNum">
</div>
</div>
<div class="row mt10">
<label class="col-md-2 control-label mt5">{{$t('preference.zipMaxSizeLimit')}} </label>
<div class="col-md-10">
<div class="row">
<div class="col-xs-6">
<input type="number" class="form-control" v-model="preference.downloadDirMaxSize">
</div>
<div class="col-xs-6" style="line-height:30px;">
{{$t('preference.current')}}:
<span v-if="preference.downloadDirMaxSize < 0">{{$t('preference.noLimit')}}</span>
<span v-else>{{preference.downloadDirMaxSize | humanFileSize}}</span>
</div>
</div>
</div>
</div>
<div class="row mt10">
<label class="col-md-2 control-label mt5">{{$t('preference.userDefaultSizeLimit')}}</label>
<div class="col-md-10">
<div class="row">
<div class="col-xs-6">
<input type="number" class="form-control" v-model="preference.defaultTotalSizeLimit">
</div>
<div class="col-xs-6" style="line-height:30px;">
{{$t('preference.current')}}:
<span v-if="preference.defaultTotalSizeLimit < 0">{{$t('preference.noLimit')}}</span>
<span v-else>{{preference.defaultTotalSizeLimit | humanFileSize}}</span>
</div>
</div>
</div>
</div>
<div class="row mt10">
<label class="col-md-2 control-label mt5">{{$t('preference.allowRegister')}}</label>
<div class="col-md-10">
<NbSwitcher v-model="preference.allowRegister"/>
</div>
</div>
</div>
<div class="row mt10">
<div class="col-md-12">
<div>
<CreateSaveButton :entity="preference" :callback="save"/>
</div>
</div>
</div>
</div>
</template>
<script>
import CreateSaveButton from '../widget/CreateSaveButton'
import MatterImage from '../matter/widget/MatterImage'
import Preference from '../../common/model/preference/Preference'
import NbSwitcher from "../../common/widget/NbSwitcher"
export default {
name: 'edit',
data() {
return {
globalPreference: this.$store.state.preference,
preference: new Preference()
}
},
components: {
MatterImage,
CreateSaveButton,
NbSwitcher
},
methods: {
save() {
let that = this;
this.preference.httpSave(function (response) {
that.$message.success({
message: that.$t('operationSuccess')
});
that.globalPreference.render(response.data.data);
that.preference.updateTitleAndFavicon();
that.$router.go(-1);
})
}
},
mounted() {
let that = this;
//为了让按钮的文字显示为“保存”
this.preference.editMode = true
this.preference.httpFetch()
}
}
</script>
<style lang="less" rel="stylesheet/less">
</style>
-150
View File
@@ -1,150 +0,0 @@
<template>
<div class="backyard-preference">
<div class="preference-block tank-box">
<div class="row">
<div class="col-md-12 form-info">
<span>{{$t('preference.websiteName')}}: </span>
<span class="bold">{{preference.name}}</span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('preference.logo')}}: </span>
<span>
<img v-if="preference.logoUrl" :src="preference.logoUrl" alt="logo" class="max-height-100">
</span>
</div>
<div class="col-md-12 form-info">
<span>favicon: </span>
<span>
<img v-if="preference.faviconUrl" :src="preference.faviconUrl" alt="favicon" class="max-height-100">
</span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('preference.copyright')}}: </span>
<span v-html="preference.copyright"></span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('preference.extraInfo')}}: </span>
<span v-html="preference.record"></span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('preference.zipMaxNumLimit')}}: </span>
<span v-html="preference.downloadDirMaxNum"></span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('preference.allowRegister')}}: </span>
<span>{{preference.allowRegister?$t('yes'):$t('no')}}</span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('preference.zipMaxSizeLimit')}}: </span>
<span>
<span class="mr10">
<span v-if="preference.downloadDirMaxSize >= 0">
{{preference.downloadDirMaxSize | humanFileSize}}
</span>
<span v-else>
{{$t('preference.noLimit')}}
</span>
</span>
</span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('preference.userDefaultSizeLimit')}}: </span>
<span>
<span class="mr10">
<span v-if="preference.defaultTotalSizeLimit >= 0">
{{preference.defaultTotalSizeLimit | humanFileSize}}
</span>
<span v-else>
{{$t('preference.noLimit')}}
</span>
</span>
</span>
</div>
<div class="col-md-12 form-info">
<span>{{$t('preference.docLink')}}: </span>
<span>
<a :href="$t('preference.tankDocLink')" target="_blank">{{$t('preference.tankDocLink')}}</a>
</span>
</div>
</div>
</div>
<div class="text-right">
<button class="btn btn-sm btn-danger mr5"
@click.stop.prevent="systemCleanup"
:title="$t('preference.systemCleanupDescription')">
<i class="fa fa-warning"></i>
{{$t('preference.systemCleanup')}}
</button>
<router-link class="btn btn-sm btn-primary mr5" to="/preference/edit">
<i class="fa fa-pencil"></i>
{{$t('edit')}}
</router-link>
</div>
</div>
</template>
<script>
import NbSwitcher from "../../common/widget/NbSwitcher"
export default {
data() {
return {
preference: this.$store.state.preference
}
},
methods: {
systemCleanup() {
let that = this
let preference = this.preference
this.$prompt(that.$t("preference.systemCleanupPrompt"), that.$t("prompt"), {
inputValue: null,
confirmButtonText: that.$t("confirm"),
cancelButtonText: that.$t("cancel"),
inputPattern: /^.{1,45}$/,
inputErrorMessage: that.$t("required")
}).then(({value}) => {
preference.httpSystemCleanup(value, function () {
that.$message.success(that.$t("operationSuccess"));
})
}).catch(() => {
});
}
},
components: {
NbSwitcher
},
mounted() {
}
}
</script>
<style lang="less" rel="stylesheet/less">
.backyard-preference {
.max-height-100 {
max-height: 100px;
}
.preference-block {
margin-top: 10px;
margin-bottom: 10px;
}
}
</style>

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