├── .babelrc ├── .dockerignore ├── .editorconfig ├── .env.example ├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── .gitlab-ci.yml ├── .postcssrc.js ├── .prettierrc.js ├── .styleci.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── Envoy.blade.php ├── LICENSE ├── README.md ├── app ├── Console │ └── Kernel.php ├── Exceptions │ └── Handler.php ├── Http │ ├── Controllers │ │ ├── Api │ │ │ ├── AuthController.php │ │ │ ├── BaseController.php │ │ │ ├── PermissionController.php │ │ │ ├── RoleController.php │ │ │ └── UserController.php │ │ ├── Controller.php │ │ └── LaravueController.php │ ├── Kernel.php │ ├── Middleware │ │ ├── Authenticate.php │ │ ├── CheckForMaintenanceMode.php │ │ ├── EncryptCookies.php │ │ ├── RedirectIfAuthenticated.php │ │ ├── TrimStrings.php │ │ ├── TrustHosts.php │ │ ├── TrustProxies.php │ │ └── VerifyCsrfToken.php │ └── Resources │ │ ├── PermissionResource.php │ │ ├── RoleResource.php │ │ └── UserResource.php ├── Laravue │ ├── Acl.php │ ├── Faker.php │ ├── JsonResponse.php │ └── Models │ │ ├── Permission.php │ │ ├── Role.php │ │ └── User.php ├── Providers │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── BroadcastServiceProvider.php │ ├── EventServiceProvider.php │ └── RouteServiceProvider.php └── User.php ├── artisan ├── bootstrap ├── app.php └── cache │ └── .gitignore ├── composer.json ├── composer.lock ├── config ├── app.php ├── auth.php ├── broadcasting.php ├── cache.php ├── cors.php ├── database.php ├── filesystems.php ├── hashing.php ├── jwt.php ├── logging.php ├── mail.php ├── permission.php ├── queue.php ├── sanctum.php ├── services.php ├── session.php └── view.php ├── database ├── .gitignore ├── factories │ └── UserFactory.php ├── migrations │ ├── 2014_10_12_000000_create_users_table.php │ ├── 2014_10_12_100000_create_password_resets_table.php │ ├── 2019_03_16_102314_add_simple_role_to_user_table.php │ ├── 2019_04_20_125200_create_permission_tables.php │ ├── 2019_04_20_130706_setup_role_permissions.php │ ├── 2019_08_19_000000_create_failed_jobs_table.php │ ├── 2019_12_14_000001_create_personal_access_tokens_table.php │ └── 2020_03_25_170854_remove_passport.php └── seeds │ ├── DatabaseSeeder.php │ └── UsersTableSeeder.php ├── docker-compose.yml ├── docker ├── .gitignore └── docker.env ├── laravue-entrypoint.sh ├── package-lock.json ├── package.json ├── phpunit.xml ├── public ├── .gitignore ├── .htaccess ├── favicon.ico ├── favicon │ ├── android-icon-144x144.png │ ├── android-icon-192x192.png │ ├── android-icon-36x36.png │ ├── android-icon-48x48.png │ ├── android-icon-72x72.png │ ├── android-icon-96x96.png │ ├── apple-icon-114x114.png │ ├── apple-icon-120x120.png │ ├── apple-icon-144x144.png │ ├── apple-icon-152x152.png │ ├── apple-icon-180x180.png │ ├── apple-icon-57x57.png │ ├── apple-icon-60x60.png │ ├── apple-icon-72x72.png │ ├── apple-icon-76x76.png │ ├── apple-icon-precomposed.png │ ├── apple-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ ├── favicon.ico │ ├── manifest.json │ ├── ms-icon-144x144.png │ ├── ms-icon-150x150.png │ ├── ms-icon-310x310.png │ └── ms-icon-70x70.png ├── images │ └── .gitignore ├── index.php ├── robots.txt ├── static │ └── tinymce4.7.5 │ │ ├── langs │ │ └── zh_CN.js │ │ ├── plugins │ │ ├── codesample │ │ │ └── css │ │ │ │ └── prism.css │ │ ├── emoticons │ │ │ └── img │ │ │ │ ├── smiley-cool.gif │ │ │ │ ├── smiley-cry.gif │ │ │ │ ├── smiley-embarassed.gif │ │ │ │ ├── smiley-foot-in-mouth.gif │ │ │ │ ├── smiley-frown.gif │ │ │ │ ├── smiley-innocent.gif │ │ │ │ ├── smiley-kiss.gif │ │ │ │ ├── smiley-laughing.gif │ │ │ │ ├── smiley-money-mouth.gif │ │ │ │ ├── smiley-sealed.gif │ │ │ │ ├── smiley-smile.gif │ │ │ │ ├── smiley-surprised.gif │ │ │ │ ├── smiley-tongue-out.gif │ │ │ │ ├── smiley-undecided.gif │ │ │ │ ├── smiley-wink.gif │ │ │ │ └── smiley-yell.gif │ │ └── visualblocks │ │ │ └── css │ │ │ └── visualblocks.css │ │ ├── skins │ │ └── lightgray │ │ │ ├── content.inline.min.css │ │ │ ├── content.min.css │ │ │ ├── fonts │ │ │ ├── tinymce-mobile.woff │ │ │ ├── tinymce-small.eot │ │ │ ├── tinymce-small.svg │ │ │ ├── tinymce-small.ttf │ │ │ ├── tinymce-small.woff │ │ │ ├── tinymce.eot │ │ │ ├── tinymce.svg │ │ │ ├── tinymce.ttf │ │ │ └── tinymce.woff │ │ │ ├── img │ │ │ ├── anchor.gif │ │ │ ├── loader.gif │ │ │ ├── object.gif │ │ │ └── trans.gif │ │ │ ├── skin.min.css │ │ │ └── skin.min.css.map │ │ └── tinymce.min.js ├── svg │ ├── 403.svg │ ├── 404.svg │ ├── 500.svg │ ├── 503.svg │ └── logo.svg └── web.config ├── resources ├── js │ ├── api │ │ ├── article.js │ │ ├── auth.js │ │ ├── order.js │ │ ├── resource.js │ │ ├── role.js │ │ ├── search.js │ │ └── user.js │ ├── app.js │ ├── assets │ │ ├── 401_images │ │ │ └── 401.gif │ │ ├── 404_images │ │ │ ├── 404.png │ │ │ └── 404_cloud.png │ │ ├── custom-theme │ │ │ ├── fonts │ │ │ │ ├── element-icons.ttf │ │ │ │ └── element-icons.woff │ │ │ └── index.css │ │ └── login │ │ │ ├── login_background.jpg │ │ │ └── logo.png │ ├── bootstrap.js │ ├── components │ │ ├── BackToTop │ │ │ └── index.vue │ │ ├── Breadcrumb │ │ │ └── index.vue │ │ ├── Charts │ │ │ ├── Keyboard.vue │ │ │ ├── LineMarker.vue │ │ │ ├── MixChart.vue │ │ │ └── mixins │ │ │ │ └── resize.js │ │ ├── DndList │ │ │ └── index.vue │ │ ├── DragSelect │ │ │ └── index.vue │ │ ├── Dropzone │ │ │ └── index.vue │ │ ├── ExampleComponent.vue │ │ ├── GithubCorner │ │ │ └── index.vue │ │ ├── Hamburger │ │ │ └── index.vue │ │ ├── HeaderSearch │ │ │ └── index.vue │ │ ├── ImageCropper │ │ │ ├── index.vue │ │ │ └── utils │ │ │ │ ├── data2blob.js │ │ │ │ ├── effect-ripple.js │ │ │ │ ├── language.js │ │ │ │ └── mimes.js │ │ ├── JsonEditor │ │ │ └── index.vue │ │ ├── Kanban │ │ │ └── index.vue │ │ ├── LangSelect │ │ │ └── index.vue │ │ ├── MDinput │ │ │ └── index.vue │ │ ├── MarkdownEditor │ │ │ ├── default-options.js │ │ │ └── index.vue │ │ ├── Pagination │ │ │ └── index.vue │ │ ├── PanThumb │ │ │ └── index.vue │ │ ├── RightPanel │ │ │ └── index.vue │ │ ├── Screenfull │ │ │ └── index.vue │ │ ├── ScrollPane │ │ │ └── index.vue │ │ ├── Share │ │ │ └── DropdownMenu.vue │ │ ├── SizeSelect │ │ │ └── index.vue │ │ ├── Sticky │ │ │ └── index.vue │ │ ├── SvgIcon │ │ │ └── index.vue │ │ ├── TextHoverEffect │ │ │ └── Mallki.vue │ │ ├── ThemePicker │ │ │ └── index.vue │ │ ├── Tinymce │ │ │ ├── components │ │ │ │ └── EditorImage.vue │ │ │ ├── index.vue │ │ │ ├── plugins.js │ │ │ └── toolbar.js │ │ ├── Upload │ │ │ └── SingleImage.vue │ │ └── UploadExcel │ │ │ └── index.vue │ ├── directive │ │ ├── clipboard │ │ │ ├── clipboard.js │ │ │ └── index.js │ │ ├── el-drag-dialog │ │ │ ├── drag.js │ │ │ └── index.js │ │ ├── el-table │ │ │ ├── adaptive.js │ │ │ └── index.js │ │ ├── permission │ │ │ ├── index.js │ │ │ └── permission.js │ │ ├── role │ │ │ ├── index.js │ │ │ └── role.js │ │ └── waves │ │ │ ├── index.js │ │ │ ├── waves.css │ │ │ └── waves.js │ ├── filters │ │ └── index.js │ ├── icons │ │ ├── index.js │ │ ├── svg │ │ │ ├── 404.svg │ │ │ ├── admin.svg │ │ │ ├── bug.svg │ │ │ ├── chart.svg │ │ │ ├── clipboard.svg │ │ │ ├── comment.svg │ │ │ ├── component.svg │ │ │ ├── create-user.svg │ │ │ ├── dashboard.svg │ │ │ ├── documentation.svg │ │ │ ├── dollar.svg │ │ │ ├── drag.svg │ │ │ ├── edit.svg │ │ │ ├── education.svg │ │ │ ├── email.svg │ │ │ ├── example.svg │ │ │ ├── excel.svg │ │ │ ├── exit-fullscreen.svg │ │ │ ├── eye-open.svg │ │ │ ├── eye.svg │ │ │ ├── form.svg │ │ │ ├── fullscreen.svg │ │ │ ├── guide 2.svg │ │ │ ├── guide.svg │ │ │ ├── icon.svg │ │ │ ├── international.svg │ │ │ ├── language.svg │ │ │ ├── layout.svg │ │ │ ├── like.svg │ │ │ ├── link.svg │ │ │ ├── list.svg │ │ │ ├── lock.svg │ │ │ ├── message.svg │ │ │ ├── money.svg │ │ │ ├── nested.svg │ │ │ ├── password.svg │ │ │ ├── pdf.svg │ │ │ ├── people.svg │ │ │ ├── peoples.svg │ │ │ ├── qq.svg │ │ │ ├── role.svg │ │ │ ├── search.svg │ │ │ ├── shopping.svg │ │ │ ├── size.svg │ │ │ ├── skill.svg │ │ │ ├── star.svg │ │ │ ├── tab.svg │ │ │ ├── table.svg │ │ │ ├── theme.svg │ │ │ ├── tree-table.svg │ │ │ ├── tree.svg │ │ │ ├── user.svg │ │ │ ├── wechat.svg │ │ │ └── zip.svg │ │ └── svgo.yml │ ├── lang │ │ ├── en.js │ │ ├── index.js │ │ ├── ru.js │ │ ├── vi.js │ │ └── zh.js │ ├── layout │ │ ├── components │ │ │ ├── AppMain.vue │ │ │ ├── Navbar.vue │ │ │ ├── Settings │ │ │ │ └── index.vue │ │ │ ├── Sidebar │ │ │ │ ├── Item.vue │ │ │ │ ├── Link.vue │ │ │ │ ├── Logo.vue │ │ │ │ ├── SidebarItem.vue │ │ │ │ └── index.vue │ │ │ ├── TagsView │ │ │ │ ├── ScrollPane.vue │ │ │ │ └── index.vue │ │ │ └── index.js │ │ ├── index.vue │ │ └── mixin │ │ │ └── resize-handler.js │ ├── permission.js │ ├── router │ │ ├── index.js │ │ └── modules │ │ │ ├── admin.js │ │ │ ├── charts.js │ │ │ ├── components.js │ │ │ ├── element-ui.js │ │ │ ├── error.js │ │ │ ├── example.js │ │ │ ├── excel.js │ │ │ ├── nested.js │ │ │ ├── permission.js │ │ │ └── table.js │ ├── settings.js │ ├── store │ │ ├── getters.js │ │ ├── index.js │ │ └── modules │ │ │ ├── app.js │ │ │ ├── permission.js │ │ │ ├── settings.js │ │ │ ├── tags-view.js │ │ │ └── user.js │ ├── styles │ │ ├── btn.scss │ │ ├── element-ui.scss │ │ ├── element-variables.scss │ │ ├── index.scss │ │ ├── laravue.scss │ │ ├── mixin.scss │ │ ├── sidebar.scss │ │ ├── transition.scss │ │ └── variables.scss │ ├── utils │ │ ├── auth.js │ │ ├── clipboard.js │ │ ├── get-page-title.js │ │ ├── i18n.js │ │ ├── index.js │ │ ├── permission.js │ │ ├── request.js │ │ ├── role.js │ │ ├── scroll-to.js │ │ └── validate.js │ ├── vendor │ │ ├── Export2Excel.js │ │ └── Export2Zip.js │ └── views │ │ ├── App.vue │ │ ├── articles │ │ ├── Create.vue │ │ ├── Edit.vue │ │ ├── List.vue │ │ └── components │ │ │ ├── ArticleDetail.vue │ │ │ └── Dropdown │ │ │ ├── Comment.vue │ │ │ ├── Platform.vue │ │ │ ├── SourceUrl.vue │ │ │ └── index.js │ │ ├── charts │ │ ├── Keyboard.vue │ │ ├── Line.vue │ │ └── MixChart.vue │ │ ├── clipboard │ │ └── index.vue │ │ ├── components-demo │ │ ├── AvatarUpload.vue │ │ ├── BackToTop.vue │ │ ├── CountTo.vue │ │ ├── DndList.vue │ │ ├── DragDialog.vue │ │ ├── DragKanban.vue │ │ ├── DragSelect.vue │ │ ├── Dropzone.vue │ │ ├── JsonEditor.vue │ │ ├── Markdown.vue │ │ ├── Mixin.vue │ │ ├── SplitPane.vue │ │ ├── Sticky.vue │ │ └── Tinymce.vue │ │ ├── dashboard │ │ ├── admin │ │ │ ├── components │ │ │ │ ├── BarChart.vue │ │ │ │ ├── BoxCard.vue │ │ │ │ ├── LineChart.vue │ │ │ │ ├── PanelGroup.vue │ │ │ │ ├── PieChart.vue │ │ │ │ ├── RaddarChart.vue │ │ │ │ ├── TodoList │ │ │ │ │ ├── Todo.vue │ │ │ │ │ ├── index.scss │ │ │ │ │ └── index.vue │ │ │ │ └── TransactionTable.vue │ │ │ └── index.vue │ │ ├── editor │ │ │ └── index.vue │ │ └── index.vue │ │ ├── documentation │ │ └── index.vue │ │ ├── error-page │ │ ├── 401.vue │ │ └── 404.vue │ │ ├── excel │ │ ├── ExportExcel.vue │ │ ├── MergeHeader.vue │ │ ├── SelectExcel.vue │ │ ├── UploadExcel.vue │ │ └── components │ │ │ ├── AutoWidthOption.vue │ │ │ ├── BookTypeOption.vue │ │ │ └── FilenameOption.vue │ │ ├── form │ │ └── index.vue │ │ ├── guide │ │ ├── define-steps.js │ │ └── index.vue │ │ ├── i18n │ │ ├── index.vue │ │ └── local.js │ │ ├── icons │ │ ├── components │ │ │ ├── ElementUI │ │ │ │ ├── index.vue │ │ │ │ └── require-icons.js │ │ │ └── IconFont │ │ │ │ ├── index.vue │ │ │ │ └── require-icons.js │ │ ├── element-icons.js │ │ ├── index.vue │ │ └── svg-icons.js │ │ ├── login │ │ ├── AuthRedirect.vue │ │ └── index.vue │ │ ├── nested │ │ ├── menu1 │ │ │ ├── index.vue │ │ │ ├── menu1-1 │ │ │ │ └── index.vue │ │ │ ├── menu1-2 │ │ │ │ ├── index.vue │ │ │ │ ├── menu1-2-1 │ │ │ │ │ └── index.vue │ │ │ │ └── menu1-2-2 │ │ │ │ │ └── index.vue │ │ │ └── menu1-3 │ │ │ │ └── index.vue │ │ └── menu2 │ │ │ └── index.vue │ │ ├── pdf │ │ ├── Download.vue │ │ ├── content.js │ │ └── index.vue │ │ ├── permission │ │ ├── Directive.vue │ │ ├── Page.vue │ │ ├── Role.vue │ │ └── components │ │ │ └── SwitchRoles.vue │ │ ├── redirect │ │ └── index.vue │ │ ├── role-permission │ │ └── List.vue │ │ ├── tab │ │ ├── components │ │ │ └── TabPane.vue │ │ └── index.vue │ │ ├── table │ │ ├── ComplexTable.vue │ │ ├── DragTable.vue │ │ ├── DynamicTable │ │ │ ├── FixedThead.vue │ │ │ ├── UnfixedThead.vue │ │ │ └── index.vue │ │ └── InlineEditTable.vue │ │ ├── theme │ │ └── index.vue │ │ ├── users │ │ ├── List.vue │ │ ├── SelfProfile.vue │ │ ├── UserProfile.vue │ │ └── components │ │ │ ├── UserActivity.vue │ │ │ ├── UserBio.vue │ │ │ └── UserCard.vue │ │ └── zip │ │ └── index.vue ├── lang │ └── en │ │ ├── auth.php │ │ ├── pagination.php │ │ ├── passwords.php │ │ └── validation.php ├── sass │ ├── _variables.scss │ └── app.scss └── views │ ├── laravue.blade.php │ ├── spa.blade.php │ └── welcome.blade.php ├── routes ├── api.php ├── channels.php ├── console.php └── web.php ├── server.php ├── storage ├── app │ ├── .gitignore │ └── public │ │ └── .gitignore ├── framework │ ├── .gitignore │ ├── cache │ │ ├── .gitignore │ │ └── data │ │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ ├── testing │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore ├── tests ├── Bootstrap.php ├── CreatesApplication.php ├── Feature │ └── ExampleTest.php ├── TestCase.php └── Unit │ └── ExampleTest.php ├── webpack.config.js ├── webpack.mix.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "corejs": "3", 7 | "useBuiltIns": "entry" 8 | } 9 | ] 10 | ], 11 | "plugins": [ 12 | "babel-plugin-syntax-dynamic-import", 13 | "@babel/plugin-syntax-dynamic-import", 14 | "@babel/plugin-transform-runtime", 15 | "babel-plugin-transform-vue-jsx" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | docker 2 | 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml,js,vue}] 15 | indent_size = 2 16 | [*.php] 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost 6 | 7 | LOG_CHANNEL=stack 8 | 9 | DB_CONNECTION=mysql 10 | DB_HOST=127.0.0.1 11 | DB_PORT=3306 12 | DB_DATABASE=laravel 13 | DB_USERNAME=root 14 | DB_PASSWORD= 15 | 16 | BROADCAST_DRIVER=log 17 | CACHE_DRIVER=file 18 | QUEUE_CONNECTION=sync 19 | SESSION_DRIVER=cookie 20 | SESSION_LIFETIME=120 21 | 22 | REDIS_HOST=127.0.0.1 23 | REDIS_PASSWORD=null 24 | REDIS_PORT=6379 25 | 26 | MAIL_MAILER=smtp 27 | MAIL_HOST=smtp.mailtrap.io 28 | MAIL_PORT=2525 29 | MAIL_USERNAME=null 30 | MAIL_PASSWORD=null 31 | MAIL_ENCRYPTION=null 32 | MAIL_FROM_ADDRESS=null 33 | MAIL_FROM_NAME="${APP_NAME}" 34 | 35 | AWS_ACCESS_KEY_ID= 36 | AWS_SECRET_ACCESS_KEY= 37 | AWS_DEFAULT_REGION=us-east-1 38 | AWS_BUCKET= 39 | 40 | PUSHER_APP_ID= 41 | PUSHER_APP_KEY= 42 | PUSHER_APP_SECRET= 43 | PUSHER_APP_CLUSTER=mt1 44 | SANCTUM_STATEFUL_DOMAINS=localhost,127.0.0.1,localhost:8000,127.0.0.1:8000 45 | 46 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 47 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 48 | 49 | BASE_API=/api 50 | LARAVUE_USE_ESLINT=true 51 | LARAVUE_PATH= 52 | MIX_BASE_API="${BASE_API}" 53 | MIX_LARAVUE_PATH="${LARAVUE_PATH}" 54 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | *.js linguist-vendored 5 | CHANGELOG.md export-ignore 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/hot 3 | /public/storage 4 | /storage/*.key 5 | /vendor 6 | .env 7 | .env.backup 8 | .phpunit.result.cache 9 | Homestead.json 10 | Homestead.yaml 11 | npm-debug.log 12 | yarn-error.log 13 | /public/js 14 | /public/css/*.css 15 | /public/css/*.map 16 | /public/css/*.gz 17 | /public/css/fonts/ 18 | /public/images/* 19 | /public/images/*.gif 20 | /public/stats.html 21 | /public/*.js 22 | /public/*.js.map 23 | .idea 24 | .DS_Store 25 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: registry.gitlab.com/bacduong/laravue:latest 2 | 3 | services: 4 | - mysql:5.7 5 | 6 | variables: 7 | MYSQL_DATABASE: homestead 8 | MYSQL_ROOT_PASSWORD: secret 9 | DB_HOST: mysql 10 | DB_USERNAME: root 11 | 12 | stages: 13 | - test 14 | - deploy 15 | 16 | unit_test: 17 | stage: test 18 | script: 19 | - cp .env.example .env 20 | - composer install 21 | - php artisan key:generate 22 | - php artisan migrate 23 | - vendor/bin/phpunit 24 | 25 | deploy_staging: 26 | stage: deploy 27 | script: 28 | - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' 29 | - eval $(ssh-agent -s) 30 | - ssh-add <(echo "$SSH_PRIVATE_KEY") 31 | - mkdir -p ~/.ssh 32 | - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' 33 | 34 | - ~/.composer/vendor/bin/envoy run deploy --commit="$CI_COMMIT_SHA" 35 | environment: 36 | name: staging 37 | url: http://laravue.cipherpols.com 38 | when: on_success 39 | only: 40 | - master -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "autoprefixer": {} 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true, 3 | semi: true, 4 | tabWidth: 2, 5 | trailingComma: 'es5', 6 | } 7 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | php: 2 | preset: laravel 3 | disabled: 4 | - unused_use 5 | finder: 6 | not-name: 7 | - index.php 8 | - server.php 9 | js: 10 | finder: 11 | not-name: 12 | - webpack.mix.js 13 | css: true 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Set the base image for subsequent instructions 2 | FROM php:7.3 3 | 4 | WORKDIR /var/www 5 | 6 | # Update packages 7 | 8 | RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - \ 9 | && apt-get update \ 10 | && apt-get install -y nodejs netcat libmcrypt-dev libjpeg-dev libpng-dev libzip-dev libfreetype6-dev libbz2-dev nodejs git \ 11 | && apt-get clean 12 | 13 | # Install extensions 14 | RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl 15 | RUN docker-php-ext-configure gd --with-gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/ 16 | RUN docker-php-ext-install gd 17 | 18 | # Install composer 19 | RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer 20 | 21 | COPY . . 22 | COPY .env.example .env 23 | 24 | CMD ["bash", "./laravue-entrypoint.sh"] 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tuan Duong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire')->hourly(); 28 | } 29 | 30 | /** 31 | * Register the commands for the application. 32 | * 33 | * @return void 34 | */ 35 | protected function commands() 36 | { 37 | $this->load(__DIR__.'/Commands'); 38 | 39 | require base_path('routes/console.php'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Exceptions/Handler.php: -------------------------------------------------------------------------------- 1 | 6 | * @package Laravue 7 | * @version 1.0 8 | */ 9 | namespace App\Http\Controllers\Api; 10 | 11 | use App\Http\Resources\UserResource; 12 | use App\Laravue\JsonResponse; 13 | use Illuminate\Http\Request; 14 | use Illuminate\Http\Response; 15 | use Illuminate\Support\Facades\Auth; 16 | 17 | /** 18 | * Class AuthController 19 | * 20 | * @package App\Http\Controllers\Api 21 | */ 22 | class AuthController extends BaseController 23 | { 24 | /** 25 | * @param Request $request 26 | * @return \Illuminate\Http\JsonResponse 27 | */ 28 | public function login(Request $request) 29 | { 30 | $credentials = $request->only('email', 'password'); 31 | if (!Auth::attempt($credentials)) { 32 | return response()->json(new JsonResponse([], 'login_error'), Response::HTTP_UNAUTHORIZED); 33 | } 34 | 35 | $user = $request->user(); 36 | 37 | return response()->json(new JsonResponse(new UserResource($user)), Response::HTTP_OK); 38 | } 39 | 40 | /** 41 | * @param Request $request 42 | * @return \Illuminate\Http\JsonResponse 43 | */ 44 | public function logout(Request $request) 45 | { 46 | Auth::guard('web')->logout(); 47 | return response()->json((new JsonResponse())->success([]), Response::HTTP_OK); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/Http/Controllers/Api/BaseController.php: -------------------------------------------------------------------------------- 1 | 6 | * @package Laravue 7 | * @version 1.0 8 | */ 9 | namespace App\Http\Controllers\Api; 10 | 11 | use App\Http\Controllers\Controller; 12 | 13 | /** 14 | * Class BaseController 15 | * 16 | * @package App\Http\Controllers\Api 17 | */ 18 | class BaseController extends Controller 19 | { 20 | // 21 | } 22 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | 6 | * @package Laravue 7 | * @version 1.0 8 | */ 9 | 10 | namespace App\Http\Controllers; 11 | 12 | /** 13 | * Class LaravueController 14 | * 15 | * @package App\Http\Controllers 16 | */ 17 | class LaravueController extends Controller 18 | { 19 | /** 20 | * Entry point for Laravue Dashboard 21 | * 22 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 23 | */ 24 | public function index() 25 | { 26 | return view('laravue'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | expectsJson()) { 18 | return route('login'); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Http/Middleware/CheckForMaintenanceMode.php: -------------------------------------------------------------------------------- 1 | check()) { 22 | return redirect(RouteServiceProvider::HOME); 23 | } 24 | 25 | return $next($request); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | allSubdomainsOfApplicationUrl(), 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrustProxies.php: -------------------------------------------------------------------------------- 1 | $this->id, 19 | 'name' => $this->name, 20 | ]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Http/Resources/RoleResource.php: -------------------------------------------------------------------------------- 1 | $this->id, 19 | 'name' => $this->name, 20 | 'permissions' => PermissionResource::collection($this->permissions), 21 | ]; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Http/Resources/UserResource.php: -------------------------------------------------------------------------------- 1 | $this->id, 19 | 'name' => $this->name, 20 | 'email' => $this->email, 21 | 'roles' => array_map( 22 | function ($role) { 23 | return $role['name']; 24 | }, 25 | $this->roles->toArray() 26 | ), 27 | 'permissions' => array_map( 28 | function ($permission) { 29 | return $permission['name']; 30 | }, 31 | $this->getAllPermissions()->toArray() 32 | ), 33 | 'avatar' => 'https://i.pravatar.cc', 34 | ]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/Laravue/Models/Permission.php: -------------------------------------------------------------------------------- 1 | 6 | * @package Laravue 7 | * @version 1.0 8 | */ 9 | 10 | namespace App\Laravue\Models; 11 | use App\Laravue\Acl; 12 | use Illuminate\Database\Query\Builder; 13 | 14 | /** 15 | * Class Permission 16 | * 17 | * @package App\Laravue\Models 18 | */ 19 | class Permission extends \Spatie\Permission\Models\Permission 20 | { 21 | public $guard_name = 'api'; 22 | 23 | /** 24 | * To exclude permission management from the list 25 | * 26 | * @param $query 27 | * @return Builder 28 | */ 29 | public function scopeAllowed($query) 30 | { 31 | return $query->where('name', '!=', Acl::PERMISSION_PERMISSION_MANAGE); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Laravue/Models/Role.php: -------------------------------------------------------------------------------- 1 | 6 | * @package Laravue 7 | * @version 8 | */ 9 | namespace App\Laravue\Models; 10 | 11 | use App\Laravue\Acl; 12 | use Spatie\Permission\Models\Permission; 13 | 14 | /** 15 | * Class Role 16 | * 17 | * @property Permission[] $permissions 18 | * @property string $name 19 | * @package App\Laravue\Models 20 | */ 21 | class Role extends \Spatie\Permission\Models\Role 22 | { 23 | public $guard_name = 'api'; 24 | 25 | /** 26 | * Check whether current role is admin 27 | * @return bool 28 | */ 29 | public function isAdmin(): bool 30 | { 31 | return $this->name === Acl::ROLE_ADMIN; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'App\Policies\ModelPolicy', 17 | ]; 18 | 19 | /** 20 | * Register any authentication / authorization services. 21 | * 22 | * @return void 23 | */ 24 | public function boot() 25 | { 26 | $this->registerPolicies(); 27 | 28 | // 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 19 | SendEmailVerificationNotification::class, 20 | ], 21 | ]; 22 | 23 | /** 24 | * Register any events for your application. 25 | * 26 | * @return void 27 | */ 28 | public function boot() 29 | { 30 | parent::boot(); 31 | 32 | // 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/User.php: -------------------------------------------------------------------------------- 1 | 'datetime', 38 | ]; 39 | } 40 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /config/cors.php: -------------------------------------------------------------------------------- 1 | [ 19 | 'api/*' 20 | ], 21 | 22 | 'allowed_methods' => ['*'], 23 | 24 | 'allowed_origins' => ['*'], 25 | 26 | 'allowed_origins_patterns' => [], 27 | 28 | 'allowed_headers' => ['*'], 29 | 30 | 'exposed_headers' => [], 31 | 32 | 'max_age' => 0, 33 | 34 | 'supports_credentials' => true, 35 | 36 | ]; 37 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 21 | ], 22 | 23 | 'postmark' => [ 24 | 'token' => env('POSTMARK_TOKEN'), 25 | ], 26 | 27 | 'ses' => [ 28 | 'key' => env('AWS_ACCESS_KEY_ID'), 29 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 30 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 31 | ], 32 | 33 | ]; 34 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | resource_path('views'), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => env( 32 | 'VIEW_COMPILED_PATH', 33 | realpath(storage_path('framework/views')) 34 | ), 35 | 36 | ]; 37 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | *.sqlite-journal 3 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | define(User::class, function (Faker $faker) { 21 | return [ 22 | 'name' => $faker->name, 23 | 'email' => $faker->unique()->safeEmail, 24 | 'email_verified_at' => now(), 25 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 26 | 'remember_token' => Str::random(10), 27 | ]; 28 | }); 29 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name'); 19 | $table->string('email')->unique(); 20 | $table->timestamp('email_verified_at')->nullable(); 21 | $table->string('password'); 22 | $table->rememberToken(); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('users'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 18 | $table->string('token'); 19 | $table->timestamp('created_at')->nullable(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('password_resets'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/migrations/2019_03_16_102314_add_simple_role_to_user_table.php: -------------------------------------------------------------------------------- 1 | string('role')->default('editor'); 19 | }); 20 | } 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::table('users', function (Blueprint $table) { 31 | $table->dropColumn('role'); 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/2019_08_19_000000_create_failed_jobs_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->text('connection'); 19 | $table->text('queue'); 20 | $table->longText('payload'); 21 | $table->longText('exception'); 22 | $table->timestamp('failed_at')->useCurrent(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('failed_jobs'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->morphs('tokenable'); 19 | $table->string('name'); 20 | $table->string('token', 64)->unique(); 21 | $table->text('abilities')->nullable(); 22 | $table->timestamp('last_used_at')->nullable(); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('personal_access_tokens'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2020_03_25_170854_remove_passport.php: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | ./tests/Unit 10 | 11 | 12 | ./tests/Feature 13 | 14 | 15 | 16 | 17 | ./app 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /public/.gitignore: -------------------------------------------------------------------------------- 1 | mix-manifest.json 2 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/android-icon-144x144.png -------------------------------------------------------------------------------- /public/favicon/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/android-icon-192x192.png -------------------------------------------------------------------------------- /public/favicon/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/android-icon-36x36.png -------------------------------------------------------------------------------- /public/favicon/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/android-icon-48x48.png -------------------------------------------------------------------------------- /public/favicon/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/android-icon-72x72.png -------------------------------------------------------------------------------- /public/favicon/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/android-icon-96x96.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon-114x114.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon-120x120.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon-144x144.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon-152x152.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon-180x180.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon-57x57.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon-60x60.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon-72x72.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon-76x76.png -------------------------------------------------------------------------------- /public/favicon/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon-precomposed.png -------------------------------------------------------------------------------- /public/favicon/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/apple-icon.png -------------------------------------------------------------------------------- /public/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /public/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /public/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/favicon.ico -------------------------------------------------------------------------------- /public/favicon/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Laravue", 3 | "icons": [ 4 | { 5 | "src": "\/favicon/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/favicon/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/favicon/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/favicon/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/favicon/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/favicon/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /public/favicon/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/ms-icon-144x144.png -------------------------------------------------------------------------------- /public/favicon/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/ms-icon-150x150.png -------------------------------------------------------------------------------- /public/favicon/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/ms-icon-310x310.png -------------------------------------------------------------------------------- /public/favicon/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/favicon/ms-icon-70x70.png -------------------------------------------------------------------------------- /public/images/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-cool.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-cool.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-cry.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-cry.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-embarassed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-embarassed.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-foot-in-mouth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-foot-in-mouth.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-frown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-frown.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-innocent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-innocent.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-kiss.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-kiss.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-laughing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-laughing.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-money-mouth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-money-mouth.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-sealed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-sealed.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-smile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-smile.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-surprised.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-surprised.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-tongue-out.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-tongue-out.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-undecided.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-undecided.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-wink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-wink.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/plugins/emoticons/img/smiley-yell.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/plugins/emoticons/img/smiley-yell.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce-mobile.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce-mobile.woff -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.eot -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.ttf -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.woff -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce.eot -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce.ttf -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/fonts/tinymce.woff -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/img/anchor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/img/anchor.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/img/loader.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/img/object.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/img/object.gif -------------------------------------------------------------------------------- /public/static/tinymce4.7.5/skins/lightgray/img/trans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/public/static/tinymce4.7.5/skins/lightgray/img/trans.gif -------------------------------------------------------------------------------- /public/web.config: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /resources/js/api/article.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export function fetchList(query) { 4 | return request({ 5 | url: '/articles', 6 | method: 'get', 7 | params: query, 8 | }); 9 | } 10 | 11 | export function fetchArticle(id) { 12 | return request({ 13 | url: '/articles/' + id, 14 | method: 'get', 15 | }); 16 | } 17 | 18 | export function fetchPv(id) { 19 | return request({ 20 | url: '/articles/' + id + '/pageviews', 21 | method: 'get', 22 | }); 23 | } 24 | 25 | export function createArticle(data) { 26 | return request({ 27 | url: '/article/create', 28 | method: 'post', 29 | data, 30 | }); 31 | } 32 | 33 | export function updateArticle(data) { 34 | return request({ 35 | url: '/article/update', 36 | method: 'post', 37 | data, 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /resources/js/api/auth.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export function login(data) { 4 | return request({ 5 | url: '/auth/login', 6 | method: 'post', 7 | data: data, 8 | }); 9 | } 10 | 11 | export function getInfo(token) { 12 | return request({ 13 | url: '/user', 14 | method: 'get', 15 | }); 16 | } 17 | 18 | export function logout() { 19 | return request({ 20 | url: '/auth/logout', 21 | method: 'post', 22 | }); 23 | } 24 | 25 | export function csrf() { 26 | return request({ 27 | url: '/sanctum/csrf-cookie', 28 | method: 'get', 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /resources/js/api/order.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export function fetchList(query) { 4 | return request({ 5 | url: '/orders', 6 | method: 'get', 7 | params: query, 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /resources/js/api/resource.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | /** 4 | * Simple RESTful resource class 5 | */ 6 | class Resource { 7 | constructor(uri) { 8 | this.uri = uri; 9 | } 10 | list(query) { 11 | return request({ 12 | url: '/' + this.uri, 13 | method: 'get', 14 | params: query, 15 | }); 16 | } 17 | get(id) { 18 | return request({ 19 | url: '/' + this.uri + '/' + id, 20 | method: 'get', 21 | }); 22 | } 23 | store(resource) { 24 | return request({ 25 | url: '/' + this.uri, 26 | method: 'post', 27 | data: resource, 28 | }); 29 | } 30 | update(id, resource) { 31 | return request({ 32 | url: '/' + this.uri + '/' + id, 33 | method: 'put', 34 | data: resource, 35 | }); 36 | } 37 | destroy(id) { 38 | return request({ 39 | url: '/' + this.uri + '/' + id, 40 | method: 'delete', 41 | }); 42 | } 43 | } 44 | 45 | export { Resource as default }; 46 | -------------------------------------------------------------------------------- /resources/js/api/role.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | import Resource from '@/api/resource'; 3 | 4 | class RoleResource extends Resource { 5 | constructor() { 6 | super('roles'); 7 | } 8 | 9 | permissions(id) { 10 | return request({ 11 | url: '/' + this.uri + '/' + id + '/permissions', 12 | method: 'get', 13 | }); 14 | } 15 | } 16 | 17 | export { RoleResource as default }; 18 | -------------------------------------------------------------------------------- /resources/js/api/search.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export function userSearch(name) { 4 | return request({ 5 | url: '/search/user', 6 | method: 'get', 7 | params: { name }, 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /resources/js/api/user.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | import Resource from '@/api/resource'; 3 | 4 | class UserResource extends Resource { 5 | constructor() { 6 | super('users'); 7 | } 8 | 9 | permissions(id) { 10 | return request({ 11 | url: '/' + this.uri + '/' + id + '/permissions', 12 | method: 'get', 13 | }); 14 | } 15 | 16 | updatePermission(id, permissions) { 17 | return request({ 18 | url: '/' + this.uri + '/' + id + '/permissions', 19 | method: 'put', 20 | data: permissions, 21 | }); 22 | } 23 | } 24 | 25 | export { UserResource as default }; 26 | -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | import '@/styles/index.scss'; 2 | import 'core-js'; 3 | import Vue from 'vue'; 4 | import Cookies from 'js-cookie'; 5 | import ElementUI from 'element-ui'; 6 | import App from './views/App'; 7 | import store from './store'; 8 | import router from '@/router'; 9 | import i18n from './lang'; // Internationalization 10 | import '@/icons'; // icon 11 | import '@/permission'; // permission control 12 | 13 | import * as filters from './filters'; // global filters 14 | 15 | Vue.use(ElementUI, { 16 | size: Cookies.get('size') || 'medium', // set element-ui default size 17 | i18n: (key, value) => i18n.t(key, value), 18 | }); 19 | 20 | // register global utility filters. 21 | Object.keys(filters).forEach(key => { 22 | Vue.filter(key, filters[key]); 23 | }); 24 | 25 | Vue.config.productionTip = false; 26 | 27 | new Vue({ 28 | el: '#app', 29 | router, 30 | store, 31 | i18n, 32 | render: h => h(App), 33 | }); 34 | -------------------------------------------------------------------------------- /resources/js/assets/401_images/401.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/resources/js/assets/401_images/401.gif -------------------------------------------------------------------------------- /resources/js/assets/404_images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/resources/js/assets/404_images/404.png -------------------------------------------------------------------------------- /resources/js/assets/404_images/404_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/resources/js/assets/404_images/404_cloud.png -------------------------------------------------------------------------------- /resources/js/assets/custom-theme/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/resources/js/assets/custom-theme/fonts/element-icons.ttf -------------------------------------------------------------------------------- /resources/js/assets/custom-theme/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/resources/js/assets/custom-theme/fonts/element-icons.woff -------------------------------------------------------------------------------- /resources/js/assets/login/login_background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/resources/js/assets/login/login_background.jpg -------------------------------------------------------------------------------- /resources/js/assets/login/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuandm/laravue/b56ec7526e47f06a37ca79cc356f545fcef21f34/resources/js/assets/login/logo.png -------------------------------------------------------------------------------- /resources/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | window._ = require('lodash'); 2 | 3 | /** 4 | * We'll load the axios HTTP library which allows us to easily issue requests 5 | * to our Laravel back-end. This library automatically handles sending the 6 | * CSRF token as a header based on the value of the "XSRF" token cookie. 7 | */ 8 | 9 | window.axios = require('axios'); 10 | 11 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 12 | window.axios.defaults.withCredentials = true; 13 | 14 | /** 15 | * Echo exposes an expressive API for subscribing to channels and listening 16 | * for events that are broadcast by Laravel. Echo and event broadcasting 17 | * allows your team to easily build robust real-time web applications. 18 | */ 19 | 20 | // import Echo from 'laravel-echo'; 21 | 22 | // window.Pusher = require('pusher-js'); 23 | 24 | // window.Echo = new Echo({ 25 | // broadcaster: 'pusher', 26 | // key: process.env.MIX_PUSHER_APP_KEY, 27 | // cluster: process.env.MIX_PUSHER_APP_CLUSTER, 28 | // forceTLS: true 29 | // }); 30 | -------------------------------------------------------------------------------- /resources/js/components/Charts/mixins/resize.js: -------------------------------------------------------------------------------- 1 | import { debounce } from '@/utils'; 2 | 3 | export default { 4 | data() { 5 | return { 6 | sidebarElm: null, 7 | }; 8 | }, 9 | mounted() { 10 | this.__resizeHandler = debounce(() => { 11 | if (this.chart) { 12 | this.chart.resize(); 13 | } 14 | }, 100); 15 | window.addEventListener('resize', this.__resizeHandler); 16 | 17 | this.sidebarElm = document.getElementsByClassName('sidebar-container')[0]; 18 | this.sidebarElm && this.sidebarElm.addEventListener('transitionend', this.sidebarResizeHandler); 19 | }, 20 | beforeDestroy() { 21 | window.removeEventListener('resize', this.__resizeHandler); 22 | 23 | this.sidebarElm && this.sidebarElm.removeEventListener('transitionend', this.sidebarResizeHandler); 24 | }, 25 | methods: { 26 | sidebarResizeHandler(e) { 27 | if (e.propertyName === 'width') { 28 | this.__resizeHandler(); 29 | } 30 | }, 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /resources/js/components/DragSelect/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 48 | 49 | 60 | -------------------------------------------------------------------------------- /resources/js/components/ExampleComponent.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 26 | -------------------------------------------------------------------------------- /resources/js/components/Hamburger/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 32 | 33 | 45 | -------------------------------------------------------------------------------- /resources/js/components/ImageCropper/utils/data2blob.js: -------------------------------------------------------------------------------- 1 | /** 2 | * database64文件格式转换为2进制 3 | * 4 | * @param {[String]} data The format of the dataURL is "data:image/png;base64,****". The comma is preceded by some descriptive text. We only need the comma after the line. 5 | * @param {[String]} mime [description] 6 | * @return {[blob]} [description] 7 | */ 8 | export default function(data, mime) { 9 | data = data.split(',')[1]; 10 | data = window.atob(data); 11 | var ia = new Uint8Array(data.length); 12 | for (var i = 0; i < data.length; i++) { 13 | ia[i] = data.charCodeAt(i); 14 | } 15 | // The default format returned by canvas.toDataURL is image/png 16 | return new Blob([ia], { 17 | type: mime, 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /resources/js/components/ImageCropper/utils/effect-ripple.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Click ripple effect 3 | * 4 | * @param {[event]} e [description] 5 | * @param {[Object]} argOpts [description] 6 | * @return {[bollean]} [description] 7 | */ 8 | export default function(e, argOpts) { 9 | var opts = Object.assign({ 10 | ele: e.target, // Corrugated element 11 | type: 'hit', // Hit click position spread center center point expansion 12 | bgc: 'rgba(0, 0, 0, 0.15)', // Ripple color 13 | }, argOpts); 14 | var target = opts.ele; 15 | if (target) { 16 | var rect = target.getBoundingClientRect(); 17 | var ripple = target.querySelector('.e-ripple'); 18 | if (!ripple) { 19 | ripple = document.createElement('span'); 20 | ripple.className = 'e-ripple'; 21 | ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'; 22 | target.appendChild(ripple); 23 | } else { 24 | ripple.className = 'e-ripple'; 25 | } 26 | switch (opts.type) { 27 | case 'center': 28 | ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'; 29 | ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'; 30 | break; 31 | default: 32 | ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'; 33 | ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'; 34 | } 35 | ripple.style.backgroundColor = opts.bgc; 36 | ripple.className = 'e-ripple z-active'; 37 | return false; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /resources/js/components/ImageCropper/utils/mimes.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'jpg': 'image/jpeg', 3 | 'png': 'image/png', 4 | 'gif': 'image/gif', 5 | 'svg': 'image/svg+xml', 6 | 'psd': 'image/photoshop', 7 | }; 8 | -------------------------------------------------------------------------------- /resources/js/components/LangSelect/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 42 | 43 | 50 | 51 | -------------------------------------------------------------------------------- /resources/js/components/MarkdownEditor/default-options.js: -------------------------------------------------------------------------------- 1 | // doc: https://nhnent.github.io/tui.editor/api/latest/ToastUIEditor.html#ToastUIEditor 2 | export default { 3 | minHeight: '200px', 4 | previewStyle: 'vertical', 5 | useCommandShortcut: true, 6 | useDefaultHTMLSanitizer: true, 7 | usageStatistics: false, 8 | hideModeSwitch: false, 9 | toolbarItems: [ 10 | 'heading', 11 | 'bold', 12 | 'italic', 13 | 'strike', 14 | 'divider', 15 | 'hr', 16 | 'quote', 17 | 'divider', 18 | 'ul', 19 | 'ol', 20 | 'task', 21 | 'indent', 22 | 'outdent', 23 | 'divider', 24 | 'table', 25 | 'image', 26 | 'link', 27 | 'divider', 28 | 'code', 29 | 'codeblock', 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /resources/js/components/Screenfull/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 41 | 42 | 52 | -------------------------------------------------------------------------------- /resources/js/components/SizeSelect/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 56 | -------------------------------------------------------------------------------- /resources/js/components/SvgIcon/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 34 | 35 | 44 | -------------------------------------------------------------------------------- /resources/js/components/Tinymce/plugins.js: -------------------------------------------------------------------------------- 1 | // Any plugins you want to use has to be imported 2 | // Detail plugins list see https://www.tinymce.com/docs/plugins/ 3 | // Custom builds see https://www.tinymce.com/download/custom-builds/ 4 | 5 | const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']; 6 | 7 | export default plugins; 8 | -------------------------------------------------------------------------------- /resources/js/components/Tinymce/toolbar.js: -------------------------------------------------------------------------------- 1 | // Here is a list of the toolbar 2 | // Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols 3 | 4 | const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']; 5 | 6 | export default toolbar; 7 | -------------------------------------------------------------------------------- /resources/js/directive/clipboard/index.js: -------------------------------------------------------------------------------- 1 | import Clipboard from './clipboard'; 2 | 3 | const install = function(Vue) { 4 | Vue.directive('Clipboard', Clipboard); 5 | }; 6 | 7 | if (window.Vue) { 8 | window.clipboard = Clipboard; 9 | Vue.use(install); // eslint-disable-line 10 | } 11 | 12 | Clipboard.install = install; 13 | export default Clipboard; 14 | -------------------------------------------------------------------------------- /resources/js/directive/el-drag-dialog/index.js: -------------------------------------------------------------------------------- 1 | import drag from './drag'; 2 | 3 | const install = function(Vue) { 4 | Vue.directive('el-drag-dialog', drag); 5 | }; 6 | 7 | if (window.Vue) { 8 | window['el-drag-dialog'] = drag; 9 | Vue.use(install); // eslint-disable-line 10 | } 11 | 12 | drag.install = install; 13 | export default drag; 14 | -------------------------------------------------------------------------------- /resources/js/directive/el-table/adaptive.js: -------------------------------------------------------------------------------- 1 | 2 | import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event'; 3 | 4 | /** 5 | * How to use 6 | * ... 7 | * el-table height is must be set 8 | * bottomOffset: 30(default) // The height of the table from the bottom of the page. 9 | */ 10 | 11 | const doResize = (el, binding, vnode) => { 12 | const { componentInstance: $table } = vnode; 13 | 14 | const { value } = binding; 15 | 16 | if (!$table.height) { 17 | throw new Error(`el-$table must set the height. Such as height='100px'`); 18 | } 19 | const bottomOffset = (value && value.bottomOffset) || 30; 20 | 21 | if (!$table) { 22 | return; 23 | } 24 | 25 | const height = window.innerHeight - el.getBoundingClientRect().top - bottomOffset; 26 | $table.layout.setHeight(height); 27 | $table.doLayout(); 28 | }; 29 | 30 | export default { 31 | bind(el, binding, vnode) { 32 | el.resizeListener = () => { 33 | doResize(el, binding, vnode); 34 | }; 35 | 36 | addResizeListener(el, el.resizeListener); 37 | }, 38 | inserted(el, binding, vnode) { 39 | doResize(el, binding, vnode); 40 | }, 41 | unbind(el) { 42 | removeResizeListener(el, el.resizeListener); 43 | }, 44 | }; 45 | -------------------------------------------------------------------------------- /resources/js/directive/el-table/index.js: -------------------------------------------------------------------------------- 1 | 2 | import adaptive from './adaptive'; 3 | 4 | const install = function(Vue) { 5 | Vue.directive('el-height-adaptive-table', adaptive); 6 | }; 7 | 8 | if (window.Vue) { 9 | window['el-height-adaptive-table'] = adaptive; 10 | Vue.use(install); // eslint-disable-line 11 | } 12 | 13 | adaptive.install = install; 14 | export default adaptive; 15 | -------------------------------------------------------------------------------- /resources/js/directive/permission/index.js: -------------------------------------------------------------------------------- 1 | import permission from './permission'; 2 | 3 | const install = function(Vue) { 4 | Vue.directive('permission', permission); 5 | }; 6 | 7 | if (window.Vue) { 8 | window['permission'] = permission; 9 | Vue.use(install); // eslint-disable-line 10 | } 11 | 12 | permission.install = install; 13 | export default permission; 14 | -------------------------------------------------------------------------------- /resources/js/directive/permission/permission.js: -------------------------------------------------------------------------------- 1 | import store from '@/store'; 2 | 3 | export default { 4 | inserted(el, binding, vnode) { 5 | const { value } = binding; 6 | const permissions = store.getters && store.getters.permissions; 7 | 8 | if (value && value instanceof Array && value.length > 0) { 9 | const requiredPermissions = value; 10 | const hasPermission = permissions.some(permission => { 11 | return requiredPermissions.includes(permission); 12 | }); 13 | 14 | if (!hasPermission) { 15 | el.parentNode && el.parentNode.removeChild(el); 16 | } 17 | } else { 18 | throw new Error(`Permissions are required! Example: v-permission="['manage user','manage permission']"`); 19 | } 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /resources/js/directive/role/index.js: -------------------------------------------------------------------------------- 1 | import role from './role'; 2 | 3 | const install = function(Vue) { 4 | Vue.directive('role', role); 5 | }; 6 | 7 | if (window.Vue) { 8 | window['role'] = role; 9 | Vue.use(install); // eslint-disable-line 10 | } 11 | 12 | role.install = install; 13 | export default role; 14 | -------------------------------------------------------------------------------- /resources/js/directive/role/role.js: -------------------------------------------------------------------------------- 1 | import store from '@/store'; 2 | 3 | export default { 4 | inserted(el, binding, vnode) { 5 | const { value } = binding; 6 | const roles = store.getters && store.getters.roles; 7 | 8 | if (value && value instanceof Array && value.length > 0) { 9 | const requiredRoles = value; 10 | const hasRole = roles.some(role => { 11 | return requiredRoles.includes(role); 12 | }); 13 | 14 | if (!hasRole) { 15 | el.parentNode && el.parentNode.removeChild(el); 16 | } 17 | } else { 18 | throw new Error(`Roles are required! Example: v-role="['admin','editor']"`); 19 | } 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /resources/js/directive/waves/index.js: -------------------------------------------------------------------------------- 1 | import waves from './waves'; 2 | 3 | const install = function(Vue) { 4 | Vue.directive('waves', waves); 5 | }; 6 | 7 | if (window.Vue) { 8 | window.waves = waves; 9 | Vue.use(install); // eslint-disable-line 10 | } 11 | 12 | waves.install = install; 13 | export default waves; 14 | -------------------------------------------------------------------------------- /resources/js/directive/waves/waves.css: -------------------------------------------------------------------------------- 1 | .waves-ripple { 2 | position: absolute; 3 | border-radius: 100%; 4 | background-color: rgba(0, 0, 0, 0.15); 5 | background-clip: padding-box; 6 | pointer-events: none; 7 | -webkit-user-select: none; 8 | -moz-user-select: none; 9 | -ms-user-select: none; 10 | user-select: none; 11 | -webkit-transform: scale(0); 12 | -ms-transform: scale(0); 13 | transform: scale(0); 14 | opacity: 1; 15 | } 16 | 17 | .waves-ripple.z-active { 18 | opacity: 0; 19 | -webkit-transform: scale(2); 20 | -ms-transform: scale(2); 21 | transform: scale(2); 22 | -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out; 23 | transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out; 24 | transition: opacity 1.2s ease-out, transform 0.6s ease-out; 25 | transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out; 26 | } -------------------------------------------------------------------------------- /resources/js/filters/index.js: -------------------------------------------------------------------------------- 1 | // set function parseTime,formatTime to filter 2 | export { parseTime, formatTime } from '@/utils'; 3 | 4 | export function pluralize(time, label) { 5 | if (time === 1) { 6 | return time + label; 7 | } 8 | return time + label + 's'; 9 | } 10 | 11 | export function timeAgo(time) { 12 | const between = Date.now() / 1000 - Number(time); 13 | if (between < 3600) { 14 | return pluralize(~~(between / 60), ' minute'); 15 | } else if (between < 86400) { 16 | return pluralize(~~(between / 3600), ' hour'); 17 | } else { 18 | return pluralize(~~(between / 86400), ' day'); 19 | } 20 | } 21 | 22 | /* Number formating*/ 23 | export function numberFormatter(num, digits) { 24 | const si = [ 25 | { value: 1E18, symbol: 'E' }, 26 | { value: 1E15, symbol: 'P' }, 27 | { value: 1E12, symbol: 'T' }, 28 | { value: 1E9, symbol: 'G' }, 29 | { value: 1E6, symbol: 'M' }, 30 | { value: 1E3, symbol: 'k' }, 31 | ]; 32 | for (let i = 0; i < si.length; i++) { 33 | if (num >= si[i].value) { 34 | return (num / si[i].value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol; 35 | } 36 | } 37 | return num.toString(); 38 | } 39 | 40 | export function toThousandFilter(num) { 41 | return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ',')); 42 | } 43 | 44 | export function uppercaseFirst(string) { 45 | return string.charAt(0).toUpperCase() + string.slice(1); 46 | } 47 | -------------------------------------------------------------------------------- /resources/js/icons/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import SvgIcon from '@/components/SvgIcon'; 3 | 4 | // register globally 5 | // eslint-disable-next-line vue/component-definition-name-casing 6 | Vue.component('svg-icon', SvgIcon); 7 | 8 | const requireAll = requireContext => requireContext.keys().map(requireContext); 9 | const req = require.context('./svg', false, /\.svg$/); 10 | requireAll(req); 11 | -------------------------------------------------------------------------------- /resources/js/icons/svg/404.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/bug.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/chart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/clipboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/comment.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/component.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/create-user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/documentation.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/drag.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/education.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/email.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/example.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/excel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/eye-open.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/eye.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/fullscreen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/guide 2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/guide.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/international.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/language.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/layout.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/like.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/lock.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/message.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/money.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/nested.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/password.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/pdf.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/people.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/peoples.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/role.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/size.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/skill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/star.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/tab.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/table.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/theme.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/tree-table.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/wechat.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svg/zip.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/icons/svgo.yml: -------------------------------------------------------------------------------- 1 | # replace default config 2 | 3 | # multipass: true 4 | # full: true 5 | 6 | plugins: 7 | 8 | # - name 9 | # 10 | # or: 11 | # - name: false 12 | # - name: true 13 | # 14 | # or: 15 | # - name: 16 | # param1: 1 17 | # param2: 2 18 | 19 | - removeAttrs: 20 | attrs: 21 | - 'fill' 22 | - 'fill-rule' 23 | -------------------------------------------------------------------------------- /resources/js/lang/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueI18n from 'vue-i18n'; 3 | import Cookies from 'js-cookie'; 4 | import elementEnLocale from 'element-ui/lib/locale/lang/en'; // element-ui lang 5 | import elementRuLocale from 'element-ui/lib/locale/lang/ru-RU'; // element-ui lang 6 | import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN';// element-ui lang 7 | import elementViLocale from 'element-ui/lib/locale/lang/vi';// element-ui lang 8 | import enLocale from './en'; 9 | import ruLocale from './ru'; 10 | import zhLocale from './zh'; 11 | import viLocale from './vi'; 12 | 13 | Vue.use(VueI18n); 14 | 15 | const messages = { 16 | en: { 17 | ...enLocale, 18 | ...elementEnLocale, 19 | }, 20 | ru: { 21 | ...ruLocale, 22 | ...elementRuLocale, 23 | }, 24 | zh: { 25 | ...zhLocale, 26 | ...elementZhLocale, 27 | }, 28 | vi: { 29 | ...viLocale, 30 | ...elementViLocale, 31 | }, 32 | }; 33 | 34 | export function getLanguage() { 35 | const chooseLanguage = Cookies.get('language'); 36 | if (chooseLanguage) { 37 | return chooseLanguage; 38 | } 39 | 40 | // if has not choose language 41 | const language = (navigator.language || navigator.browserLanguage).toLowerCase(); 42 | const locales = Object.keys(messages); 43 | for (const locale of locales) { 44 | if (language.indexOf(locale) > -1) { 45 | return locale; 46 | } 47 | } 48 | return 'en'; 49 | } 50 | const i18n = new VueI18n({ 51 | // set locale 52 | // options: en | ru | vi | zh 53 | locale: getLanguage(), 54 | // set locale messages 55 | messages, 56 | }); 57 | 58 | export default i18n; 59 | -------------------------------------------------------------------------------- /resources/js/layout/components/AppMain.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 24 | 25 | 49 | 50 | -------------------------------------------------------------------------------- /resources/js/layout/components/Sidebar/Item.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 38 | -------------------------------------------------------------------------------- /resources/js/layout/components/Sidebar/Link.vue: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 40 | -------------------------------------------------------------------------------- /resources/js/layout/components/Sidebar/index.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 51 | 54 | -------------------------------------------------------------------------------- /resources/js/layout/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as Navbar } from './Navbar'; 2 | export { default as Sidebar } from './Sidebar'; 3 | export { default as AppMain } from './AppMain'; 4 | export { default as TagsView } from './TagsView'; 5 | export { default as Settings } from './Settings'; 6 | -------------------------------------------------------------------------------- /resources/js/layout/mixin/resize-handler.js: -------------------------------------------------------------------------------- 1 | import store from '@/store'; 2 | 3 | const { body } = document; 4 | const WIDTH = 992; // refer to Bootstrap's responsive design 5 | 6 | export default { 7 | watch: { 8 | $route(route) { 9 | if (this.device === 'mobile' && this.sidebar.opened) { 10 | store.dispatch('app/closeSideBar', { withoutAnimation: false }); 11 | } 12 | }, 13 | }, 14 | beforeMount() { 15 | window.addEventListener('resize', this.resizeHandler); 16 | }, 17 | beforeDestroy() { 18 | window.removeEventListener('resize', this.resizeHandler); 19 | }, 20 | mounted() { 21 | const isMobile = this.isMobile(); 22 | if (isMobile) { 23 | store.dispatch('app/toggleDevice', 'mobile'); 24 | store.dispatch('app/closeSideBar', { withoutAnimation: true }); 25 | } 26 | }, 27 | methods: { 28 | isMobile() { 29 | const rect = body.getBoundingClientRect(); 30 | return rect.width - 1 < WIDTH; 31 | }, 32 | resizeHandler() { 33 | if (!document.hidden) { 34 | const isMobile = this.isMobile(); 35 | store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop'); 36 | 37 | if (isMobile) { 38 | store.dispatch('app/closeSideBar', { withoutAnimation: true }); 39 | } 40 | } 41 | }, 42 | }, 43 | }; 44 | -------------------------------------------------------------------------------- /resources/js/router/modules/charts.js: -------------------------------------------------------------------------------- 1 | /** When your routing table is too long, you can split it into small modules**/ 2 | import Layout from '@/layout'; 3 | 4 | const chartsRoutes = { 5 | path: '/charts', 6 | component: Layout, 7 | redirect: 'noredirect', 8 | name: 'Charts', 9 | meta: { 10 | title: 'charts', 11 | icon: 'chart', 12 | permissions: ['view menu charts'], 13 | }, 14 | children: [ 15 | { 16 | path: 'keyboard', 17 | component: () => import('@/views/charts/Keyboard'), 18 | name: 'KeyboardChart', 19 | meta: { title: 'keyboardChart', noCache: true }, 20 | }, 21 | { 22 | path: 'line', 23 | component: () => import('@/views/charts/Line'), 24 | name: 'LineChart', 25 | meta: { title: 'lineChart', noCache: true }, 26 | }, 27 | { 28 | path: 'mixchart', 29 | component: () => import('@/views/charts/MixChart'), 30 | name: 'MixChart', 31 | meta: { title: 'mixChart', noCache: true }, 32 | }, 33 | ], 34 | }; 35 | 36 | export default chartsRoutes; 37 | -------------------------------------------------------------------------------- /resources/js/router/modules/element-ui.js: -------------------------------------------------------------------------------- 1 | import Layout from '@/layout'; 2 | 3 | const elementUiRoutes = { 4 | path: '/element-ui', 5 | component: Layout, 6 | redirect: '/element-ui/form', 7 | name: 'Element UI', 8 | meta: { 9 | title: 'elementUi', 10 | icon: 'layout', 11 | permissions: ['view menu element ui'], 12 | }, 13 | children: [ 14 | { 15 | path: 'form', 16 | name: 'Form', 17 | component: () => import('@/views/form/index'), 18 | meta: { title: 'form', icon: 'form' }, 19 | }, 20 | { 21 | path: 'icons', 22 | component: () => import('@/views/icons/index'), 23 | name: 'Icons', 24 | meta: { title: 'icons', icon: 'el-icon-info', noCache: true }, 25 | }, 26 | { 27 | path: 'tab', 28 | component: () => import('@/views/tab'), 29 | name: 'Tab', 30 | meta: { title: 'tab', icon: 'tab' }, 31 | }, 32 | ], 33 | }; 34 | 35 | export default elementUiRoutes; 36 | -------------------------------------------------------------------------------- /resources/js/router/modules/error.js: -------------------------------------------------------------------------------- 1 | /** When your routing table is too long, you can split it into small modules**/ 2 | import Layout from '@/layout'; 3 | 4 | const errorRoutes = { 5 | path: '/error', 6 | component: Layout, 7 | redirect: 'noredirect', 8 | name: 'ErrorPages', 9 | meta: { 10 | title: 'errorPages', 11 | icon: '404', 12 | }, 13 | children: [ 14 | { 15 | path: '401', 16 | component: () => import('@/views/error-page/401'), 17 | name: 'Page401', 18 | meta: { title: 'page401', noCache: true }, 19 | }, 20 | { 21 | path: '404', 22 | component: () => import('@/views/error-page/404'), 23 | name: 'Page404', 24 | meta: { title: 'page404', noCache: true }, 25 | }, 26 | ], 27 | }; 28 | 29 | export default errorRoutes; 30 | -------------------------------------------------------------------------------- /resources/js/router/modules/example.js: -------------------------------------------------------------------------------- 1 | /** When your routing table is too long, you can split it into small modules**/ 2 | import Layout from '@/layout'; 3 | 4 | const exampleRoutes = { 5 | path: '/example', 6 | component: Layout, 7 | redirect: '/example/list', 8 | name: 'Example', 9 | meta: { 10 | title: 'example', 11 | icon: 'example', 12 | }, 13 | children: [ 14 | { 15 | path: 'create', 16 | component: () => import('@/views/example/Create'), 17 | name: 'CreateArticle', 18 | meta: { title: 'createArticle', icon: 'edit' }, 19 | }, 20 | { 21 | path: 'edit/:id(\\d+)', 22 | component: () => import('@/views/example/Edit'), 23 | name: 'EditArticle', 24 | meta: { title: 'editArticle', noCache: true }, 25 | hidden: true, 26 | }, 27 | { 28 | path: 'list', 29 | component: () => import('@/views/example/List'), 30 | name: 'ArticleList', 31 | meta: { title: 'articleList', icon: 'list' }, 32 | }, 33 | ], 34 | }; 35 | 36 | export default exampleRoutes; 37 | -------------------------------------------------------------------------------- /resources/js/router/modules/excel.js: -------------------------------------------------------------------------------- 1 | /** When your routing table is too long, you can split it into small modules**/ 2 | import Layout from '@/layout'; 3 | 4 | const excelRoutes = { 5 | path: '/excel', 6 | component: Layout, 7 | redirect: '/excel/export-excel', 8 | name: 'Excel', 9 | meta: { 10 | title: 'excel', 11 | icon: 'excel', 12 | permissions: ['view menu excel'], 13 | }, 14 | children: [ 15 | { 16 | path: 'export-excel', 17 | component: () => import('@/views/excel/ExportExcel'), 18 | name: 'exportExcel', 19 | meta: { title: 'exportExcel' }, 20 | }, 21 | { 22 | path: 'export-selected-excel', 23 | component: () => import('@/views/excel/SelectExcel'), 24 | name: 'SelectExcel', 25 | meta: { title: 'selectExcel' }, 26 | }, 27 | { 28 | path: 'export-merge-header', 29 | component: () => import('@/views/excel/MergeHeader'), 30 | name: 'MergeHeader', 31 | meta: { title: 'mergeHeader' }, 32 | }, 33 | { 34 | path: 'upload-excel', 35 | component: () => import('@/views/excel/UploadExcel'), 36 | name: 'UploadExcel', 37 | meta: { title: 'uploadExcel' }, 38 | }, 39 | ], 40 | }; 41 | 42 | export default excelRoutes; 43 | -------------------------------------------------------------------------------- /resources/js/router/modules/permission.js: -------------------------------------------------------------------------------- 1 | import Layout from '@/layout'; 2 | 3 | const permissionRoutes = { 4 | path: '/permission', 5 | component: Layout, 6 | redirect: '/permission/index', 7 | alwaysShow: true, // will always show the root menu 8 | meta: { 9 | title: 'permission', 10 | icon: 'lock', 11 | permissions: ['view menu permission'], 12 | }, 13 | children: [ 14 | { 15 | path: 'page', 16 | component: () => import('@/views/permission/Page'), 17 | name: 'PagePermission', 18 | meta: { 19 | title: 'pagePermission', 20 | permissions: ['manage permission'], 21 | }, 22 | }, 23 | { 24 | path: 'directive', 25 | component: () => import('@/views/permission/Directive'), 26 | name: 'directivePermission', 27 | meta: { 28 | title: 'directivePermission', 29 | // if do not set roles neither permissions, means: this page does not require permission 30 | }, 31 | }, 32 | ], 33 | }; 34 | 35 | export default permissionRoutes; 36 | -------------------------------------------------------------------------------- /resources/js/router/modules/table.js: -------------------------------------------------------------------------------- 1 | import Layout from '@/layout'; 2 | 3 | const tableRoutes = { 4 | path: '/table', 5 | component: Layout, 6 | redirect: '/table/complex-table', 7 | name: 'Complex Table', 8 | meta: { 9 | title: 'table', 10 | icon: 'table', 11 | permissions: ['view menu table'], 12 | }, 13 | children: [ 14 | { 15 | path: 'drag-table', 16 | component: () => import('@/views/table/DragTable'), 17 | name: 'DragTable', 18 | meta: { title: 'dragTable' }, 19 | }, 20 | { 21 | path: 'inline-edit-table', 22 | component: () => import('@/views/table/InlineEditTable'), 23 | name: 'InlineEditTable', 24 | meta: { title: 'inlineEditTable' }, 25 | }, 26 | { 27 | path: 'complex-table', 28 | component: () => import('@/views/table/ComplexTable'), 29 | name: 'ComplexTable', 30 | meta: { title: 'complexTable' }, 31 | }, 32 | ], 33 | }; 34 | export default tableRoutes; 35 | -------------------------------------------------------------------------------- /resources/js/settings.js: -------------------------------------------------------------------------------- 1 | import variables from '@/styles/element-variables.scss'; 2 | 3 | export default { 4 | /** 5 | * @type {String} 6 | */ 7 | title: 'Laravue Admin', 8 | theme: variables.theme, 9 | 10 | /** 11 | * @type {boolean} true | false 12 | * @description Whether show the settings right-panel 13 | */ 14 | showSettings: true, 15 | 16 | /** 17 | * @type {boolean} true | false 18 | * @description Whether need tagsView 19 | */ 20 | tagsView: true, 21 | 22 | /** 23 | * @type {boolean} true | false 24 | * @description Whether fix the header 25 | */ 26 | fixedHeader: false, 27 | 28 | /** 29 | * @type {boolean} true | false 30 | * @description Whether show the logo in sidebar 31 | */ 32 | sidebarLogo: false, 33 | 34 | /** 35 | * @type {string | array} 'production' | ['production','development'] 36 | * @description Need show err logs component. 37 | * The default is only used in the production env 38 | * If you want to also use it in dev, you can pass ['production','development'] 39 | */ 40 | errorLog: 'production', 41 | }; 42 | -------------------------------------------------------------------------------- /resources/js/store/getters.js: -------------------------------------------------------------------------------- 1 | const getters = { 2 | sidebar: state => state.app.sidebar, 3 | language: state => state.app.language, 4 | size: state => state.app.size, 5 | device: state => state.app.device, 6 | visitedViews: state => state.tagsView.visitedViews, 7 | cachedViews: state => state.tagsView.cachedViews, 8 | userId: state => state.user.id, 9 | token: state => state.user.token, 10 | avatar: state => state.user.avatar, 11 | name: state => state.user.name, 12 | user: state => state.user.user, 13 | introduction: state => state.user.introduction, 14 | roles: state => state.user.roles, 15 | permissions: state => state.user.permissions, 16 | permissionRoutes: state => state.permission.routes, 17 | addRoutes: state => state.permission.addRoutes, 18 | }; 19 | export default getters; 20 | -------------------------------------------------------------------------------- /resources/js/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import getters from './getters'; 4 | 5 | Vue.use(Vuex); 6 | 7 | // https://webpack.js.org/guides/dependency-management/#requirecontext 8 | const modulesFiles = require.context('./modules', false, /\.js$/); 9 | 10 | // you do not need `import app from './modules/app'` 11 | // it will auto require all vuex module from modules file 12 | const modules = modulesFiles.keys().reduce((modules, modulePath) => { 13 | // set './app.js' => 'app' 14 | const moduleName = (modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')).replace(/-([a-z])/g, g => g[1].toUpperCase()); 15 | // camelCase(modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')); 16 | const value = modulesFiles(modulePath); 17 | modules[moduleName] = value.default; 18 | return modules; 19 | }, {}); 20 | 21 | const store = new Vuex.Store({ 22 | modules, 23 | getters, 24 | }); 25 | 26 | export default store; 27 | -------------------------------------------------------------------------------- /resources/js/store/modules/settings.js: -------------------------------------------------------------------------------- 1 | import defaultSettings from '@/settings'; 2 | const { showSettings, tagsView, fixedHeader, sidebarLogo, theme } = defaultSettings; 3 | 4 | const state = { 5 | theme: theme, 6 | showSettings: showSettings, 7 | tagsView: tagsView, 8 | fixedHeader: fixedHeader, 9 | sidebarLogo: sidebarLogo, 10 | }; 11 | 12 | const mutations = { 13 | CHANGE_SETTING: (state, { key, value }) => { 14 | if (Object.prototype.hasOwnProperty.call(state, key)) { 15 | state[key] = value; 16 | } 17 | }, 18 | }; 19 | 20 | const actions = { 21 | changeSetting({ commit }, data) { 22 | commit('CHANGE_SETTING', data); 23 | }, 24 | }; 25 | 26 | export default { 27 | namespaced: true, 28 | state, 29 | mutations, 30 | actions, 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /resources/js/styles/element-ui.scss: -------------------------------------------------------------------------------- 1 | //to reset element-ui default css 2 | .el-breadcrumb__inner, 3 | .el-breadcrumb__inner a { 4 | font-weight: 400 !important; 5 | } 6 | 7 | .el-upload { 8 | input[type="file"] { 9 | display: none !important; 10 | } 11 | } 12 | 13 | .el-upload__input { 14 | display: none; 15 | } 16 | 17 | .cell { 18 | .el-tag { 19 | margin-right: 0px; 20 | } 21 | } 22 | 23 | .small-padding { 24 | .cell { 25 | padding-left: 5px; 26 | padding-right: 5px; 27 | } 28 | } 29 | 30 | .fixed-width { 31 | .el-button--mini { 32 | padding: 7px 10px; 33 | width: 60px; 34 | } 35 | } 36 | 37 | .status-col { 38 | .cell { 39 | padding: 0 10px; 40 | text-align: center; 41 | 42 | .el-tag { 43 | margin-right: 0px; 44 | } 45 | } 46 | } 47 | 48 | .el-dialog { 49 | transform: none; 50 | left: 0; 51 | position: relative; 52 | margin: 0 auto; 53 | } 54 | 55 | .article-textarea { 56 | textarea { 57 | padding-right: 40px; 58 | resize: none; 59 | border: none; 60 | border-radius: 0px; 61 | border-bottom: 1px solid #bfcbd9; 62 | } 63 | } 64 | 65 | //element ui upload 66 | .upload-container { 67 | .el-upload { 68 | width: 100%; 69 | 70 | .el-upload-dragger { 71 | width: 100%; 72 | height: 200px; 73 | } 74 | } 75 | } 76 | 77 | //dropdown 78 | .el-dropdown-menu { 79 | a { 80 | display: block 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /resources/js/styles/element-variables.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * I think element-ui's default theme color is too light for long-term use. 3 | * So I modified the default color and you can modify it to your liking. 4 | **/ 5 | 6 | /* theme color */ 7 | $--color-primary: #1890ff; 8 | $--color-success: #13ce66; 9 | $--color-warning: #FFBA00; 10 | $--color-danger: #ff4949; 11 | // $--color-info: #1E1E1E; 12 | 13 | $--button-font-weight: 400; 14 | 15 | // $--color-text-regular: #1f2d3d; 16 | 17 | $--border-color-light: #dfe4ed; 18 | $--border-color-lighter: #e6ebf5; 19 | 20 | $--table-border:1px solid#dfe6ec; 21 | 22 | /* icon font path, required */ 23 | $--font-path: 'css/fonts'; 24 | 25 | @import "~element-ui/packages/theme-chalk/src/index"; 26 | 27 | // the :export directive is the magic sauce for webpack 28 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass 29 | :export { 30 | theme: $--color-primary; 31 | } 32 | -------------------------------------------------------------------------------- /resources/js/styles/laravue.scss: -------------------------------------------------------------------------------- 1 | .box-center { 2 | margin: 0 auto; 3 | display: table; 4 | } 5 | .text-muted { 6 | color: #777; 7 | } 8 | .pull-right { 9 | float: right !important; 10 | } 11 | 12 | .permissions-container { 13 | .block { 14 | .el-form-item__label { 15 | padding-left: 24px; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /resources/js/styles/mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix { 2 | &:after { 3 | content: ""; 4 | display: table; 5 | clear: both; 6 | } 7 | } 8 | 9 | @mixin scrollBar { 10 | &::-webkit-scrollbar-track-piece { 11 | background: #d3dce6; 12 | } 13 | 14 | &::-webkit-scrollbar { 15 | width: 6px; 16 | } 17 | 18 | &::-webkit-scrollbar-thumb { 19 | background: #99a9bf; 20 | border-radius: 20px; 21 | } 22 | } 23 | 24 | @mixin relative { 25 | position: relative; 26 | width: 100%; 27 | height: 100%; 28 | } 29 | -------------------------------------------------------------------------------- /resources/js/styles/transition.scss: -------------------------------------------------------------------------------- 1 | //globl transition css 2 | 3 | /*fade*/ 4 | .fade-enter-active, 5 | .fade-leave-active { 6 | transition: opacity 0.28s; 7 | } 8 | 9 | .fade-enter, 10 | .fade-leave-active { 11 | opacity: 0; 12 | } 13 | 14 | /*fade-transform*/ 15 | .fade-transform-leave-active, 16 | .fade-transform-enter-active { 17 | transition: all .5s; 18 | } 19 | 20 | .fade-transform-enter { 21 | opacity: 0; 22 | transform: translateX(-30px); 23 | } 24 | 25 | .fade-transform-leave-to { 26 | opacity: 0; 27 | transform: translateX(30px); 28 | } 29 | 30 | /*fade*/ 31 | .breadcrumb-enter-active, 32 | .breadcrumb-leave-active { 33 | transition: all .5s; 34 | } 35 | 36 | .breadcrumb-enter, 37 | .breadcrumb-leave-active { 38 | opacity: 0; 39 | transform: translateX(20px); 40 | } 41 | 42 | .breadcrumb-move { 43 | transition: all .5s; 44 | } 45 | 46 | .breadcrumb-leave-active { 47 | position: absolute; 48 | } 49 | -------------------------------------------------------------------------------- /resources/js/styles/variables.scss: -------------------------------------------------------------------------------- 1 | // base color 2 | $blue:#324157; 3 | $light-blue:#3A71A8; 4 | $red:#C03639; 5 | $pink: #E65D6E; 6 | $green: #30B08F; 7 | $tiffany: #4AB7BD; 8 | $yellow:#FEC171; 9 | $panGreen: #30B08F; 10 | 11 | //sidebar 12 | $menuText:#bfcbd9; 13 | $menuActiveText:#409EFF; 14 | $subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951 15 | 16 | $menuBg:#304156; 17 | $menuHover:#263445; 18 | 19 | $subMenuBg:#1f2d3d; 20 | $subMenuHover:#001528; 21 | 22 | $sideBarWidth: 210px; 23 | 24 | // the :export directive is the magic sauce for webpack 25 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass 26 | :export { 27 | menuText: $menuText; 28 | menuActiveText: $menuActiveText; 29 | subMenuActiveText: $subMenuActiveText; 30 | menuBg: $menuBg; 31 | menuHover: $menuHover; 32 | subMenuBg: $subMenuBg; 33 | subMenuHover: $subMenuHover; 34 | sideBarWidth: $sideBarWidth; 35 | } 36 | -------------------------------------------------------------------------------- /resources/js/utils/auth.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie'; 2 | 3 | const TokenKey = 'isLogged'; 4 | 5 | export function isLogged() { 6 | return Cookies.get(TokenKey) === '1'; 7 | } 8 | 9 | export function setLogged(isLogged) { 10 | return Cookies.set(TokenKey, isLogged); 11 | } 12 | 13 | export function removeToken() { 14 | return Cookies.remove(TokenKey); 15 | } 16 | -------------------------------------------------------------------------------- /resources/js/utils/clipboard.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Clipboard from 'clipboard'; 3 | 4 | function clipboardSuccess() { 5 | Vue.prototype.$message({ 6 | message: 'Copy successfully', 7 | type: 'success', 8 | duration: 1500, 9 | }); 10 | } 11 | 12 | function clipboardError() { 13 | Vue.prototype.$message({ 14 | message: 'Copy failed', 15 | type: 'error', 16 | }); 17 | } 18 | 19 | export default function handleClipboard(text, event) { 20 | const clipboard = new Clipboard(event.target, { 21 | text: () => text, 22 | }); 23 | 24 | clipboard.on('success', () => { 25 | clipboardSuccess(); 26 | clipboard.off('error'); 27 | clipboard.off('success'); 28 | clipboard.destroy(); 29 | }); 30 | 31 | clipboard.on('error', () => { 32 | clipboardError(); 33 | clipboard.off('error'); 34 | clipboard.off('success'); 35 | clipboard.destroy(); 36 | }); 37 | 38 | clipboard.onClick(event); 39 | } 40 | -------------------------------------------------------------------------------- /resources/js/utils/get-page-title.js: -------------------------------------------------------------------------------- 1 | import defaultSettings from '@/settings'; 2 | import i18n from '@/lang'; 3 | 4 | const title = defaultSettings.title || 'Laravue Admin'; 5 | 6 | export default function getPageTitle(key) { 7 | const hasKey = i18n.te(`route.${key}`); 8 | if (hasKey) { 9 | const pageName = i18n.t(`route.${key}`); 10 | return `${pageName} - ${title}`; 11 | } 12 | return `${title}`; 13 | } 14 | -------------------------------------------------------------------------------- /resources/js/utils/i18n.js: -------------------------------------------------------------------------------- 1 | // translate router.meta.title, be used in breadcrumb sidebar tagsview 2 | export function generateTitle(title) { 3 | const hasKey = this.$te('route.' + title); 4 | 5 | if (hasKey) { 6 | // $t :this method from vue-i18n, inject in @/lang/index.js 7 | const translatedTitle = this.$t('route.' + title); 8 | 9 | return translatedTitle; 10 | } 11 | return title; 12 | } 13 | -------------------------------------------------------------------------------- /resources/js/utils/permission.js: -------------------------------------------------------------------------------- 1 | import store from '@/store'; 2 | 3 | /** 4 | * @param {Array} value 5 | * @returns {Boolean} 6 | * @example see @/views/permission/Directive.vue 7 | */ 8 | export default function checkPermission(value) { 9 | if (value && value instanceof Array && value.length > 0) { 10 | const permissions = store.getters && store.getters.permissions; 11 | const requiredPermissions = value; 12 | 13 | const hasPermission = permissions.some(permission => { 14 | return requiredPermissions.includes(permission); 15 | }); 16 | 17 | return hasPermission; 18 | } else { 19 | console.error(`Need permissions! Like v-permission="['manage permission','edit article']"`); 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /resources/js/utils/request.js: -------------------------------------------------------------------------------- 1 | import '@/bootstrap'; 2 | import { Message } from 'element-ui'; 3 | // import { isLogged, setLogged } from '@/utils/auth'; 4 | 5 | // Create axios instance 6 | const service = window.axios.create({ 7 | baseURL: process.env.MIX_BASE_API, 8 | timeout: 10000, // Request timeout 9 | }); 10 | 11 | // Request intercepter 12 | service.interceptors.request.use( 13 | config => { 14 | // const token = isLogged(); 15 | // if (token) { 16 | // config.headers['Authorization'] = 'Bearer ' + isLogged(); // Set JWT token 17 | // } 18 | return config; 19 | }, 20 | error => { 21 | // Do something with request error 22 | console.log(error); // for debug 23 | Promise.reject(error); 24 | } 25 | ); 26 | 27 | // response pre-processing 28 | service.interceptors.response.use( 29 | response => { 30 | // if (response.headers.authorization) { 31 | // setLogged(response.headers.authorization); 32 | // response.data.token = response.headers.authorization; 33 | // } 34 | 35 | return response.data; 36 | }, 37 | error => { 38 | let message = error.message; 39 | if (error.response.data && error.response.data.errors) { 40 | message = error.response.data.errors; 41 | } else if (error.response.data && error.response.data.error) { 42 | message = error.response.data.error; 43 | } 44 | 45 | Message({ 46 | message: message, 47 | type: 'error', 48 | duration: 5 * 1000, 49 | }); 50 | return Promise.reject(error); 51 | } 52 | ); 53 | 54 | export default service; 55 | -------------------------------------------------------------------------------- /resources/js/utils/role.js: -------------------------------------------------------------------------------- 1 | import store from '@/store'; 2 | 3 | /** 4 | * @param {Array} value 5 | * @returns {Boolean} 6 | * @example see @/views/permission/Directive.vue 7 | */ 8 | export default function checkRole(value) { 9 | if (value && value instanceof Array && value.length > 0) { 10 | const roles = store.getters && store.getters.roles; 11 | const requiredRoles = value; 12 | 13 | const hasRole = roles.some(role => { 14 | return requiredRoles.includes(role); 15 | }); 16 | 17 | return hasRole; 18 | } else { 19 | console.error(`Need roles! Like v-role="['admin','editor']"`); 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /resources/js/vendor/Export2Zip.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('script-loader!file-saver'); 3 | import JSZip from 'jszip' 4 | 5 | export function export_txt_to_zip(th, jsonData, txtName, zipName) { 6 | const zip = new JSZip() 7 | const txt_name = txtName || 'file' 8 | const zip_name = zipName || 'file' 9 | const data = jsonData 10 | let txtData = `${th}\r\n` 11 | data.forEach((row) => { 12 | let tempStr = '' 13 | tempStr = row.toString() 14 | txtData += `${tempStr}\r\n` 15 | }) 16 | zip.file(`${txt_name}.txt`, txtData) 17 | zip.generateAsync({ 18 | type: "blob" 19 | }).then((blob) => { 20 | saveAs(blob, `${zip_name}.zip`) 21 | }, (err) => { 22 | alert('导出失败') 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /resources/js/views/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /resources/js/views/articles/Create.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | 14 | -------------------------------------------------------------------------------- /resources/js/views/articles/Edit.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | 14 | -------------------------------------------------------------------------------- /resources/js/views/articles/components/Dropdown/Comment.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 42 | -------------------------------------------------------------------------------- /resources/js/views/articles/components/Dropdown/Platform.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 47 | -------------------------------------------------------------------------------- /resources/js/views/articles/components/Dropdown/SourceUrl.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 39 | -------------------------------------------------------------------------------- /resources/js/views/articles/components/Dropdown/index.js: -------------------------------------------------------------------------------- 1 | export { default as CommentDropdown } from './Comment'; 2 | export { default as PlatformDropdown } from './Platform'; 3 | export { default as SourceUrlDropdown } from './SourceUrl'; 4 | -------------------------------------------------------------------------------- /resources/js/views/charts/Keyboard.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | 16 | 23 | 24 | -------------------------------------------------------------------------------- /resources/js/views/charts/Line.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | 16 | 23 | 24 | -------------------------------------------------------------------------------- /resources/js/views/charts/MixChart.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | 16 | 23 | 24 | -------------------------------------------------------------------------------- /resources/js/views/clipboard/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 49 | 50 | -------------------------------------------------------------------------------- /resources/js/views/components-demo/BackToTop.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 40 | 41 | 51 | -------------------------------------------------------------------------------- /resources/js/views/components-demo/DndList.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 39 | 40 | -------------------------------------------------------------------------------- /resources/js/views/components-demo/DragSelect.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 44 | -------------------------------------------------------------------------------- /resources/js/views/components-demo/Dropzone.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 29 | 30 | -------------------------------------------------------------------------------- /resources/js/views/components-demo/JsonEditor.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | 26 | 32 | -------------------------------------------------------------------------------- /resources/js/views/components-demo/SplitPane.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 34 | 35 | 63 | -------------------------------------------------------------------------------- /resources/js/views/components-demo/Tinymce.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 30 | 31 | 36 | 37 | -------------------------------------------------------------------------------- /resources/js/views/dashboard/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 32 | -------------------------------------------------------------------------------- /resources/js/views/excel/UploadExcel.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 43 | -------------------------------------------------------------------------------- /resources/js/views/excel/components/AutoWidthOption.vue: -------------------------------------------------------------------------------- 1 | Tinymce/components/EditorImage.vue 2 | -------------------------------------------------------------------------------- /resources/js/views/excel/components/BookTypeOption.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 40 | -------------------------------------------------------------------------------- /resources/js/views/excel/components/FilenameOption.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 29 | -------------------------------------------------------------------------------- /resources/js/views/guide/define-steps.js: -------------------------------------------------------------------------------- 1 | const steps = [ 2 | { 3 | element: '#hamburger-container', 4 | popover: { 5 | title: 'Hamburger', 6 | description: 'Open && Close sidebar', 7 | position: 'bottom', 8 | }, 9 | }, 10 | { 11 | element: '#breadcrumb-container', 12 | popover: { 13 | title: 'Breadcrumb', 14 | description: 'Indicate the current page location', 15 | position: 'bottom', 16 | }, 17 | }, 18 | { 19 | element: '#header-search', 20 | popover: { 21 | title: 'Page Search', 22 | description: 'Page search, quick navigation', 23 | position: 'left', 24 | }, 25 | }, 26 | { 27 | element: '#screenfull', 28 | popover: { 29 | title: 'Screenfull', 30 | description: 'Set the page into fullscreen', 31 | position: 'left', 32 | }, 33 | }, 34 | { 35 | element: '#size-select', 36 | popover: { 37 | title: 'Switch Size', 38 | description: 'Switch the system size', 39 | position: 'left', 40 | }, 41 | }, 42 | { 43 | element: '#tags-view-container', 44 | popover: { 45 | title: 'Tags view', 46 | description: 'The history of the page you visited', 47 | position: 'bottom', 48 | }, 49 | padding: 0, 50 | }, 51 | ]; 52 | 53 | export default steps; 54 | -------------------------------------------------------------------------------- /resources/js/views/guide/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 37 | -------------------------------------------------------------------------------- /resources/js/views/icons/components/IconFont/require-icons.js: -------------------------------------------------------------------------------- 1 | const req = require.context('@/icons/svg', false, /\.svg$/); 2 | const requireAll = requireContext => requireContext.keys(); 3 | 4 | const re = /\.\/(.*)\.svg/; 5 | 6 | const icons = requireAll(req).map(i => { 7 | return i.match(re)[1]; 8 | }); 9 | 10 | export default icons; 11 | -------------------------------------------------------------------------------- /resources/js/views/icons/element-icons.js: -------------------------------------------------------------------------------- 1 | const elementIcons = ['info', 'error', 'success', 'warning', 'question', 'back', 'arrow-left', 'arrow-down', 'arrow-right', 'arrow-up', 'caret-left', 'caret-bottom', 'caret-top', 'caret-right', 'd-arrow-left', 'd-arrow-right', 'minus', 'plus', 'remove', 'circle-plus', 'remove-outline', 'circle-plus-outline', 'close', 'check', 'circle-close', 'circle-check', 'circle-close-outline', 'circle-check-outline', 'zoom-out', 'zoom-in', 'd-caret', 'sort', 'sort-down', 'sort-up', 'tickets', 'document', 'goods', 'sold-out', 'news', 'message', 'date', 'printer', 'time', 'bell', 'mobile-phone', 'service', 'view', 'menu', 'more', 'more-outline', 'star-on', 'star-off', 'location', 'location-outline', 'phone', 'phone-outline', 'picture', 'picture-outline', 'delete', 'search', 'edit', 'edit-outline', 'rank', 'refresh', 'share', 'setting', 'upload', 'upload2', 'download', 'loading']; 2 | export default elementIcons; 3 | -------------------------------------------------------------------------------- /resources/js/views/icons/svg-icons.js: -------------------------------------------------------------------------------- 1 | const req = require.context('../../icons/svg', false, /\.svg$/); 2 | const requireAll = requireContext => requireContext.keys(); 3 | 4 | const re = /\.\/(.*)\.svg/; 5 | 6 | const svgIcons = requireAll(req).map(i => { 7 | return i.match(re)[1]; 8 | }); 9 | 10 | export default svgIcons; 11 | -------------------------------------------------------------------------------- /resources/js/views/login/AuthRedirect.vue: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /resources/js/views/nested/menu1/index.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /resources/js/views/nested/menu1/menu1-1/index.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /resources/js/views/nested/menu1/menu1-2/index.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /resources/js/views/nested/menu1/menu1-2/menu1-2-1/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /resources/js/views/nested/menu1/menu1-2/menu1-2-2/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /resources/js/views/nested/menu1/menu1-3/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /resources/js/views/nested/menu2/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /resources/js/views/pdf/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /resources/js/views/permission/Page.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | -------------------------------------------------------------------------------- /resources/js/views/redirect/index.vue: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /resources/js/views/tab/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 40 | 41 | 46 | -------------------------------------------------------------------------------- /resources/js/views/table/DynamicTable/UnfixedThead.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 51 | -------------------------------------------------------------------------------- /resources/js/views/table/DynamicTable/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 24 | 25 | -------------------------------------------------------------------------------- /resources/js/views/users/SelfProfile.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 44 | -------------------------------------------------------------------------------- /resources/js/views/users/UserProfile.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 52 | -------------------------------------------------------------------------------- /resources/lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Your password has been reset!', 17 | 'sent' => 'We have emailed your password reset link!', 18 | 'throttled' => 'Please wait before retrying.', 19 | 'token' => 'This password reset token is invalid.', 20 | 'user' => "We can't find a user with that email address.", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /resources/sass/_variables.scss: -------------------------------------------------------------------------------- 1 | 2 | // Body 3 | $body-bg: #f8fafc; 4 | 5 | // Typography 6 | $font-family-sans-serif: "Nunito", sans-serif; 7 | $font-size-base: 0.9rem; 8 | $line-height-base: 1.6; 9 | 10 | // Colors 11 | $blue: #3490dc; 12 | $indigo: #6574cd; 13 | $purple: #9561e2; 14 | $pink: #f66D9b; 15 | $red: #e3342f; 16 | $orange: #f6993f; 17 | $yellow: #ffed4a; 18 | $green: #38c172; 19 | $teal: #4dc0b5; 20 | $cyan: #6cb2eb; 21 | -------------------------------------------------------------------------------- /resources/sass/app.scss: -------------------------------------------------------------------------------- 1 | // Fonts 2 | @import url('https://fonts.googleapis.com/css?family=Nunito'); 3 | 4 | // Variables 5 | @import 'variables'; 6 | 7 | .navbar-laravel { 8 | background-color: #fff; 9 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04); 10 | } 11 | -------------------------------------------------------------------------------- /routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 18 | }); 19 | -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 19 | })->describe('Display an inspiring quote'); 20 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | 'web'], function () { 21 | Route::get(env('LARAVUE_PATH'), 'LaravueController@index')->where('any', '.*')->name('laravue'); 22 | }); 23 | -------------------------------------------------------------------------------- /server.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | $uri = urldecode( 11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 12 | ); 13 | 14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the 15 | // built-in PHP web server. This provides a convenient way to test a Laravel 16 | // application without having installed a "real" web server software here. 17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { 18 | return false; 19 | } 20 | 21 | require_once __DIR__.'/public/index.php'; 22 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !public/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | config.php 2 | routes.php 3 | schedule-* 4 | compiled.php 5 | services.json 6 | events.scanned.php 7 | routes.scanned.php 8 | down 9 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/Bootstrap.php: -------------------------------------------------------------------------------- 1 | createApplication()->make(Kernel::class); 27 | 28 | $commands = [ 29 | 'config:cache', 30 | 'event:cache', 31 | ]; 32 | 33 | foreach ($commands as $command) { 34 | $console->call($command); 35 | } 36 | } 37 | 38 | public function executeAfterLastTest(): void 39 | { 40 | array_map('unlink', glob('bootstrap/cache/*.phpunit.php')); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 19 | 20 | return $app; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | get('/'); 18 | 19 | $response->assertStatus(200); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 3 | 4 | function resolve(dir) { 5 | return path.join( 6 | __dirname, 7 | '/resources/js', 8 | dir 9 | ); 10 | } 11 | 12 | const rawArgv = process.argv.slice(2); 13 | const args = rawArgv.join(' '); 14 | const report = rawArgv.includes('--report'); 15 | let plugins = []; 16 | if (report) { 17 | plugins.push(new BundleAnalyzerPlugin({ 18 | openAnalyzer: true, 19 | })); 20 | } 21 | module.exports = { 22 | resolve: { 23 | extensions: ['.js', '.vue', '.json'], 24 | alias: { 25 | vue$: 'vue/dist/vue.esm.js', 26 | '@': path.join(__dirname, '/resources/js'), 27 | }, 28 | }, 29 | module: { 30 | rules: [ 31 | { 32 | test: /\.svg$/, 33 | loader: 'svg-sprite-loader', 34 | include: [resolve('icons')], 35 | options: { 36 | symbolId: 'icon-[name]', 37 | }, 38 | }, 39 | ], 40 | }, 41 | plugins: plugins, 42 | output: { 43 | filename: '[name].js', 44 | chunkFilename: 'js/app.[chunkhash:6].js', 45 | }, 46 | }; 47 | --------------------------------------------------------------------------------