From dd44cab777e8a984c515d963ecb6f3b52a1e0274 Mon Sep 17 00:00:00 2001 From: php_Team <> Date: Sun, 16 Apr 2023 23:05:17 +0800 Subject: [PATCH] Initial commit --- .gitignore | 8 + .travis.yml | 42 + LICENSE.txt | 32 + README.md | 56 + app/.htaccess | 1 + app/AppService.php | 22 + app/BaseController.php | 138 + app/BaseModel.php | 16 + app/BasePivot.php | 16 + app/ExceptionHandle.php | 133 + app/Request.php | 80 + app/admin/controller/Common.php | 55 + .../controller/Dictionary/Dictionary.php | 234 + app/admin/controller/Flow/Flow.php | 307 + app/admin/controller/Gen/Gen.php | 2039 +++ app/admin/controller/Login.php | 145 + app/admin/controller/Menu/Menu.php | 368 + app/admin/controller/News/News.php | 291 + app/admin/controller/Product/Product.php | 220 + app/admin/controller/Product/ProductParam.php | 148 + app/admin/controller/Product/ProductType.php | 271 + app/admin/controller/Role/Role.php | 198 + app/admin/controller/School/Classes.php | 111 + app/admin/controller/School/Student.php | 544 + app/admin/controller/Tdk/Tdk.php | 133 + app/admin/controller/User/User.php | 371 + app/admin/controller/User/UserRole.php | 153 + app/admin/middleware/Auth.php | 84 + app/admin/route.php | 12 + app/api/controller/Crawler/Crawler.php | 112 + app/api/controller/Flow/Flow.php | 33 + app/api/controller/Login.php | 144 + app/api/controller/News/News.php | 88 + app/api/controller/Product/Product.php | 107 + app/api/controller/Product/ProductType.php | 68 + app/api/controller/User/User.php | 130 + app/api/middleware/Auth.php | 85 + app/api/route.php | 12 + app/common.php | 178 + app/common/arw/adjfut/composer.json | 39 + app/common/arw/adjfut/src/ArrayFilter.php | 170 + app/common/arw/adjfut/src/Base64.php | 174 + app/common/arw/adjfut/src/ChunkUpload.php | 258 + .../arw/adjfut/src/Config/chunkUpload.php | 9 + app/common/arw/adjfut/src/Config/wechat.php | 39 + app/common/arw/adjfut/src/Curl.php | 790 + app/common/arw/adjfut/src/Excel.php | 519 + .../arw/adjfut/src/Exception/ErrorMsg.php | 12 + app/common/arw/adjfut/src/Model/Pivot.php | 258 + app/common/arw/adjfut/src/PartitionTable.php | 261 + app/common/arw/adjfut/src/ReTry.php | 250 + .../arw/adjfut/src/Service/Validate.php | 68 + app/common/arw/adjfut/src/Tool.php | 196 + .../arw/adjfut/src/Traits/Dictionary.php | 223 + app/common/arw/adjfut/src/Traits/Event.php | 62 + app/common/arw/adjfut/src/Traverse.php | 240 + app/common/arw/adjfut/src/Unit/File.php | 86 + app/common/arw/adjfut/src/UploadFile.php | 289 + app/common/arw/adjfut/src/Validate.php | 254 + app/common/arw/adjfut/src/WeChat/Config.php | 123 + app/common/arw/adjfut/src/WeChat/Gzh.php | 348 + .../arw/adjfut/src/WeChat/GzhCommon.php | 459 + app/common/arw/adjfut/src/WeChat/Xcx.php | 232 + .../arw/adjfut/src/WeChat/XcxCommon.php | 279 + app/common/exception/Base64.php | 174 + app/common/exception/LoginTimeOut.php | 12 + app/common/exception/Map.php | 37 + app/common/exception/NotAuthApi.php | 12 + app/common/exception/RegularVerification.php | 49 + app/common/exception/Tool.php | 414 + app/common/listener/DelayToken.php | 20 + app/common/logic/Login.php | 170 + app/common/model/AboutUs/AboutUs.php | 105 + app/common/model/Banner/Banner.php | 77 + app/common/model/Consult/Consult.php | 101 + app/common/model/ContactUs/ContactUs.php | 101 + app/common/model/Dictionary/Dictionary.php | 243 + app/common/model/Flow/Flow.php | 258 + .../model/LeaveMessage/LeaveMessage.php | 222 + app/common/model/Menu/Menu.php | 128 + app/common/model/Menu/MenuApi.php | 142 + app/common/model/News/News.php | 99 + app/common/model/Product/Product.php | 227 + app/common/model/Product/ProductParam.php | 93 + app/common/model/Product/ProductType.php | 182 + app/common/model/Role/Role.php | 146 + app/common/model/Role/RoleMenu.php | 162 + app/common/model/School/Classes.php | 77 + app/common/model/School/Student.php | 627 + app/common/model/School/StudentService.php | 81 + .../model/ServiceSupport/ServiceSupport.php | 93 + app/common/model/Tdk/Tdk.php | 83 + app/common/model/Token.php | 337 + app/common/model/User/User.php | 548 + app/common/model/User/UserRole.php | 157 + app/common/traits/Auth.php | 110 + app/common/traits/Model.php | 254 + app/event.php | 20 + app/middleware.php | 10 + app/provider.php | 9 + app/resources/view/admin/controller.tpl | 83 + app/resources/view/admin/model.tpl | 71 + app/resources/view/api/controller.tpl | 55 + app/resources/view/business/webApi.tpl | 23 + .../view/business/webApiController.tpl | 32 + app/resources/view/business/webController.tpl | 44 + app/resources/view/business/webIndex.tpl | 90 + app/resources/view/jsVue/add.tpl | 102 + app/resources/view/jsVue/api.tpl | 56 + app/resources/view/jsVue/detail.tpl | 62 + app/resources/view/jsVue/edit.tpl | 100 + app/resources/view/jsVue/index.tpl | 153 + app/service.php | 9 + composer.json | 60 + composer.lock | 3025 ++++ config/app.php | 33 + config/cache.php | 29 + config/captcha.php | 46 + config/chunkUpload.php | 9 + config/console.php | 10 + config/cookie.php | 20 + config/database.php | 63 + config/filesystem.php | 37 + config/lang.php | 27 + config/log.php | 124 + config/middleware.php | 8 + config/route.php | 50 + config/session.php | 19 + config/wechat.php | 39 + package-lock.json | 6 + public/.htaccess | 8 + public/admin.php | 36 + public/api.php | 36 + public/excel/产品.xlsx | Bin 0 -> 11430 bytes public/excel/产品导入模板 (2).xlsx | Bin 0 -> 12672 bytes public/excel/产品类型导入模板 (3).xlsx | Bin 0 -> 10010 bytes public/excel/产品类型导入模板.xlsx | Bin 0 -> 8872 bytes public/excel/关键词导入模板 (2).xlsx | Bin 0 -> 9547 bytes public/excel/关键词导入模板.xlsx | Bin 0 -> 8856 bytes public/excel/字典导入模板.xlsx | Bin 0 -> 9286 bytes public/excel/学生导入模板 (3).xlsx | Bin 0 -> 10487 bytes public/excel/学生导入模板 (6).xlsx | Bin 0 -> 11902 bytes public/excel/用户导入模板 (1).xlsx | Bin 0 -> 9948 bytes public/excel/用户导入模板.xlsx | Bin 0 -> 9173 bytes public/favicon.ico | Bin 0 -> 1150 bytes public/robots.txt | 2 + public/router.php | 19 + public/static/.gitignore | 0 public/static/css/Contact.css | 346 + public/static/css/JoinFlow.css | 338 + public/static/css/animation.css | 169 + public/static/css/bootstrap.css | 11422 +++++++++++++++ public/static/css/button.css | 38 + public/static/css/companyIntro.css | 327 + public/static/css/developmentHistory.css | 338 + public/static/css/enterpriseCulture.css | 183 + public/static/css/footer.css | 10 + public/static/css/headNavFoot.css | 1058 ++ public/static/css/header.css | 6 + public/static/css/honour.css | 320 + public/static/css/index.css | 800 + public/static/css/joinAgent.css | 241 + public/static/css/joinPolicy.css | 256 + public/static/css/news.css | 632 + public/static/css/news_detail.css | 350 + public/static/css/poster.css | 32 + public/static/css/product.css | 351 + public/static/css/productInfo.css | 180 + public/static/css/swiper-bundle.css | 647 + public/static/js/button.js | 25 + public/static/js/contact.js | 69 + .../static/js/hyw/bootstrap/css/bootstrap.css | 10224 +++++++++++++ .../static/js/hyw/bootstrap/js/bootstrap.js | 4521 ++++++ public/static/js/hyw/css/animation.css | 169 + public/static/js/hyw/css/headNavFoot.css | 486 + public/static/js/hyw/css/index.css | 625 + public/static/js/hyw/css/product.css | 138 + public/static/js/hyw/js/event/bindEvent.js | 144 + public/static/js/hyw/js/event/event.js | 509 + public/static/js/hyw/js/event/event.js.rej | 15 + public/static/js/hyw/js/headNavEnd.js | 12 + public/static/js/hyw/js/index.js | 38 + public/static/js/hyw/js/plugin/getElPlugin.js | 20 + public/static/js/hyw/js/plugin/htmlPlugin.js | 61 + .../static/js/hyw/js/plugin/swiper-bundle.js | 10663 ++++++++++++++ public/static/js/hyw/js/product.js | 13 + public/static/js/hyw/js/productInfo.js | 10 + public/static/js/hyw/js/shares/reg.js | 16 + public/static/js/hyw/js/shares/utils.js | 530 + public/static/js/hyw/js/template.js | 42 + public/static/js/hyw/main.js | 27 + .../img/16cdb0fc7a88a99037adc1ab156eee5.jpg | Bin 0 -> 134458 bytes .../img/7bf36e3926a5c35bcd9bb071fb3cd2d.jpg | Bin 0 -> 102830 bytes .../img/80d4a347bb60e4b52bf05fff444aac8.jpg | Bin 0 -> 175069 bytes public/static/js/hyw/static/img/abotImg.png | Bin 0 -> 564189 bytes .../static/js/hyw/static/img/endPhoneIcon.png | Bin 0 -> 1209 bytes public/static/js/hyw/static/img/erweima1.png | Bin 0 -> 20665 bytes public/static/js/hyw/static/img/erweima2.png | Bin 0 -> 14571 bytes public/static/js/hyw/static/img/erweima3.png | Bin 0 -> 18391 bytes public/static/js/hyw/static/img/foot2Img.png | Bin 0 -> 94824 bytes public/static/js/hyw/static/img/footedImg.png | Bin 0 -> 421886 bytes public/static/js/hyw/static/img/glhicon.png | Bin 0 -> 19825 bytes public/static/js/hyw/static/img/jz1.png | Bin 0 -> 75528 bytes public/static/js/hyw/static/img/jz2.png | Bin 0 -> 49011 bytes public/static/js/hyw/static/img/jz3.png | Bin 0 -> 59649 bytes public/static/js/hyw/static/img/jz4.png | Bin 0 -> 78310 bytes .../static/js/hyw/static/img/moreButton.png | Bin 0 -> 299 bytes public/static/js/hyw/static/img/next.png | Bin 0 -> 937 bytes public/static/js/hyw/static/img/prev.png | Bin 0 -> 395 bytes public/static/js/hyw/static/img/search.png | Bin 0 -> 6343 bytes public/static/js/hyw/static/img/show1.png | Bin 0 -> 700 bytes public/static/js/hyw/static/img/show2.png | Bin 0 -> 1109 bytes public/static/js/hyw/static/img/show3.png | Bin 0 -> 620 bytes public/static/js/hyw/static/img/show4.png | Bin 0 -> 347 bytes .../hyw/static/img/showContentLeftButton.png | Bin 0 -> 2027 bytes .../hyw/static/img/showContentRightButton.png | Bin 0 -> 1987 bytes public/static/js/hyw/static/img/txImg.png | Bin 0 -> 53190 bytes .../static/js/hyw/static/img/xiyouyanji.png | Bin 0 -> 78231 bytes .../js/hyw/static/img/zoujingaoluhua.png | Bin 0 -> 155278 bytes .../js/hyw/static/img/zoujingaoluhuaImg.png | Bin 0 -> 252634 bytes public/static/js/jquery.js | 8755 +++++++++++ public/static/js/news.js | 27 + public/static/js/vue.js | 12014 ++++++++++++++++ think | 10 + 224 files changed, 90196 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 app/.htaccess create mode 100644 app/AppService.php create mode 100644 app/BaseController.php create mode 100644 app/BaseModel.php create mode 100644 app/BasePivot.php create mode 100644 app/ExceptionHandle.php create mode 100644 app/Request.php create mode 100644 app/admin/controller/Common.php create mode 100644 app/admin/controller/Dictionary/Dictionary.php create mode 100644 app/admin/controller/Flow/Flow.php create mode 100644 app/admin/controller/Gen/Gen.php create mode 100644 app/admin/controller/Login.php create mode 100644 app/admin/controller/Menu/Menu.php create mode 100644 app/admin/controller/News/News.php create mode 100644 app/admin/controller/Product/Product.php create mode 100644 app/admin/controller/Product/ProductParam.php create mode 100644 app/admin/controller/Product/ProductType.php create mode 100644 app/admin/controller/Role/Role.php create mode 100644 app/admin/controller/School/Classes.php create mode 100644 app/admin/controller/School/Student.php create mode 100644 app/admin/controller/Tdk/Tdk.php create mode 100644 app/admin/controller/User/User.php create mode 100644 app/admin/controller/User/UserRole.php create mode 100644 app/admin/middleware/Auth.php create mode 100644 app/admin/route.php create mode 100644 app/api/controller/Crawler/Crawler.php create mode 100644 app/api/controller/Flow/Flow.php create mode 100644 app/api/controller/Login.php create mode 100644 app/api/controller/News/News.php create mode 100644 app/api/controller/Product/Product.php create mode 100644 app/api/controller/Product/ProductType.php create mode 100644 app/api/controller/User/User.php create mode 100644 app/api/middleware/Auth.php create mode 100644 app/api/route.php create mode 100644 app/common.php create mode 100644 app/common/arw/adjfut/composer.json create mode 100644 app/common/arw/adjfut/src/ArrayFilter.php create mode 100644 app/common/arw/adjfut/src/Base64.php create mode 100644 app/common/arw/adjfut/src/ChunkUpload.php create mode 100644 app/common/arw/adjfut/src/Config/chunkUpload.php create mode 100644 app/common/arw/adjfut/src/Config/wechat.php create mode 100644 app/common/arw/adjfut/src/Curl.php create mode 100644 app/common/arw/adjfut/src/Excel.php create mode 100644 app/common/arw/adjfut/src/Exception/ErrorMsg.php create mode 100644 app/common/arw/adjfut/src/Model/Pivot.php create mode 100644 app/common/arw/adjfut/src/PartitionTable.php create mode 100644 app/common/arw/adjfut/src/ReTry.php create mode 100644 app/common/arw/adjfut/src/Service/Validate.php create mode 100644 app/common/arw/adjfut/src/Tool.php create mode 100644 app/common/arw/adjfut/src/Traits/Dictionary.php create mode 100644 app/common/arw/adjfut/src/Traits/Event.php create mode 100644 app/common/arw/adjfut/src/Traverse.php create mode 100644 app/common/arw/adjfut/src/Unit/File.php create mode 100644 app/common/arw/adjfut/src/UploadFile.php create mode 100644 app/common/arw/adjfut/src/Validate.php create mode 100644 app/common/arw/adjfut/src/WeChat/Config.php create mode 100644 app/common/arw/adjfut/src/WeChat/Gzh.php create mode 100644 app/common/arw/adjfut/src/WeChat/GzhCommon.php create mode 100644 app/common/arw/adjfut/src/WeChat/Xcx.php create mode 100644 app/common/arw/adjfut/src/WeChat/XcxCommon.php create mode 100644 app/common/exception/Base64.php create mode 100644 app/common/exception/LoginTimeOut.php create mode 100644 app/common/exception/Map.php create mode 100644 app/common/exception/NotAuthApi.php create mode 100644 app/common/exception/RegularVerification.php create mode 100644 app/common/exception/Tool.php create mode 100644 app/common/listener/DelayToken.php create mode 100644 app/common/logic/Login.php create mode 100644 app/common/model/AboutUs/AboutUs.php create mode 100644 app/common/model/Banner/Banner.php create mode 100644 app/common/model/Consult/Consult.php create mode 100644 app/common/model/ContactUs/ContactUs.php create mode 100644 app/common/model/Dictionary/Dictionary.php create mode 100644 app/common/model/Flow/Flow.php create mode 100644 app/common/model/LeaveMessage/LeaveMessage.php create mode 100644 app/common/model/Menu/Menu.php create mode 100644 app/common/model/Menu/MenuApi.php create mode 100644 app/common/model/News/News.php create mode 100644 app/common/model/Product/Product.php create mode 100644 app/common/model/Product/ProductParam.php create mode 100644 app/common/model/Product/ProductType.php create mode 100644 app/common/model/Role/Role.php create mode 100644 app/common/model/Role/RoleMenu.php create mode 100644 app/common/model/School/Classes.php create mode 100644 app/common/model/School/Student.php create mode 100644 app/common/model/School/StudentService.php create mode 100644 app/common/model/ServiceSupport/ServiceSupport.php create mode 100644 app/common/model/Tdk/Tdk.php create mode 100644 app/common/model/Token.php create mode 100644 app/common/model/User/User.php create mode 100644 app/common/model/User/UserRole.php create mode 100644 app/common/traits/Auth.php create mode 100644 app/common/traits/Model.php create mode 100644 app/event.php create mode 100644 app/middleware.php create mode 100644 app/provider.php create mode 100644 app/resources/view/admin/controller.tpl create mode 100644 app/resources/view/admin/model.tpl create mode 100644 app/resources/view/api/controller.tpl create mode 100644 app/resources/view/business/webApi.tpl create mode 100644 app/resources/view/business/webApiController.tpl create mode 100644 app/resources/view/business/webController.tpl create mode 100644 app/resources/view/business/webIndex.tpl create mode 100644 app/resources/view/jsVue/add.tpl create mode 100644 app/resources/view/jsVue/api.tpl create mode 100644 app/resources/view/jsVue/detail.tpl create mode 100644 app/resources/view/jsVue/edit.tpl create mode 100644 app/resources/view/jsVue/index.tpl create mode 100644 app/service.php create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 config/app.php create mode 100644 config/cache.php create mode 100644 config/captcha.php create mode 100644 config/chunkUpload.php create mode 100644 config/console.php create mode 100644 config/cookie.php create mode 100644 config/database.php create mode 100644 config/filesystem.php create mode 100644 config/lang.php create mode 100644 config/log.php create mode 100644 config/middleware.php create mode 100644 config/route.php create mode 100644 config/session.php create mode 100644 config/wechat.php create mode 100644 package-lock.json create mode 100644 public/.htaccess create mode 100644 public/admin.php create mode 100644 public/api.php create mode 100644 public/excel/产品.xlsx create mode 100644 public/excel/产品导入模板 (2).xlsx create mode 100644 public/excel/产品类型导入模板 (3).xlsx create mode 100644 public/excel/产品类型导入模板.xlsx create mode 100644 public/excel/关键词导入模板 (2).xlsx create mode 100644 public/excel/关键词导入模板.xlsx create mode 100644 public/excel/字典导入模板.xlsx create mode 100644 public/excel/学生导入模板 (3).xlsx create mode 100644 public/excel/学生导入模板 (6).xlsx create mode 100644 public/excel/用户导入模板 (1).xlsx create mode 100644 public/excel/用户导入模板.xlsx create mode 100644 public/favicon.ico create mode 100644 public/robots.txt create mode 100644 public/router.php create mode 100644 public/static/.gitignore create mode 100644 public/static/css/Contact.css create mode 100644 public/static/css/JoinFlow.css create mode 100644 public/static/css/animation.css create mode 100644 public/static/css/bootstrap.css create mode 100644 public/static/css/button.css create mode 100644 public/static/css/companyIntro.css create mode 100644 public/static/css/developmentHistory.css create mode 100644 public/static/css/enterpriseCulture.css create mode 100644 public/static/css/footer.css create mode 100644 public/static/css/headNavFoot.css create mode 100644 public/static/css/header.css create mode 100644 public/static/css/honour.css create mode 100644 public/static/css/index.css create mode 100644 public/static/css/joinAgent.css create mode 100644 public/static/css/joinPolicy.css create mode 100644 public/static/css/news.css create mode 100644 public/static/css/news_detail.css create mode 100644 public/static/css/poster.css create mode 100644 public/static/css/product.css create mode 100644 public/static/css/productInfo.css create mode 100644 public/static/css/swiper-bundle.css create mode 100644 public/static/js/button.js create mode 100644 public/static/js/contact.js create mode 100644 public/static/js/hyw/bootstrap/css/bootstrap.css create mode 100644 public/static/js/hyw/bootstrap/js/bootstrap.js create mode 100644 public/static/js/hyw/css/animation.css create mode 100644 public/static/js/hyw/css/headNavFoot.css create mode 100644 public/static/js/hyw/css/index.css create mode 100644 public/static/js/hyw/css/product.css create mode 100644 public/static/js/hyw/js/event/bindEvent.js create mode 100644 public/static/js/hyw/js/event/event.js create mode 100644 public/static/js/hyw/js/event/event.js.rej create mode 100644 public/static/js/hyw/js/headNavEnd.js create mode 100644 public/static/js/hyw/js/index.js create mode 100644 public/static/js/hyw/js/plugin/getElPlugin.js create mode 100644 public/static/js/hyw/js/plugin/htmlPlugin.js create mode 100644 public/static/js/hyw/js/plugin/swiper-bundle.js create mode 100644 public/static/js/hyw/js/product.js create mode 100644 public/static/js/hyw/js/productInfo.js create mode 100644 public/static/js/hyw/js/shares/reg.js create mode 100644 public/static/js/hyw/js/shares/utils.js create mode 100644 public/static/js/hyw/js/template.js create mode 100644 public/static/js/hyw/main.js create mode 100644 public/static/js/hyw/static/img/16cdb0fc7a88a99037adc1ab156eee5.jpg create mode 100644 public/static/js/hyw/static/img/7bf36e3926a5c35bcd9bb071fb3cd2d.jpg create mode 100644 public/static/js/hyw/static/img/80d4a347bb60e4b52bf05fff444aac8.jpg create mode 100644 public/static/js/hyw/static/img/abotImg.png create mode 100644 public/static/js/hyw/static/img/endPhoneIcon.png create mode 100644 public/static/js/hyw/static/img/erweima1.png create mode 100644 public/static/js/hyw/static/img/erweima2.png create mode 100644 public/static/js/hyw/static/img/erweima3.png create mode 100644 public/static/js/hyw/static/img/foot2Img.png create mode 100644 public/static/js/hyw/static/img/footedImg.png create mode 100644 public/static/js/hyw/static/img/glhicon.png create mode 100644 public/static/js/hyw/static/img/jz1.png create mode 100644 public/static/js/hyw/static/img/jz2.png create mode 100644 public/static/js/hyw/static/img/jz3.png create mode 100644 public/static/js/hyw/static/img/jz4.png create mode 100644 public/static/js/hyw/static/img/moreButton.png create mode 100644 public/static/js/hyw/static/img/next.png create mode 100644 public/static/js/hyw/static/img/prev.png create mode 100644 public/static/js/hyw/static/img/search.png create mode 100644 public/static/js/hyw/static/img/show1.png create mode 100644 public/static/js/hyw/static/img/show2.png create mode 100644 public/static/js/hyw/static/img/show3.png create mode 100644 public/static/js/hyw/static/img/show4.png create mode 100644 public/static/js/hyw/static/img/showContentLeftButton.png create mode 100644 public/static/js/hyw/static/img/showContentRightButton.png create mode 100644 public/static/js/hyw/static/img/txImg.png create mode 100644 public/static/js/hyw/static/img/xiyouyanji.png create mode 100644 public/static/js/hyw/static/img/zoujingaoluhua.png create mode 100644 public/static/js/hyw/static/img/zoujingaoluhuaImg.png create mode 100644 public/static/js/jquery.js create mode 100644 public/static/js/news.js create mode 100644 public/static/js/vue.js create mode 100644 think diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..daef398 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/.idea +/.vscode +/vendor +/public/uploads/** +*.log +.env +*.http +runtime/* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..36f7b6f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,42 @@ +sudo: false + +language: php + +branches: + only: + - stable + +cache: + directories: + - $HOME/.composer/cache + +before_install: + - composer self-update + +install: + - composer install --no-dev --no-interaction --ignore-platform-reqs + - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip . + - composer require --update-no-dev --no-interaction "topthink/think-image:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0" + - composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0" + - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip . + +script: + - php think unit + +deploy: + provider: releases + api_key: + secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw= + file: + - ThinkPHP_Core.zip + - ThinkPHP_Full.zip + skip_cleanup: true + on: + tags: true diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..574a39c --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,32 @@ + +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 +版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn) +All rights reserved。 +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 + +Apache Licence是著名的非盈利开源组织Apache采用的协议。 +该协议和BSD类似,鼓励代码共享和尊重原作者的著作权, +允许代码修改,再作为开源或商业软件发布。需要满足 +的条件: +1. 需要给代码的用户一份Apache Licence ; +2. 如果你修改了代码,需要在被修改的文件中说明; +3. 在延伸的代码中(修改和有源代码衍生的代码中)需要 +带有原来代码中的协议,商标,专利声明和其他原来作者规 +定需要包含的说明; +4. 如果再发布的产品中包含一个Notice文件,则在Notice文 +件中需要带有本协议内容。你可以在Notice中增加自己的 +许可,但不可以表现为对Apache Licence构成更改。 +具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0 + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2929dad --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +ThinkPHP 6.0 +=============== + +> 运行环境要求PHP7.1+,兼容PHP8.0。 + +[官方应用服务市场](https://market.topthink.com) | [`ThinkAPI`——官方统一API服务](https://docs.topthink.com/think-api) + +ThinkPHPV6.0版本由[亿速云](https://www.yisu.com/)独家赞助发布。 + +## 主要新特性 + +* 采用`PHP7`强类型(严格模式) +* 支持更多的`PSR`规范 +* 原生多应用支持 +* 更强大和易用的查询 +* 全新的事件系统 +* 模型事件和数据库事件统一纳入事件系统 +* 模板引擎分离出核心 +* 内部功能中间件化 +* SESSION/Cookie机制改进 +* 对Swoole以及协程支持改进 +* 对IDE更加友好 +* 统一和精简大量用法 + +## 安装 + +~~~ +composer create-project topthink/think tp 6.0.* +~~~ + +如果需要更新框架使用 +~~~ +composer update topthink/framework +~~~ + +## 文档 + +[完全开发手册](https://www.kancloud.cn/manual/thinkphp6_0/content) + +## 参与开发 + +请参阅 [ThinkPHP 核心框架包](https://github.com/top-think/framework)。 + +## 版权信息 + +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 + +本项目包含的第三方源码和二进制文件之版权信息另行标注。 + +版权所有Copyright © 2006-2020 by ThinkPHP (http://thinkphp.cn) + +All rights reserved。 + +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 + +更多细节参阅 [LICENSE.txt](LICENSE.txt) diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/app/AppService.php b/app/AppService.php new file mode 100644 index 0000000..96556e8 --- /dev/null +++ b/app/AppService.php @@ -0,0 +1,22 @@ +app = $app; + $this->request = $this->app->request; + + // 控制器初始化 + $this->initialize(); + } + + // 初始化 + protected function initialize() + { + } + + /** + * 验证数据 + * @access protected + * @param array $data 数据 + * @param string|array $validate 验证器名或者验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return array|string|true + * @throws ValidateException + */ + protected function validate(array $data, $validate, array $message = [], bool $batch = true) + { + if (is_array($validate)) { + $v = new Validate(); + $v->rule($validate); + } else { + if (strpos($validate, '.')) { + // 支持场景 + [$validate, $scene] = explode('.', $validate); + } + $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate); + $v = new $class(); + if (!empty($scene)) { + $v->scene($scene); + } + } + + $v->message($message); + + // 是否批量验证 + if ($batch || $this->batchValidate) { + $v->batch(true); + } + + return $v->failException(true)->check($data); + } + + /** + * 开启事务 + * + * @param callable $cb + * @param array $args + * @return mixed + * @date 2022-07-22 + * @example + * @author admin + * @since 1.0.0 + */ + protected static function transaction(callable $cb, array $args = []) + { + Db::startTrans(); + try { + $result = invoke($cb, $args); + Db::commit(); + return $result; + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 分页包装器 + * + * @param $query + * @date 2022-03-03 + * @example + * @author admin + * @since 1.0.0 + */ + protected static function pageWrapper($query) + { + return (clone $query)->page( + (int) Request::param('page', 1), + (int) Request::param('limit', 10) + ); + } +} diff --git a/app/BaseModel.php b/app/BaseModel.php new file mode 100644 index 0000000..ce65c75 --- /dev/null +++ b/app/BaseModel.php @@ -0,0 +1,16 @@ +respone([ + 'code' => 40050, + 'msg' => $e->getMessage(), + ]); + } + // 登录超时 + if ($e instanceof LoginTimeOut) { + return $this->respone([ + 'code' => 40026, + 'msg' => $request->isDev() ? $e->getMessage() : '登录超时', + ]); + } + // 参数验证不通过 + if ($e instanceof ValidateException) { + return $this->respone([ + 'code' => 40030, + 'msg' => $e->getMessage() + ]); + } + // 业务异常 + if ($e instanceof ErrorMsg || $e instanceof ExceptionErrorMsg) { + $code = $e->getCode(); + return $this->respone([ + 'code' => $code == 0 ? 40052 : $code, + 'msg' => $e->getMessage(), + ], $e); + } + // 服务器异常 + // if ($e instanceof Exception) { + // return $this->respone([ + // 'code' => 40051, + // 'msg' => '服务器异常', + // ], $e); + // } + // 其他错误交给系统处理 + return parent::render($request, $e); + } + + /** + * 返回 + * + * @param array $data + * @param Throwable $e + * @return Response + * @date 2022-04-15 + * @example + * @author admin + * @since 1.0.0 + */ + private function respone(array $data, $e = null): Response + { + $request = $this->app->request; + if ($e && Env::get('app_show_error')) { + $data['__error'] = [ + 'File' => $e->getFile(), + 'Line' => $e->getLine(), + 'Message' => $e->getMessage(), + 'Trace' => $e->getTrace() + ]; + $data['__param'] = $request->param(); + } + if ($request->isAjax()) { + return Response::create($data, 'json'); + } else { + return Response::create(json_encode($data), 'html'); + } + } +} diff --git a/app/Request.php b/app/Request.php new file mode 100644 index 0000000..dc5103c --- /dev/null +++ b/app/Request.php @@ -0,0 +1,80 @@ +param('dirName'); + + $upload = new UploadFile('uploads', 'file'); + $path = $upload->putFile($dirName . 'Img'); + return [ + 'code' => 0, + 'data' => [ + "name" => $path, + "url" => "/uploads/" . $path, + ], + 'msg' => '上传成功!' + ]; + } + + /** + * 上传文件 + */ + public function uploadFile(Request $request) + { + $dirName = $request->param('dirName'); + + $upload = new UploadFile('uploads', 'file'); + $path = $upload->putFile($dirName . 'File'); + return [ + 'code' => 0, + 'data' => [ + "name" => $path, + "url" => "/uploads/" . $path, + ], + 'msg' => '上传成功!' + ]; + } +} diff --git a/app/admin/controller/Dictionary/Dictionary.php b/app/admin/controller/Dictionary/Dictionary.php new file mode 100644 index 0000000..3a6533c --- /dev/null +++ b/app/admin/controller/Dictionary/Dictionary.php @@ -0,0 +1,234 @@ +order([ + 'dictionary_index', + 'dictionary_order' => 'desc', + ])->select(); + return [ + 'code' => 0, + 'msg' => 'ok', + 'data' => $select + ]; + } + + /** + * 获取菜单树 + * + * @param Request $request + * @return array + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function getDictionaryTree(Request $request) + { + $dictionary = ModelDictionary::withoutGlobalScope(['status'])->order([ + 'dictionary_index', + 'dictionary_order' => 'desc', + ])->field([ + 'dictionary_parent_guid', + 'dictionary_name', + 'dictionary_index', + 'dictionary_value', + 'dictionary_order', + 'dictionary_status', + 'dictionary_allow_update', + 'dictionary_list_class', + 'dictionary_guid', + ])->select()->toArray(); + + array_unshift($dictionary, [ + 'dictionary_guid' => '0', + 'dictionary_parent_guid' => '-1', + 'dictionary_name' => '系统字典', + 'dictionary_index' => 0, + 'dictionary_value' => '', + 'dictionary_order' => 0, + 'dictionary_status' => 0, + 'dictionary_allow_update' => 2, + 'dictionary_list_class' => '', + ]); + + $Traverse = new Traverse('dictionary_guid', 'dictionary_parent_guid'); + $dictionaryTree = $Traverse->tree($dictionary, '-1', function ($v) { + return [ + 'label' => $v['dictionary_name'], + 'id' => $v['dictionary_guid'], + 'parent_id' => $v['dictionary_parent_guid'], + 'index' => $v['dictionary_index'], + 'order' => $v['dictionary_order'], + 'status' => $v['dictionary_status'], + 'allow' => $v['dictionary_allow_update'], + 'value' => $v['dictionary_value'], + 'list_class' => $v['dictionary_list_class'] + ]; + }); + + return [ + 'code' => 0, + 'msg' => 'ok', + 'data' => $dictionaryTree + ]; + } + + /** + * 添加字典 + * + * @param Request $request + * @return array + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function addDictionary(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'dictionary_name' => 'require', + 'dictionary_index' => 'require', + 'dictionary_order' => 'require', + 'dictionary_parent_guid' => 'require', + ]); + if (isset($params['dictionary_guid'])) { + unset($params['dictionary_guid']); + } + ModelDictionary::create($params); + return [ + 'code' => 0, + 'msg' => '添加成功' + ]; + } + + /** + * 更新部门 + * + * @param Request $request + * @return array + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function updateDictionary(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'dictionary_guid' => 'require' + ]); + ModelDictionary::withoutGlobalScope(['status'])->update($params, [ + 'dictionary_guid' => $params['dictionary_guid'] + ]); + return [ + 'code' => 0, + 'msg' => '更新成功' + ]; + } + + /** + * 删除菜单 + * + * @param Request $request + * @return array + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function deleteDictionary(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'dictionary_guid' => 'require' + ]); + ModelDictionary::find($params['dictionary_guid'])->delete(); + return [ + 'code' => 0, + 'msg' => '删除成功' + ]; + } + + // 获取字典 + public function getDictionary(Request $request) + { + $dictionary_value = $request->param('dictionary_value'); + + $dictionary_guid = ModelDictionary::where('dictionary_value', $dictionary_value)->find()['dictionary_guid']; + $res = ModelDictionary::field([ + 'dictionary_guid', + 'dictionary_parent_guid', + 'dictionary_name', + 'dictionary_value', + 'dictionary_list_class', + ])->where('dictionary_parent_guid', $dictionary_guid) + ->where('dictionary_status', 1)->select(); + if (!$res) throwErrorMsg("字典不存在"); + else return $res; + } + + + /** + * 下载导入模板 + */ + public function downloadTemplate(Request $request) + { + $params = $request->param(); + $data = [ + [ + '上级字典', + '名称', + '值', + '层级', + '排序', + '回显', + ] + ]; + + $data[] = ['','状态','status','1','0','',]; + $data[] = ['状态','启用','1','2','1','primary']; + $data[] = ['状态','禁用','2','2','2','danger',]; + + $excel = (new Excel())->exporTsheet($data); + $excel->save('字典导入模板.xlsx'); + } + + /** + * 导入excel + */ + public function importExcel(Request $request) + { + $file = new UploadFile('uploads', 'fileExt:xlsx'); + $file->putFile('Dictionary'); + + $msg = ModelDictionary::importExcel($file); + + return [ + 'code' => 0, + 'msg' => $msg + ]; + } +} diff --git a/app/admin/controller/Flow/Flow.php b/app/admin/controller/Flow/Flow.php new file mode 100644 index 0000000..7edceac --- /dev/null +++ b/app/admin/controller/Flow/Flow.php @@ -0,0 +1,307 @@ +track(); + + /** + * 查询流量访问记录 + * @throws \think\db\exception\DbException + */ + public function getFlowRecord(Request $request): array + { + $query = ModelFlow::where([]); + $select = self::pageWrapper($query) + ->field([ + 'flow_id', + 'flow_record_no', + 'flow_visitor_ip', + 'flow_location', + 'flow_create_time', + 'flow_source', + 'flow_target', + 'flow_os', + 'flow_browser' + ]) + ->order('flow_id', 'desc') + ->select(); + + $count = $query->count(); + return [ + 'msg' => '查询成功', + 'code' => 0, + 'data' => $select, + 'count' => $count + ]; + } + + /** + * 查询流量来源统计 + */ + public function getFlowSourceCount(): array + { + $query = ModelFlow::where([]); + $count = $query->count(); + $select = $query->field([ + 'flow_id', + 'flow_source', + ])->select(); + $GDP = $query->field([ + + 'flow_source', + ])->group('flow_source')->select(); + foreach ($GDP as $k => &$i) { + $i['number'] = 0; + $i['percentage'] = 0; + } + foreach ($select as $key => &$item) { + foreach ($GDP as $k => &$i) { + if ($item['flow_source'] === $i['flow_source']) { + $i['number'] += 1; + } + } + } + foreach ($GDP as $k => $i) { + $i['percentage'] = round($i['number'] / $count * 100); + } + return [ + 'msg' => '查询完成', + 'code' => 0, + 'count' => $count, + 'data' => [ + 'GDP' => $GDP, + 'select' => $select + ] + ]; + } + + /** + * 查询流量浏览器统计 + */ + public function getFlowBrowserCount(): array + { + $query = ModelFlow::where([]); + $count = $query->count(); + $select = $query->field([ + 'flow_id', + 'flow_browser', + ])->select(); + $GDP = $query->field([ + + 'flow_browser', + ])->group('flow_browser')->select(); + foreach ($GDP as $k => &$i) { + $i['number'] = 0; + $i['percentage'] = 0; + } + foreach ($select as $key => &$item) { + foreach ($GDP as $k => &$i) { + if ($item['flow_browser'] === $i['flow_browser']) { + $i['number'] += 1; + } + } + } + foreach ($GDP as $k => $i) { + $i['percentage'] = round($i['number'] / $count * 100); + } + return [ + 'msg' => '查询完成', + 'code' => 0, + 'count' => $count, + 'data' => [ + 'select' => $select, + 'GDP' => $GDP + ] + ]; + } + + /** + * 查询流量月统计 + */ + public function getFlowMonthCount(Request $request): array + { + $current_year = input('post.current_year') ?? 0; + $query = ModelFlow::where([]); + $current_year = date('Y', strtotime("$current_year year")); + $count = $query->whereYear('flow_create_time', $current_year) + ->field([ + 'flow_create_time', + ]) + ->select()->count(); + $select = $query->whereYear('flow_create_time', $current_year) + ->field([ + 'flow_id', + 'flow_record_no', + 'flow_visitor_ip', + 'flow_location', + 'flow_create_time', + 'flow_source', + 'flow_target', + 'flow_os', + 'flow_browser' + ]) + ->order('flow_id', 'desc') + ->select()->toArray(); + $res_select = []; + for ($i = 1; $i <= 12; $i++) { + array_push($res_select, [ + 'flow_Date' => $current_year . + '-' . + date('m', strtotime($current_year . '-' . $i)), + 'number' => 0, + 'percentage' => 0 + ]); + } + foreach ($select as $key => &$item) { + $date_format = explode('-', explode(' ', $item['flow_create_time'])[0]); + + $item['flow_Date'] = $date_format[0] . '-' . $date_format[1]; + foreach ($res_select as $k => &$it) { + if ($item['flow_Date'] == $it['flow_Date']) { + $it['number'] += 1; + } + } + foreach ($res_select as $k => &$it) { + $it['percentage'] = round($it['number'] / $count * 100); + } + }; + foreach ($res_select as $k => &$it) { + foreach ($select as $key => &$item) { + if ($it['flow_Date'] === $item['flow_Date']) { + $it = array_merge($it, $item); + } + } + } + return [ + 'code' => 0, + 'msg' => '查询成功', + 'count' => $count, + 'data' => [ + 'current_date' => ['y' => $current_year], + 'select' => $res_select + ] + ]; + } + + /** + * 查询流量日统计 + */ + public function getFlowDayCount(Request $request) + { + $current_month = input('post.current_month') ?? 0; + // return ['a'=>$current_month]; + $query = ModelFlow::where([]); + $current_month_date = date('Y-m', strtotime(date('Y-m-01') . "$current_month month")); + // return ['a'=>$current_month_date]; + $count = $query->whereMonth('flow_create_time', $current_month_date) + ->field([ + 'flow_create_time', + ]) + ->select()->count(); + // $select = $query->whereMonth('flow_create_time', $current_month_date) + // ->field([ + // 'flow_create_time', + // ]) + // ->order('flow_id', 'desc') + // ->select()->toArray(); + $select = $query->whereMonth('flow_create_time', $current_month_date) + ->field([ + 'flow_create_time', + ]) + ->buildSql(); + return $select; + $GDP = []; + $res_select = []; + for ($i = 1; $i <= date('t', strtotime(date('Y-m-01') . "$current_month month")); $i++) { + + array_push($res_select, [ + 'week' => $this->getWeek(date('Y-m', strtotime(date('Y-m-01') . "$current_month month")) + . '-' + . date('d', strtotime(date('Y-m', strtotime(date('Y-m-01') . "$current_month month")) . "-$i"))), + 'flow_Date' => date('Y-m', strtotime(date('Y-m-01') . "$current_month month")) + . '-' + . date('d', strtotime(date('Y-m', strtotime(date('Y-m-01') . "$current_month month")) . "-$i")), + 'number' => 0, 'percentage' => 0 + ]); + } + foreach ($select as $key => &$item) { + + $item['flow_Date'] = explode(' ', $item['flow_create_time'])[0]; + foreach ($res_select as $k => &$it) { + if ($item['flow_Date'] == $it['flow_Date']) { + $it['number'] += 1; + } + } + foreach ($res_select as $k => &$it) { + $it['percentage'] = round($it['number'] / $count * 100); + } + }; + foreach ($res_select as $k => &$it) { + foreach ($select as $key => &$item) { + if ($it['flow_Date'] === $item['flow_Date']) { + $it = array_merge($it, $item); + } + } + } + return [ + 'code' => 0, + 'msg' => '查询成功', + 'count' => $count, + 'data' => [ + 'current_date' => ['y' => date('Y', strtotime(date('Y-m-01') . "$current_month month")), 'm' => date('m', strtotime(date('Y-m-01') . "$current_month month"))], + 'select' => $res_select + ] + ]; + } + + /** + * @param $date + * @return string + * @descript 获取指定日期星期 + */ + private function getWeek($date): string + { + //强制转换日期格式 + $date_str = date('Y-m-d', strtotime($date)); + + //封装成数组 + $arr = explode("-", $date_str); + + //参数赋值 + //年 + $year = $arr[0]; + + //月,输出2位整型,不够2位右对齐 + $month = sprintf('%02d', $arr[1]); + + //日,输出2位整型,不够2位右对齐 + $day = sprintf('%02d', $arr[2]); + + //时分秒默认赋值为0; + $hour = $minute = $second = 0; + + //转换成时间戳 + $strap = mktime($hour, $minute, $second, $month, $day, $year); + + //获取数字型星期几 + $number_wk = date("w", $strap); + + //自定义星期数组 + $weekArr = array("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"); + + //获取数字对应的星期 + return $weekArr[$number_wk]; + } + +} diff --git a/app/admin/controller/Gen/Gen.php b/app/admin/controller/Gen/Gen.php new file mode 100644 index 0000000..8a33200 --- /dev/null +++ b/app/admin/controller/Gen/Gen.php @@ -0,0 +1,2039 @@ + 0, + 'msg' => '一键删除表成功!' + ]; + } catch (\Throwable $th) { + throw $th; + } + } + + //一键生成表 + public function createTable() + { + try { + Db::execute(" + CREATE TABLE `gen_table` ( + `tableId` int(0) NOT NULL AUTO_INCREMENT COMMENT '编号', + `tableName` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '表名称', + `tableComment` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '表描述', + `className` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '实体类名称', + `tplCategory` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'crud' COMMENT '使用的模板(crud单表操作 tree树表操作)', + `moduleName` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成模块名', + `businessName` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成业务名', + `functionName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成功能名', + `functionAuthor` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成功能作者', + `genType` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '生成代码方式(0zip压缩包 1自定义路径)', + `genPath` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '/' COMMENT '生成路径(不填默认项目路径)', + `options` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '其它生成选项', + `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime(0) NULL DEFAULT NULL, + `create_user_guid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + `update_time` datetime(0) NULL DEFAULT NULL, + `update_user_guid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + `delete_time` datetime(0) NULL DEFAULT NULL, + `delete_user_guid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`tableId`) USING BTREE + ) ENGINE = InnoDB AUTO_INCREMENT = 79 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '生成表' ROW_FORMAT = DYNAMIC; + "); + + Db::execute(" + CREATE TABLE `gen_table_column` ( + `columnId` int(0) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '编号', + `tableName` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表名', + `tableId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '归属表编号', + `columnName` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '列名称', + `columnComment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '列描述', + `columnType` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '列类型', + `isPk` tinyint(1) NULL DEFAULT NULL COMMENT '是否主键(1是)', + `isIncrement` tinyint(1) NULL DEFAULT NULL COMMENT '是否自增(1是)', + `isRequired` tinyint(1) NULL DEFAULT NULL COMMENT '是否必填(1是)', + `isInsert` tinyint(1) NULL DEFAULT NULL COMMENT '是否为插入字段(1是)', + `isEdit` tinyint(1) NULL DEFAULT NULL COMMENT '是否编辑字段(1是)', + `isList` tinyint(1) NULL DEFAULT NULL COMMENT '是否列表字段(1是)', + `isQuery` tinyint(0) NULL DEFAULT NULL COMMENT '是否查询字段(1是)', + `isSort` tinyint(0) NULL DEFAULT NULL COMMENT '是否排序字段(1是)', + `queryType` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'EQ' COMMENT '查询方式(等于、不等于、大于、小于、范围)', + `htmlType` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + `dictType` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '字典类型', + `sort` int(0) NULL DEFAULT NULL COMMENT '排序', + `isInit` tinyint(1) NULL DEFAULT 0 COMMENT '是否初始化字段(1是)', + `create_time` datetime(0) NULL DEFAULT NULL, + `create_user_guid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + `update_time` datetime(0) NULL DEFAULT NULL, + `update_user_guid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + `delete_time` datetime(0) NULL DEFAULT NULL, + `delete_user_guid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`columnId`) USING BTREE + ) ENGINE = InnoDB AUTO_INCREMENT = 534 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '生成表字段' ROW_FORMAT = DYNAMIC; + "); + + return [ + 'code' => 0, + 'msg' => '一键生成表成功!' + ]; + } catch (\Throwable $th) { + throw $th; + } + } + + // 获取所有表名称 + public function getTatbleList(Request $request) + { + $data_base_name_arr = Db::query("select database()"); + $tableName = $request->param('tableName'); + + // $select = Db::getTables(); + $select = Db::query("show tables"); + $selecJs = []; + + $data_base_name = $data_base_name_arr[0]['database()']; + + foreach ($select as $key => $value) { + array_push($selecJs, ['name' => $value["Tables_in_{$data_base_name}"]]); + } + + $arr = []; + if ($tableName) { + foreach ($selecJs as $key => $value) { + if (strstr($value["name"], $tableName)) { + // return 1; + array_push($arr, $value); + } + } + } + if (count($arr) > 0) { + $selecJs = $arr; + } + + $count = count($selecJs); + return [ + 'code' => 200, + 'data' => [ + 'pageIndex' => 1, + 'pageSize' => 10, + 'result' => $selecJs, + 'totalNum' => $count, + 'totalPage' => 1, + ], + 'msg' => 'SUCCESS' + ]; + } + + // 获取生成表列表 + public function getGenTableList(Request $request) + { + $tableName = $request->param('tableName'); + $search = []; + if ($tableName) { + $search['tableName'] = $tableName; + } + + $select = Db::name('gen_table') + ->where($search) + ->order('tableId', 'desc'); + + $count = $select->count(); + $select = self::pageWrapper($select)->select(); + + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + + // 获取生成表详情 + public function getGenTableDetail(Request $request) + { + $tableId = $request->param('tableId'); + + $select = Db::name('gen_table') + ->where('tableId', $tableId) + ->find(); + + $columns = Db::name('gen_table_column') + ->where('tableId', $tableId) + ->select()->toArray(); + + $select['options'] = json_decode($select['options']); + foreach ($columns as $key => $value) { + $columns[$key]['isEdit'] = $this->intToBool($value['isEdit']); + $columns[$key]['isPk'] = $this->intToBool($value['isPk']); + $columns[$key]['isIncrement'] = $this->intToBool($value['isIncrement']); + $columns[$key]['isRequired'] = $this->intToBool($value['isRequired']); + $columns[$key]['isInsert'] = $this->intToBool($value['isInsert']); + $columns[$key]['isList'] = $this->intToBool($value['isList']); + $columns[$key]['isQuery'] = $this->intToBool($value['isQuery']); + $columns[$key]['isSort'] = $this->intToBool($value['isSort']); + $columns[$key]['isInit'] = $this->intToBool($value['isInit']); + } + + return [ + 'code' => 0, + 'data' => $select, + 'columns' => $columns, + 'msg' => 'ok' + ]; + } + + // 删除生成表 + public function delTable(Request $request) + { + $params = $request->param(); + + $gen = Db::name('gen_table')->where([ + 'tableId' => $params['tableId'] + ]); + $id = $gen->find()['tableId']; + // return $gen->find()['tableId']; + $gen->delete(); + + $gen_column = Db::name('gen_table_column')->where('tableId', $id); + $gen_column->delete(); + + return [ + 'code' => 200, + 'msg' => "删除成功" + ]; + } + + // 导入表 + public function importTable(Request $request) + { + $tables = $request->param('tables'); + + // 初始化表数据 + $tableInfo = Db::query("SHOW TABLE STATUS where Name = '$tables[0]'")[0]; + $tabledata = $this->initTable($tableInfo); + // return $tabledata; + $id = Db::name('gen_table')->strict()->insertGetId($tabledata); + + // 初始化字段数据 + $fields = Db::getFields($tables[0]); + + foreach ($fields as $value) { + // return $value; + $fieldsdata = $this->initFields($tables[0], $id, $value); + $fieldid = Db::name('gen_table_column')->strict()->insertGetId($fieldsdata); + } + + return [ + 'code' => 200, + 'msg' => '导入成功' + ]; + } + + /** + * 编辑生成 + */ + public function updateGenTable(Request $request) + { + $params = $request->param(); + // return $params['options']; + + $options = [ + "ParentMenuId" => $params['ParentMenuId'], + "SortType" => $params['SortType'], + "SortField" => $params['SortField'], + "CheckedBtn" => $params['CheckedBtn'], + "ColNum" => $params['ColNum'], + ]; + + $model = Db::name('gen_table')->where([ + 'tableId' => $params['tableId'] + ])->update([ + 'tableName' => $params['tableName'], + 'tableComment' => $params['tableComment'], + 'className' => $params['className'], + 'tplCategory' => $params['tplCategory'], + 'moduleName' => $params['moduleName'], + 'businessName' => $params['businessName'], + 'functionName' => $params['functionName'], + 'functionAuthor' => $params['functionAuthor'], + 'genType' => $params['genType'], + 'genPath' => $params['genPath'], + 'options' => json_encode($options), + 'remark' => $params['remark'], + ]); + // if (!$model) { + // throwErrorMsg("生成表不存在", 1); + // } + // $model->save($params); + + $model2 = Db::name('gen_table_column')->where([ + 'tableId' => $params['tableId'] + ])->select(); + if (!$model2) { + throwErrorMsg("生成表字段不存在", 1); + } + // return $model2; + foreach ($model2 as $key => $item1) { + // return $item1; + foreach ($params['columns'] as $key => $item2) { + if ($item1['columnId'] == $item2['columnId']) { + // return $item2; + // return var_dump($item2); + $item = Db::name('gen_table_column')->where([ + 'columnId' => $item2['columnId'] + ])->update($item2); + } + } + } + + return [ + 'code' => 200, + 'msg' => '编辑成功' + ]; + } + + // 生成代码入口 + public function genCode(Request $request) + { + $tableId = $request->param('tableId'); + + $table = Db::name('gen_table') + ->where('tableId', $tableId) + ->find(); + + $columns = Db::name('gen_table_column') + ->where('tableId', $tableId) + ->select()->toArray(); + + $table['options'] = json_decode($table['options']); + foreach ($columns as $key => $value) { + $columns[$key]['isEdit'] = $this->intToBool($value['isEdit']); + $columns[$key]['isPk'] = $this->intToBool($value['isPk']); + $columns[$key]['isIncrement'] = $this->intToBool($value['isIncrement']); + $columns[$key]['isRequired'] = $this->intToBool($value['isRequired']); + $columns[$key]['isInsert'] = $this->intToBool($value['isInsert']); + $columns[$key]['isList'] = $this->intToBool($value['isList']); + $columns[$key]['isQuery'] = $this->intToBool($value['isQuery']); + $columns[$key]['isSort'] = $this->intToBool($value['isSort']); + $columns[$key]['isInit'] = $this->intToBool($value['isInit']); + } + + // return $table; + + try { + if ($table['tplCategory'] == "web_static") { + $this->createAdminController($columns, $table); + $this->createNewModel($columns, $table); + $this->createJsWebStaticIndex($columns, $table); + $this->createJsApi($columns, $table); + } else if ($table['tplCategory'] == "crud") { + $this->createAdminController($columns, $table); + $this->createNewModel($columns, $table); + $this->createJsVue($columns, $table); + $this->createJsAdd($columns, $table); + $this->createJsEdit($columns, $table); + $this->createJsDetail($columns, $table); + $this->createJsApi($columns, $table); + } + } catch (\Throwable $th) { + throw $th; + } + + return [ + 'code' => 200, + 'msg' => '生成成功' + ]; + } + + // 生成Api代码入口 + public function codeGeneratorApi(Request $request) + { + $tableId = $request->param('tableId'); + + $table = Db::name('gen_table') + ->where('tableId', $tableId) + ->find(); + + $columns = Db::name('gen_table_column') + ->where('tableId', $tableId) + ->select()->toArray(); + + $table['options'] = json_decode($table['options']); + foreach ($columns as $key => $value) { + $columns[$key]['isEdit'] = $this->intToBool($value['isEdit']); + $columns[$key]['isPk'] = $this->intToBool($value['isPk']); + $columns[$key]['isIncrement'] = $this->intToBool($value['isIncrement']); + $columns[$key]['isRequired'] = $this->intToBool($value['isRequired']); + $columns[$key]['isInsert'] = $this->intToBool($value['isInsert']); + $columns[$key]['isList'] = $this->intToBool($value['isList']); + $columns[$key]['isQuery'] = $this->intToBool($value['isQuery']); + $columns[$key]['isSort'] = $this->intToBool($value['isSort']); + $columns[$key]['isInit'] = $this->intToBool($value['isInit']); + } + + $this->createApiController($columns, $table, 2); + + return [ + 'code' => 200, + 'msg' => '生成成功' + ]; + } + + // 初始化表数据 + private function initTable($tableInfo) + { + $options = [ + "ParentMenuId" => 0, + "SortType" => "desc", + "SortField" => $tableInfo['Name'] . "_update_time", + "CheckedBtn" => [1, 2, 3, 5], + "ColNum" => 0, + ]; + + $tabledata = [ + // 'tplCategory' => $tableInfo['tplCategory'], + 'tableName' => $tableInfo['Name'], + 'tableComment' => $tableInfo['Comment'], + 'className' => Tool::camelize($tableInfo['Name']), + 'businessName' => $tableInfo['Name'], + 'moduleName' => Tool::camelize($tableInfo['Name']), + 'functionName' => $tableInfo['Comment'], + 'functionAuthor' => 'admin', + 'genType' => 1, + 'genPath' => $this->address, // 自定义路径 + 'options' => json_encode($options), + 'create_time' => date('Y-m-d H:i:s'), + ]; + return $tabledata; + } + + // 初始化字段数据 + private function initFields($tableName, $id, $value) + { + // 初始字段 + $inputDtoNoFieldArr = [ + $tableName . "_" . "id", + $tableName . "_" . "guid", + $tableName . "_" . "create_time", + $tableName . "_" . "create_user_guid", + $tableName . "_" . "update_time", + $tableName . "_" . "update_user_guid", + $tableName . "_" . "delete_time", + $tableName . "_" . "delete_user_guid" + ]; + // 查询字段 + $ListFieldArr = [ + $tableName . "_" . "create_time", + $tableName . "_" . "create_user_guid", + $tableName . "_" . "update_time", + $tableName . "_" . "update_user_guid", + $tableName . "_" . "delete_time", + $tableName . "_" . "delete_user_guid" + ]; + // 图片字段 + $imageFiledArr = [ + $tableName . "_" . "icon", + $tableName . "_" . "img", + $tableName . "_" . "image", + $tableName . "_" . "url", + $tableName . "_" . "pic", + $tableName . "_" . "photo", + $tableName . "_" . "avatar" + ]; + // 下拉框字段 + $selectFiledArr = [ + $tableName . "_" . "status", + $tableName . "_" . "type", + $tableName . "_" . "state", + $tableName . "_" . "sex", + $tableName . "_" . "gender" + ]; + // 类型判断 + $type = $this->FieldsType($value['type']); + $queryType = ''; + + if (in_array($value["name"], $inputDtoNoFieldArr)) $isInsert = false; + else $isInsert = true; + + if (in_array($value["name"], $inputDtoNoFieldArr)) $isInit = true; + else $isInit = false; + + if ($value["primary"] || $value["autoinc"] || in_array($value["name"], $inputDtoNoFieldArr)) $isEdit = false; + else $isEdit = true; + + if (in_array($value["name"], $ListFieldArr)) $isList = false; + else $isList = true; + + //时间类型初始化between范围查询 + if ($value['type'] == "datetime") { + $queryType = "BETWEEN"; + } + + $fieldData = [ + 'tableName' => $tableName, + 'tableId' => $id, + 'columnName' => $value["name"], + 'columnComment' => $value["comment"], + 'columnType' => $type, + 'isPk' => $value["primary"], + 'isIncrement' => $value["autoinc"], + 'isRequired' => $value["notnull"], + 'isInsert' => $isInsert, + 'isEdit' => $isEdit, + 'isList' => $isList, + 'isQuery' => false, + 'htmlType' => $this->FieldsHtmlType($value["name"], $tableName), + 'queryType' => $queryType, + 'isInit' => $isInit, + 'create_time' => date('Y-m-d H:i:s'), + ]; + + return $fieldData; + // return 6; + } + + //生成模型 + private function createNewModel($fields, $table) + { + $root = base_path(); //根地址 + $model_path_name = $table['className']; + + //模型路径并创建 + $is_multiple = false; + $multiple_name = ''; + + $model_path = str_replace('/', DIRECTORY_SEPARATOR, $root . "common/model/" . $table['moduleName']); + if (true !== $res = $this->mkdir($model_path)) { + return $res; + } + + $temp_path = str_replace('/', DIRECTORY_SEPARATOR, $root . 'resources/view/admin/model.tpl'); + $gen_path = str_replace('/', DIRECTORY_SEPARATOR, $root . "common/model/" . $table['moduleName'] . '/' . $model_path_name . ".php"); //生成的模型地址\ + + $fieldArr = ''; + foreach ($fields as $value) { + $fieldArr .= ' + ' . '"' . $value['columnName'] . '"' . " => " . '"' . $value['columnType'] . '",' . " + "; + } + + $checked_btn_arr = $table['options']->CheckedBtn; //其他选项 4:导出 6:导入 + $init_fields = []; //初始化(业务字段) 例: user_name => 用户名称 + foreach ($fields as $key => $val) { + if (!$val['isInit']) $init_fields[$val['columnName']] = $val['columnComment']; + } + + //模型的示例代码 + $tem_f = fopen($temp_path, "r"); + $temp_str = fread($tem_f, filesize($temp_path)); + self::getImportExcelTempStr($fields, $table, $init_fields, 'imp_mod'); + $temp_str = str_replace( + [ + '{$className}', + '{$moduleName}', + '{$businessName}', + '{$fields}', + '{$multiple_name}', + '{$exportExcelContent}', + '{$importExcelContent}', + '{$importExcelInitContent}', + '{$importExcelField}' + ], + [ + $table['className'], + $table['moduleName'], + $table['businessName'], + $fieldArr, + $multiple_name, + in_array('4', $checked_btn_arr) ? self::getExportExcelTempStr($fields, $table, $init_fields, 'export_mod') : null, + in_array('6', $checked_btn_arr) ? self::getImportExcelTempStr($fields, $table, $init_fields, 'imp_mod') : null, + in_array('6', $checked_btn_arr) ? self::getImportExcelTempStr($fields, $table, $init_fields, 'imp_init') : null, + in_array('6', $checked_btn_arr) ? self::getImportExcelTempStr($fields, $table, $init_fields, 'imp_fie') : null, + ], + $temp_str + ); + // return $temp_str; + $gen_model = fopen($gen_path, 'w'); + fwrite($gen_model, $temp_str); + return true; + } + + //生成后台控制器 + private function createAdminController($fields, $table) + { + $root = base_path(); //根地址 + $module_name = $table['moduleName']; //模块名 + $class_name = $table['className']; //实体类名 + + //控制器模块构建 + $con_path = str_replace('/', DIRECTORY_SEPARATOR, "{$root}admin/controller/{$module_name}"); + if (true !== $res = $this->mkdir($con_path)) return $res; + //模板路径构建 + + if ($table['tplCategory'] == "crud") { + $temp_path = str_replace('/', DIRECTORY_SEPARATOR, "{$root}resources/view/admin/controller.tpl"); + } else if ($table['tplCategory'] == "web_static") { + $temp_path = str_replace('/', DIRECTORY_SEPARATOR, "{$root}resources/view/business/webController.tpl"); + } + + //控制器生成后的路径构建 + $gen_path = str_replace('/', DIRECTORY_SEPARATOR, "{$root}admin/controller/{$module_name}/{$class_name}.php"); + + + $function_name = $table['functionName']; //功能名 + $business_name = $table['businessName']; //业务名 + $checked_btn_arr = $table['options']->CheckedBtn; //其他选项 4:导出 6:导入 + $query_fields = []; //查询列表可显字段 + $order_field = "'{$table['options']->SortField}'"; //排序字段 + $order_mode = "'{$table['options']->SortType}'"; //排序方式 + $edit_allow_fields = ["{$business_name}_update_user_guid"]; //编辑允许字段 + $add_allow_fields = ["{$business_name}_guid", "{$business_name}_create_user_guid", "{$business_name}_update_user_guid"]; //新增允许字段 + $where_content_arr = []; //列表查询条件 + $init_fields = []; //初始化(业务字段) + $is_img_upload = false; + $add_require_fields = []; //新增必填字段 + $edit_require_fields = []; //编辑必填字段 + foreach ($fields as $key => $val) { + $column_name = $val['columnName']; + if (!$val['isInit']) $init_fields[$column_name] = $val['columnComment']; + if ($val['isList']) $query_fields[] = $column_name; + + if ($val['isEdit'] && !in_array($column_name, $edit_allow_fields)) { + $edit_allow_fields[] = $column_name; + if ($val['isRequired']) $edit_require_fields[] = $column_name; + } + if ($val['isInsert'] && !in_array($column_name, $add_allow_fields)) { + $add_allow_fields[] = $column_name; + if ($val['isRequired']) $add_require_fields[] = $column_name; + } + if ($val['isQuery']) $where_content_arr[] = [$column_name, $val['queryType']]; + if ($val['htmlType'] == 'imageUpload') $is_img_upload = true; + if ($val['htmlType'] == 'fileUpload') $is_file_upload = true; + } + + //打开模板文件资源(只读) + $temp_res_r = fopen($temp_path, "r"); + //获取模板内容 + $temp_res_str = fread($temp_res_r, filesize($temp_path)); + //模板内容替换 + $temp_str = str_replace( + [ + '{$moduleName}', + '{$className}', + '{$functionName}', + '{$businessName}', + '{$queryFields}', + '{$orderField}', + '{$orderMode}', + '{$editAllowFields}', + '{$addAllowFields}', + '{$whereContent}', + '{$exportExcelContent}', + '{$importExcelContent}', + '{$downloadTempContent}', + '{$editRequireFields}', + '{$addRequireFields}', + ], + [ + $module_name, + $class_name, + $function_name, + $business_name, + self::toFormTempStr($query_fields, $init_fields), + $order_field ?? "'{$business_name}_update_time'", + $order_mode ?? "'desc'", + self::toFormTempStr($edit_allow_fields, $init_fields), + self::toFormTempStr($add_allow_fields, $init_fields), + self::toFormTempStr($where_content_arr, $init_fields, 3), + in_array('4', $checked_btn_arr) ? self::getExportExcelTempStr($fields, $table, $init_fields, 'export_con') : null, + in_array('6', $checked_btn_arr) ? self::getImportExcelTempStr($fields, $table, $init_fields, 'imp_con') : null, + in_array('6', $checked_btn_arr) ? self::getExportExcelTempStr($fields, $table, $init_fields, 'temp') : null, + self::toFormTempStr($edit_require_fields, $init_fields, 2), + self::toFormTempStr($add_require_fields, $init_fields, 2), + + ], + $temp_res_str + ); + //渲染(写入)文件 + $gen_con = fopen($gen_path, 'w'); + fwrite($gen_con, $temp_str); + return true; + } + + //生成前台控制器 + private function createApiController($fields, $table) + { + $root = base_path(); //根地址 + $module_name = $table['moduleName']; //模块名 + $class_name = $table['className']; //实体类名 + $function_name = $table['functionName']; //功能名 + $business_name = $table['businessName']; //业务名 + + //控制器模块构建 + $con_path = str_replace('/', DIRECTORY_SEPARATOR, "{$root}api/controller/{$module_name}"); + if (true !== $res = $this->mkdir($con_path)) return $res; + //模板路径构建 + if ($table['tplCategory'] == "crud") { + $temp_path = str_replace('/', DIRECTORY_SEPARATOR, "{$root}resources/view/api/controller.tpl"); + } else if ($table['tplCategory'] == "web_static") { + $temp_path = str_replace('/', DIRECTORY_SEPARATOR, "{$root}resources/view/business/webApiController.tpl"); + } + + //控制器生成后的路径构建 + $gen_path = str_replace('/', DIRECTORY_SEPARATOR, "{$root}api/controller/{$module_name}/{$class_name}.php"); + + $query_fields = []; //查询列表可显字段 + $order_field = "'{$table['options']->SortField}'"; //排序字段 + $order_mode = "'{$table['options']->SortType}'"; //排序方式 + $edit_allow_fields = ["{$business_name}_update_user_guid"]; //编辑允许字段 + $add_allow_fields = ["{$business_name}_guid", "{$business_name}_create_user_guid", "{$business_name}_update_user_guid"]; //新增允许字段 + $where_content_arr = []; //列表查询条件 + $init_fields = []; //初始化(业务字段) + $add_require_fields = []; //新增必填字段 + $edit_require_fields = []; //编辑必填字段 + foreach ($fields as $key => $val) { + $column_name = $val['columnName']; + if (!$val['isInit']) $init_fields[$column_name] = $val['columnComment']; + if ($val['isList']) $query_fields[] = $column_name; + if ($val['isEdit'] && !in_array($column_name, $edit_allow_fields)) { + $edit_allow_fields[] = $column_name; + if ($val['isRequired']) $edit_require_fields[] = $column_name; + } + if ($val['isInsert'] && !in_array($column_name, $add_allow_fields)) { + $add_allow_fields[] = $column_name; + if ($val['isRequired']) $add_require_fields[] = $column_name; + } + if ($val['isQuery']) $where_content_arr[] = [$column_name, $val['queryType']]; + } + + //打开模板文件资源(只读) + $temp_res_r = fopen($temp_path, "r"); + //获取模板内容 + $temp_res_str = fread($temp_res_r, filesize($temp_path)); + //模板内容替换 + $temp_str = str_replace( + [ + '{$moduleName}', + '{$className}', + '{$functionName}', + '{$businessName}', + '{$queryFields}', + '{$orderField}', + '{$orderMode}', + '{$editAllowFields}', + '{$addAllowFields}', + '{$whereContent}', + '{$imgUploadContent}', + '{$fileUpload}', + '{$imgUrlPrefixPadding}', + '{$editRequireFields}', + '{$addRequireFields}', + ], + [ + $module_name, + $class_name, + $function_name, + $business_name, + self::toFormTempStr($query_fields, $init_fields), + $order_field ?? "'{$business_name}_update_time'", + $order_mode ?? "'desc'", + self::toFormTempStr($edit_allow_fields, $init_fields), + self::toFormTempStr($add_allow_fields, $init_fields), + self::toFormTempStr($where_content_arr, $init_fields, 3), + self::toFormTempStr($edit_require_fields, $init_fields, 2), + self::toFormTempStr($add_require_fields, $init_fields, 2), + ], + $temp_res_str + ); + //渲染(写入)文件 + $gen_con = fopen($gen_path, 'w'); + fwrite($gen_con, $temp_str); + return true; + } + + // Js版本 1.20 + + //生成JsVue页面 + private function createJsVue($fields, $table) + { + $root = base_path(); //根地址 + + // return $table; + $vue_path = $table['genPath'] . DIRECTORY_SEPARATOR . "src" . DIRECTORY_SEPARATOR . "pages\index" . DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR . $table['businessName']; + $vue_compoment_path = $vue_path . DIRECTORY_SEPARATOR . "components"; + if (true !== $res = $this->mkdir($vue_path)) { + return $res; + } + if (true !== $res = $this->mkdir($vue_compoment_path)) { + return $res; + } + + // return $fields; + $columnsArr = " + { + fixed: true, + type: 'selection' + },"; + + $btn = ''; + $btnFunName = ''; + $btnFun = ''; + $imgTemplate = ''; + $search = ''; + $dictFun = ''; + $dict = ''; + $dictScope = ''; + $query = ''; + + $btn_arr = $table['options']->CheckedBtn; // 勾选按钮 + // return $btn_arr; + foreach ($btn_arr as $key => $item) { + switch ($item) { + case 6: + $btn .= ' + + + 导入 + + + + 下载导入模板 + '; + + $btnFunName .= ', downloadTemplate , importExcel '; + + $btnFun .= ' + // 导入方法 + let loadingImoprt = null; + const uploadLoading = () => { + loadingImoprt = ElLoading.service({ + lock: true, + text: "正在导入中...", + background: "rgba(255, 255, 255, 0.7)", + }); + }; + const closeUploadLoading = () => loadingImoprt.close(); + const handleExcelSuccess = (value) => { + if (value.code == 0) { + ElMessageBox.alert(value.msg, "导入信息", { + dangerouslyUseHTMLString: true, + confirmButtonText: "确定", + }); + } else { + ElMessage.error(value.msg); + } + closeUploadLoading(); + tableRef.value.reload(); + }; + + '; + break; + case 4: + $btn .= ' + + 导出 + '; + + $btnFunName .= ' , exportExcel'; + break; + } + } + + foreach ($fields as $value) { + if ($value['isList'] == true) { + if ($value['isInit'] == false) { + $columnsArr .= ' + ' . '{ + prop: "' . $value['columnName'] . '", + ' . + "label: '" . $value['columnComment'] . "', + " . + "width: '150' + },"; + } + } + + if ($value['isQuery'] == true) { + $query .= $value['columnName'] . ': "", + '; + } + + if ($value['isQuery'] == true) { + if ($value['htmlType'] == "input") { + $search .= ' + ' . ' + ' . " + "; + } + if ($value['htmlType'] == "select") { + $search .= ' + ' . ' + ' . ' + + + '; + } + } + + if ($value['dictType'] != null) { + $dictFun = ", getDictionary"; + + $dictScope .= " + + "; + + $dict .= " + // 字典获取 + const " . $value['dictType'] . " = ref([]);" . ' + ' . "async function get_" . $value['dictType'] . "() { + await getDictionary({ dictionary_value: '" . $value['dictType'] . "'}).then((res) => {" . ' + ' . $value['dictType'] . ".value = res + }) + }" . ' + ' . + "get_" . $value['dictType'] . "()"; + } + + if ($value['htmlType'] == 'imageUpload') { + $imgTemplate .= " + '; + } + } + $columnsArr .= " + { + label: '操作', + prop: 'chaoz', + width: '250' + }"; + + // return $imgTemplate; + + // //模型的示例代码 + $temp_path = str_replace('/', DIRECTORY_SEPARATOR, $root . 'resources/view/jsVue/index.tpl'); + $gen_path = $vue_path . DIRECTORY_SEPARATOR . "index.vue"; //生成Js的index.vue的地址 + $tem_f = fopen($temp_path, "r"); + $temp_str = fread($tem_f, filesize($temp_path)); + $temp_str = str_replace( + [ + '${functionName}', + '${moduleName}', + '${search}', + '${className}', + '${btn}', + '${imgTemplate}', + '${dictFun}', + '${cloumns}', + '${businessName}', + '${dict}', + '${btnFunName}', + '${btnFun}', + '${query}', + '${dictScope}' + ], + [ + $table['functionName'], + $table['moduleName'], + $search, + $table['className'], + $btn, + $imgTemplate, + $dictFun, + $columnsArr, + $table['businessName'], + $dict, + $btnFunName, + $btnFun, + $query, + $dictScope + ], + $temp_str + ); + // return $temp_str; + $gen_model = fopen($gen_path, 'w'); + fwrite($gen_model, $temp_str); + return true; + } + + //生成JsWebStaticIndex页面 + private function createJsWebStaticIndex($fields, $table) + { + $root = base_path(); //根地址 + $vue_path = $table['genPath'] . DIRECTORY_SEPARATOR . "src" . DIRECTORY_SEPARATOR . "pages\index" . DIRECTORY_SEPARATOR . $table['businessName']; + if (true !== $res = $this->mkdir($vue_path)) { + return $res; + } + + $rulesArr = ""; + $col = ""; + $mapParm = ''; + $mapFun = ''; + $mapOpen = ''; + $mapOpenFun = 'getContent()'; + + $col = $this->getCol($fields); + + foreach ($fields as $value) { + if ($value['isInit'] == false) { + if ($value['isRequired'] == true) { + if ($value['isInsert'] == true) { + $rulesArr .= + $value['columnName'] . ": [ + { + required: true, + message: '" . $value['columnComment'] . "不能为空' + } + ], + "; + } + } + } + + if ($value['htmlType'] == "map") { + $mapParm = "const locationList = ref({})"; + + $mapFun = " + // 地址处理 + if (!locationList.value.address) { + ElMessage.error('请选择{$value['columnName']}'); + return + } + let locationData = locationList.value + formData.{$value['columnName']} = locationData.address + formData.longitude = locationData.longitude + formData.latitude = locationData.latitude + "; + + $mapOpen = " + if (formData.value.longitude) { + locationList.value.address = formData.value.{$value['columnName']}; + locationList.value.longitude = formData.value.longitude; + locationList.value.latitude = formData.value.latitude; + } + "; + + $mapOpenFun = " + let mapCb = function(){ + getContent() + }"; + } + } + + $temp_path = str_replace('/', DIRECTORY_SEPARATOR, $root . 'resources/view/business/webIndex.tpl'); + $gen_path = $vue_path . DIRECTORY_SEPARATOR . "index.vue"; //生成Js的index.vue的地址 + $tem_f = fopen($temp_path, "r"); + $temp_str = fread($tem_f, filesize($temp_path)); + $temp_str = str_replace( + [ + '${functionName}', + '${className}', + '${rules}', + '${businessName}', + '${col}', + '${mapParm}', + '${mapFun}', + '${mapOpen}', + '${mapOpenFun}', + ], + [ + $table['functionName'], + $table['className'], + $rulesArr, + $table['businessName'], + $col, + $mapParm, + $mapFun, + $mapOpen, + $mapOpenFun + ], + $temp_str + ); + $gen_model = fopen($gen_path, 'w'); + fwrite($gen_model, $temp_str); + return true; + } + + //生成JsAdd添加页面 + private function createJsAdd($fields, $table) + { + $root = base_path(); //根地址 + $vue_compoment_path = $table['genPath'] . DIRECTORY_SEPARATOR . "src" . DIRECTORY_SEPARATOR . "pages\index" . DIRECTORY_SEPARATOR . $table['businessName'] . DIRECTORY_SEPARATOR . "components"; + + $rulesArr = ""; + $col = ""; + $dictFunName = ''; + $dictFunName2 = ''; + $dictFun = ''; + $mapParm = ''; + $mapFun = ''; + + $col = $this->getCol($fields); + + foreach ($fields as $value) { + if ($value['isInit'] == false) { + if ($value['isRequired'] == true) { + if ($value['isInsert'] == true) { + $rulesArr .= + $value['columnName'] . ": [ + { + required: true, + message: '" . $value['columnComment'] . "不能为空' + } + ], + "; + } + } + } + + if ($value['dictType'] != null) { + $dictFunName = ", getDictionary"; + $dictFunName2 .= "get_" . $value['dictType'] . "()" . ' + '; + + $dictFun .= " + // 字典获取 + const " . $value['dictType'] . " = ref([]);" . ' + ' . "async function get_" . $value['dictType'] . "() { + await getDictionary({ dictionary_value: '" . $value['dictType'] . "'}).then((res) => {" . ' + ' . $value['dictType'] . ".value = res + }) + }"; + } + + if ($value['htmlType'] == "map") { + $mapParm = "const locationList = ref({})"; + + $mapFun = " + // 地址处理 + if (!locationList.value.address) { + ElMessage.error('请选择{$value['columnName']}'); + return + } + let locationData = locationList.value + formData.{$value['columnName']} = locationData.address + formData.longitude = locationData.longitude + formData.latitude = locationData.latitude + "; + } + } + + $temp_path = str_replace('/', DIRECTORY_SEPARATOR, $root . 'resources/view/jsVue/add.tpl'); + $gen_path = $vue_compoment_path . DIRECTORY_SEPARATOR . "Add" . $table['className'] . 'Dialog' . ".vue"; //生成Js的index.vue的地址 + $tem_f = fopen($temp_path, "r"); + $temp_str = fread($tem_f, filesize($temp_path)); + $temp_str = str_replace( + [ + '${functionName}', + '${className}', + '${rules}', + '${businessName}', + '${dictFunName}', + '${dictFunName2}', + '${dictFun}', + '${col}', + '${mapParm}', + '${mapFun}', + ], + [ + $table['functionName'], + $table['className'], + $rulesArr, + $table['businessName'], + $dictFunName, + $dictFunName2, + $dictFun, + $col, + $mapParm, + $mapFun, + ], + $temp_str + ); + $gen_model = fopen($gen_path, 'w'); + fwrite($gen_model, $temp_str); + return true; + } + + //生成JsEdit编辑页面 + private function createJsEdit($fields, $table) + { + $root = base_path(); //根地址 + + $vue_compoment_path = $table['genPath'] . DIRECTORY_SEPARATOR . "src" . DIRECTORY_SEPARATOR . "pages\index" . DIRECTORY_SEPARATOR . $table['businessName'] . DIRECTORY_SEPARATOR . "components"; + + // return $fields; + $rulesArr = ""; + $dictFunName = ''; + $dictFunName2 = ''; + $dictFun = ''; + $col = ''; + $mapParm = ''; + $mapFun = ''; + $mapOpen = ''; + + $col = $this->getCol($fields); + + foreach ($fields as $value) { + if ($value['isInit'] == false) { + if ($value['isRequired'] == true) { + if ($value['isEdit'] == true) { + $rulesArr .= + $value['columnName'] . ": [ + { + required: true, + message: '" . $value['columnComment'] . "不能为空' + } + ], + "; + } + } + } + + if ($value['dictType'] != null) { + $dictFunName = ", getDictionary"; + $dictFunName2 .= "get_" . $value['dictType'] . "()" . ' + '; + + $dictFun .= " + // 字典获取 + const " . $value['dictType'] . " = ref([]);" . ' + ' . "async function get_" . $value['dictType'] . "() { + await getDictionary({ dictionary_value: '" . $value['dictType'] . "'}).then((res) => {" . ' + ' . $value['dictType'] . ".value = res + }) + }"; + } + + if ($value['htmlType'] == "map") { + $mapParm = "const locationList = ref({})"; + + $mapFun = " + // 地址处理 + let locationData = locationList.value + formData.value.{$value['columnName']} = locationData.address + formData.value.longitude = locationData.longitude + formData.value.latitude = locationData.latitude + "; + + $mapOpen = " + if (formData.value.longitude) { + locationList.value.address = formData.value.{$value['columnName']}; + locationList.value.longitude = formData.value.longitude; + locationList.value.latitude = formData.value.latitude; + } + "; + } + } + // return $rulesArr; + + $temp_path = str_replace('/', DIRECTORY_SEPARATOR, $root . 'resources/view/jsVue/edit.tpl'); + $gen_path = $vue_compoment_path . DIRECTORY_SEPARATOR . "Edit" . $table['className'] . 'Dialog' . ".vue"; //生成Js的index.vue的地址 + $tem_f = fopen($temp_path, "r"); + $temp_str = fread($tem_f, filesize($temp_path)); + $temp_str = str_replace( + [ + '${functionName}', + '${className}', + '${rules}', + '${businessName}', + '${dictFunName}', + '${dictFunName2}', + '${dictFun}', + '${col}', + '${mapParm}', + '${mapFun}', + '${mapOpen}', + ], + [ + $table['functionName'], + $table['className'], + $rulesArr, + $table['businessName'], + $dictFunName, + $dictFunName2, + $dictFun, + $col, + $mapParm, + $mapFun, + $mapOpen, + ], + $temp_str + ); + // return $temp_str; + $gen_model = fopen($gen_path, 'w'); + fwrite($gen_model, $temp_str); + return true; + } + + //生成JsDetail详情页面 + private function createJsDetail($fields, $table) + { + $root = base_path(); //根地址 + + $vue_compoment_path = $table['genPath'] . DIRECTORY_SEPARATOR . "src" . DIRECTORY_SEPARATOR . "pages\index" . DIRECTORY_SEPARATOR . $table['businessName'] . DIRECTORY_SEPARATOR . "components"; + + $dictFunName = ''; + $dictFunName2 = ''; + $dictFun = ''; + $col = ''; + $mapParm = ''; + $mapOpen = ''; + + $col = $this->getCol($fields); + + foreach ($fields as $key => $value) { + if ($value['dictType'] != null) { + $dictFunName = "import { getDictionary } from '~/service/{$table['businessName']}';"; + $dictFunName2 .= "get_" . $value['dictType'] . "()" . ' + '; + + $dictFun .= " + // 字典获取 + const " . $value['dictType'] . " = ref([]);" . ' + ' . "async function get_" . $value['dictType'] . "() { + await getDictionary({ dictionary_value: '" . $value['dictType'] . "'}).then((res) => {" . ' + ' . $value['dictType'] . ".value = res + }) + }"; + } + if ($value['htmlType'] == "map") { + $mapParm = "const locationList = ref({})"; + + $mapOpen = " + if (formData.value.longitude) { + locationList.value.address = formData.value.{$value['columnName']}; + locationList.value.longitude = formData.value.longitude; + locationList.value.latitude = formData.value.latitude; + } + "; + } + } + + $temp_path = str_replace('/', DIRECTORY_SEPARATOR, $root . 'resources/view/jsVue/detail.tpl'); + $gen_path = $vue_compoment_path . DIRECTORY_SEPARATOR . "Detail" . $table['className'] . 'Dialog' . ".vue"; //生成的index.vue的地址 + $tem_f = fopen($temp_path, "r"); + $temp_str = fread($tem_f, filesize($temp_path)); + $temp_str = str_replace( + [ + '${functionName}', + '${className}', + '${businessName}', + '${dictFunName}', + '${dictFunName2}', + '${dictFun}', + '${col}', + '${mapParm}', + '${mapOpen}', + ], + [ + $table['functionName'], + $table['className'], + $table['businessName'], + $dictFunName, + $dictFunName2, + $dictFun, + $col, + $mapParm, + $mapOpen, + ], + $temp_str + ); + // return $temp_str; + $gen_model = fopen($gen_path, 'w'); + fwrite($gen_model, $temp_str); + return true; + } + + //生成Api页面 + private function createJsApi($fields, $table) + { + $root = base_path(); //根地址 + + $vue_api_path = $table['genPath'] . DIRECTORY_SEPARATOR . "src" . DIRECTORY_SEPARATOR . "service"; + + // return $fields; + + $urlStr = ""; + $listArr = ""; + $imageFun = ""; + $fileFun = ""; + $dictFun = ""; + + $excelFun = ""; + + $btn_arr = $table['options']->CheckedBtn; // 勾选按钮 + // return $btn_arr; + + foreach ($btn_arr as $key => $item) { + switch ($item) { + case 6: + $excelFun .= ' + /** + * 下载' . $table['tableComment'] . '模板 + * @param {Object} data + * @return {Promise} api + */ + export function downloadTemplate(data) { + downloadFile(createApiUrl(' . "'" . $table['moduleName'] . "." . $table['className'] . "/downloadTemplate'), data); + }" . ' + + /** + * 导入' . $table['tableComment'] . ' + * @param {Object} data + * @return {Promise} api + */ + export const importExcel = createApiUrl(' . "'" . $table['moduleName'] . "." . $table['className'] . "/importExcel'); + "; + break; + case 4: + $excelFun .= ' + /** + * 导出' . $table['tableComment'] . ' + * @param {Object} data + * @return {Promise} api + */ + export function exportExcel(data) { + downloadFile(createApiUrl(' . "'" . $table['moduleName'] . "." . $table['className'] . "/exportExcel'), data); + } + "; + break; + } + } + + foreach ($fields as $value) { + if ($value['isList'] == true) { + if ($value['isInit'] == false) { + $listArr .= + $value['columnName'] . ":" . self::FieldsJsType($value['columnType']) . ", + "; + + if ($value['htmlType'] == 'imageUpload' || $value['htmlType'] == 'fileUpload') { + $urlStr = 'url: "",'; + } + } + + if ($value['dictType'] != null) { + $dictFun = " + /** + * 获取字典值 + * @param {Object} data + * @return {Promise} api + */ + export function getDictionary(data) { + return api.post('Dictionary.Dictionary/getDictionary', data, { + }); + } + "; + } + // if ($value['htmlType'] == 'imageUpload') { + // $imageFun = " + // /** + // * 上传图片 + // */ + // export const upload" . $table['className'] . "Img = createApiUrl('" . $table['className'] . "." . $table['className'] . "/upload" . $table['className'] . "Img'); + // "; + // } + // if ($value['htmlType'] == 'fileUpload') { + // $fileFun = " + // /** + // * 上传文件 + // */ + // export const upload" . $table['className'] . "File = createApiUrl('" . $table['className'] . "." . $table['className'] . "/upload" . $table['className'] . "File'); + // "; + // } + } + } + + if ($table['tplCategory'] == "web_static") $temp_path = str_replace('/', DIRECTORY_SEPARATOR, $root . 'resources/view/business/webApi.tpl'); + else if ($table['tplCategory'] == "crud") $temp_path = str_replace('/', DIRECTORY_SEPARATOR, $root . 'resources/view/jsVue/api.tpl'); + $gen_path = $vue_api_path . DIRECTORY_SEPARATOR . $table['businessName'] . ".js"; //生成的api的地址 + $tem_f = fopen($temp_path, "r"); + $temp_str = fread($tem_f, filesize($temp_path)); + $temp_str = str_replace( + [ + '${moduleName}', + '${functionName}', + '${className}', + '${businessName}', + '${list}', + '${imageFun}', + '${fileFun}', + '${dictFun}', + '${excelFun}', + '${urlStr}', + ], + [ + $table['moduleName'], + $table['functionName'], + $table['className'], + $table['businessName'], + $listArr, + $imageFun, + $fileFun, + $dictFun, + $excelFun, + $urlStr, + ], + $temp_str + ); + // return $temp_str; + $gen_model = fopen($gen_path, 'w'); + fwrite($gen_model, $temp_str); + return true; + } + + + + //创建文件夹 + private function mkdir($path) + { + if (!is_dir($path)) { + if (false === @mkdir($path, 0777, true) && !is_dir($path)) { + throwErrorMsg('创建文件夹失败:' . $path); + } + } + return true; + } + + //判断字段类型 + private function FieldsType($type) + { + // return $type; + switch ($type) { + case strstr($type, 'int'): + return "int"; + break; + case strstr($type, 'double'): + return "double"; + break; + case strstr($type, 'varchar'): + return "string"; + break; + case strstr($type, 'text'): + return "string"; + break; + case strstr($type, 'datetime'): + return "datetime"; + break; + + default: + $type; + } + } + + //判断Js字段类型 + private function FieldsJsType($type) + { + switch ($type) { + case strstr($type, 'int'): + return "number"; + break; + case strstr($type, 'decimal'): + return "number"; + break; + case strstr($type, 'datetime'): + return "Date"; + break; + + default: + $type; + } + return $type; + } + + //判断Js默认值字段类型 + private function FieldsJsDefaultValue($type) + { + switch ($type) { + case strstr($type, 'string'): + return '""'; + break; + case strstr($type, 'int'): + return "0"; + break; + case strstr($type, 'decimal'): + return "0"; + break; + case strstr($type, 'datetime'): + return 'null'; + break; + + default: + $type; + } + return ""; + } + + //判断HTML类型 + private function FieldsHtmlType($name, $tableName) + { + // 图片字段 + $imageFiledArr = [ + $tableName . "_" . "icon", + $tableName . "_" . "img", + $tableName . "_" . "image", + $tableName . "_" . "url", + $tableName . "_" . "pic", + $tableName . "_" . "photo", + $tableName . "_" . "avatar" + ]; + // 下拉框字段 + $selectFiledArr = [ + $tableName . "_" . "status", + $tableName . "_" . "type", + $tableName . "_" . "state", + $tableName . "_" . "sex", + $tableName . "_" . "gender" + ]; + // 时间字段 + $timeFiledArr = [ + $tableName . "_" . "datetime", + $tableName . "_" . "time", + $tableName . "_" . "date", + $tableName . "_" . "timestamp" + ]; + + + $htmlType = 'input'; + + if (in_array($name, $imageFiledArr)) { + $htmlType = "imageUpload"; + } else if (in_array($name, $timeFiledArr)) { + $htmlType = "datetime"; + } else if (strstr($name, 'content')) { + $htmlType = "editor"; + } else if (in_array($name, $selectFiledArr)) { + $htmlType = "select"; + } + + return $htmlType; + } + + public function intToBool($value) + { + return (bool)$value; + } + + + public function getCol($fields) + { + $col = ''; + + foreach ($fields as $value) { + if ($value['isList'] == true) { + if ($value['isInit'] == false) { + if ($value['htmlType'] == "input") { + $col .= ' + + ' . ' + ' . " + + "; + } + if ($value['htmlType'] == "textarea") { + $col .= ' + + ' . ' + ' . " + + "; + } + if ($value['htmlType'] == "select") { + $col .= ' + + ' . ' + ' . ' + + + + '; + } + if ($value['htmlType'] == "datetime") { + $col .= ' + + + + + '; + } + if ($value['htmlType'] == "imageUpload") { + + $col .= " + + + + + + "; + } + if ($value['htmlType'] == "fileUpload") { + + $col .= " + + + + + + "; + } + if ($value['htmlType'] == "editor") { + $col .= ' + + ' . ' + ' . " + + "; + } + if ($value['htmlType'] == "inputNumber") { + $col .= ' + + ' . ' + ' . " + + "; + } + if ($value['htmlType'] == "map") { + $col .= " + + + + + + "; + } + } + } + } + + return $col; + } + + + /** + * 数组转换为模板字符串 + * @param array $arr 数组 + * @param array $service_fields 业务字段 + * @param int $type 模板字符类型 1:一维数组格式 2:验证器格式 3:列表条件查询 4:关联数组格式 + */ + private static function toFormTempStr(array $arr, array $service_fields, int $type = 1) + { + $str = ""; + switch ($type) { + case 1: + $str = str_replace('##', "'", "[\n##" . implode("##,\n##", $arr) . "##\n]"); + break; + case 2: + foreach ($service_fields as $key => &$val) { + foreach ($arr as $key1 => &$val1) { + if ($key == $val1) { + $val1 .= "|{$val}"; + } + } + } + $str = str_replace('##', "'", "[\n##" . implode("##=>'require',\n##", $arr) . "##=>##require##\n]"); + break; + case 3: + $str .= "\$con = Tool::getOptionalQuery("; + foreach ($arr as $key => $val) { + if ($val[1]) { + $str .= self::getListConditionalQuery($val[0], $val[1]); + } + }; + $str .= ");"; + break; + case 4: + foreach ($arr as $key => $val) { + $str .= "'{$key}' => '{$val}',\n"; + } + $str = "[\n$str],"; + break; + default: + break; + } + return $str; + } + + /** + * 获取列表条件表达式查询对应模板字符串 + * @param string $column_name 字段名 + * @param string $ope 运算符 + */ + private static function getListConditionalQuery(string $column_name, string $ope): string + { + return [ + 'LIKE' => self::geJsimpleExpTempStr($column_name, 'LIKE'), + 'BETWEEN' => self::geJsimpleExpTempStr($column_name, 'BETWEEN'), + 'EQ' => self::geJsimpleExpTempStr($column_name, '='), + 'LT' => self::geJsimpleExpTempStr($column_name, '<'), + 'LTE' => self::geJsimpleExpTempStr($column_name, '<='), + 'GTE' => self::geJsimpleExpTempStr($column_name, '>='), + 'GT' => self::geJsimpleExpTempStr($column_name, '>'), + 'NE' => self::geJsimpleExpTempStr($column_name, '!='), + ][$ope]; + } + + /** + * 获取简易表达式对应模板字符串 + * @param string $column_name 字段名 + * @param string $ope 运算符 + */ + private static function geJsimpleExpTempStr(string $column_name, string $ope): string + { + return "['{$column_name}','{$ope}'],"; + } + + /** + * 获取导出模板字符串 + * @param array $fields 字段信息 + * @param array $table 表信息 + * @param array $init_fields 业务字段 + * @param string $type 导出类型: export_con:导出-控制器 | export_mod:导出-模型层 | temp : 下载模板 + */ + private static function getExportExcelTempStr(array $fields, array $table, array $init_fields, string $type): string + { + $module_name = $table['moduleName']; //模块名 例:News + $function_name = $table['functionName']; //功能名 例:新闻 + $business_name = $table['businessName']; //业务名 例:news + $class_name = $table['className']; //类名 例:News + $init_fields_arr = []; + $init_fields_text = []; + $data_str = ''; + + $img_field = false; + foreach ($fields as $key => $val) { + if ($val['htmlType'] == 'imageUpload') $img_field = $val['columnName']; + } + + foreach ($init_fields as $key => $val) { + $init_fields_arr[] = $key; + $init_fields_text[] = $val; + + if ($key == $img_field) { + $data_str .= "Excel::ExportImgFiled(\$val['$img_field']),\n"; + } else { + $data_str .= "\$val['{$key}'],\n"; + } + } + $data_str = "[\n{$data_str}]"; //导出数据模板字段 + $init_fields_arr_str = self::toFormTempStr($init_fields_arr, $init_fields); //字段名(模板字符串) + $init_fields_text_str = self::toFormTempStr($init_fields_text, $init_fields); //字段注释(模板字符串) + switch ($type) { + case 'export_con': + $order_field = "'{$table['options']->SortField}'"; //排序字段 + $order_mode = "'{$table['options']->SortType}'"; //排序方式 + $order_field ?? $order_field = "'{$business_name}_update_time'"; + $order_mode ?? $order_mode = "'desc'"; + return "/**\n* 导出Excel\n*/ + public function exportExcel(Request \$request) + { + \$params = \$request->param(); + \$select = Model{$class_name}::field({$init_fields_arr_str}) + ->order({$order_field}, $order_mode ) + ->select(); + return Model{$class_name}::exportExcel(\$select); + }"; + case 'export_mod': + return "/**\n* 导出Excel\n*/ + public static function exportExcel(\$select) + { + \$data = [{$init_fields_text_str}]; + foreach (\$select as \$key => \$val) { + \$data[] = {$data_str}; + } + \$excel = (new Excel())->exporTsheet(\$data); + \$excel->save('{$function_name}.xlsx'); + }"; + case 'temp': + return "/**\n* 下载导入模板\n*/ + public function downloadTemplate(Request \$request) + { + \$params = \$request->param(); + \$data = array_values(Model{$class_name}::EXCELFIELD); + \$excel = (new Excel())->exporTsheet(\$data); + \$excel->save('{$function_name}导入模板.xlsx'); + }"; + default: + break; + } + } + + /** + * 获取有关文件上传的模板字符串 + * @param array $table 表信息 + * @param string $type 类型 img图片上传 file文件上传 + * @param string $is_multiple 是否为多应用类型 false => 单应用 true =>多应用 + */ + private static function getFileUploadTempStr(array $table, string $type): string + { + $class_name = $table['className']; //类名 例:News + + return [ + 'img' => + "/**\n* 上传图片\n*/ + public function upload{$class_name}Img(Request \$request) + { + \$upload = new UploadFile('uploads', 'file'); + \$path = \$upload->putFile('{$table['className']}Img'); + + return [ + 'code' => 0, + 'data' => '/uploads/' . \$path, + 'msg' => '上传成功!' + ]; + }", + 'file' => + "/**\n* 上传文件\n*/ + public function uploadFile(Request \$request): array + { + \$upload = new UploadFile('uploads', 'file'); + \$path = \$upload->putFile('{$table['className']}File'); + \$FileUrl = Env::get('自行替换.FileUrl'); + return [ + 'code' => 0, + 'data' => \$path, + 'url' => \$FileUrl, + 'msg' => '上传成功!' + ]; + }" + ][$type]; + } + + /** + * 获取导入模板字符串 + * @param array $fields 字段信息 + * @param array $table 表信息 + * @param array $init_fields 业务字段 + * @param string $type 导出类型: imp_con:导入-控制器 | imp_mod:导入-模型层 | imp_init : 导入初始化 | imp_fie : 导入/下载模板表头 + */ + private static function getImportExcelTempStr(array $fields, array $table, array $init_fields, string $type): string + { + $module_name = $table['moduleName']; //模块名 例:News + $function_name = $table['functionName']; //功能名 例:新闻 + $business_name = $table['businessName']; //业务名 例:news + $class_name = $table['className']; //类名 例:News + + $fields_val_allocation_str = ""; //字段值分配 + $add_fields_str = ""; //新增允许字段模板字符串 + foreach ($init_fields as $field => $name) { + $fields_val_allocation_str .= "\${$field} = \$value['{$field}'];"; + $add_fields_str .= "'{$field}' => \${$field},\n"; + }; + $add_fields_str = "[\n$add_fields_str]"; + + $init_fields_str = self::toFormTempStr($init_fields, $init_fields, 4); + $init_fields_str = substr($init_fields_str, 0, strlen($init_fields_str) - 1); + switch ($type) { + case "imp_con": + return "/**\n* 导入excel\n*/ + public function importExcel(Request \$request) + { + \$file = new UploadFile('uploads', 'fileExt:xlsx'); + \$file->putFile('{$business_name}'); + + \$msg = Model{$class_name}::importExcel(\$file); + return [ + 'code' => 0, + 'msg' => \$msg + ]; + }"; + case "imp_mod": + return "/**\n* 导入excel\n*/ + public static function importExcel(\$file) + { + \$msg = []; + + Db::startTrans(); + try { + \$excel = new Excel(\$file); + \$data = \$excel->parseExcel( + Tool::getExcelRule(self::EXCELFIELD), + [ + 'titleLine' => [1] + ]); + if (!\$data) throwErrorMsg('excel无数据', 1); + \$msg = []; + foreach (\$data as \$line => \$value) { + try { + \$model = self::importExcelInit(\$value); + \$msg[] = \"{\$line} 新增成功!
\"; + } catch (\Throwable \$th) { + \$msg[] = \"{\$line} {\$th->getMessage()}
\"; + } + } + Db::commit(); + return implode(', ', \$msg); + } catch (\Throwable \$th) { + Db::rollback(); + throw \$th; + } + }"; + case "imp_init": + return "/**\n* 导入excel初始化\n*/ + public static function importExcelInit(\$value) + { + {$fields_val_allocation_str} + return self::create({$add_fields_str}); + }"; + case "imp_fie": + return " + // excel导入/下载模板表头 + public const EXCELFIELD = {$init_fields_str}; + "; + }; + } +} diff --git a/app/admin/controller/Login.php b/app/admin/controller/Login.php new file mode 100644 index 0000000..63d99bd --- /dev/null +++ b/app/admin/controller/Login.php @@ -0,0 +1,145 @@ +middleware[SessionInit::class] = [ + 'only' => ['accountLogin', 'getCaptcha'] + ]; + } + + /** + * 验证token + * + * @param Request $request + * @return void + */ + public function validateToken(Request $request) + { + $token = $request->getCurrentToken(); + return [ + 'code' => 0, + 'data' => [ + 'exp_time' => $token->token_exp_time, + ], + 'msg' => 'ok' + ]; + } + + /** + * 西北政法大学单点登陆 + * + * @param Request $request + * @return Response + * @date 2023-01-04 + * @example + * @author admin + * @since 1.0.0 + */ + public function casOauthLogin(Request $request): Response + { + $url = $request->param('url'); + return LogicLogin::casOauthLogin( + LogicLogin::casOauthLoginHandle($url) + ); + } + + /** + * 西北政法大学单点登出 + * + * @param Request $request + * @return Response + * @date 2023-01-04 + * @example + * @author admin + * @since 1.0.0 + */ + public function casOauthLogout(Request $request): Response + { + $url = $request->param('url'); + return LogicLogin::casOauthLogout($url); + } + + /** + * 用户账号登录 + * + * @param Request $request + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function accountLogin(Request $request): array + { + $param = Validate::param([ + 'account|账号' => 'require', + 'password|密码' => 'require', + // 'captcha|验证码' => $request->isProd() ? 'require|captcha' : false + ]); + $token = LogicLogin::accountLogin( + $param['account'], + $param['password'] + ); + + return [ + 'code' => 0, + 'data' => [ + 'token' => $token->token_content, + 'exp_time' => $token->token_exp_time, + ], + 'msg' => 'ok' + ]; + } + + /** + * 生成验证码 + * + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function getCaptcha() + { + return Captcha::create(); + } + + /** + * 用户登出 + * + * @param Request $request + * @date 2022-03-09 + * @example + * @author admin + * @since 1.0.0 + */ + public function userLogout(Request $request): array + { + $token = $request->getCurrentToken(); + $token->logout(); + return [ + 'code' => 0, + 'msg' => '登出成功' + ]; + } +} diff --git a/app/admin/controller/Menu/Menu.php b/app/admin/controller/Menu/Menu.php new file mode 100644 index 0000000..00ead1e --- /dev/null +++ b/app/admin/controller/Menu/Menu.php @@ -0,0 +1,368 @@ + 'desc', + ])->field([ + 'menu_guid', + 'menu_parent_guid', + 'menu_name', + 'menu_url', + ])->select()->toArray(); + + $menuApi = []; + foreach (MenuApi::select() as $value) { + if (!isset($menuApi[$value->menu_guid])) { + $menuApi[$value->menu_guid] = []; + } + $menuApi[$value->menu_guid][] = $value->menu_api_url; + } + + $Traverse = new Traverse('menu_guid', 'menu_parent_guid'); + $menuTree = $Traverse->tree($menu, '0', function ($v) use ($menuApi) { + return [ + 'menu_api_url' => isset($menuApi[$v['menu_guid']]) ? $menuApi[$v['menu_guid']] : [], + 'menu_name' => $v['menu_name'], + 'menu_guid' => $v['menu_guid'], + 'menu_parent_guid' => $v['menu_parent_guid'], + 'menu_url' => $v['menu_url'], + ]; + }, function ($v) { + $v['hasChildren'] = isset($value['children']) && count($value['children']); + return $v; + }); + + return [ + 'code' => 0, + 'msg' => 'ok', + 'data' => $menuTree, + ]; + } + + /** + * 添加菜单接口 + * + * @param Request $request + * @return array + * @date 2022-03-08 + * @example + * @author admin + * @since 1.0.0 + */ + public function addMenuApi(Request $request) + { + Db::startTrans(); + try { + $params = $request->param(); + $this->validate($params, [ + 'menu_guid' => 'require', + 'menu_api_url' => 'require' + ]); + foreach (explode(',', $params['menu_api_url']) as $menu_api_url) { + MenuApi::create([ + 'menu_guid' => $params['menu_guid'], + 'menu_api_url' => $menu_api_url, + ]); + } + Db::commit(); + return [ + 'code' => 0, + 'msg' => '添加成功', + ]; + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 删除菜单接口 + * + * @param Request $request + * @return array + * @date 2022-03-08 + * @example + * @author admin + * @since 1.0.0 + */ + public function deleteMenuApi(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'menu_api_guid' => 'require' + ]); + MenuApi::where([ + 'menu_api_guid' => explode(',', $params['menu_api_guid']) + ])->select()->delete(); + return [ + 'code' => 0, + 'msg' => "删除成功" + ]; + } + + /** + * 获取菜单接口列表 + * + * @param Request $request + * @return array + * @date 2022-03-07 + * @example + * @author admin + * @since 1.0.0 + */ + public function getMenuApiList(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'menu_guid' => 'require' + ]); + $query = ModelMenu::find($params['menu_guid'])->apis()->append([ + 'menu_api_status_text' + ]); + $data = self::pageWrapper($query)->select(); + $count = $query->count(); + return [ + 'code' => 0, + 'msg' => 'ok', + 'data' => $data, + 'count' => $count + ]; + } + + /** + * 获取菜单树 + * + * @param Request $request + * @return array + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function getMenuTree(Request $request) + { + $menu = ModelMenu::order([ + 'menu_index', + 'menu_order' => 'desc', + ])->field([ + 'menu_parent_guid', + 'menu_name', + 'menu_url', + 'menu_index', + 'menu_order', + 'menu_status', + 'menu_show', + 'menu_guid', + ])->select()->toArray(); + + array_unshift($menu, [ + 'menu_guid' => '0', + 'menu_parent_guid' => '-1', + 'menu_name' => '系统菜单', + 'menu_index' => 0, + 'menu_order' => 0, + 'menu_status' => 0, + 'menu_show' => 0, + 'menu_url' => '', + ]); + + $Traverse = new Traverse('menu_guid', 'menu_parent_guid'); + $menuTree = $Traverse->tree($menu, '-1', function ($v) { + return [ + 'label' => $v['menu_name'], + 'id' => $v['menu_guid'], + 'parent_id' => $v['menu_parent_guid'], + 'index' => $v['menu_index'], + 'order' => $v['menu_order'], + 'status' => $v['menu_status'], + 'show' => $v['menu_show'], + 'url' => $v['menu_url'], + ]; + }); + + return [ + 'code' => 0, + 'msg' => 'ok', + 'data' => $menuTree + ]; + } + + /** + * 获取角色菜单 + * + * @param Request $request + * @return array + * @date 2022-03-09 + * @example + * @author admin + * @since 1.0.0 + */ + public function getRoleMenu(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'role_guid' => 'require' + ]); + $menus = Role::getByRoleGuid($params['role_guid'])->menus; + $menu_guids = []; + $menu_parent_guids = []; + foreach ($menus as $menu) { + if (!in_array($menu->menu_guid, $menu_guids)) { + $menu_guids[] = $menu->menu_guid; + } + if (!in_array($menu->menu_parent_guid, $menu_parent_guids)) { + $menu_parent_guids[] = $menu->menu_parent_guid; + } + } + // 去除父id 存在父id会全选子节点 + $temp = []; + foreach ($menu_guids as $menu_guid) { + if (!in_array($menu_guid, $menu_parent_guids)) { + $temp[] = $menu_guid; + } + } + return [ + 'code' => 0, + 'data' => $temp, + 'msg' => 'ok' + ]; + } + + /** + * 绑定角色菜单 + * + * @param Request $request + * @return array + * @date 2022-03-09 + * @example + * @author admin + * @since 1.0.0 + */ + public function bindRoleMenu(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'role_guid' => 'require', + 'menu_guid' => 'require' + ]); + $menus = array_map(function ($v) { + return ModelMenu::find($v); + }, explode(',', $params['menu_guid'])); + RoleMenu::rebindRoleMenu( + [ + Role::getByRoleGuid($params['role_guid']), + ], + array_filter($menus) + ); + return [ + 'code' => 0, + 'msg' => '绑定成功' + ]; + } + + /** + * 添加菜单 + * + * @param Request $request + * @return array + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function addMenu(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'menu_name' => 'require', + 'menu_index' => 'require', + 'menu_order' => 'require', + 'menu_show' => 'require', + 'menu_parent_guid' => 'require', + ]); + if (isset($params['menu_guid'])) { + unset($params['menu_guid']); + } + ModelMenu::create($params); + return [ + 'code' => 0, + 'msg' => '添加成功' + ]; + } + + /** + * 更新菜单 + * + * @param Request $request + * @return array + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function updateMenu(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'menu_guid' => 'require' + ]); + ModelMenu::withoutGlobalScope(['status'])->update($params, [ + 'menu_guid' => $params['menu_guid'] + ]); + return [ + 'code' => 0, + 'msg' => '更新成功' + ]; + } + + /** + * 删除菜单 + * + * @param Request $request + * @return array + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function deleteMenu(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'menu_guid' => 'require' + ]); + ModelMenu::where([ + 'menu_guid' => explode(',', $params['menu_guid']) + ])->select()->delete(); + return [ + 'code' => 0, + 'msg' => '删除成功' + ]; + } +} diff --git a/app/admin/controller/News/News.php b/app/admin/controller/News/News.php new file mode 100644 index 0000000..ee7c4b2 --- /dev/null +++ b/app/admin/controller/News/News.php @@ -0,0 +1,291 @@ +param(); + $con = []; + + if (isset($params['news_title']) && $params['news_title']) { + $con[] = ['news_title', 'LIKE', '%' . $params['news_title'] . '%']; + }; + if (isset($params['news_type']) && $params['news_type']) { + $con[] = ['news_type', '=', $params['news_type']]; + }; + + $query = ModelNews::where($con); + $select = self::pageWrapper($query) + ->field([ + 'news_id', + 'news_guid', + 'news_title', + 'news_author', + 'news_intro', + 'news_type', + 'news_img', + 'news_content', + 'news_num' + ]) + ->order('news_update_time', 'desc') + ->select(); + + $count = $query->count(); + + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + + /** + * 编辑新闻 + */ + public function editNews(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'news_title|新闻标题' => 'require', + 'news_author|新闻作者' => 'require', + 'news_intro|新闻简介' => 'require', + 'news_type|新闻类型' => 'require', + 'news_img|新闻封面' => 'require', + ]); + $model = ModelNews::where('news_guid', $params['news_guid'])->find(); + if (!$model) throwErrorMsg("该新闻不存在", 1); + $model->allowField([ + 'news_update_user_guid', + 'news_title', + 'news_author', + 'news_intro', + 'news_type', + 'news_img', + 'news_content', + + 'news_num' + ])->save($params); + return [ + 'code' => 0, + 'msg' => '编辑成功' + ]; + } + + /** + * 添加新闻 + */ + public function addNews(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'news_title|新闻标题' => 'require', + 'news_author|新闻作者' => 'require', + 'news_intro|新闻简介' => 'require', + 'news_type|新闻类型' => 'require', + 'news_img|新闻封面' => 'require', + + ]); + $model = ModelNews::create($params, [ + 'news_guid', + 'news_create_user_guid', + 'news_update_user_guid', + 'news_title', + 'news_author', + 'news_intro', + 'news_type', + 'news_img', + 'news_content', + + + 'news_num' + ]); + return [ + 'code' => 0, + 'msg' => '添加成功' + ]; + } + + /** + * 删除新闻 + */ + public function deleteNews(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'news_guid' => 'require', + ]); + $news = ModelNews::where([ + 'news_guid' => explode(',', $params['news_guid']) + ])->select(); + $news->delete(); + return [ + 'code' => 0, + 'msg' => "删除成功" + ]; + } + + /** + * 导出Excel + */ + public function exportExcel(Request $request) + { + $params = $request->param(); + $select = ModelNews::field([ + 'news_title', + 'news_author', + 'news_intro', + 'news_type', + 'news_img', + 'news_content', + + 'news_num' + ]) + ->order('news_update_time', 'desc') + ->select(); + $data = [[ + '新闻标题', + '新闻作者', + '新闻简介', + '新闻类型', + '新闻封面', + '新闻内容', + + '新闻数量' + ]]; + foreach ($select as $key => $val) { + $data[] = [ + $val['news_title'], + $val['news_author'], + $val['news_intro'], + $val['news_type'], + $val['news_img'], + $val['news_content'], + + $val['news_num'], + ]; + } + $excel = (new Excel())->exporTsheet($data); + $excel->save('新闻.xlsx'); + } + + /** + * 下载导入模板 + */ + public function downloadTemplate(Request $request) + { + $params = $request->param(); + $data = [ + '新闻标题', + '新闻作者', + '新闻简介', + '新闻类型', + '新闻封面', + '新闻内容', + + '新闻数量' + ]; + $excel = (new Excel())->exporTsheet($data); + $excel->save('新闻导入模板.xlsx'); + } + + /** + * 导入excel + */ + public function importExcel(Request $request) + { + $file = new UploadFile('uploads', 'fileExt:xlsx'); + $file->putFile('news'); + Db::startTrans(); + try { + $excel = new Excel($file); + $data = $excel->parseExcel( + [[ + 'title' => '新闻标题', + 'validate' => 'require', + 'field' => 'news_title', + ], [ + 'title' => '新闻作者', + 'validate' => 'require', + 'field' => 'news_author', + ], [ + 'title' => '新闻简介', + 'validate' => 'require', + 'field' => 'news_intro', + ], [ + 'title' => '新闻类型', + 'validate' => 'require', + 'field' => 'news_type', + ], [ + 'title' => '新闻封面', + 'validate' => 'require', + 'field' => 'news_img', + ], [ + 'title' => '新闻内容', + 'validate' => 'require', + 'field' => 'news_content', + ], [ + 'title' => '新闻数量', + 'validate' => 'require', + 'field' => 'news_num', + ],], + [ + 'titleLine' => [1] + ] + ); + if (!$data) throwErrorMsg('excel无数据', 1); + $error = []; + foreach ($data as $line => $value) { + try { + $news_title = $value['news_title']; + $news_author = $value['news_author']; + $news_intro = $value['news_intro']; + $news_type = $value['news_type']; + $news_img = $value['news_img']; + $news_content = $value['news_content']; + $news_data = $value['news_data']; + $news_time = $value['news_time']; + $news_num = $value['news_num']; + ModelNews::create([ + 'news_title' => $news_title, + 'news_author' => $news_author, + 'news_intro' => $news_intro, + 'news_type' => $news_type, + 'news_img' => $news_img, + 'news_content' => $news_content, + + 'news_num' => $news_num, + ]); + } catch (\Throwable $th) { + $error[] = $line . ':' . $th->getMessage(); + } + } + if ($error) throwErrorMsg(implode(', ', $error), 1); + Db::commit(); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + return [ + 'code' => 0, + 'msg' => '导入成功!' + ]; + } +} diff --git a/app/admin/controller/Product/Product.php b/app/admin/controller/Product/Product.php new file mode 100644 index 0000000..9b6923c --- /dev/null +++ b/app/admin/controller/Product/Product.php @@ -0,0 +1,220 @@ +param(); + $con = []; + + $con = Tool::getOptionalQuery( + ['product.product_name', 'LIKE'], + ['product.product_type_guid'], + ); + + $query = ModelProduct::where($con) + ->leftJoin('product_type', 'product_type.product_type_guid = product.product_type_guid') + ->field([ + 'product.product_id', + 'product.product_guid', + 'product.product_type_guid', + 'product.product_name', + 'product.product_img', + 'product.product_params', + 'product.product_details', + 'product.product_price', + 'product_type.product_type_name' + ]) + ->order('product_id', 'desc'); + + return msg("获取产品列表成功!", $query); + Db::commit(); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 编辑产品接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function editProduct(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'product_type_guid|产品系列guid' => 'require', + 'product_name|名称' => 'require', + 'product_img|图片' => 'require', + 'product_details|详情' => 'require', + 'product_price|价格' => 'require' + ]); + $model = ModelProduct::where('product_guid', $params['product_guid'])->find(); + if (!$model) throwErrorMsg("该产品不存在", 1); + // Tool::sortEditProc( + // new ModelProduct, + // ["product_guid" => $params['product_guid']], + // ["product_type_order" => $params['product_type_order']], + // ); + $model->allowField([ + 'product_update_user_guid', + 'product_type_guid', + 'product_name', + 'product_img', + 'product_params', + 'product_details', + 'product_price' + ])->save($params); + return msg('编辑成功!'); + } + + /** + * 添加产品接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function addProduct(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'product_type_guid|产品系列guid' => 'require', + 'product_name|名称' => 'require', + 'product_img|图片' => 'require', + 'product_details|详情' => 'require', + 'product_price|价格' => 'require' + ]); + + ModelProduct::create($params, [ + 'product_guid', + 'product_create_user_guid', + 'product_update_user_guid', + 'product_type_guid', + 'product_name', + 'product_img', + 'product_params', + 'product_details', + 'product_price' + ]); + return msg('添加成功!'); + } + + /** + * 删除产品接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function deleteProduct(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'product_guid|产品系列' => 'require', + ]); + $product = ModelProduct::where([ + 'product_guid' => explode(',', $params['product_guid']) + ])->select(); + $product->delete(); + return msg('删除成功!'); + } + + /** + * 导出Excel接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function exportExcel(Request $request) + { + $params = $request->param(); + $select = ModelProduct::field([ + 'product_type_guid', + 'product_name', + 'product_img', + 'product_params', + 'product_details', + 'product_price' + ]) + ->order('product_update_time', 'desc') + ->select(); + return ModelProduct::exportExcel($select); + } + + /** + * 下载导入模板接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function downloadTemplate(Request $request) + { + $params = $request->param(); + $data = array_values(ModelProduct::EXCELFIELD); + $excel = (new Excel())->exporTsheet($data); + $excel->save('产品导入模板.xlsx'); + } + + /** + * 导入excel接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function importExcel(Request $request) + { + $file = new UploadFile('uploads', 'fileExt:xlsx'); + $file->putFile('product'); + + $msg = ModelProduct::importExcel($file); + return [ + 'code' => 0, + 'msg' => $msg + ]; + } +} diff --git a/app/admin/controller/Product/ProductParam.php b/app/admin/controller/Product/ProductParam.php new file mode 100644 index 0000000..9c7be06 --- /dev/null +++ b/app/admin/controller/Product/ProductParam.php @@ -0,0 +1,148 @@ +field([ + 'product_param.product_param_id', + 'product_param.product_param_guid', + 'product_param.product_param_name', + 'product_param.product_type_guid', + 'product_param.product_param_order', + 'product_type.product_type_name' + ]) + ->leftJoin('product_type', 'product_type.product_type_guid = product_param.product_type_guid') + ->order('product_param_order', 'asc'); + + return msg("获取产品参数列表成功!", $query); + } + + /** + * 获取指定系列参数模板接口 + * + * @param Request request + * @date 2023-04-02 + * @example + * @author xjh + * @since 1.0.0 + */ + public function getProductParamTemplate(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'product_type_guid|产品系列guid' => 'require' + ]); + + $data = ModelProductParam::field(['product_param_name', 'product_param_order']) + ->where('product_type_guid', $params['product_type_guid']) + ->order('product_param_order', 'desc') + ->append(['product_param_value']) + ->select(); + + return msg(0, '获取指定系列参数模板成功!', ['data' => $data]); + } + + /** + * 编辑产品参数接口 + * + * @param Request request + * @date 2023-04-02 + * @example + * @author xjh + * @since 1.0.0 + */ + public function editProductParam(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'product_param_name|产品参数名称' => 'require', + 'product_type_guid|产品系列guid' => 'require' + ]); + $model = ModelProductParam::where('product_param_guid', $params['product_param_guid'])->find(); + if (!$model) throwErrorMsg("该产品参数不存在", 1); + $model->allowField([ + 'product_param_update_user_guid', + 'product_param_name', + 'product_type_guid', + 'product_param_order' + ])->save($params); + return msg('编辑成功!'); + } + + /** + * 添加产品参数接口 + * + * @param Request request + * @date 2023-04-02 + * @example + * @author xjh + * @since 1.0.0 + */ + public function addProductParam(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'product_param_name|产品参数名称' => 'require', + 'product_type_guid|产品系列guid' => 'require' + ]); + $model = ModelProductParam::create($params, [ + 'product_param_guid', + 'product_param_create_user_guid', + 'product_param_update_user_guid', + 'product_param_name', + 'product_param_order', + 'product_type_guid' + ]); + return msg('添加成功!'); + } + + /** + * 删除产品参数接口 + * + * @param Request request + * @date 2023-04-02 + * @example + * @author xjh + * @since 1.0.0 + */ + public function deleteProductParam(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'product_param_guid' => 'require', + ]); + $product_param = ModelProductParam::where([ + 'product_param_guid' => explode(',', $params['product_param_guid']) + ])->select(); + $product_param->delete(); + return msg('删除成功!'); + } +} diff --git a/app/admin/controller/Product/ProductType.php b/app/admin/controller/Product/ProductType.php new file mode 100644 index 0000000..4086cfa --- /dev/null +++ b/app/admin/controller/Product/ProductType.php @@ -0,0 +1,271 @@ + "product_type_parent_name", + 'a.product_type_order', + 'a.product_type_guid', + 'a.product_type_icon', + 'a.product_type_cover', + ]) + ->alias('a') + ->leftjoin('product_type b', 'a.product_type_parent_guid = b.product_type_guid') + ->where($con) + ->order(['product_type_order' => 'asc']) + ->select()->toArray(); + + $Traverse = new Traverse('product_type_guid', 'product_type_parent_guid'); + $product_type_tree = $Traverse->tree($product_type, '0', function ($v) { + return [ + 'product_type_name' => $v['product_type_name'], + 'product_type_parent_name' => $v['product_type_parent_name'], + 'product_type_guid' => $v['product_type_guid'], + 'product_type_parent_guid' => $v['product_type_parent_guid'], + 'product_type_order' => $v['product_type_order'], + 'product_type_icon' => $v['product_type_icon'], + 'product_type_cover' => $v['product_type_cover'], + ]; + }); + + return msg("获取产品系列列表成功!", $product_type_tree); + } + + /** + * 编辑产品系列接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function editProductType(Request $request): array + { + Db::startTrans(); + try { + $params = $request->param(); + $this->validate($params, [ + 'product_type_name|产品系列名称' => 'require', + 'product_type_icon|产品系列图标' => 'require', + 'product_type_cover|产品系列封面' => 'require', + 'product_type_guid|产品系列guid' => 'require', + 'product_type_order|产品系列排序' => 'require', + ]); + + $model = ModelProductType::where('product_type_guid', $params['product_type_guid'])->find(); + if (!$model) throwErrorMsg("该产品系列不存在", 1); + + ModelProductType::isDuplicateName($params['product_type_name'], $params['product_type_guid']); + + $params['product_type_ancestors_guid'] = ModelProductType::buildAncestorsGuid($params['product_type_parent_guid']); + + Tool::sortEditProc( + new ModelProductType, + ["product_type_order" => $params['product_type_order']], + ["product_type_guid" => $params['product_type_guid']], + ["product_type_parent_guid" => $params['product_type_parent_guid']], + ); + + + $model->allowField([ + 'product_type_update_user_guid', + 'product_type_title', + 'product_type_icon', + 'product_type_cover', + 'product_type_ancestors_guid', + 'product_type_parent_guid', + 'product_type_order', + ])->save($params); + Db::commit(); + return msg('编辑成功!'); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + + /** + * 添加产品系列接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function addProductType(Request $request): array + { + Db::startTrans(); + try { + $params = $request->param(); + $this->validate($params, [ + 'product_type_name|产品类型名称' => 'require', + 'product_type_icon|产品系列图标' => 'require', + 'product_type_cover|产品系列封面' => 'require', + 'product_type_order|产品系列排序' => 'require' + ]); + + ModelProductType::isDuplicateName($params['product_type_name']); + + + $product_type_parent_where = []; + if (!empty($params['product_type_parent_guid'])) { + $params['product_type_ancestors_guid'] = ModelProductType::buildAncestorsGuid($params['product_type_parent_guid']); + $product_type_parent_where['product_type_parent_guid'] = $params['product_type_parent_guid']; + } + + Tool::sortInsertProc( + new ModelProductType, + ["product_type_order" => $params['product_type_order']], + $product_type_parent_where, + ); + + ModelProductType::create($params, [ + 'product_type_guid', + 'product_type_create_user_guid', + 'product_type_update_user_guid', + 'product_type_parent_guid', + 'product_type_ancestors_guid', + 'product_type_name', + 'product_type_icon', + 'product_type_cover', + 'product_type_order' + ]); + Db::commit(); + return msg("添加成功!"); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 删除产品系列接口接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function deleteProductType(Request $request): array + { + Db::startTrans(); + try { + $params = $request->param(); + $this->validate($params, [ + 'product_type_guid|产品系列guid' => 'require', + ]); + $guids = explode(',', $params['product_type_guid']); + + Tool::sortDeleteProc( + new ModelProductType, + 'product_type_order', + ["product_type_guid" => $guids], + ["product_type_parent_guid"], + ); + ModelProductType::where(['product_type_guid' => $guids])->select()->delete(); + Db::commit(); + return msg('删除成功!'); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 导出Excel接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function exportExcel(Request $request) + { + $params = $request->param(); + $select = ModelProductType::field([ + 'product_type_title', + 'product_type_icon', + 'product_type_cover' + ]) + ->order('product_type_update_time', 'desc') + ->select(); + return ModelProductType::exportExcel($select); + } + + /** + * 下载导入模板接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function downloadTemplate(Request $request) + { + $params = $request->param(); + $data = array_values(ModelProductType::EXCELFIELD); + $excel = (new Excel())->exporTsheet($data); + $excel->save('产品系列导入模板.xlsx'); + } + + /** + * 导入excel接口 + * + * @param Request request + * @date 2023-03-25 + * @example + * @author xjh + * @since 1.0.0 + */ + public function importExcel(Request $request) + { + $file = new UploadFile('uploads', 'fileExt:xlsx'); + $file->putFile('product_type'); + + $msg = ModelProductType::importExcel($file); + return [ + 'code' => 0, + 'msg' => $msg + ]; + } +} diff --git a/app/admin/controller/Role/Role.php b/app/admin/controller/Role/Role.php new file mode 100644 index 0000000..9299621 --- /dev/null +++ b/app/admin/controller/Role/Role.php @@ -0,0 +1,198 @@ +param('role_status'); + $role = $request->param('role'); + $scope = explode(',', $request->param('scope', '')); + $con = [ + // 'role_status' => 1 + ]; + if ($role) { + $con['role_name'] = $role; + } + if ($role_status) { + $con['role_status'] = $role_status; + } + $query = ModelRole::scope($scope)->withSearch(['role_name'], $con)->where($con); + $select = self::pageWrapper($query)->field([ + 'role_name', + 'role_status', + 'role_guid', + ])->append([ + 'role_status_text' + ])->order([ + 'role_id' => 'desc' + ])->select(); + $count = $query->count(); + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + + /** + * 获取角色菜单 + * + * @param Request $request + * @date 2022-03-08 + * @example + * @author admin + * @since 1.0.0 + */ + public function getRoleMenu(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'role_guid' => 'require' + ]); + dump(ModelRole::getByRoleGuid($params['role_guid'])->menus); + return [ + 'code' => 0, + 'msg' => 'ok', + // 'data' => $data + ]; + } + + /** + * 编辑角色 + * + * @param Request $request + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public function editRole(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'role_guid' => 'require', + 'role_name' => 'require', + ]); + $role = ModelRole::where([ + 'role_guid' => $params['role_guid'] + ])->find(); + if (!$role) { + throwErrorMsg("角色不存在", 1); + } + $role->save([ + 'role_name' => $params['role_name'], + ]); + return [ + 'code' => 0, + 'msg' => '编辑成功' + ]; + } + + /** + * 添加角色 + * + * @param Request $request + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public function addRole(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'role_name' => 'require', + ]); + ModelRole::create([ + 'role_name' => $params['role_name'], + ]); + return [ + 'code' => 0, + 'msg' => '添加成功' + ]; + } + + /** + * 删除角色 + * + * @param Request $request + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public function deleteRole(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'role_guid' => 'require', + ]); + $roles = ModelRole::where([ + 'role_guid' => ['in', $params['role_guid']] + ])->select(); + $roles->delete(); + return [ + 'code' => 0, + 'msg' => "删除成功" + ]; + } + + /** + * 更新角色状态 + * + * @param Request $request + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public function updateRoleStatus(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'role_guid' => 'require', + 'role_status' => 'require|in:1,2', + ]); + $role_status = $params['role_status']; + $roles = ModelRole::where([ + 'role_guid' => explode(',', $params['role_guid']) + ])->select(); + $roles->update([ + 'role_status' => $role_status + ]); + return [ + 'code' => 0, + 'msg' => "更新成功" + ]; + } +} diff --git a/app/admin/controller/School/Classes.php b/app/admin/controller/School/Classes.php new file mode 100644 index 0000000..796b581 --- /dev/null +++ b/app/admin/controller/School/Classes.php @@ -0,0 +1,111 @@ +param(); + $con = []; + + if (isset($params['classes_name']) && $params['classes_name']) { + $con[] = ['classes_name', 'LIKE', '%' . $params['classes_name'] . '%']; + }; + + $query = ModelClasses::where($con); + $select = self::pageWrapper($query) + ->field([ + 'classes_id', + 'classes_guid', + 'classes_name' + ]) + ->order('classes_update_time', 'desc') + ->select(); + + $count = $query->count(); + + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + + /** + * 编辑班级 + */ + public function editClasses(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'classes_name|班级名称' => 'require' + ]); + $model = ModelClasses::where('classes_guid', $params['classes_guid'])->find(); + if (!$model) throwErrorMsg("该班级不存在", 1); + $model->allowField([ + 'classes_update_user_guid', + 'classes_name' + ])->save($params); + return [ + 'code' => 0, + 'msg' => '编辑成功' + ]; + } + + /** + * 添加班级 + */ + public function addClasses(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'classes_name|班级名称' => 'require' + ]); + $model = ModelClasses::create($params, [ + 'classes_guid', + 'classes_create_user_guid', + 'classes_update_user_guid', + 'classes_name' + ]); + return [ + 'code' => 0, + 'msg' => '添加成功' + ]; + } + + /** + * 删除班级 + */ + public function deleteClasses(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'classes_guid' => 'require', + ]); + $classes = ModelClasses::where([ + 'classes_guid' => explode(',', $params['classes_guid']) + ])->select(); + $classes->delete(); + return [ + 'code' => 0, + 'msg' => "删除成功" + ]; + } +} diff --git a/app/admin/controller/School/Student.php b/app/admin/controller/School/Student.php new file mode 100644 index 0000000..9bac8c4 --- /dev/null +++ b/app/admin/controller/School/Student.php @@ -0,0 +1,544 @@ +user_guid; + + $jwd = Map::getLongitudeAndLatitude("广东省佛山市顺德区容桂街道保利·德胜湾保利外滩一号"); + return $jwd; + // return date('Y-m-d H:i:s', strtotime('+3 month')); + } + + /** + * 获取学生列表 + */ + public function getStudentList(Request $request) + { + $params = $request->param(); + $con = []; + $conOr = []; + + if (isset($params['student_name']) && $params['student_name']) { + $con[] = ['student_name', 'LIKE', '%' . $params['student_name'] . '%']; + }; + if (isset($params['studnet_phone']) && $params['studnet_phone']) { + $con[] = ['studnet_phone', 'LIKE', '%' . $params['studnet_phone'] . '%']; + }; + if (isset($params['student_id_card']) && $params['student_id_card']) { + $con[] = ['student_id_card', 'LIKE', '%' . $params['student_id_card'] . '%']; + }; + if (isset($params['student_email']) && $params['student_email']) { + $con[] = ['student_email', 'LIKE', '%' . $params['student_email'] . '%']; + }; + if (isset($params['student_sex']) && $params['student_sex']) { + $con[] = ['student_sex', '=', $params['student_sex']]; + }; + if (isset($params['student_membe_type']) && $params['student_membe_type']) { + $con[] = ['student_membe_type', '=', $params['student_membe_type']]; + }; + if (isset($params['student_audit_status']) && $params['student_audit_status']) { + $con[] = ['student_audit_status', '=', $params['student_audit_status']]; + }; + if (isset($params['product_type']) && $params['product_type']) { + $con[] = ['a.product_type', '=', $params['product_type']]; + $conOr[] = ['c.product_type_parent_guid', '=', $params['product_type']]; + }; + if (isset($params['product_guid']) && $params['product_guid']) { + $con[] = ['a.product_guid', '=', $params['product_guid']]; + }; + if (isset($params['product_parts_guid']) && $params['product_parts_guid']) { + $con[] = ['a.product_parts_guid', '=', $params['product_parts_guid']]; + }; + if (isset($params['student_brithday']) && $params['student_brithday']) { + $con[] = ['student_brithday', 'BETWEEN', implode(',', $params['student_brithday'])]; + }; + + // return $con; + + $query = ModelStudent::alias('a') + ->leftjoin('user b', 'a.user_guid = b.user_guid') + ->leftjoin('product_type c', 'a.product_type = c.product_type_guid') + ->leftjoin('product d', 'a.product_guid = d.product_guid') + ->leftjoin('product_parts e', 'a.product_parts_guid = e.product_parts_guid') + ->leftjoin('classes f', 'a.classes_guid = f.classes_guid') + ->where($con) + ->whereOr(function ($query) use ($conOr) { + $query->whereOr($conOr); + }); + + if (isset($params['student_member_time']) && $params['student_member_time']) { + $query->where(" + ( + student_member_begin_time >= '{$params['student_member_time'][0]}' + AND + student_member_begin_time <= '{$params['student_member_time'][1]}' + ) + OR + ( + student_member_end_time >= '{$params['student_member_time'][0]}' + AND + student_member_end_time <= '{$params['student_member_time'][1]}' + ) + OR + ( + student_member_begin_time >= '{$params['student_member_time'][0]}' + AND + student_member_end_time <= '{$params['student_member_time'][1]}' + ) + "); + } + + + + $select = self::pageWrapper($query) + ->field([ + 'a.student_id', + 'a.student_guid', + 'a.student_name', + 'a.user_guid', + 'b.user_name', + 'a.classes_guid', + 'f.classes_name', + 'a.studnet_phone', + 'a.student_id_card', + 'a.student_email', + 'a.student_sex', + 'a.student_price', + 'a.student_brithday', + 'a.product_type', + 'c.product_type_name', + 'a.product_guid', + 'd.product_name', + 'a.product_parts_guid', + 'e.product_parts_name', + 'a.student_img', + 'a.student_banner_img', + 'a.student_attachment', + 'a.student_intro', + 'a.student_location', + 'a.longitude', + 'a.latitude', + 'a.student_membe_type', + 'a.student_member_begin_time', + 'a.student_member_end_time', + 'a.student_audit_status', + 'a.student_audit_user_guid', + "(SELECT `user`.`user_name` FROM `user` WHERE `user`.user_guid = `a`.`student_audit_user_guid`) as student_audit_user_name", + ]) + ->append([ + 'student_member_time', + 'student_service', + ]) + ->order('student_update_time', 'desc') + ->select(); + + $count = $query->count(); + + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + + /** + * 编辑学生 + */ + public function editStudent(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'student_name|学生名称' => 'require', + 'user_guid|用户' => 'require', + 'classes_guid|班级' => 'require', + 'studnet_phone|手机号' => 'require', + 'student_id_card|身份证号' => 'require', + 'student_sex|性别' => 'require', + 'student_price|学生价格' => 'require', + 'product_type|产品类型' => 'require', + 'product_guid|产品' => 'require', + 'product_parts_guid|产品零件' => 'require', + 'student_img|头像' => 'require', + 'student_intro|简介' => 'require', + 'student_location|家庭住址' => 'require', + 'longitude|经度' => 'require', + 'latitude|纬度' => 'require' + ]); + $model = ModelStudent::where('student_guid', $params['student_guid'])->find(); + if (!$model) throwErrorMsg("该学生不存在", 1); + + + $student_member_time = $params['student_member_time']; + $params['student_member_begin_time'] = $student_member_time[0]; + $params['student_member_end_time'] = $student_member_time[1]; + + // return $params; + + + $model->allowField([ + 'student_update_user_guid', + 'student_name', + 'user_guid', + 'classes_guid', + 'studnet_phone', + 'student_id_card', + 'student_email', + 'student_sex', + 'student_price', + 'student_brithday', + 'product_type', + 'product_guid', + 'product_parts_guid', + 'student_img', + 'student_banner_img', + 'student_attachment', + 'student_intro', + 'student_location', + 'longitude', + 'latitude', + 'student_membe_type', + 'student_member_begin_time', + 'student_member_end_time', + 'student_audit_status', + 'student_audit_user_guid' + ])->save($params); + + // 学生服务编辑 + ModelStudent::editStudentService($params); + + return [ + 'code' => 0, + 'msg' => '编辑成功' + ]; + } + + /** + * 添加学生 + */ + public function addStudent(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'student_name|学生名称' => 'require', + 'user_name|用户' => 'require', + 'classes_guid|班级' => 'require', + 'studnet_phone|手机号' => 'require', + 'student_id_card|身份证号' => 'require', + 'student_sex|性别' => 'require', + 'student_price|学生价格' => 'require', + 'product_type|产品类型' => 'require', + 'product_guid|产品' => 'require', + 'product_parts_guid|产品零件' => 'require', + 'student_img|头像' => 'require', + 'student_intro|简介' => 'require', + 'student_location|家庭住址' => 'require', + 'longitude|经度' => 'require', + 'latitude|纬度' => 'require', + 'student_membe_type|会员类型' => 'require', + ]); + + $params = ModelStudent::initAdd($params); + + $model = ModelStudent::create($params, [ + 'student_guid', + 'student_create_user_guid', + 'student_update_user_guid', + 'student_name', + 'user_guid', + 'classes_guid', + 'studnet_phone', + 'student_id_card', + 'student_email', + 'student_sex', + 'student_price', + 'student_brithday', + 'product_type', + 'product_guid', + 'product_parts_guid', + 'student_img', + 'student_banner_img', + 'student_attachment', + 'student_intro', + 'student_location', + 'longitude', + 'latitude', + 'student_membe_type', + 'student_member_begin_time', + 'student_member_end_time', + 'student_audit_status', + 'student_audit_user_guid' + ]); + + if (!$model) throwErrorMsg("添加失败"); + $student_guid = $model->student_guid; + + // 添加学生服务 + ModelStudent::addStudentService($student_guid, $params); + + return [ + 'code' => 0, + 'msg' => '添加成功' + ]; + } + + /** + * 删除学生 + */ + public function deleteStudent(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'student_guid' => 'require', + ]); + $student = ModelStudent::where([ + 'student_guid' => explode(',', $params['student_guid']) + ])->select(); + $student->delete(); + + // 从学生服务(副表)查询出所有当前学生的服务,进行删除 + ModelStudentService::where('student_guid', $params['student_guid'])->select()->delete(); + + return [ + 'code' => 0, + 'msg' => "删除成功" + ]; + } + + /** + * 查找未绑定用户列表 + */ + public function notBindUserList(Request $request) + { + $user = $request->param('user'); + $con = [ + 'user_status' => 1, + ]; + $search = []; + if ($user) { + $search['user_name'] = $user; + } + + $query = ModelUser::alias('a') + ->join('student b', 'a.user_guid != b.user_guid') + ->withSearch(array_keys($search), $search)->where($con) + ->whereNotExists(function ($query) { + $query->table('student')->alias('b')->where("a.user_guid = b.user_guid"); + }); + $select = self::pageWrapper($query)->field([ + 'a.user_name', + ]) + ->group('user.user_guid')->order([ + 'user.user_update_time' => 'desc' + ])->select(); + $count = $query->count(); + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + + /** + * 审核学生 + */ + public function auditStudent(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'student_guid|学生guid' => 'require', + 'student_audit_status|审核状态' => 'require|in:2,3', + ]); + + ModelStudent::auditStudent($params); + + return [ + 'code' => 0, + 'msg' => '审核成功' + ]; + } + + /** + * 导出Excel + */ + public function exportExcel(Request $request) + { + $params = $request->param(); + return ModelStudent::exportStudent(); + } + + /** + * 下载导入模板 + */ + public function downloadTemplate(Request $request) + { + $params = $request->param(); + $data = [ + ['学生名称', '用户', '班级', '手机号', '身份证号', '邮箱', '性别', '学生价格', '生日', '产品类型', '产品', '产品零件', '头像', '轮播图片', '简介', '家庭住址', '会员类型',] + ]; + + $data[] = ['张思', '负责人', '网络3+2', '19882556281', '110223790813697', '2679599887@163.com', '男', '99.99', '2023-02-19', '小米10', '小米10代手机 全面屏 3亿像素', '小米专属钢化膜', 'https://hjczx.net/intelligent_clique/public/uploads/hjczx//student_img/2022/459/210744-compression.jpg', 'http://aerwen.net/prod-api/student/20230218/C9B76FC1E616EE6A.jpg,http://aerwen.net/prod-api/key/20230217/628A9C1A391ABD61.jpg', '我是三好学生', '广东省佛山市顺德区容桂街道胡锦超职业技术学校', '季卡']; + $excel = (new Excel())->exporTsheet($data); + $excel->save('学生导入模板.xlsx'); + } + + /** + * 导入excel + */ + public function importExcel(Request $request) + { + $file = new UploadFile('uploads', 'fileExt:xlsx'); + $file->putFile('student'); + + $msg = ModelStudent::ImportStudent($file); + return [ + 'code' => 0, + 'msg' => $msg + ]; + } + + + /** + * 获取点击后的产品列表 + */ + public function getClickProduct(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'product_type_guid|产品类型' => 'require', + ]); + + $product_type_guid = $params['product_type_guid']; + + $products = ModelProduct::alias('a') + ->leftjoin('product_type b', "a.product_type_guid = b.product_type_guid") + ->where("a.product_type_guid = '$product_type_guid' or b.product_type_parent_guid = '$product_type_guid'")->select(); + return [ + 'code' => 0, + 'data' => $products, + 'msg' => "获取点击后的产品列表成功" + ]; + } + + /** + * 获取点击后的产品零件列表 + */ + public function getClickProductParts(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'product_guid|产品' => 'require', + ]); + + $products_parts = ModelProductParts::where('product_guid', $params['product_guid'])->select(); + return [ + 'code' => 0, + 'data' => $products_parts, + 'msg' => "获取点击后的产品零件列表成功" + ]; + } + + + /** + * 获取侧边产品数据 + */ + public function getProductTree(): array + { + $data = []; + $product_types = ModelProductType::field([ + 'product_type_name', + 'product_type_guid', + 'product_type_parent_guid', + ])->select(); + foreach ($product_types as $key => $value) { + $product_type_guid = $value['product_type_guid']; + $product_type_parent_guid = $value['product_type_parent_guid']; + $data[] = [ + 'id' => $product_type_guid, + 'parent_id' => $product_type_parent_guid, + 'name' => $value['product_type_name'], + 'type' => 'product_type', + 'data' => [ + 'parent_id' => $product_type_parent_guid, + 'product_type_guid' => $value['product_type_guid'] + ], + ]; + } + $products = ModelProduct::field([ + 'product_name', + 'product_guid', + 'product_type_guid', + ])->select(); + foreach ($products as $value) { + $product_guid = $value['product_guid']; + $product_type_guid = $value['product_type_guid']; + $id = $product_guid; + $data[] = [ + 'id' => $id, + 'parent_id' => $product_type_guid, + 'name' => $value['product_name'], + 'type' => 'product', + 'data' => [ + 'product_type_guid' => $product_type_guid, + 'product_guid' => $product_guid + ], + ]; + + $product_parts = ModelProductParts::field([ + 'product_parts_name', + 'product_parts_guid', + 'product_guid', + ])->where('product_guid', $product_guid)->select(); + foreach ($product_parts as $value) { + $product_parts_guid = $value['product_parts_guid']; + $product_guid = $value['product_guid']; + $id = $product_parts_guid; + $data[] = [ + 'id' => $id, + 'parent_id' => $product_guid, + 'name' => $value['product_parts_name'], + 'type' => 'product_parts', + 'data' => [ + 'product_type_guid' => $product_type_guid, + 'product_guid' => $product_guid, + 'product_parts_guid' => $product_parts_guid + ], + ]; + } + } + // return $data; + $Traverse = new Traverse('id', 'parent_id'); + return $Traverse->tree($data, '0', function (array $value) { + return $value; + }); + return [ + 'code' => 0, + 'data' => $data, + 'msg' => 'ok' + ]; + } +} diff --git a/app/admin/controller/Tdk/Tdk.php b/app/admin/controller/Tdk/Tdk.php new file mode 100644 index 0000000..8b044db --- /dev/null +++ b/app/admin/controller/Tdk/Tdk.php @@ -0,0 +1,133 @@ +param(); + $con = []; + + if (isset($params['tdk_type']) && $params['tdk_type']) { + $con[] = ['tdk_type', '=', $params['tdk_type']]; + }; + if (isset($params['tdk_title']) && $params['tdk_title']) { + $con[] = ['tdk_title', 'LIKE', '%' . $params['tdk_title'] . '%']; + }; + + $query = ModelTdk::where($con); + $select = self::pageWrapper($query) + ->field([ + 'tdk_id', + 'tdk_guid', + 'tdk_type', + 'tdk_title', + 'tdk_description', + 'tdk_keyword' + ]) + ->order('tdk_update_time', 'desc') + ->select(); + + $count = $query->count(); + + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + + /** + * 编辑网站tdk + */ + public function editTdk(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'tdk_type|tdk所属模块' => 'require', + 'tdk_title|网页标题' => 'require', + 'tdk_description|网页简介' => 'require', + 'tdk_keyword|网页关键词' => 'require' + ]); + $model = ModelTdk::where('tdk_guid', $params['tdk_guid'])->find(); + if (!$model) throwErrorMsg("该网站tdk不存在", 1); + $model->allowField([ + 'tdk_update_user_guid', + 'tdk_type', + 'tdk_title', + 'tdk_description', + 'tdk_keyword' + ])->save($params); + return [ + 'code' => 0, + 'msg' => '编辑成功' + ]; + } + + /** + * 添加网站tdk + */ + public function addTdk(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'tdk_type|tdk所属模块' => 'require', + 'tdk_title|网页标题' => 'require', + 'tdk_description|网页简介' => 'require', + 'tdk_keyword|网页关键词' => 'require' + ]); + + $type = ModelTdk::where('tdk_type',$params['tdk_type'])->find(); + if($type) throwErrorMsg("{$type->title} 已设置,请勿重复设置!"); + + $model = ModelTdk::create($params, [ + 'tdk_guid', + 'tdk_create_user_guid', + 'tdk_update_user_guid', + 'tdk_type', + 'tdk_title', + 'tdk_description', + 'tdk_keyword' + ]); + return [ + 'code' => 0, + 'msg' => '添加成功' + ]; + } + + /** + * 删除网站tdk + */ + public function deleteTdk(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'tdk_guid' => 'require', + ]); + $tdk = ModelTdk::where([ + 'tdk_guid' => explode(',', $params['tdk_guid']) + ])->select(); + $tdk->delete(); + return [ + 'code' => 0, + 'msg' => "删除成功" + ]; + } +} diff --git a/app/admin/controller/User/User.php b/app/admin/controller/User/User.php new file mode 100644 index 0000000..0f80762 --- /dev/null +++ b/app/admin/controller/User/User.php @@ -0,0 +1,371 @@ +getCurrentUser(); + return [ + 'code' => 0, + 'data' => [ + 'user_name' => $user['user_name'] + ], + 'msg' => 'ok' + ]; + } + + /** + * 获取用户菜单 + * + * @param Request $request + * @return array + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function getUserMenu(Request $request) + { + // $user = $request->getCurrentUser(); + // $menus = []; + // foreach ($user->roles as $role) { + // $menus = array_merge($menus, $role->menus->toArray()); + // } + + // array_multisort(array_column($menus, 'menu_order'), SORT_DESC, $menus); + + // var_dump($menus); + + $token = Token::getCurrent(); + $menus = $token->token_menu; + + $Traverse = new Traverse('menu_guid', 'menu_parent_guid'); + + $tree = $Traverse->tree($menus, '0', function ($v) { + return [ + 'key' => $v['menu_guid'], + 'name' => $v['menu_name'], + 'url' => $v['menu_url'], + 'show' => $v['menu_show'], + 'icon' => $v['menu_icon'], + ]; + }); + + return [ + 'code' => 0, + 'msg' => 'ok', + 'data' => $tree + ]; + } + + /** + * 获取用户列表 + * + * @param Request $request + * @date 2022-02-25 + * @example + * @author admin + * @since 1.0.0 + */ + public function getUserList(Request $request): array + { + $user = $request->param('user'); + $con = [ + // 'user_status' => 1 + ]; + $search = []; + if ($user) { + $search['user_name'] = $user; + } + + $query = ModelUser::scope(['admin']) + ->withSearch(array_keys($search), $search)->where($con) + ->leftjoin('user_role', 'user_role.user_guid = user.user_guid') + ->join('role', join(' AND ', [ + 'role.role_guid = user_role.role_guid', + 'role.role_status = 1', + 'role.role_delete_time IS NULL', + ]), 'left')->where($con); + $select = self::pageWrapper($query)->field([ + 'user.user_guid', + 'user.user_name', + 'user.user_phone', + 'user.user_position', + 'user.user_department', + 'user.user_img', + 'user.user_status', + 'role.role_name', + ]) + ->append([ + 'roles', + ]) + ->group('user.user_guid')->order([ + 'user.user_update_time' => 'desc' + ])->select(); + $count = $query->count(); + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + + /** + * 编辑用户 + * + * @param Request $request + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public function editUser(Request $request): array + { + $params = Validate::param([ + 'user_guid' => 'require', + 'user_name' => 'require', + 'roles|角色' => 'require', + ]); + $model = ModelUser::where([ + 'user_guid' => $params['user_guid'] + ])->find(); + if (!$model) { + throwErrorMsg("用户不存在", 1); + } + $model->save($params); + ModelUser::editUserRole($params); + return [ + 'code' => 0, + 'msg' => '编辑成功' + ]; + } + + /** + * 添加用户 + * + * @param Request $request + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public function addUser(Request $request): array + { + $params = Validate::param([ + 'user_name' => 'require', + 'user_password' => 'require', + 'roles|角色' => 'require', + ]); + $params['user_status'] = 1; + + $model = ModelUser::create($params); + + $user_guid = $model->user_guid; + + ModelUser::addUserRole($user_guid, $params); + + return [ + 'code' => 0, + 'msg' => '添加成功' + ]; + } + + /** + * 删除用户 + * + * @param Request $request + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public function deleteUser(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'user_guid' => 'require', + ]); + $users = ModelUser::where([ + 'user_guid' => explode(',', $params['user_guid']) + ])->select(); + $users->delete(); + return [ + 'code' => 0, + 'msg' => "删除成功" + ]; + } + + /** + * 更新用户状态 + * + * @param Request $request + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public function updateUserStatus(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'user_guid' => 'require', + 'user_status' => 'require|in:1,2', + ]); + $user_status = $params['user_status']; + $users = ModelUser::where([ + 'user_guid' => explode(',', $params['user_guid']) + ])->select(); + $users->update([ + 'user_status' => $user_status + ]); + return [ + 'code' => 0, + 'msg' => "更新成功" + ]; + } + + /** + * 重置用户密码 + * + * @param Request $request + * @date 2022-02-25 + * @example + * @author admin + * @since 1.0.0 + */ + public function resetUserPassword(Request $request): array + { + $params = Validate::param([ + 'user_guid' => 'require', + 'password' => 'require', + ]); + $password = $params['password']; + $users = ModelUser::select(explode(',', $params['user_guid'])); + // $users = ModelUser::where([ + // 'user_guid' => ['in', $params['user_guid']] + // ])->select(); + $users->update([ + 'user_password' => $password + ]); + return [ + 'code' => 0, + 'msg' => "密码已重置为:$password ,请及时修改密码" + ]; + } + + + /** + * 导出Excel + */ + public function exportExcel(Request $request) + { + $user = $request->param('user'); + $con = [ + // 'user_status' => 1 + ]; + $search = []; + if ($user) { + $search['user_name'] = $user; + } + + $select = ModelUser::scope(['admin']) + ->where($con)->field([ + 'user.user_guid', + 'user.user_name', + 'user.user_phone', + 'user.user_position', + 'user.user_department', + 'user.user_img', + 'role.role_name', + ]) + ->append([ + 'roles', + ]) + ->withSearch(array_keys($search), $search)->where($con) + ->leftjoin('user_role', 'user_role.user_guid = user.user_guid') + ->join('role', join(' AND ', [ + 'role.role_guid = user_role.role_guid', + 'role.role_status = 1', + 'role.role_delete_time IS NULL', + ]), 'left') + ->group('user.user_guid')->order([ + 'user.user_update_time' => 'desc' + ])->select(); + + return ModelUser::exportExcel($select); + } + + /** + * 下载导入模板 + */ + public function downloadTemplate(Request $request) + { + $params = $request->param(); + $data = [ + [ + '用户名', + '头像', + '角色', + '手机号', + '密码', + ] + ]; + + $data[] = [ + '负责人', + 'https://img13.360buyimg.com/n5/jfs/t1/195344/2/24691/95759/6295e145E6fae20b9/1172b44c351eeaab.jpg.avif', + '管理员,部门负责人', + '10086', + '123456@aerwen', + ]; + + $excel = (new Excel())->exporTsheet($data); + $excel->save('用户导入模板.xlsx'); + } + + /** + * 导入excel + */ + public function importExcel(Request $request) + { + $file = new UploadFile('uploads', 'fileExt:xlsx'); + $file->putFile('User'); + + $msg = ModelUser::importExcel($file); + + return [ + 'code' => 0, + 'msg' => $msg + ]; + } + +} diff --git a/app/admin/controller/User/UserRole.php b/app/admin/controller/User/UserRole.php new file mode 100644 index 0000000..971e593 --- /dev/null +++ b/app/admin/controller/User/UserRole.php @@ -0,0 +1,153 @@ +param('role_guid'); + $user = $request->param('user'); + $this->validate($request->param(), [ + 'role_guid' => 'require' + ]); + $user_guids = []; + $con = []; + $users = ModelRole::getByRoleGuid($role_guid)->users; + if ($users) { + $user_guids = $users->column('user_guid'); + } + if ($user) { + $con['user_name'] = $user; + } + $query = ModelUser::withSearch(['user_name'], $con)->where($con)->where('user_guid', 'not in', $user_guids); + $select = self::pageWrapper($query)->field([ + 'user_name', + 'user_guid', + ])->order([ + 'user_id' => 'desc' + ])->select(); + $count = $query->count(); + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + /** + * 获取绑定角色用户列表 + * + * @param Request $request + * @return void + * @date 2022-03-02 + * @example + * @author admin + * @since 1.0.0 + */ + public function getBindUserList(Request $request): array + { + $role_guid = $request->param('role_guid'); + $user = $request->param('user'); + $this->validate($request->param(), [ + 'role_guid' => 'require' + ]); + $user_ids = []; + $con = []; + $users = ModelRole::getByRoleGuid($role_guid)->users; + if ($users) { + $user_ids = $users->column('user_id'); + } + if ($user) { + $con['user_name'] = $user; + } + $query = ModelUser::withSearch(['user_name'], $con)->where($con)->where('user_id', 'in', $user_ids); + $select = self::pageWrapper($query)->field([ + 'user_name', + 'user_guid', + ])->order([ + 'user_id' => 'desc' + ])->select(); + $count = $query->count(); + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + + /** + * 绑定用户角色 + * + * @param Request $request + * @date 2022-03-02 + * @example + * @author admin + * @since 1.0.0 + */ + public function bindUserRole(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'user_guid' => 'require', + 'role_guid' => 'require', + ]); + $users = array_map(function ($v) { + return ModelUser::getByUserGuid($v); + }, explode(',', $params['user_guid'])); + $roles = array_map(function ($v) { + return ModelRole::getByRoleGuid($v); + }, explode(',', $params['role_guid'])); + ModelUserRole::bindUserRole($users, $roles); + return [ + 'code' => 0, + 'msg' => '绑定成功' + ]; + } + + /** + * 绑定用户角色 + * + * @param Request $request + * @date 2022-03-02 + * @example + * @author admin + * @since 1.0.0 + */ + public function unBindUserRole(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + 'user_guid' => 'require', + 'role_guid' => 'require', + ]); + $users = array_map(function ($v) { + return ModelUser::getByUserGuid($v); + }, explode(',', $params['user_guid'])); + $roles = array_map(function ($v) { + return ModelRole::getByRoleGuid($v); + }, explode(',', $params['role_guid'])); + ModelUserRole::unbindUserRole($users, $roles); + return [ + 'code' => 0, + 'msg' => '解绑成功' + ]; + } +} diff --git a/app/admin/middleware/Auth.php b/app/admin/middleware/Auth.php new file mode 100644 index 0000000..c67b42f --- /dev/null +++ b/app/admin/middleware/Auth.php @@ -0,0 +1,84 @@ + ['*'], + 'admin' => ['*'], + ]; + + /** + * 处理请求 + * + * @param \app\Request $request + * @param \Closure $next + * @return Response + */ + public function handle(Request $request, \Closure $next): Response + { + $this->request = $request; + + if ($this->isIgnoreLogin()) { + return $next($request); + } + + if ($request->isLogin()) { + $user = $request->getCurrentUser(); + if ($user->user_admin) { + return $next($request); + } + } + + $api = join('/', [ + $request->controller(), + $request->action() + ]); + + $token = Token::getCurrent(); + + /** + * 缓存接口权限验证 + */ + $validate = $this->validateApi($token->token_api); + /** + * 缓存权限验证不通过 + */ + if ($validate === false) { + /** + * 自定义验证权限 + * 如果验证通过刷新缓存接口 + */ + $validate = $this->validateUser(); + if ($validate) { + Token::getCurrentUser()->login(); + } + } + /** + * 权限验证通过 + */ + if ($validate) { + return $next($request); + } + throw new NotAuthApi("未授权接口 [ $api ]", 1); + } +} diff --git a/app/admin/route.php b/app/admin/route.php new file mode 100644 index 0000000..90d0835 --- /dev/null +++ b/app/admin/route.php @@ -0,0 +1,12 @@ + [ + // 接口鉴权 + \app\admin\middleware\Auth::class + ], +]; diff --git a/app/api/controller/Crawler/Crawler.php b/app/api/controller/Crawler/Crawler.php new file mode 100644 index 0000000..aef3bea --- /dev/null +++ b/app/api/controller/Crawler/Crawler.php @@ -0,0 +1,112 @@ +request('GET', $url); + + // 选择要解析的HTML元素 + $titles = $crawler->filter('.productsBody .productItem .products'); + $imgs = $crawler->filter('.productsBody .productItem .products .productImg'); + // return $titles; + // dump($titles); + // die; + + $title111 = $titles->filter('.productType')->text(); + $img111 = $titles->filter('.productImg')->eq(2)->attr('lazyload'); + // return $img111; + // return $title111; + + + // 在全部元素中筛选 + // $products = $crawler->filter('.productsBody .productItem .products'); + + // foreach ($products as $key => $value) { + // // dump($value->filter('.productType')->eq($key)->text()); + // // die; + // foreach ($titles->filter('.productType')->eq($key) as $key => $value) { + // $title = $value->textContent; + // } + + // // return $title; + // } + + + $titleArr = []; + // 遍历元素并输出结果 + foreach ($titles as $title) { + $titleArr[] = $title->textContent; + } + + return $titleArr; + + // $imgArr = []; + foreach ($imgs as $img) { + // var_dump($img->getAttribute('lazyload')); + // die; + // return $img->getAttribute('lazyload'); + $src = $img->getAttribute('lazyload'); + + if (strpos($src, 'http') === 0) { + $img_url = $src; + } else { + $img_url = $base_url . $src; + } + // return $img_url; + + // 文件夹名称 + $dirName = "product" . "Img"; + // 文件保存位置 + $fileSaveLocation = public_path('uploads') . $dirName . "\\"; + // return $fileSaveLocation; + if (true !== $res = Tool::mkdir($fileSaveLocation)) { + return $res; + } + + // 获取图片二进制数据 + $imageContent = file_get_contents($img_url); + // var_dump($imageContent); + // die; + // return $imageContent; + + // 保存图片到本地文件系统 + file_put_contents($fileSaveLocation . basename($img_url), $imageContent); + + $res_img_url = "/uoloads" . "/" . $dirName . "/" . basename($img_url); + return $res_img_url; + } + + + // return $imgArr; + return $titleArr; + } +} diff --git a/app/api/controller/Flow/Flow.php b/app/api/controller/Flow/Flow.php new file mode 100644 index 0000000..2a7bbfc --- /dev/null +++ b/app/api/controller/Flow/Flow.php @@ -0,0 +1,33 @@ +param(); + $this->validate($params, ['flow_target' => 'require']); + $flow_target = $params['flow_target']; + + try { + return (new ModelFlow)->track($flow_target); + return json(msg("添加流量访问记录成功")); + } catch (\Throwable $th) { + throwErrorMsg("错误信息:" . $th); + } + } + +} diff --git a/app/api/controller/Login.php b/app/api/controller/Login.php new file mode 100644 index 0000000..f6704b5 --- /dev/null +++ b/app/api/controller/Login.php @@ -0,0 +1,144 @@ +middleware[SessionInit::class] = [ + 'only' => ['accountLogin', 'getCaptcha'] + ]; + } + + /** + * 验证token + * + * @param Request $request + * @return void + */ + public function validateToken(Request $request) + { + $token = $request->getCurrentToken(); + return [ + 'code' => 0, + 'data' => [ + 'exp_time' => $token->token_exp_time, + ], + 'msg' => 'ok' + ]; + } + + /** + * 西北政法大学单点登陆 + * + * @param Request $request + * @return Response + * @date 2023-01-04 + * @example + * @author admin + * @since 1.0.0 + */ + public function casOauthLogin(Request $request): Response + { + $url = $request->param('url'); + return LogicLogin::casOauthLogin( + LogicLogin::casOauthLoginHandle($url) + ); + } + + /** + * 西北政法大学单点登出 + * + * @param Request $request + * @return Response + * @date 2023-01-04 + * @example + * @author admin + * @since 1.0.0 + */ + public function casOauthLogout(Request $request): Response + { + $url = $request->param('url'); + return LogicLogin::casOauthLogout($url); + } + + /** + * 用户账号登录 + * + * @param Request $request + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function accountLogin(Request $request): array + { + $param = Validate::param([ + 'account|账号' => 'require', + 'password|密码' => 'require', + 'captcha|验证码' => $request->isProd() ? 'require|captcha' : false + ]); + $token = LogicLogin::accountLogin( + $param['account'], + $param['password'] + ); + + return [ + 'code' => 0, + 'data' => [ + 'token' => $token->token_content, + 'exp_time' => $token->token_exp_time, + ], + 'msg' => 'ok' + ]; + } + + /** + * 生成验证码 + * + * @date 2022-03-05 + * @example + * @author admin + * @since 1.0.0 + */ + public function getCaptcha() + { + return Captcha::create(); + } + + /** + * 用户登出 + * + * @param Request $request + * @date 2022-03-09 + * @example + * @author admin + * @since 1.0.0 + */ + public function userLogout(Request $request): array + { + $token = $request->getCurrentToken(); + $token->logout(); + return [ + 'code' => 0, + 'msg' => '登出成功' + ]; + } +} diff --git a/app/api/controller/News/News.php b/app/api/controller/News/News.php new file mode 100644 index 0000000..f2185c9 --- /dev/null +++ b/app/api/controller/News/News.php @@ -0,0 +1,88 @@ +param(); + $con = []; + + $con = Tool::getOptionalQuery(['news_type', '='],); + + $query = ModelNews::where($con) + ->field([ + 'news_id', + 'news_guid', + 'news_title', + 'news_intro', + 'news_type', + 'news_img', + 'news_create_time', + ]) + ->append(['news_created_time']) + ->hidden(['news_create_time']) + // ->append('news_create_time') + ->order('news_create_time', 'desc'); + + + + return msg("获取新闻列表成功!", $query); + } + + /** + * 获取新闻详情 + */ + public function getNewsInfo(Request $request): array + { + $params = $request->param(); + + $this->validate($params, ['news_id' => 'require']); + + $find = ModelNews::field([ + 'news_id', + 'news_guid', + 'news_title', + 'news_author', + 'news_intro', + 'news_type', + 'news_img', + 'news_content', + 'news_num', + 'news_create_time' + ]) + ->where('news_id', $params['news_id']) + ->find(); + if (!$find) throwErrorMsg('该新闻不存在!'); + + $last_next_id = Tool::getLastNextId( + new ModelNews, + ['news_id', $find->news_id], + 'all', + [['news_type', '=', $find->news_type]] + ); + + return msg(0, '获取新闻详情成功!', [ + 'data' => $find, + 'last_id' => $last_next_id[0], + 'next_id' => $last_next_id[1], + ]); + } +} diff --git a/app/api/controller/Product/Product.php b/app/api/controller/Product/Product.php new file mode 100644 index 0000000..2f2b572 --- /dev/null +++ b/app/api/controller/Product/Product.php @@ -0,0 +1,107 @@ +param(); + $this->validate($params, [ + 'product_type_id|产品系列' => 'require', + ]); + + $product_type = ModelProductType::where('product_type_id', $params['product_type_id'])->find(); + if (!$product_type) throwErrorMsg('产品系列不存在!'); + + $con = [ + ['product_type_guid', '=', $product_type->product_type_guid] + ]; + + $query = ModelProduct::where($con) + ->field([ + 'product_id', + 'product_guid', + 'product_type_guid', + 'product_name', + 'product_img', + 'product_price', + ]) + ->withAttr('product_img', function ($value, $data) { + return explode(',', $data['product_img'])[0]; + }) + ->order('product_id', 'desc'); + + return msg("获取产品列表成功!", $query); + } + + /** + * 获取产品详情接口 + * + * @param Request request + * @date 2023-04-03 + * @example + * @author xjh + * @since 1.0.0 + */ + public function getProductInfo(Request $request) + { + $params = $request->param(); + $this->validate($params, [ + 'product_id|产品id' => 'require', + ]); + + $find = ModelProduct::where('product_id', $params['product_id']) + ->field([ + 'product_id', + 'product_guid', + 'product_type_guid', + 'product_name', + 'product_img', + 'product_price', + 'product_params', + 'product_details', + ]) + ->find(); + if (!$find) throwErrorMsg('该产品不存在!'); + + $last_next_id = Tool::getLastNextId( + new ModelProduct, + ['product_id', $find->product_id], + 'all', + [['product_type_guid', '=', $find->product_type_guid]] + ); + + return msg( + "获取产品详情成功!", + [ + 'data' => $find, + 'last_id' => $last_next_id[0], + 'next_id' => $last_next_id[1], + ] + ); + } +} diff --git a/app/api/controller/Product/ProductType.php b/app/api/controller/Product/ProductType.php new file mode 100644 index 0000000..2bfa84f --- /dev/null +++ b/app/api/controller/Product/ProductType.php @@ -0,0 +1,68 @@ + "product_type_parent_name", + 'a.product_type_order', + 'a.product_type_guid', + 'a.product_type_id', + 'a.product_type_icon', + 'a.product_type_cover', + ]) + ->alias('a') + ->leftjoin('product_type b', 'a.product_type_parent_guid = b.product_type_guid') + ->where($con) + ->order(['product_type_order' => 'asc']) + ->select()->toArray(); + + $Traverse = new Traverse('product_type_guid', 'product_type_parent_guid'); + $product_type_tree = $Traverse->tree($product_type, '0', function ($v) { + return [ + 'product_type_name' => $v['product_type_name'], + 'product_type_parent_name' => $v['product_type_parent_name'], + 'product_type_guid' => $v['product_type_guid'], + 'product_type_id' => $v['product_type_id'], + 'product_type_parent_guid' => $v['product_type_parent_guid'], + 'product_type_order' => $v['product_type_order'], + 'product_type_icon' => $v['product_type_icon'], + 'product_type_cover' => $v['product_type_cover'], + ]; + }); + + return msg("获取产品系列列表成功!", $product_type_tree); + } +} diff --git a/app/api/controller/User/User.php b/app/api/controller/User/User.php new file mode 100644 index 0000000..8cff71e --- /dev/null +++ b/app/api/controller/User/User.php @@ -0,0 +1,130 @@ + 'require', + 'user_phone' => 'require|mobile', + 'user_id_card' => 'require' + ]); + $user = $request->getCurrentUser(); + $user->allowField([ + 'user_id_card', + 'user_phone', + 'user_name' + ]); + $user->save($param); + return [ + 'code' => 0, + 'msg' => '更新成功' + ]; + } + /** + * 获取用户列表 + */ + public function getUserList(Request $request): array + { + $user = $request->param('user'); + $con = [ + 'user_status' => UserUser::STATUS_ENABLE + ]; + $search = []; + if ($user) { + $search['user_name'] = $user; + } + $query = UserUser::withSearch( + array_keys($search), + $search + )->where($con); + $select = self::pageWrapper($query)->field([ + 'user.user_guid', + 'user.user_name', + 'user.user_phone', + 'user.user_position', + 'user.user_department', + ])->group('user.user_guid')->order([ + 'user_id' => 'desc' + ])->select(); + $count = $query->count(); + return [ + 'code' => 0, + 'data' => $select, + 'count' => $count, + 'msg' => 'ok' + ]; + } + /** + * 获取用户信息 + */ + public function getUserInfo(Request $request): array + { + $user = $request->getCurrentUser(); + $token = $request->getCurrentToken(); + return [ + 'code' => 0, + 'data' => [ + 'user_img' => $user->user_img, + 'user_name' => $user->user_name, + 'user_phone' => $user->user_phone, + 'user_position' => $user->user_position, + 'user_department' => $user->user_department, + 'user_create_name' => $user->user_create_name, + 'user_department' => $user->user_department, + 'user_sex' => $user->user_sex, + 'token_update_time' => $token->token_update_time, + ], + 'msg' => 'ok' + ]; + } + + /** + * 更新用户头像 + */ + public function updateUserImg(Request $request): array + { + $user = $request->getCurrentUser(); + $upload = new UploadFile('uploads', 'image'); + $path = $upload->putFile('UserImg'); + $user->user_img = $path; + $user->save(); + return [ + 'code' => 0, + 'msg' => '更新成功' + ]; + } + + /** + * 更新用户密码 + */ + public function updateUserPassword(Request $request): array + { + $param = Validate::param([ + 'origin' => 'require', + 'new' => 'require', + ]); + $user = $request->getCurrentUser(); + $origin = UserUser::encryptPassword($param['origin']); + if ($origin != $user->user_password) { + throwErrorMsg('原密码错误'); + } + $user->user_password = $param['new']; + $user->save(); + return [ + 'code' => 0, + 'msg' => '修改成功' + ]; + } +} diff --git a/app/api/middleware/Auth.php b/app/api/middleware/Auth.php new file mode 100644 index 0000000..4c16d83 --- /dev/null +++ b/app/api/middleware/Auth.php @@ -0,0 +1,85 @@ + ['*'], + 'admin' => ['*'], + 'Consult' => ['*'], + ]; + + /** + * 处理请求 + * + * @param \app\Request $request + * @param \Closure $next + * @return Response + */ + public function handle(Request $request, \Closure $next): Response + { + $this->request = $request; + + if ($this->isIgnoreLogin()) { + return $next($request); + } + + if ($request->isLogin()) { + $user = $request->getCurrentUser(); + if ($user->user_admin) { + return $next($request); + } + } + + $api = join('/', [ + $request->controller(), + $request->action() + ]); + + $token = Token::getCurrent(); + + /** + * 缓存接口权限验证 + */ + $validate = $this->validateApi($token->token_api); + /** + * 缓存权限验证不通过 + */ + if ($validate === false) { + /** + * 自定义验证权限 + * 如果验证通过刷新缓存接口 + */ + $validate = $this->validateUser(); + if ($validate) { + Token::getCurrentUser()->login(); + } + } + /** + * 权限验证通过 + */ + if ($validate) { + return $next($request); + } + throw new NotAuthApi("未授权接口 [ $api ]", 1); + } +} diff --git a/app/api/route.php b/app/api/route.php new file mode 100644 index 0000000..4198024 --- /dev/null +++ b/app/api/route.php @@ -0,0 +1,12 @@ + [ + // 接口鉴权 + // \app\api\middleware\Auth::class + ], +]; diff --git a/app/common.php b/app/common.php new file mode 100644 index 0000000..14fbb3b --- /dev/null +++ b/app/common.php @@ -0,0 +1,178 @@ +\n(\s+)/m', '] => ', ob_get_clean()); + + if (!extension_loaded('xdebug')) { + $output = htmlspecialchars($output, $flags); + } + + $output = '
' . $label . $output . '
'; + + if ($echo) { + echo ($output); + return; + } + + return $output; +} + +/** + * 抛出业务异常 + * + * @param string $msg + * @param integer $code + * @return void + * @throws ErrorMsg + * @date 2022-12-27 + * @example + * @author admin + * @since 1.0.0 + */ +function throwErrorMsg(string $msg, int $code = 1): void +{ + throw new ErrorMsg($msg, $code); +} + +/** + * 计算年龄 + * + * @param string $birthday Y-m-d + * @return int + * @date 2022-03-11 + * @example + * @author admin + * @since 1.0.0 + */ +function sumAge($birthday): int +{ + $age = 0; + try { + if (!is_string($birthday)) { + throw new ErrorMsg("非法日期", 1); + } + $birthday = explode("-", date('Y-m-d', strtotime($birthday))); + $date = explode("-", date('Y-m-d')); + if (count($birthday) === 3) { + list($y, $m, $d) = $birthday; + } else { + list($y, $m, $d) = $date; + } + // list($y, $m, $d) = $birthday; + list($dy, $dm, $dd) = $date; + + $age = $dy - $y; + if ($dm >= $m) { + if ($dm == $m) { + if ($dd >= $d) { + } else { + $age--; + } + } + } else { + $age--; + } + return $age; + } catch (\Throwable $th) { + } + return $age; +} + +Validate::maker(function (ThinkValidate $validate) { + $validate->extend( + 'string', + function ($value) { + return is_string($value); + }, + ':attribute 数据类型非法 不是字符串' + ); +}); + +/** + * 接口返回封装 + */ +function msg(...$arr) +{ + $msg_data = ['code' => 0]; + $default_code_msg = [0 => '操作成功!', 1 => '操作失败!']; + + //data数据构建 + function constructData(&$msg_data, $code, $msg_str, &$arr2) + { + $msg_data['code'] = $code; + $msg_data['msg'] = $msg_str; + if (is_array($arr2)) { //数组 + $msg_data['data'] = $arr2; + } + if (is_object($arr2)) { //查询对象 + $obj = $arr2; + $soft_delete_field = '_delete_time'; //软删除默认后缀 + //模型层 || Db层 + if ($obj instanceof think\db\Query || $obj instanceof think\Collection) { + //join软删除字段过滤补全(暂时只适应软删除为 【前缀名_delete_time】存储为datetime 的设计) + if (isset($obj->getOptions()['join']) && $join_data = $obj->getOptions('join')) { + $join_soft_delete = []; + foreach ($join_data as $key => $join) { + $join_table_name = is_array($join[0]) ? array_keys($join[0])[0] : $join[0]; //联表表名 + $join_soft_delete[] = [$join_table_name . $soft_delete_field, 'NULL', null]; + } + $obj = $obj->where($join_soft_delete); + } + //select()、count()补全 + $msg_data['data'] = $obj->page((int) Request::param('page', 1), (int) Request::param('limit', 10))->select(); + $msg_data['count'] = $obj->count(); + } else { + return ['code' => 444, 'msg' => '对象只允许传递来自think\db\Query类和instanceof think\Collection类的实例!']; + } + } + }; + + switch (count($arr)) { + case 1: //单参数 + constructData($msg_data, 0, '查询成功!', $arr[0],); + if (is_string($arr[0])) $msg_data['msg'] = $arr[0]; + if (is_int($arr[0])) { + $msg_data['code'] = $arr[0]; + $msg_data['msg'] = $default_code_msg[$arr[0]]; + } + break; + case 2: //双参数 + if (is_int($arr[0]) && is_string($arr[1])) { + $msg_data['code'] = $arr[0]; + $msg_data['msg'] = $arr[1]; + } else { + constructData($msg_data, 0, $arr[0], $arr[1]); + } + break; + case 3: //三参数 + $msg_data['code'] = $arr[0]; + $msg_data['msg'] = $arr[1]; + if (is_object($arr[2])) { + $msg_data['data'] = $arr[2]; + } else { + foreach ($arr[2] as $key => $val) + $msg_data[$key] = $val; + } + break; + default: + return ['code' => 444, 'msg' => 'msg()最多参数只允许3个!']; + } + + return $msg_data; +} diff --git a/app/common/arw/adjfut/composer.json b/app/common/arw/adjfut/composer.json new file mode 100644 index 0000000..7991c90 --- /dev/null +++ b/app/common/arw/adjfut/composer.json @@ -0,0 +1,39 @@ +{ + "name": "arw/adjfut", + "type": "library", + "autoload": { + "psr-4": { + "arw\\adjfut\\": "src/" + } + }, + "authors": [{ + "name": "arw", + "email": "2679599887@qq.com" + }], + "require": { + "php": ">=7.1.0", + "phpoffice/phpspreadsheet": "^1.12", + "topthink/framework": "^6.0.0", + "topthink/think-filesystem": "^2.0" + }, + "config": { + "sort-packages": true + }, + "repositories": { + "packagist": { + "type": "composer", + "url": "https://mirrors.aliyun.com/composer/" + } + }, + "extra": { + "think": { + "services": [ + "arw\\adjfut\\Service\\Validate" + ], + "config": { + "wechat": "src/Config/wechat.php", + "chunkUpload": "src/Config/chunkUpload.php" + } + } + } +} diff --git a/app/common/arw/adjfut/src/ArrayFilter.php b/app/common/arw/adjfut/src/ArrayFilter.php new file mode 100644 index 0000000..dcd0ede --- /dev/null +++ b/app/common/arw/adjfut/src/ArrayFilter.php @@ -0,0 +1,170 @@ +data = $data; + } + + /** + * 二维数组排除字段 + * + * @param array $array + * @param array $except + * @return array + * @date 2023-01-13 + * @example + * @author arw + * @since 1.0.0 + */ + public static function exceptFields(array $array, array $except): array + { + foreach ($array as &$value) { + $self = new self($value); + $value = $self->except($except)->toArray(); + unset($value, $self); + } + return $array; + } + + /** + * 二维数组指定字段 + * + * @param array $array + * @param array $only + * @return array + * @date 2023-01-13 + * @example + * @author arw + * @since 1.0.0 + */ + public static function onlyFields(array $array, array $only): array + { + foreach ($array as &$value) { + $self = new self($value); + $value = $self->only($only)->toArray(); + unset($value, $self); + } + return $array; + } + + /** + * 排除某些变量 + * + * @param array $fields + * @return self + * @date 2023-01-13 + * @example + * @author arw + * @since 1.0.0 + */ + public function except(array $fields): self + { + $data = $this->data; + // $fields = [id,name] + foreach ($fields as $field) { + if (isset($data[$field])) { + unset($data[$field]); + } + } + return new self($data); + } + + /** + * 获取部分变量 + * + * @param array $fields + * @return self + * @date 2023-01-13 + * @example + * @author arw + * @since 1.0.0 + */ + public function only(array $fields): self + { + $data = $this->data; + $result = []; + // $fields = [id,name] + // $fields = [id=>0,name=>asdasd] + foreach ($fields as $key => $value) { + if (is_int($key)) { + if (isset($data[$value])) { + $result[$value] = $data[$value]; + } + } else { + $result[$key] = isset($data[$key]) ? $data[$key] : $value; + } + } + return new self($result); + } + + /** + * 获取数据 + * + * @return array + * @date 2023-01-13 + * @example + * @author arw + * @since 1.0.0 + */ + public function toArray(): array + { + return $this->data; + } + + + public function __get($name) + { + return $this->offsetGet($name); + } + + public function __set($name, $value) + { + return $this->offsetSet($name, $value); + } + + public function offsetExists($offset): bool + { + return isset($this->data[$offset]); + } + + public function offsetGet($offset) + { + return $this->data[$offset]; + } + + public function offsetSet($offset, $value): void + { + $this->data[$offset] = $value; + } + + public function offsetUnset($offset): void + { + unset($this->data[$offset]); + } +} diff --git a/app/common/arw/adjfut/src/Base64.php b/app/common/arw/adjfut/src/Base64.php new file mode 100644 index 0000000..4bb6653 --- /dev/null +++ b/app/common/arw/adjfut/src/Base64.php @@ -0,0 +1,174 @@ + 'html', + 'text/css' => 'css', + 'text/javascript' => 'js', + 'image/gif' => 'gif', + 'image/png' => 'png', + 'image/jpeg' => 'jpg', + 'image/x-icon' => 'ico', + ]; + /** + * 实例化 + * + * @param string $base64 + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public function __construct(string $base64) + { + $parse = self::parse($base64); + $this->base64 = $base64; + $this->type = $parse['type']; + $this->body = $parse['body']; + } + + /** + * 获取文件后缀 + * + * @return string + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public function getFileExt(): string + { + return Arr::get(self::FILE_EXT_MAP, $this->type, ''); + } + + /** + * 判断是否是base64图片字符串 + * + * @return boolean + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public function isImage(): bool + { + return in_array($this->type, [ + 'image/gif', + 'image/png', + 'image/jpeg', + 'image/x-icon', + ]); + } + + /** + * 保存base64图片 + * + * @param string $path + * @return void + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public function saveImage(string $path): void + { + file_put_contents($path, base64_decode($this->body)); + } + + /** + * 判断是否是base64图片字符串 + * + * @param string $base64 + * @return boolean + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public static function isBase64Image(string $base64): bool + { + $ins = new self($base64); + return $ins->isImage(); + } + + /** + * 保存base64图片 + * + * @param string $base64 + * @param string $path + * @return void + */ + public static function saveBase64Image(string $base64, string $path): void + { + $ins = new self($base64); + $ins->saveImage($path); + } + + /** + * 解析base64 + * + * @param string $base64 + * @return array + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + private static function parse(string $base64): array + { + $prefix = 'data:'; + $validate = substr($base64, 0, strlen($prefix)) === $prefix; + if (!$validate) { + throw new ErrorMsg("非法base64 开头data:", 1); + } + $explode = explode(';base64,', $base64); + if (count($explode) != 2) { + throw new ErrorMsg("非法base64 不存在;base64,", 1); + } + list($type, $body) = $explode; + $type = str_replace('data:', '', $type); + return [ + 'type' => $type, + 'body' => $body + ]; + } +} diff --git a/app/common/arw/adjfut/src/ChunkUpload.php b/app/common/arw/adjfut/src/ChunkUpload.php new file mode 100644 index 0000000..1990fc2 --- /dev/null +++ b/app/common/arw/adjfut/src/ChunkUpload.php @@ -0,0 +1,258 @@ +id = $id; + if (is_string($file)) { + $file = Request::file($file); + } + if (is_array($file)) { + $file = new UploadedFile(...$file); + } + if (!($file instanceof UploadedFile)) { + throw new ErrorMsg("非法文件", 1); + } + $this->file = $file; + } + + /** + * 获取存储配置 + * + * @return Driver + * @date 2022-08-21 + * @example + * @author arw + * @since 1.0.0 + */ + public function getDisk(): Driver + { + return Filesystem::disk(self::$disk); + } + + /** + * 分片是否上传完成 + * + * @return boolean + * @date 2022-08-22 + * @example + * @author arw + * @since 1.0.0 + */ + public function isDone(): bool + { + return $this->isDone; + } + + /** + * 合并文件 + * + * @return self + * @date 2022-08-21 + * @example + * @author arw + * @since 1.0.0 + */ + public function merge(string $name): self + { + if (!$this->isDone()) { + throw new ErrorMsg("文件未上传完成 禁止合并", 1); + } + + $id = $this->id; + + $root = self::getDiskConfig('root'); + + $path = join('', [ + $root, + $id, + '.' . pathinfo($name, PATHINFO_EXTENSION) + ]); + + for ($i = 0; $i <= $this->total; $i++) { + $_path = $root . $id . DIRECTORY_SEPARATOR . $i; + file_put_contents( + $path, + file_get_contents($_path), + FILE_APPEND + ); + unlink($_path); + } + rmdir($root . $id); + $this->mergeFile = new UploadedFile($path, $name); + return $this; + } + + /** + * 获取合并文件 + * + * @return UploadedFile + * @date 2022-08-22 + * @example + * @author arw + * @since 1.0.0 + */ + public function getMergeFile(): UploadedFile + { + if (!$this->mergeFile) { + throw new ErrorMsg("未合并文件", 1); + } + return $this->mergeFile; + } + + /** + * 获取上传文件 + * + * @param string $diskName + * @param string $validate + * @return UploadFile + * @date 2022-08-22 + * @example + * @author arw + * @since 1.0.0 + */ + public function getUploadFile(string $diskName, string $validate = ''): UploadFile + { + return new UploadFile( + $diskName, + $validate, + $this->getMergeFile() + ); + } + + /** + * 保存文件 + * + * @param integer $index + * @param integer $total + * @return self + * @date 2022-08-21 + * @example + * @author arw + * @since 1.0.0 + */ + public function put(int $index, int $total): self + { + $this->total = $total; + $this->getDisk()->putFileAs( + $this->id, + $this->file, + $index + ); + $this->isDone = $index === $total; + return $this; + } + + /** + * 删除文件 + * + * @return void + * @date 2022-08-22 + * @example + * @author arw + * @since 1.0.0 + */ + public function delete(): void + { + $this->getDisk()->delete($this->getMergeFile()->getFilename()); + } + + /** + * 初始化配置 + * + * @param array $config + * @return void + * @date 2022-08-21 + * @example + * @author arw + * @since 1.0.0 + */ + public static function init(array $config): void + { + self::$disk = Arr::get($config, 'disk', ''); + $type = self::getDiskConfig('type'); + if ($type != 'local') { + throw new ErrorMsg("分片上传仅支持 local类型磁盘", 1); + } + } + + /** + * 获取磁盘配置 + * + * @param string $name + * @param mixed $default + * @return mixed + * @date 2022-08-22 + * @example + * @author arw + * @since 1.0.0 + */ + public static function getDiskConfig($name = null, $default = null) + { + return Filesystem::getDiskConfig(self::$disk, $name, $default); + } + + /** + * 生成上传唯一id + * + * @return string + * @date 2022-08-21 + * @example + * @author arw + * @since 1.0.0 + */ + public static function generateUploadId(): string + { + return md5(join('-', [ + Request::ip(), + time() + ])); + } +} diff --git a/app/common/arw/adjfut/src/Config/chunkUpload.php b/app/common/arw/adjfut/src/Config/chunkUpload.php new file mode 100644 index 0000000..6a888bb --- /dev/null +++ b/app/common/arw/adjfut/src/Config/chunkUpload.php @@ -0,0 +1,9 @@ + '' +]; diff --git a/app/common/arw/adjfut/src/Config/wechat.php b/app/common/arw/adjfut/src/Config/wechat.php new file mode 100644 index 0000000..7c798be --- /dev/null +++ b/app/common/arw/adjfut/src/Config/wechat.php @@ -0,0 +1,39 @@ + '', + // 中控层地址 + 'server_base' => 'http://clique.dszjjt.com:7001/', + // 公众号配置 + 'gzh' => [ + // 缓存key + 'cache_key' => 'wechat.gzh', + // 日志通道 + 'log_channel' => 'wechat/gzh', + // 公众号模板推送 + 'template' => [ + // {{first.DATA}} + // 申请人:{{keyword1.DATA}} + // 申请时间:{{keyword2.DATA}} + // 调课时间:{{keyword3.DATA}} + // {{remark.DATA}} + '申请审核通知' => 'iLuqzUrQM8-v_7ilxageUZoi9v-SQWipkTYVZXB1GeI' + ], + 'appid' => 'wx99caf571c9fb1cc5', + 'secret' => '61100d9c4fff5acf97517f0c8799e2e2', + ], + // 小程序配置 + 'xcx' => [ + // 缓存key + 'cache_key' => 'wechat.xcx', + // 日志通道 + 'log_channel' => 'wechat/xcx', + + 'appid' => 'wx2495492e15854b02', + 'secret' => '5b4fcb27324398083fba4a3c39e8a557', + ], +]; diff --git a/app/common/arw/adjfut/src/Curl.php b/app/common/arw/adjfut/src/Curl.php new file mode 100644 index 0000000..22f65f6 --- /dev/null +++ b/app/common/arw/adjfut/src/Curl.php @@ -0,0 +1,790 @@ + [], + /** + * http 超时 + */ + CURLOPT_TIMEOUT => 0, + /** + * http 代理 + */ + CURLOPT_PROXY => '', + /** + * http 代理端口 + */ + CURLOPT_PROXYPORT => '', + /** + * 来源页面 + */ + CURLOPT_REFERER => '', + /** + * 用户代理 + */ + CURLOPT_USERAGENT => '', + /** + * 响应中是否显示header + */ + CURLOPT_HEADER => 0 + ]; + /** + * Get请求参数 + * + * @var null + */ + private $httpParams = null; + /** + * Post请求参数 + * + * @var null + */ + private $httpData = null; + /** + * 异常信息 + * + * @var string + */ + private $error = ''; + /** + * url是否编码 + * + * @var boolean + */ + private $urlEncode = false; + /** + * 验证http请求状态码 + * + * @var boolean + */ + private $httpCode = true; + /** + * 请求路径 + * + * @var string + */ + private $path = ''; + /** + * 请求url + * + * @var string + */ + private $url = ''; + /** + * 请求类型 + * + * @var string + */ + private $method = 'get'; + /** + * 返回内容 + * + * @var string + */ + private $content = ''; + /** + * 请求信息 + * + * @var array + */ + private $status = []; + /** + * 调试模式 + * + * @var boolean + */ + private $debug = false; + /** + * 是否上传文件 + * + * @var boolean + */ + private $isUploadFile = false; + + /** + * 初始化 + * + * @date 2022-03-24 + * @example + * @author arw + * @since 1.0.0 + */ + public function __construct() + { + } + + /** + * 初始化请求 + * + * @return $this + */ + public static function instance() + { + return new self; + } + + /** + * 获取请求url + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * 获取请求路径 + */ + public function getPath(): string + { + return $this->path; + } + + /** + * 获取返回内容 + * + * @return string + */ + public function getContent(): string + { + return $this->content; + } + + /** + * 格式化返回 + * + * @param string $type 返回类型(默认使用 $this->dataType) + * @return mixed + * @date 2022-03-24 + * @example + * @author arw + * @since 1.0.0 + */ + public function formatContent(string $type = '') + { + $content = $this->content; + if (!$type) { + $type = $this->dataType; + } + switch ($type) { + case 'json': + case 'object': + return json_decode($content, $type === 'json'); + break; + default: + return $content; + break; + } + } + + /** + * 获取请求信息 + */ + public function getStatus(): array + { + return $this->status; + } + + /** + * 设置是否上传文件 + */ + public function setIsUploadFile(bool $isUploadFile): self + { + $this->isUploadFile = $isUploadFile; + return $this; + } + + /** + * 设置请求路径 + */ + public function setPath(string $path): self + { + if (count(explode('?', $path)) != 1) { + throw new Exception("请求路径不能携带参数 请使用setParams设置请求参数", 1); + } + $this->path = $path; + return $this; + } + + /** + * 设置调试模式 + */ + public function setDeBug(bool $debug): self + { + $this->debug = $debug; + return $this; + } + + /** + * 验证http状态码 + * + * @param boolean|int $code + */ + public function setHttpCode($code): self + { + $this->httpCode = $code; + return $this; + } + + /** + * 设置url是否编码 + */ + public function setUrlEncode(bool $urlEncode): self + { + $this->urlEncode = $urlEncode; + return $this; + } + + /** + * 设置请求前缀 + */ + public function setBaseUrl(string $baseUrl): self + { + if (count(explode('?', $baseUrl)) != 1) { + throw new Exception("请求前缀不能携带参数 请使用setParams设置请求参数", 1); + } + $this->baseUrl = $baseUrl; + return $this; + } + + /** + * 设置返回数据类型 + */ + public function setDataType(string $dataType): self + { + $this->dataType = $dataType; + return $this; + } + + /** + * 设置http header + */ + public function setHeader(array $header): self + { + $_header = []; + foreach ($header as $key => $value) { + if (is_numeric($key)) { + $_header[] = $value; + } else { + $_header[] = "$key: $value"; + } + } + $this->config[CURLOPT_HTTPHEADER] = array_merge($this->config[CURLOPT_HTTPHEADER], $_header); + return $this; + } + + /** + * 设置http 超时 + */ + public function setTimeout(int $time): self + { + $this->config[CURLOPT_TIMEOUT] = $time <= 0 ? 5 : $time; + return $this; + } + + /** + * 设置http 代理 + */ + public function setProxy(string $proxy): self + { + $this->config[CURLOPT_PROXY] = $proxy; + return $this; + } + + /** + * 设置http 代理端口 + */ + public function setProxyPort(int $port): self + { + $this->config[CURLOPT_PROXYPORT] = $port; + return $this; + } + + /** + * 设置来源页面 + */ + public function setReferer(string $referer = ""): self + { + $this->config[CURLOPT_REFERER] = $referer; + return $this; + } + + /** + * 设置用户代理 + */ + public function setUserAgent(string $agent = ""): self + { + $this->config[CURLOPT_USERAGENT] = $agent; + return $this; + } + + /** + * http响应中是否显示header + */ + public function showResponseHeader(bool $show): self + { + $this->config[CURLOPT_HEADER] = $show ? 1 : 0; + return $this; + } + + /** + * 获取get请求参数 + */ + public function getParams() + { + return $this->httpParams; + } + + /** + * 设置get请求的参数 + */ + public function setParams($params): self + { + $_params = $this->trigger('beforeSetParams', [$params]); + $this->httpParams = $_params ? $_params : $params; + return $this; + } + + /** + * 获取post请求参数 + */ + public function getData() + { + return $this->httpData; + } + + /** + * 设置post请求的参数 + */ + public function setData($data): self + { + $_data = $this->trigger('beforeSetData', [$data]); + $this->httpData = $_data ? $_data : $data; + return $this; + } + + /** + * 设置http请求的cookie信息 + */ + public function setCookie(array $cookie): self + { + $_cookie = []; + foreach ($cookie as $key => $value) { + $_cookie[] = "$key=$value"; + } + $this->config[CURLOPT_COOKIE] = join(';', $_cookie); + return $this; + } + + /** + * 设置证书路径 + */ + public function setCainfo(string $file): self + { + $this->config[CURLOPT_CAINFO] = $file; + return $this; + } + + /** + * 获取请求异常 + */ + public function getError(): string + { + return $this->error; + } + + /** + * 绑定 + * + * @param string $name + * @param callable $cb + * @date 2022-03-26 + * @example + * @author arw + * @since 1.0.0 + */ + public function bind(string $name, callable $cb): self + { + $this->bind[$name] = $cb; + return $this; + } + + /** + * GET请求 + * @param string $path + * @return mixed + */ + public function get(string $path = '') + { + if ($path) { + $this->setPath($path); + } + $this->method = 'get'; + $respone = $this->fetch(); + if (!$path) { + return $this; + } + return $respone; + } + + /** + * POST请求 + * + * @param string $path + * @return mixed + */ + public function post(string $path = '') + { + if ($path) { + $this->setPath($path); + } + $this->method = 'post'; + $respone = $this->fetch(); + if (!$path) { + return $this; + } + return $respone; + } + + /** + * PUT请求 + * + * @param string $path + * @return mixed + */ + public function put(string $path = '') + { + if ($path) { + $this->setPath($path); + } + $this->method = 'put'; + $respone = $this->fetch(); + if (!$path) { + return $this; + } + return $respone; + } + + /** + * DELETE请求 + * + * @param string $path + * @return mixed + */ + public function delete(string $path = '') + { + if ($path) { + $this->setPath($path); + } + $this->method = 'delete'; + $respone = $this->fetch(); + if (!$path) { + return $this; + } + return $respone; + } + + /** + * PATCH请求 + * + * @param string $path + * @return mixed + */ + public function patch(string $path = '') + { + if ($path) { + $this->setPath($path); + } + $this->method = 'patch'; + $respone = $this->fetch(); + if (!$path) { + return $this; + } + return $respone; + } + + /** + * 设置get传参前 + * + * @param callable $cb($params) + * @param mixed $params 参数 + * @date 2022-03-26 + * @example + * @author arw + * @since 1.0.0 + */ + public function onBeforeSetParams(callable $cb): self + { + return $this->event('beforeSetParams', $cb); + } + + /** + * 设置post传参前 + * + * @param callable $cb($data) + * @param mixed $data 参数 + * @date 2022-03-26 + * @example + * @author arw + * @since 1.0.0 + */ + public function onBeforeSetData(callable $cb): self + { + return $this->event('beforeSetData', $cb); + } + + /** + * 请求前 + * + * @param callable $cb($ch) + * @param self $ch + * @date 2022-03-26 + * @example + * @author arw + * @since 1.0.0 + */ + public function onBeforeFetch(callable $cb): self + { + return $this->event('beforeFetch', $cb); + } + + /** + * 请求后 + * + * @param callable $cb($ch,$info) + * @param self $ch + * @param array $info + * @param string $info[url] 请求完整url + * @param string $info[content] 返回信息 + * @param array $info[status] 请求信息 + * @date 2022-03-26 + * @example + * @author arw + * @since 1.0.0 + */ + public function onAfterFetch(callable $cb) + { + return $this->event('afterFetch', $cb); + } + + /** + * 请求异常(返回true阻止抛出异常) + * + * @param callable $cb($ch,$th) + * @param self $ch + * @param \Throwable $th + * @date 2022-03-26 + * @example + * @author arw + * @since 1.0.0 + */ + public function onFetchError(callable $cb) + { + return $this->event('fetchError', $cb); + } + + /** + * 发起请求 + * + * @return mixed + * @date 2022-03-25 + * @example + * @author arw + * @since 1.0.0 + */ + public function fetch() + { + $this->url = $url = $this->baseUrl . $this->path; + + $this->trigger('beforeFetch', [$this]); + + try { + $httpParams = $this->httpParams; + if (!empty($httpParams) && is_array($httpParams)) { + $url .= (strpos($url, '?') === false ? '?' : '') . http_build_query($httpParams); + } + + if ($this->urlEncode === false) { + $url = urldecode($url); + } + + $ch = $this->curlInit($url); + // 设为TRUE把curl_exec()结果转化为字串,而不是直接输出 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + + $this->content = $content = curl_exec($ch); + $this->status = $status = curl_getinfo($ch); + + if ($content === false) { + $this->error = curl_error($ch); + } + + if ($this->debug) { + dump([ + 'ch' => $ch, + 'url' => $url, + 'httpParams' => $this->httpParams, + 'httpData' => $this->httpData, + 'contentArray' => json_decode($content, true), + 'content' => $content, + 'status' => $status + ]); + } + curl_close($ch); + + $httpCode = $this->httpCode; + + if ($httpCode === true) { + $httpCode = 200; + } + if (is_numeric($httpCode)) { + if (!isset($status['http_code'])) { + throw new Exception("服务器未返回状态码", 1); + } + if ($status['http_code'] !== $httpCode) { + throw new Exception(sprintf("服务器返回状态码异常[ %s ]", $status['http_code']), 1); + } + } + + $this->trigger('afterFetch', [$this, [ + 'url' => $url, + 'content' => $content, + 'status' => $status + ]]); + + return $this->formatContent(); + } catch (\Throwable $th) { + if (!$this->trigger('fetchError', [$this, $th])) { + throw $th; + } + } + } + + public function __call($name, $arguments) + { + array_unshift($arguments, $this); + call_user_func_array($this->bind[$name], $arguments); + } + + /** + * 事件 + * + * @param string $type beforeSetParams | beforeSetData | beforeFetch | AfterFetch + * @param callable $cb + */ + private function event(string $type, callable $cb): self + { + $this->event[strtoupper($type)] = $cb; + return $this; + } + + /** + * 事件触发器 + * + * @param string $type + * @return mixed + * @date 2022-03-25 + * @example + * @author arw + * @since 1.0.0 + */ + private function trigger(string $type, array $args = []) + { + $type = strtoupper($type); + if (isset($this->event[$type])) { + return call_user_func_array($this->event[$type], $args); + } + } + + /** + * 初始化请求 + * + * @param string $url + * @return resource|CurlHandle + * @date 2022-04-24 + * @example + * @author arw + * @since 1.0.0 + */ + private function curlInit(string $url) + { + $ch = curl_init($url); + if (stripos($url, 'https://') !== false) { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_SSLVERSION, 1); + } + + foreach ($this->config as $option => $value) { + if (!$value && $option != CURLOPT_HEADER) { + continue; + } + curl_setopt($ch, $option, $value); + } + + switch ($this->method) { + case 'get': + break; + case 'post': + curl_setopt($ch, CURLOPT_POST, true); + break; + default: + // delete put patch + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($this->method)); + break; + } + $httpData = $this->httpData; + // 设置post body + if ($httpData) { + $data = null; + if (is_array($httpData)) { + if ($this->isUploadFile) { + $data = $httpData; + } else { + $data = http_build_query($httpData); + } + } else if (is_string($httpData)) { + $data = $httpData; + } + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + } + return $ch; + } +} diff --git a/app/common/arw/adjfut/src/Excel.php b/app/common/arw/adjfut/src/Excel.php new file mode 100644 index 0000000..51ccaa6 --- /dev/null +++ b/app/common/arw/adjfut/src/Excel.php @@ -0,0 +1,519 @@ +getRealPath(); + } + $this->spreadsheet = self::loadExcel($path); + $this->path = $path; + } else { + $this->spreadsheet = new Spreadsheet(); + } + } + + /** + * 设置工作表样式 + * + * @param array $options + * @param boolean $options[autoBorder] 是否自动添加边框 + * @param boolean $options[freezeLine] 是否自动冻结首行 + * @return self + */ + public function setWorksheetStyle(array $options): self + { + $this->worksheetStyle = $options; + return $this; + } + + /** + * 获取当前Spreadsheet + * + * @return Spreadsheet + * @date 2020-11-23 + * @example + * @author arw + * @since 1.0.0 + */ + public function getSpreadsheet(): Spreadsheet + { + return $this->spreadsheet; + } + + /** + * 读取excel + * + * @param string $path excel路径 + * @return Spreadsheet + */ + public static function loadExcel(string $path): Spreadsheet + { + if (!is_file($path)) { + throw new ErrorMsg("文件不存在 $path", 1); + } + $ext = pathinfo($path, PATHINFO_EXTENSION); + return IOFactory::createReader(ucfirst($ext))->load($path); + } + + /** + * 获取工作表 + * 默认获取当前激活的 + * + * @param string $sheet + * @return Worksheet + */ + public function getWorksheet(string $sheet = 'active'): Worksheet + { + $Spreadsheet = $this->getSpreadsheet(); + if ($sheet === 'active') { + $Worksheet = $Spreadsheet->getActiveSheet(); + } else { + $Worksheet = $Spreadsheet->getSheet($sheet); + } + return $Worksheet; + } + + /** + * 获取excel数据 + * + * @param string $sheet + * @return array + */ + public function getExcelData(string $sheet = 'active'): array + { + return $this->getWorksheet($sheet)->toArray(); + } + + /** + * 解析excel + * + * @param array $rules + * @param string $rules[][title] 表头 + * @param string $rules[][validate] 验证器 + * @param string $rules[][field] 字段名 + * @param string $rules[][type] 数据类型 date:日期格式(Y-m-d H:i:s) + * @param array $options + * @param array $options[titleLine] 表头行 + * @param boolean $options[autoRemove] 解析后移除文件 + * @param boolean $options[ignoreNullRow] 忽略空行 + * @return array + * @date 2022-04-11 + * @example + * @author arw + * @since 1.0.0 + */ + public function parseExcel(array $rules, array $options = []): array + { + $titleLine = Arr::get($options, 'titleLine', [1]); + $autoRemove = Arr::get($options, 'autoRemove', true); + $ignoreNullRow = Arr::get($options, 'ignoreNullRow', true); + + if ($autoRemove) { + if (is_file($this->path)) { + unlink($this->path); + } + } + + $title = []; + $_title = []; + $_field = []; + $_type = []; + $_validate = []; + foreach ($rules as $rule) { + $_title[] = $rule['title']; + if (isset($rule['field'])) { + $_field[] = $rule['field']; + if (isset($rule['validate'])) { + $_validate[join('|', [ + $rule['field'], + $rule['title'] + ])] = $rule['validate']; + } + } else { + $_field[] = ''; + } + if (isset($rule['type'])) { + $_type[] = $rule['type']; + } else { + $_type[] = ''; + } + } + $Worksheet = $this->getWorksheet(); + $data = $Worksheet->toArray(); + // 获取表头 合并复杂表头 + foreach ($titleLine as $line) { + $values = $data[$line - 1]; + foreach ($values as $key => $value) { + if ($value) { + $title[$key] = $value; + } + } + } + // 验证表头 + if ($title != $_title) { + throw new ErrorMsg("表头不一致 请确认excel是否正确", 1); + } + // 去除非数据字段 + $i = max($titleLine) - 1; + do { + unset($data[$i]); + $i--; + } while ($i >= 0); + + $validate = new Validate; + $validate->rule($_validate)->batch(true)->failException(true); + + $result = []; + $error = []; + foreach ($data as $row => $value) { + $index = $row + 1; + $line = "第${index}行"; + $_value = []; + if ($ignoreNullRow && self::isNullRow($value)) { + continue; + } + foreach ($_field as $column => $field) { + if ($field) { + if ($_type[$column]) { + $type = $_type[$column]; + if (Str::startsWith($type, 'date') && $value[$column]) { + $format = 'Y-m-d H:i:s'; + $types = explode(':', $type); + if (isset($types[1])) { + $format = $types[1]; + } + $value[$column] = Tool::conversionDateTime($value[$column], $format); + } + } + $_value[$field] = $value[$column]; + } + } + // 验证数据 + if ($_validate) { + try { + $validate->check($_value); + } catch (\Throwable $th) { + $error[] = $line . ':' . $th->getMessage(); + } + } + + $result[$line] = $_value; + } + + if ($error) { + throw new ErrorMsg(join(PHP_EOL, $error), 1); + } + + return $result; + } + + /** + * 导出excel + * + * @param array $data 数据 + * @param array $options + * @param boolean $options[autoBorder] 是否自动添加边框 + * @param string $options[freezeLine] 是否自动冻结首行 + * @date 2022-04-11 + * @example + * @author arw + * @since 1.0.0 + */ + public static function exportSheet(array $data, array $options = []) + { + $excel = new self; + $excel->setWorksheetStyle($options); + $spreadsheet = $excel->getSpreadsheet(); + $worksheet = $spreadsheet->getActiveSheet(); + $worksheet->fromArray($data); + return $excel; + } + + /** + * 导出处理图片字段 + */ + public static function ExportImgFiled($value) + { + if(strpos($value,"http") !== false){ + $base_url = ""; + }else{ + $base_url = Env::get('APP.DEFAULT_IMG_URL'); + } + return $base_url . $value; + } + + /** + * 导出excel 多sheet + * + * @param array $data 数据 + * @param array $options + * @param boolean $options[autoBorder] 是否自动添加边框 + * @param string $options[freezeLine] 是否自动冻结首行 + * @date 2022-04-11 + * @example + * @author arw + * @since 1.0.0 + */ + public static function exportMoreSheet(array $data, array $options = []) + { + $excel = new self; + $excel->setWorksheetStyle($options); + $spreadsheet = $excel->getSpreadsheet(); + $spreadsheet->removeSheetByIndex(0); + foreach ($data as $key => $value) { + $worksheet = new Worksheet($spreadsheet, $key); + $worksheet->fromArray($value); + $spreadsheet->addSheet($worksheet); + } + $spreadsheet->setActiveSheetIndex(0); + return $excel; + } + + /** + * 保存excel + * + * @param string $name 文件名 + * @param string $save 保存路径 + * @date 2022-04-11 + * @example + * @author arw + * @since 1.0.0 + */ + public function save(string $name, string $save = 'php://output') + { + $spreadsheet = $this->getSpreadsheet(); + $writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); + $_name = $name; + if (!preg_match("/\./", $name)) { + $_name .= '.Xlsx'; + } + $worksheets = $spreadsheet->getAllSheets(); + foreach ($worksheets as $worksheet) { + $this->_setWorksheetStyle($worksheet); + } + // 保存前 + $this->trigger('beforeSave', [$spreadsheet]); + // 浏览器下载 + if ($save === 'php://output') { + Tool::obEndClean(); + header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + header('Cache-Control: max-age=0'); + header('Content-Disposition:inline;filename="' . $_name . '"'); + $writer->save($save); + } else { + Tool::mkdir($save); + // 保存到本地目录 + $writer->save(join(DIRECTORY_SEPARATOR, [ + $save, $_name, + ])); + } + $spreadsheet->disconnectWorksheets(); + unset($spreadsheet); + // 保存后 + $this->trigger('AfterSave'); + } + + /** + * 保存前 + * + * @param callable $cb + * @date 2022-04-11 + * @example + * @author arw + * @since 1.0.0 + */ + public function onBeforeSave(callable $cb): self + { + return $this->event('beforeSave', $cb); + } + + /** + * 保存后 + * + * @param callable $cb + * @date 2022-04-11 + * @example + * @author arw + * @since 1.0.0 + */ + public function onAfterSave(callable $cb): self + { + return $this->event('afterSave', $cb); + } + + /** + * 判断是否空行 + * + * @param array $rows + * @return boolean + * @date 2021-11-27 + * @example + * @author arw + * @since 1.0.0 + */ + public static function isNullRow(array $rows) + { + $rows = array_unique($rows); + $rows = array_filter($rows, function ($v) { + return !is_null($v); + }); + return count($rows) == 0; + } + + /** + * 快捷设置excel样式 + * 首行冻结 自动添加边框 + * + * @param Worksheet $worksheet + * @return Worksheet $worksheet + * @date 2021-01-25 + * @author arw + * @since 1.0.0 + */ + private function _setWorksheetStyle(Worksheet $worksheet): Worksheet + { + $options = $this->worksheetStyle; + $autoBorder = Arr::get($options, 'autoBorder', true); + $freezeLine = Arr::get($options, 'freezeLine', 'A2'); + $autoBackground = Arr::get($options, 'autoBackground', true); + if ($freezeLine) { + $worksheet->freezePane($freezeLine); + } + if ($autoBorder) { + $worksheet->getStyle(join(':', [ + 'A1', + $worksheet->getHighestDataColumn() . $worksheet->getHighestDataRow() + ]))->applyFromArray([ + 'borders' => [ + 'allBorders' => [ + 'borderStyle' => Border::BORDER_THIN, //细边框 + ], + ], + ]); + } + if($autoBackground){ + $style = join(':', [ + 'A1', + $worksheet->getHighestDataColumn() . "1" + ]); + + // 列宽 + $worksheet -> getDefaultColumnDimension() -> setWidth(25); + // $worksheet -> getColumnDimension('A') -> setWidth(30); //设置A列宽度为30 + //行高 + // $worksheet -> getRowDimension(1) -> setRowHeight(25); + $worksheet -> getDefaultRowDimension() -> setRowHeight(25); + + //样式设置 - 字体 + $worksheet -> getStyle($style) -> getFont() + // -> setBold(true) + ->setName('微软雅黑') + -> setSize(13); + + //样式设置 - 字体颜色 + // $worksheet -> getStyle('A1') -> getFont() + // -> getColor() -> setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_RED); //设置单元格A1的字体颜色 + + // $font = $worksheet -> getCell('B1') -> getColor() -> setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_RED); + + // if(substr($font,0,1) == "*"){ + + // } + + // $worksheet -> setCellValue('A2', substr($font,0,1) ); + + //样式设置 - 水平、垂直居中 + $styleArray = [ + 'alignment' => [ + 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, + 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER + ], + ]; + $worksheet -> getStyle($style) -> applyFromArray($styleArray); + + //样式设置 - 单元格背景颜色 + $worksheet->getStyle($style)->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setARGB('FFFFFF00'); + } + return $worksheet; + } + + /** + * 数字转字母 + * 1 => A + * + * @param integer $index + * @return string + * @date 2021-01-23 + * @author arw + * @since 1.0.0 + */ + public static function stringToIndex(int $index) + { + return Coordinate::stringFromColumnIndex($index); + } + + /** + * 字母转数字 + * A => 1 + * + * @param string $string + * @return int + * @date 2021-01-23 + * @author arw + * @since 1.0.0 + */ + public static function indexToString(string $string) + { + return Coordinate::columnIndexFromString($string); + } +} diff --git a/app/common/arw/adjfut/src/Exception/ErrorMsg.php b/app/common/arw/adjfut/src/Exception/ErrorMsg.php new file mode 100644 index 0000000..437d9ce --- /dev/null +++ b/app/common/arw/adjfut/src/Exception/ErrorMsg.php @@ -0,0 +1,12 @@ +pivotClass = $pivotClass; + $this->masterClass = $masterClass; + $this->subClass = $subClass; + $this->softDelete = $softDelete; + + $this->pivotPk = (new $pivotClass)->getPk(); + $this->masterPk = (new $masterClass)->getPk(); + $this->subPk = (new $subClass)->getPk(); + } + + /** + * 绑定 + * + * @param array|Collection $masters + * @param array|Collection $subs + * @param array $extra 中间表额外数据 + * @return void + * @date 2022-12-29 + * @example + * @author arw + * @since 1.0.0 + */ + public function bind($masters, $subs, array $extra = []): void + { + $this->_bind($masters, $subs, $extra, false); + } + + /** + * 解绑 + * + * @param array|Collection $masters + * @param array|Collection $subs + * @return void + * @date 2022-12-29 + * @example + * @author arw + * @since 1.0.0 + */ + public function unbind(array $masters, array $subs): void + { + $masters = self::formatModel($masters, $this->masterClass); + $subs = self::formatModel($subs, $this->subClass); + + $pivotClass = $this->pivotClass; + + $pivotPk = $this->pivotPk; + $masterPk = $this->masterPk; + $subPk = $this->subPk; + + foreach ($masters as $master) { + // 查询已绑定的数据 + $subPks = $pivotClass::where([ + $masterPk => $master->$masterPk + ])->column($subPk); + foreach ($subs as $sub) { + if (in_array($sub->$subPk, $subPks)) { + $pivotClass::where([ + $subPk => $sub->$subPk, + $masterPk => $master->$masterPk + ])->field([ + $pivotPk + ])->select()->delete(); + } + } + } + } + + /** + * 重新绑定 + * + * @param array|Collection $masters + * @param array|Collection $subs + * @param array $extra 中间表额外数据 + * @return void + * @date 2022-12-29 + * @example + * @author arw + * @since 1.0.0 + */ + public function rebind($masters, $subs, array $extra = []): void + { + $this->_bind($masters, $subs, $extra, true); + } + + /** + * 格式化模型 + * + * @param array|Collection $models + * @param string $class + * @return Collection + * @date 2022-12-29 + * @example + * @author arw + * @since 1.0.0 + */ + private static function formatModel($models, string $class): Collection + { + if ($models instanceof Collection) { + return $models; + } else if (is_array($models)) { + $Collection = new Collection(); + foreach ($models as $model) { + if ($model instanceof $class) { + } else if (is_string($model) || is_numeric($model)) { + $model = $class::find($model); + } + $Collection->push($model); + } + return $Collection; + } else { + throw new ErrorMsg("类型异常", 1); + } + } + + /** + * 绑定数据 + * + * @param array|Collection $masters + * @param array|Collection $subs + * @param array $extra + * @param boolean $rebind + * @return void + * @date 2022-12-29 + * @example + * @author arw + * @since 1.0.0 + */ + private function _bind($masters, $subs, array $extra = [], bool $rebind = false) + { + $masters = self::formatModel($masters, $this->masterClass); + $subs = self::formatModel($subs, $this->subClass); + + $pivotClass = $this->pivotClass; + + $softDelete = $this->softDelete; + + $pivotPk = $this->pivotPk; + $masterPk = $this->masterPk; + $subPk = $this->subPk; + + foreach ($masters as $master) { + if ($rebind) { + $pivots = $pivotClass::where([ + [$masterPk, '=', $master->$masterPk], + [$subPk, 'not in', $subs->column($subPk)], + ])->select(); + if (!$pivots->isEmpty()) { + // 重新绑定 + $this->unbind([$master], $pivots->column($subPk)); + } + } + foreach ($subs as $sub) { + $pivot = null; + if ($softDelete) { + $pivot = $pivotClass::withTrashed()->where([ + $subPk => $sub->$subPk, + $masterPk => $master->$masterPk + ])->find(); + } else { + $pivot = $pivotClass::where([ + $subPk => $sub->$subPk, + $masterPk => $master->$masterPk + ])->find(); + } + if (is_null($pivot) || $pivot->isEmpty()) { + $pivotClass::create($extra + [ + $subPk => $sub->$subPk, + $masterPk => $master->$masterPk + ]); + } else { + if ($softDelete) { + $pivot->restore(); + } + if ($extra) { + $pivotClass::update($extra, [ + $pivotPk => $pivot->$pivotPk + ]); + } + } + } + } + } +} diff --git a/app/common/arw/adjfut/src/PartitionTable.php b/app/common/arw/adjfut/src/PartitionTable.php new file mode 100644 index 0000000..d0e5a71 --- /dev/null +++ b/app/common/arw/adjfut/src/PartitionTable.php @@ -0,0 +1,261 @@ +originTable = $table; + $this->targetTable = join('_', [$table, $suffix]); + + $this->checkTargetTable(); + } + + /** + * 是否锁表 + * + * @param boolean|string $lock + * @return self + * @date 2023-01-04 + * @example + * @author arw + * @since 1.0.0 + */ + public function setLockTable($lock): self + { + $this->lockTable = $lock; + return $this; + } + + /** + * 设置唯一字段(设置后将删除原表数据) + * + * @param string $uniqueField + * @date 2022-03-24 + * @example + * @author arw + * @since 1.0.0 + */ + public function setUniqueField(string $uniqueField): self + { + $this->uniqueField = $uniqueField; + return $this; + } + + /** + * 设置查询条件 + * + * @param callable $cb + * @date 2022-03-24 + * @example + * @author arw + * @since 1.0.0 + */ + public function setQuery(callable $cb): self + { + $this->query = call_user_func($cb, $this->getOriginDb()); + return $this; + } + + /** + * 跨月查询 + * + * @param string $table + * @param string $field 字段 + * @param array $option + * @param array $option[start] 开始时间 Y-m-d H:i:s + * @param array $option[end] 结束时间 Y-m-d H:i:s + * @date 2022-04-06 + * @example + * @author arw + * @since 1.0.0 + */ + public static function queryForMonth(string $table, string $field, array $option): Query + { + $start = Arr::get($option, 'start'); + $end = Arr::get($option, 'end'); + if (!$start || !$end) { + throw new \Exception("缺少时间限制", 1); + } + $result = Db::query("SHOW TABLES LIKE '${table}_%'"); + $tables = []; + foreach ($result as $value) { + $tables = array_merge($tables, array_values($value)); + } + $startYm = date('Ym', strtotime($start)); + $endYm = date('Ym', strtotime($end)); + $months = []; + $months[] = $startYm; + + if ($startYm != $endYm) { + $current = $startYm; + while (true) { + $current = date('Ym', strtotime($current . "01 +1month")); + $months[] = $current; + if ($current === $endYm) { + break; + } + } + // $months[] = $endYm; + } + + $temp = array_filter($tables, function ($v) use ($table, $months) { + return in_array(explode("${table}_", $v)[1], $months); + }); + + $query = Db::table(in_array(date('Ym'), $months) ? $table : array_shift($temp)); + + $query->union(array_map(function ($v) { + return Db::name($v)->fetchSql()->select(); + }, $temp)); + + return Db::table(join(' ', [ + $query->buildSql(), + $table + ]))->whereBetweenTime($field, $start, $end); + } + + /** + * 迁移数据 + * + * @date 2022-03-24 + * @example + * @author arw + * @since 1.0.0 + */ + public function save() + { + Db::startTrans(); + try { + $lockTable = $this->lockTable; + if ($lockTable) { + $this->getOriginDb()->lock($lockTable)->select(); + $this->getTargetDb()->lock($lockTable)->select(); + } + + $target = $this->targetTable; + $originSql = $this->query->fetchSql()->select(); + $result = Db::execute("REPLACE INTO `$target` $originSql;"); + if ($result === false) { + throw new \Exception("迁移数据失败", 1); + } + + $uniqueField = $this->uniqueField; + if ($uniqueField) { + $this->getTargetDb()->field([ + $uniqueField + ])->chunk(500, function (Collection $ids) use ($uniqueField) { + $this->getOriginDb()->whereIn( + $uniqueField, + $ids->column($uniqueField) + )->delete(); + }, $uniqueField); + } + Db::commit(); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 获取原始表 + * + * @date 2022-03-24 + * @example + * @author arw + * @since 1.0.0 + */ + private function getOriginDb(): Query + { + return Db::name($this->originTable); + } + + /** + * 获取目标表 + * + * @date 2022-03-24 + * @example + * @author arw + * @since 1.0.0 + */ + private function getTargetDb(): Query + { + return Db::name($this->targetTable); + } + + /** + * 检查目标表 + * + * @return void + * @date 2022-03-24 + * @example + * @author arw + * @since 1.0.0 + */ + private function checkTargetTable(): void + { + if (!in_array($this->targetTable, Db::getTables())) { + $origin = $this->originTable; + $target = $this->targetTable; + $result = Db::execute("CREATE TABLE `$target` LIKE `$origin`"); + if ($result === false) { + throw new \Exception("创建迁移表失败", 1); + } + } + } +} diff --git a/app/common/arw/adjfut/src/ReTry.php b/app/common/arw/adjfut/src/ReTry.php new file mode 100644 index 0000000..58a482a --- /dev/null +++ b/app/common/arw/adjfut/src/ReTry.php @@ -0,0 +1,250 @@ +setHandle($handle); + $ins->setLimit($limit); + return $ins; + } + /** + * 自增 + * + * @param integer $step 步长 + * @return self + * @date 2022-12-28 + * @example + * @author arw + * @since 1.0.0 + */ + public function inc(int $step = 1): self + { + $this->limit += $step; + return $this; + } + /** + * 自减 + * + * @param integer $step + * @return self + * @date 2022-12-28 + * @example + * @author arw + * @since 1.0.0 + */ + public function dec(int $step = 1): self + { + $this->limit -= $step; + return $this; + } + + /** + * 获取执行次数 + * + * @return integer + * @date 2022-12-30 + * @example + * @author arw + * @since 1.0.0 + */ + public function getCount(): int + { + return $this->count; + } + + /** + * 获取执行上限 + * + * @return integer + * @date 2022-12-28 + * @example + * @author arw + * @since 1.0.0 + */ + public function getLimit(): int + { + return $this->limit; + } + + /** + * 设置执行上限 + * + * @param integer $limit + * @return self + * @date 2022-12-28 + * @example + * @author arw + * @since 1.0.0 + */ + public function setLimit(int $limit): self + { + $this->limit = $limit; + $this->last_limit = $limit; + return $this; + } + + /** + * 设置执行器 + * + * @param callable $cb + * @return self + * @date 2022-12-28 + * @example + * @author arw + * @since 1.0.0 + */ + public function setHandle(callable $cb): self + { + $this->handle = $cb; + return $this; + } + + /** + * 执行是否成功 + * + * @param boolean $success + * @return self + * @date 2022-12-28 + * @example + * @author arw + * @since 1.0.0 + */ + public function success(bool $success): self + { + $this->success = $success; + return $this; + } + + /** + * 重试上限 + * + * @param callable $cb + * @return self + * @date 2022-12-28 + * @example + * @author arw + * @since 1.0.0 + */ + public function onRetryMax(callable $cb): self + { + $this->event('reTryMax', $cb); + return $this; + } + + /** + * 执行异常 + * + * @param callable $cb + * @return self + * @date 2022-12-30 + * @example + * @author arw + * @since 1.0.0 + */ + public function onError(callable $cb): self + { + $this->event('error', $cb); + return $this; + } + + /** + * 执行 + * + * @param mixed ...$args + * @return void + * @date 2022-12-30 + * @example + * @author arw + * @since 1.0.0 + */ + public function run(...$args) + { + $this->reset(); + array_unshift($args, $this); + $handle = $this->handle; + $res = null; + while (true) { + try { + $res = call_user_func_array($handle, $args); + } catch (\Throwable $th) { + $this->trigger('error', [$th]); + } + $this->count++; + // 执行成功 + if ($this->success) { + break; + } + // 执行上限 + if ($this->count > $this->limit) { + // 不减1会导致 获取到的执行次数多1 + $this->count--; + $this->trigger('reTryMax'); + break; + } + } + return $res; + } + + /** + * 重置执行器 + * + * @return void + * @date 2022-12-30 + * @example + * @author arw + * @since 1.0.0 + */ + private function reset(): void + { + $this->count = 1; + $this->setLimit($this->last_limit); + } +} diff --git a/app/common/arw/adjfut/src/Service/Validate.php b/app/common/arw/adjfut/src/Service/Validate.php new file mode 100644 index 0000000..514bdf4 --- /dev/null +++ b/app/common/arw/adjfut/src/Service/Validate.php @@ -0,0 +1,68 @@ +extend('string', function ($value) { + return is_string($value); + }, ':attribute 数据类型非法 不是字符串'); + + $validate->extend('json', function ($value) { + try { + $value = json_decode($value, true); + return is_array($value); + } catch (\Throwable $th) { + // throw $th; + } + return false; + }, ':attribute 数据格式错误 不是json字符串'); + + $validate->extend('modelHas', function ($value, $rule) { + $rules = explode(',', $rule); + $class = Arr::get($rules, 0); + $pk = Arr::get($rules, 1); + if (!class_exists($class)) { + throw new ErrorMsg("$class 类不存在"); + } + /** + * @var \think\Model + */ + $model = new $class; + if (!($model instanceof Model)) { + throw new ErrorMsg("$class 该类未继承 \\think\\Model"); + } + if (!$pk) { + $pk = $model->getPk(); + } + return (bool) $model->where($pk, $value)->value($pk); + }, ':attribute 数据不存在'); + }); + } +} diff --git a/app/common/arw/adjfut/src/Tool.php b/app/common/arw/adjfut/src/Tool.php new file mode 100644 index 0000000..10c7770 --- /dev/null +++ b/app/common/arw/adjfut/src/Tool.php @@ -0,0 +1,196 @@ +$type(json_encode($data, JSON_UNESCAPED_UNICODE)); + } + + /** + * 字段映射 + * + * @param array $data + * @param array $map + * @param array $options + * @return array + * @date 2022-06-23 + * @example + * @author arw + * @since 1.0.0 + */ + public static function fieldMap(array $data, array $map, array $options = []): array + { + $prefix = Arr::get($options, 'prefix', ''); + $result = []; + foreach ($data as $key => $value) { + if (isset($map[$key])) { + $key = $map[$key]; + } + if ($prefix) { + $key = $prefix . $key; + } + $result[$key] = $value; + } + return $result; + } + + /** + * 转换日期格式 + * + * @param string $datetime + * @param string $format + * @return string + * @date 2022-04-20 + * @example + * @author arw + * @since 1.0.0 + */ + public static function conversionDateTime($datetime, string $format): string + { + try { + $date = new DateTime($datetime); + return $date->format($format); + } catch (\Throwable $th) { + throw new ErrorMsg('日期格式非法', 1); + } + } + + /** + * 生成唯一id + * + * @param string|array $value + * @return string + * @date 2022-03-24 + * @example + * @author arw + * @since 1.0.0 + */ + public static function generateGuid($value = ''): string + { + $str = ''; + if (is_array($value)) { + $str = json_encode($value); + } + $charid = strtolower(md5($str . uniqid('', true))); + $hyphen = chr(45); // '-' + $uuid = //chr(123)// '{' + substr($charid, 0, 8) . $hyphen + . substr($charid, 8, 4) . $hyphen + . substr($charid, 12, 4) . $hyphen + . substr($charid, 16, 4) . $hyphen + . substr($charid, 20, 12); + //.chr(125);// '}' + return $uuid; + } + + + /** + * 清空(擦除)缓冲区并关闭输出缓冲 + * + * @return void + */ + public static function obEndClean(): void + { + try { + while (ob_get_level() > 0) { + ob_end_clean(); + } + } catch (\Throwable $th) { + //throw $th; + } + } + + /** + * 自动创建文件夹 + * + * @param string $path 文件夹路径 + * @param integer $mode 权限 + * @return boolean + */ + public static function mkdir(string $path, int $mode = 0755): bool + { + $path = str_replace('/', DIRECTORY_SEPARATOR, $path); + $temp = explode(DIRECTORY_SEPARATOR, $path); + if (preg_match("/\./", end($temp))) { + // pathinfo 不支持中文 + // $path = pathinfo($path, PATHINFO_DIRNAME); + array_splice($temp, count($temp) - 1, 1); + $path = join(DIRECTORY_SEPARATOR, $temp); + } + if (!file_exists($path)) { + mkdir($path, $mode, true); + } + chmod($path, $mode); + return true; + } +} diff --git a/app/common/arw/adjfut/src/Traits/Dictionary.php b/app/common/arw/adjfut/src/Traits/Dictionary.php new file mode 100644 index 0000000..2d3ab09 --- /dev/null +++ b/app/common/arw/adjfut/src/Traits/Dictionary.php @@ -0,0 +1,223 @@ + &$dictionary) { + list($field, $title) = self::getDictionaryField($field); + if (in_array($field, $ignoreField)) { + continue; + } + $value = $this->$field; + if (is_null($value) && $ignoreNull) { + continue; + } + $dictionary = self::getDictionaryFieldMap($field); + $keys = array_keys($dictionary); + if (!in_array($value, $keys)) { + $values = array_values($dictionary); + $msg = join(',', $values); + $errors[] = "$title 应在[ $msg ]"; + } + unset($dictionary); + } + if ($errors) { + throw new ValidateException($errors); + } + } + + /** + * 获取字典值 + * + * @param string $field 字段 + * @param mixed $value 设置器内调用无法会无法获取当前值 需要手动传入 + * @return mixed + * @date 2023-01-11 + * @example + * @author arw + * @since 1.0.0 + */ + public function getDictionaryValue(string $field, $value = null) + { + $map = self::getDictionaryFieldMap($field); + if (is_null($value)) { + $value = $this->$field; + } + if (isset($map[$value])) { + return $value; + } + $key = array_search($value, $map); + if ($key === false) { + $msg = join(',', array_values($map)); + throw new ErrorMsg("$field 应在[ $msg ]", 1); + } + return $key; + } + + /** + * 获取字典名称 + * + * @param string $field 字段 + * @param mixed $default 默认值 如果默认值在字典值内 则返回字典名称 + * @return mixed + * @date 2023-01-11 + * @example + * @author arw + * @since 1.0.0 + */ + public function getDictionaryName(string $field, $default = null) + { + $map = self::getDictionaryFieldMap($field); + if (isset($map[$default])) { + $default = $map[$default]; + } + return Arr::get($map, $this->$field, $default); + } + + /** + * 获取字典名称(弃用保留兼容) + * 请调用 getDictionaryName + * + * @param string $field 字段 + * @param mixed $default 默认值 + * @deprecated 1.0.0 + * @return mixed + * @date 2023-01-10 + * @example + * @author arw + * @since 1.0.0 + */ + public function getDictionaryText(string $field, $default = null) + { + return $this->getDictionaryName($field, $default); + } + + /** + * 获取字典字段映射 + * + * @param string $field 字段 + * @return array + * @date 2023-01-10 + * @example + * @author arw + * @since 1.0.0 + */ + public static function getDictionaryFieldMap(string $field): array + { + list($field) = self::getDictionaryField($field); + $cache = Arr::get(self::$dictionaryCache, $field); + if (is_array($cache)) { + return $cache; + } + $map = Arr::get(self::getDictionaryMap(), $field); + if (!$map) { + throw new ErrorMsg("未定义字段映射", 1); + } + if (is_array($map)) { + self::$dictionaryCache[$field] = $map; + return self::$dictionaryCache[$field]; + } + if (is_string($map)) { + self::$dictionaryCache[$field] = self::getDictionaryModelMap($map); + return self::$dictionaryCache[$field]; + } + return []; + } + + /** + * 获取字典映射 + * + * @return array + * @date 2023-01-10 + * @example + * @author arw + * @since 1.0.0 + */ + public static function getDictionaryMap(): array + { + $self = new self; + $exists = property_exists($self, 'dictionaryMap') && isset($self::$dictionaryMap); + return $exists ? $self::$dictionaryMap : []; + } + + /** + * 获取字典字段 + * + * @param string $value + * @return array + * @date 2023-01-13 + * @example + * @author arw + * @since 1.0.0 + */ + private static function getDictionaryField(string $value): array + { + $temp = explode('|', $value); + $field = Arr::get($temp, '0'); + $title = Arr::get($temp, '1', $field); + return [$field, $title]; + } +} diff --git a/app/common/arw/adjfut/src/Traits/Event.php b/app/common/arw/adjfut/src/Traits/Event.php new file mode 100644 index 0000000..fa7c3f0 --- /dev/null +++ b/app/common/arw/adjfut/src/Traits/Event.php @@ -0,0 +1,62 @@ +event[strtoupper($type)] = $cb; + return $this; + } + + /** + * 事件触发器 + * + * @param string $type + * @param array $args + * @param boolean $withThis + * @return mixed + * @date 2022-12-28 + * @example + * @author arw + * @since 1.0.0 + */ + private function trigger(string $type, array $args = [], bool $withThis = true) + { + $type = strtoupper($type); + if (isset($this->event[$type])) { + if ($withThis) { + array_unshift($args, $this); + } + return call_user_func_array($this->event[$type], $args); + } + } +} diff --git a/app/common/arw/adjfut/src/Traverse.php b/app/common/arw/adjfut/src/Traverse.php new file mode 100644 index 0000000..2ceb857 --- /dev/null +++ b/app/common/arw/adjfut/src/Traverse.php @@ -0,0 +1,240 @@ +current = $current; + $this->parent = $parent; + $this->children = $children; + } + + /** + * 获取子集 + * @access public + * @param array $data 要遍历的数组 + * @param integer|string $id 要查找哪个id下的子集 + * @param bool $loop 是否循环遍历 + * @return array + */ + public function next(array $data = [], $id = 0, bool $loop = false): array + { + $this->setData($data); + $this->setLoop($loop); + return $this->generateNext($id); + } + + /** + * 获取父集 + * @access public + * @param array $data 要遍历的数组 + * @param integer|string $id 要查找哪个id下的父集 + * @param bool $loop 是否循环遍历 + * @return array + */ + public function prev(array $data = [], $id = 0, bool $loop = false): array + { + $this->setData($data); + $this->setLoop($loop); + return $this->generatePrev($id); + } + + /** + * 获取无限层级树状图 + * + * @param array $data 要遍历的数组 + * @param integer|string $parent_id 起点id + * @param callable $format 自定义树数据 + * @return array + * @date 2020-04-09 + * @example + * @author arw + * @since 1.0.0 + */ + public function tree(array $data, $parent_id, callable $format): array + { + $this->setData($data); + $this->setFormat($format); + return $this->generateTree($parent_id); + } + + /** + * 获取全部子集数据 + * + * @param integer|string $id + * @return array + * @date 2022-08-08 + * @example + * @author arw + * @since 1.0.0 + */ + public function getCurrentData($id): array + { + $data = array_filter($this->data, function ($v) use ($id) { + return $v[$this->current] == $id; + }); + $data = array_values($data); + return $data; + } + + /** + * 获取全部父集数据 + * + * @param integer|string $id + * @return array + * @date 2022-08-08 + * @example + * @author arw + * @since 1.0.0 + */ + public function getParentData($id): array + { + $data = array_filter($this->data, function ($v) use ($id) { + return $v[$this->parent] == $id; + }); + $data = array_values($data); + return $data; + } + + /** + * 设置循环 + * + * @param boolean $loop + * @return self + * @date 2022-08-08 + * @example + * @author arw + * @since 1.0.0 + */ + public function setLoop(bool $loop): self + { + $this->loop = $loop; + return $this; + } + + /** + * 设置数据 + * + * @param array $data + * @return self + * @date 2022-08-08 + * @example + * @author arw + * @since 1.0.0 + */ + public function setData(array $data): self + { + $this->data = $data; + return $this; + } + + /** + * 设置格式化函数 + * + * @param callable $cb + * @return self + * @date 2022-08-08 + * @example + * @author arw + * @since 1.0.0 + */ + public function setFormat(callable $cb): self + { + $this->format = $cb; + return $this; + } + + /** + * 生成树 + * + * @param integer|string $parent_id + * @return array + * @date 2022-08-08 + * @example + * @author arw + * @since 1.0.0 + */ + public function generateTree($parent_id): array + { + $data = $this->getParentData($parent_id); + foreach ($data as &$value) { + $children = $this->generateTree($value[$this->current]); + $value[$this->children] = $children; + if (is_callable($this->format)) { + $formatReturn = call_user_func($this->format, $value); + if (!isset($formatReturn[$this->children])) { + $formatReturn[$this->children] = $children; + } + if ($formatReturn) { + $value = $formatReturn; + } + } + unset($value); + } + return $data; + } + + /** + * 获取子集 + * + * @param integer|string $id + * @return array + * @date 2022-08-08 + * @example + * @author arw + * @since 1.0.0 + */ + public function generateNext($id): array + { + $re = []; + $data = $this->getParentData($id); + foreach ($data as $value) { + $current = $value[$this->current]; + $re[] = $current; + if ($this->loop) { + $re = array_merge($re, $this->generateNext($current)); + } + } + return array_unique($re); + } + + + /** + * 获取父集 + * + * @param integer|string $id + * @return array + * @date 2022-08-08 + * @example + * @author arw + * @since 1.0.0 + */ + public function generatePrev($id): array + { + $re = []; + $data = $this->getCurrentData($id); + foreach ($data as $value) { + $parent = $value[$this->parent]; + $re[] = $parent; + if ($this->loop) { + $re = array_merge($re, $this->generatePrev($parent)); + } + } + return array_unique($re); + } +} diff --git a/app/common/arw/adjfut/src/Unit/File.php b/app/common/arw/adjfut/src/Unit/File.php new file mode 100644 index 0000000..87c8072 --- /dev/null +++ b/app/common/arw/adjfut/src/Unit/File.php @@ -0,0 +1,86 @@ += self::INTERVAL && $i < 4; $i++) { + $size = bcdiv($size, self::INTERVAL); + } + return round($size, 2) . self::ORDER[$i]; + } + + public static function __callStatic($name, $arguments) + { + $number = Arr::get($arguments, 0, 0); + $scale = Arr::get($arguments, 1, 0); + $name = Str::lower($name); + $a = null; + $b = null; + if (Str::contains($name, 2)) { + list($a, $b) = explode('2', $name); + } else { + list($a, $b) = explode('to', $name); + } + $a_index = array_search($a, self::ORDER); + $b_index = array_search($b, self::ORDER); + $type = $a_index < $b_index; + for ($i = 0; $i < abs(bcsub($a_index, $b_index, 0)); $i++) { + if ($type) { + $number = bcdiv($number, self::INTERVAL, $scale); + } else { + $number = bcmul($number, self::INTERVAL, $scale); + } + } + return $number; + } +} diff --git a/app/common/arw/adjfut/src/UploadFile.php b/app/common/arw/adjfut/src/UploadFile.php new file mode 100644 index 0000000..ccb0ac4 --- /dev/null +++ b/app/common/arw/adjfut/src/UploadFile.php @@ -0,0 +1,289 @@ + $file + ], [ + 'file|文件' => $validate + ]); + } catch (ValidateException $th) { + $this->getDisk()->delete($file->getFilename()); + throw $th; + } + } + + $this->diskName = $diskName; + $this->file = $file; + } + + /** + * 上传base64图片 + * + * @param string $diskName 磁盘 + * @param string $base64 base64 + * @return self + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public static function uploadBase64Image( + string $diskName, + string $base64 + ): self { + $Base64 = new Base64($base64); + if (!$Base64->isImage()) { + throw new ErrorMsg("非法图片base64", 1); + } + $path = tempnam(sys_get_temp_dir(), 'saveBase64Image'); + $Base64->saveImage($path); + $name = md5(md5_file($path) . Tool::generateGuid() . time()) . '.' . $Base64->getFileExt(); + return new self($diskName, '', [ + $path, + $name + ]); + } + + /** + * 获取文件 + * + * @return UploadedFile + * @date 2022-07-05 + * @example + * @author arw + * @since 1.0.0 + */ + public function getFile(): UploadedFile + { + return $this->file; + } + + /** + * 获取磁盘名称 + * + * @return string + * @date 2022-07-05 + * @example + * @author arw + * @since 1.0.0 + */ + public function getDiskName(): string + { + return $this->diskName; + } + + /** + * 获取配置项 + * + * @param string $key + * @param mixed $default + * @return mixed + * @date 2022-04-15 + * @example + * @author arw + * @since 1.0.0 + */ + public function getConfig(string $key, $default = null) + { + return Arr::get( + Filesystem::getDiskConfig($this->diskName), + $key, + $default + ); + } + + /** + * 获取文件相对路径 + * + * @date 2022-04-15 + * @example + * @author arw + * @since 1.0.0 + */ + public function getPath(): string + { + if (!$this->path) { + throw new ErrorMsg("请保存文件后使用", 1); + } + return $this->path; + } + + /** + * 获取文件真实路径 + * + * @return string + * @date 2022-07-19 + * @example + * @author arw + * @since 1.0.0 + */ + public function getRealPath(): string + { + $path = $this->getPath(); + if ($this->getConfig('type') != 'local') { + throw new ErrorMsg("非本地文件类型 无法获取真实路径", 1); + } + return str_replace(['\\', '/'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $this->getConfig('root') . DIRECTORY_SEPARATOR . $path); + } + + /** + * 获取文件绝对路径 + * + * @date 2022-04-15 + * @deprecated 1.0.0 + * @example + * @author arw + * @since 1.0.0 + */ + public function getFullPath(): string + { + return $this->getRealPath(); + } + + /** + * 保存文件 + * @param string $path 路径 + * @param null|string|\Closure $rule 文件名规则 + * @param array $options 参数 + * @return string + */ + public function putFile( + string $path, + $rule = null, + array $options = [] + ): string { + $this->path = $this->getDisk()->putFile( + $path, + $this->file, + $rule, + $options + ); + if (!$this->path) { + throw new ErrorMsg("文件保存失败", 1); + } + return $this->path; + } + + /** + * 指定文件名保存文件 + * @param string $path 路径 + * @param string $name 文件名 + * @param array $options 参数 + * @return string + */ + public function putFileAs( + string $path, + string $name = '', + array $options = [] + ): string { + $this->path = $this->getDisk()->putFileAs( + $path, + $this->file, + $name, + $options + ); + if (!$this->path) { + throw new ErrorMsg("文件保存失败", 1); + } + return $this->path; + } + + /** + * 删除文件 + * + * @return void + * @date 2022-08-22 + * @example + * @author arw + * @since 1.0.0 + */ + public function delete(): void + { + $this->getDisk()->delete($this->file->getFilename()); + } + + /** + * 移除文件 + * + * @date 2022-04-15 + * @deprecated 1.0.0 + * @example + * @author arw + * @since 1.0.0 + */ + public function unlink(): void + { + $this->delete(); + } + + /** + * 获取存储配置 + * + * @return Driver + * @date 2022-04-15 + * @example + * @author arw + * @since 1.0.0 + */ + public function getDisk(): Driver + { + return Filesystem::disk($this->diskName); + } +} diff --git a/app/common/arw/adjfut/src/Validate.php b/app/common/arw/adjfut/src/Validate.php new file mode 100644 index 0000000..bd598b8 --- /dev/null +++ b/app/common/arw/adjfut/src/Validate.php @@ -0,0 +1,254 @@ +data = $data; + return $this; + } + + /** + * 当条件满足时 验证 + * + * @param array $when + * @param array $validate + * @param array $message + * @param bool $batch + * @return void + */ + public function when(array $when, array $validate, array $message = [], bool $batch = true): void + { + $data = $this->data; + $whenCount = 0; + foreach ($when as $field => $value) { + if (!isset($data[$field])) { + continue; + } + if ($data[$field] == $value) { + $whenCount++; + } + } + $_validate = $whenCount == count($when); + if ($_validate) { + self::check($data, $validate, $message, $batch); + } + } + + /** + * 验证是否唯一 + * + * @param string $model 模型类 + * @param string|int $id 排除主键id + * @param array $rules[field] => name,validateField,pk|其他规则 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return void + * @throws ValidateException + */ + public static function unique( + string $model, + $id, + array $data, + array $rules = [], + array $message = [], + bool $batch = true + ): void { + $_rules = []; + foreach ($rules as $field => $validate) { + $validates = explode('|', $validate); + $_rule = explode(',', $validates[0]); + $name = Arr::get($_rule, 0); + $validateField = Arr::get($_rule, 1); + $pk = Arr::get($_rule, 2); + + $validates[0] = self::createUniqueRule($model, [ + 'field' => $validateField ?: $field, + 'id' => $id, + 'pk' => $pk, + ]); + + $_rules[$field . ($name ? "|$name" : '')] = $validates; + } + self::check($data, $_rules, $message, $batch); + } + + /** + * 创建数据表唯一验证 + * + * @param string $class 模型类 + * @param array $options 配置项 + * @param string $options[field] 字段名 + * @param string $options[id] 排除ID + * @param string $options[pk] 主键名 + * @return string + * @date 2022-04-16 + * @example + * @author arw + * @since 1.0.0 + */ + public static function createUniqueRule(string $class, array $options = []): string + { + $field = Arr::get($options, 'field'); + $id = Arr::get($options, 'id'); + $pk = Arr::get($options, 'pk'); + if (!$field) { + throw new ErrorMsg("字段名不能为空", 1); + } + return 'unique:' . join(',', [ + $class, + $field, + $id, + $pk + ]); + } + + /** + * 类场景验证 + * + * @param string $validate + * @param string $scene + * @param boolean $batch + * @return void + * @throws ValidateException + */ + public static function classScene(array $validate, array $data, bool $batch = true): void + { + list($class, $scene) = $validate; + /** + * @var ThinkValidate + */ + $validate = new $class; + $validate->scene($scene)->batch($batch); + $validate->failException(true)->check($data); + } + + /** + * 类场景验证 param参数 + * + * @param array $validate + * @param boolean $batch + * @return array + * @throws ValidateException + */ + public static function classSceneParam(array $validate, bool $batch = true): array + { + $data = Request::param(); + self::classScene($validate, $data, $batch); + return $data; + } + + + /** + * 类场景验证 get参数 + * + * @param array $validate + * @param boolean $batch + * @return array + * @throws ValidateException + */ + public static function classSceneGet(array $validate, bool $batch = true): array + { + $data = Request::get(); + self::classScene($validate, $data, $batch); + return $data; + } + + /** + * 类场景验证 post参数 + * + * @param array $validate + * @param boolean $batch + * @return array + * @throws ValidateException + */ + public static function classScenePost(array $validate, bool $batch = true): array + { + $data = Request::post(); + self::classScene($validate, $data, $batch); + return $data; + } + + /** + * param参数验证 + * + * @param array $validate 验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return array + * @throws ValidateException + */ + public static function param(array $validate, array $message = [], bool $batch = true): array + { + $data = Request::param(); + self::check($data, $validate, $message, $batch); + return $data; + } + + /** + * get参数验证 + * + * @param array $validate 验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return array + * @throws ValidateException + */ + public static function get(array $validate, array $message = [], bool $batch = true): array + { + $data = Request::get(); + self::check($data, $validate, $message, $batch); + return $data; + } + + + /** + * post参数验证 + * + * @param array $validate 验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return array + * @throws ValidateException + */ + public static function post(array $validate, array $message = [], bool $batch = true): array + { + $data = Request::post(); + self::check($data, $validate, $message, $batch); + return $data; + } + + /** + * 验证数据 + * + * @param array $data 数据 + * @param array $validate 验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return void + * @throws ValidateException + */ + public static function check(array $data, array $validate, array $message = [], bool $batch = true): void + { + $v = new ThinkValidate(); + $v->rule($validate); + $v->message($message); + $v->batch($batch); + $v->failException(true)->check($data); + } +} diff --git a/app/common/arw/adjfut/src/WeChat/Config.php b/app/common/arw/adjfut/src/WeChat/Config.php new file mode 100644 index 0000000..3480c6e --- /dev/null +++ b/app/common/arw/adjfut/src/WeChat/Config.php @@ -0,0 +1,123 @@ + '', + 'server_base' => '', + // 小程序配置 + 'xcx' => [ + 'appid' => '', + 'secret' => '', + + 'cache_key' => '', + 'log_channel' => '', + ], + // 公众号配置 + 'gzh' => [ + 'appid' => '', + 'secret' => '', + // 推送模板 + 'template' => [ + '模板名称' => '模板id' + ], + + 'cache_key' => '', + 'log_channel' => '', + ], + ]; + + public function __construct() + { + $setConfig = function (string $key) { + $this->setConfig($key, FacadeConfig::get("wechat.$key")); + }; + foreach ([ + 'access_key', 'server_base', + 'xcx.cache_key', 'xcx.log_channel', + 'xcx.appid', 'xcx.secret', + 'gzh.cache_key', 'gzh.log_channel', + 'gzh.appid', 'gzh.secret', 'gzh.template' + ] as $key) { + $setConfig($key); + } + } + + /** + * 实例 + * + * @return self + * @date 2022-05-19 + * @example + * @author arw + * @since 1.0.0 + */ + public static function instance(): self + { + if (!self::$instance) { + self::$instance = new self; + } + return self::$instance; + } + + /** + * 设置配置项 + * + * @param string $key + * @param mixed $value + * @return void + * @date 2022-05-19 + * @example + * @author arw + * @since 1.0.0 + */ + public function setConfig(string $key, $value) + { + Arr::set($this->config, $key, $value); + } + + /** + * 获取配置项 + * + * @param string $key + * @param mixed $default + * @return mixed + * @date 2022-05-19 + * @example + * @author arw + * @since 1.0.0 + */ + public static function get(string $key, $default = null) + { + return Arr::get( + self::instance()->config, + $key, + $default + ); + } +} diff --git a/app/common/arw/adjfut/src/WeChat/Gzh.php b/app/common/arw/adjfut/src/WeChat/Gzh.php new file mode 100644 index 0000000..2384443 --- /dev/null +++ b/app/common/arw/adjfut/src/WeChat/Gzh.php @@ -0,0 +1,348 @@ +_AccessToken($refresh); + } + + /** + * 获取JsApiTicket + * + * @param boolean $refresh 是否强制刷新 + * @return void + * @date 2020-05-29 + * @example + * @author arw + * @since 1.0.0 + */ + public function GetJsApiTicket($refresh = false) + { + return $this->_JsApiTicket($refresh); + } + + /** + * 网页授权/获取用户基本信息 + * https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html + * @param array $config 配置项 [ + * "scope" => "snsapi_base", 应用授权作用域, + * snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid), + * snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 ) + * "state" => "", 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节 + * "lang" => "zh_CN", 当scope等于snsapi_userinfo才生效 + * 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语 + * ] + * @param callable $success 回调用户授权成功调用函数 ($userinfo,$state) + * @param callable $error 执行错误回调 ($msg) + * @return null + */ + public function authorize(array $config, callable $success, callable $error) + { + try { + $config["scope"] = Arr::get($config, "scope", "snsapi_base"); + $config["state"] = Arr::get($config, "state", ""); + $config["lang"] = Arr::get($config, "lang", "zh_CN"); + + $config["redirect_uri"] = Arr::get($config, "redirect_uri", Request::url(true)); + + $code = Arr::get($_GET, "code"); + + if (!$code) { + $url = "https://open.weixin.qq.com/connect/oauth2/authorize"; + $url .= "?" . http_build_query([ + "appid" => $this->appid, + "redirect_uri" => $config["redirect_uri"], + "response_type" => "code", + "scope" => $config["scope"], + "state" => $config["state"], + ]); + $url .= "#wechat_redirect"; + return Response::create($url, 'redirect', 302); + } + $curl = Curl::instance(); + $param = []; + $param["appid"] = $this->appid; + $param["secret"] = $this->secret; + $param["code"] = $code; + $param["grant_type"] = "authorization_code"; + $url = "https://api.weixin.qq.com/sns/oauth2/access_token"; + $access_token = $curl->setParams($param)->get($url); + + $judge = (Arr::get($access_token, "access_token") && Arr::get($access_token, "openid")); + if (!$judge || !$access_token) { + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getParams(), + 'content' => $curl->getContent(), + 'msg' => '获取access_token失败', + ], 'error'); + return $error("获取access_token失败"); + } + if ($config["scope"] === "snsapi_userinfo") { + $curl = Curl::instance(); + $url = "https://api.weixin.qq.com/sns/userinfo"; + $param = []; + $param["access_token"] = Arr::get($access_token, "access_token"); + $param["openid"] = Arr::get($access_token, "openid"); + $param["lang"] = $config["lang"]; + $user_info = $curl->setParams($param)->get($url); + $errcode = Arr::get($user_info, "errcode", false); + if ($errcode !== false) { + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getParams(), + 'result' => $curl->getContent(), + 'msg' => '获取用户信息失败', + ], 'error'); + return $error("获取微信用户信息失败"); + } + $access_token = array_merge($access_token, $user_info); + } + return $success($access_token, $_GET["state"]); + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + return $error($th->getMessage()); + } + } + + /** + * 微信模板消息推送 + * 微信返回errcode等于40001会更新缓存AccessToken + * 并重新推送一次 + * https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html#5 + * @param string $touser 推送给谁 + * @param string $template_id 模板名称 + * @param array $data 推送数据 + * [ + * "touser" => "openid", + * "template_id" => "template_id", + * "url" => "url", + * "miniprogram" => [ + * "appid" => "appid", + * "pagepath" => "pagepath", + * ], + * "data" => [ + * "first" => [ + * "value" => "value", + * "color" => "color", + * ], + * "keyword1" => [ + * "value" => "value", + * "color" => "color", + * ], + * "keyword2" => [ + * "value" => "value", + * "color" => "color", + * ], + * "keyword3" => [ + * "value" => "value", + * "color" => "color", + * ], + * "remark" => [ + * "value" => "value", + * "color" => "color", + * ], + * ], + * ] + * @param boolean $refresh 是否刷新【 access_token 】 + * @param integer $limit 调用上限(允许自动重试次数) + * @return bool + * @date 2020-05-26 + * @example + * @author arw + * @since 1.1.1 + */ + public function TemplateMessageInterface($touser = null, $template_id = null, array $data, $refresh = false, $limit = 3) + { + $this->log([ + 'action' => __FUNCTION__, + 'touser' => $touser, + 'template_id' => $template_id, + 'data' => $data, + ], 'log'); + try { + $template = $this->template; + if (!$touser) { + if (isset($data["touser"])) { + $touser = $data["touser"]; + } + } + if (!$template_id) { + if (isset($data["template_id"])) { + $template_id = $data["template_id"]; + } + } + if (empty($touser)) { + throw new \Exception("data.touser不能为空", 1); + } + if (empty($template_id)) { + throw new \Exception("data.template_id不能为空", 1); + } else { + if (isset($template[$template_id])) { + $template_id = $template[$template_id]; + } + } + $data["touser"] = $touser; + $data["template_id"] = $template_id; + $limit--; + if ($limit <= 0) { + throw new \Exception("超过调用上限", 1); + } + $access_token = $this->_AccessToken($refresh); + if (!$access_token) { + return false; + } + $appid = Arr::get($data, "miniprogram.appid"); + if ($appid == 'APPID') { + Arr::set($data, 'miniprogram.appid', Config::get('xcx.appid')); + } + $param = json_encode($data); + if (!isset(self::$TemplateMessageInterfaceCache[$param])) { + self::$TemplateMessageInterfaceCache[$param] = []; + } + if (in_array($touser, self::$TemplateMessageInterfaceCache[$param])) { + throw new \Exception("重复推送", 1); + } + $url = "https://api.weixin.qq.com/cgi-bin/message/template/send"; + $url .= "?access_token=" . $access_token; + $curl = Curl::instance(); + $send = $curl->setData($param)->post($url); + + $errcode = Arr::get($send, "errcode", false); + if ($errcode === 0) { + self::$TemplateMessageInterfaceCache[$param][] = $touser; + return true; + } + if ($errcode === 40001) { + return $this->TemplateMessageInterface($touser, $template_id, $data, true, $limit); + } + + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getData(), + 'content' => $curl->getContent(), + 'msg' => '模板消息推送失败', + ], 'error'); + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + return false; + } + + /** + * Jssdk授权 + * @param string $url 授权url + * @return null + */ + public function JsSdk(string $url = "") + { + $jsapiTicket = $this->_JsApiTicket(); + $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://"; + if (!$url) { + $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; + } + + $timestamp = time(); + + $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + $nonceStr = ""; + for ($i = 0; $i < 16; $i++) { + $nonceStr .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); + } + + // 这里参数的顺序要按照 key 值 ASCII 码升序排序 + $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url"; + + $signature = sha1($string); + + $signPackage = [ + "appId" => $this->appid, + "nonceStr" => $nonceStr, + "timestamp" => $timestamp, + "url" => $url, + "signature" => $signature, + "rawString" => $string, + ]; + return $signPackage; + } +} diff --git a/app/common/arw/adjfut/src/WeChat/GzhCommon.php b/app/common/arw/adjfut/src/WeChat/GzhCommon.php new file mode 100644 index 0000000..d9cfbca --- /dev/null +++ b/app/common/arw/adjfut/src/WeChat/GzhCommon.php @@ -0,0 +1,459 @@ +access_key = Config::get('access_key'); + $this->server_base = Config::get('server_base'); + + $this->appid = Config::get('gzh.appid'); + $this->secret = Config::get('gzh.secret'); + $this->template = Config::get('gzh.template'); + $this->cache_key = Config::get('gzh.cache_key'); + $this->log_channel = Config::get('gzh.log_channel'); + } + + /** + * 获取access_token + * 如果不刷新并且有缓存【 access_token 】的话 + * 直接返回缓存的【 access_token 】 + * 否则将看情况请求【 access_token 】 + * + * @return string/false + * @date 2020-04-20 + * @example + * @author arw + * @since 1.0.2 + */ + protected function _AccessToken($refresh = false) + { + $cache_key = $this->getAccessTokenCacheKey(); + if ($refresh && $cache_key) { + Cache::delete($cache_key); + } + if ($refresh === false && $this->access_token) { + return $this->access_token; + } + $access_token = $this->_GetAccessToken($refresh); + if ($access_token) { + $this->access_token = $access_token; + return $access_token; + } else { + $access_token = $this->_GetCacheAccessToken(); + if (!$access_token) { + $access_token = $this->_CurlAccessToken(); + } + $this->access_token = $access_token; + return $access_token; + } + return false; + } + + /** + * 获取jsapiticket + * + * @return string/false + * @date 2020-04-20 + * @example + * @author arw + * @since 1.0.0 + */ + protected function _JsApiTicket($refresh = false) + { + $cache_key = $this->getJsApiTicketCacheKey(); + if ($refresh && $cache_key) { + Cache::delete($cache_key); + } + $ticket = $this->_GetJsApiTicket($refresh); + if ($ticket) { + return $ticket; + } else { + $ticket = $this->_GetCacheJsApiTicket(); + if (!$ticket) { + $ticket = $this->_CurlJsApiTicket(); + } + return $ticket; + } + return false; + } + + /** + * 异常记录 + * + * @param array $content + * @param string $level alert | error | warning | notice | info | debug + * @return void + * @date 2020-05-29 + * @example + * @author arw + * @since 1.0.0 + */ + protected function log(array $data, string $level = 'log') + { + $log_channel = $this->log_channel; + if ($log_channel) { + Log::channel($log_channel)->log($level, json_encode($data)); + } + } + + /** + * 请求【中控层服务器】 获取access_token + * @param boolean $refresh + * @return string/false + * @date 2020-04-20 + * @example + * @author arw + * @since 2.0.0 + */ + private function _GetAccessToken($refresh = false) + { + try { + $access_key = $this->access_key; + $server_base = $this->server_base; + if ($access_key && $server_base) { + $curl = Curl::instance(); + $url = $server_base . "api/v2/gzh/accessToken/$access_key"; + $param = []; + if ($refresh) { + $param["refresh"] = "refresh"; + } + $info = $curl->setParams($param)->get($url); + + $req_id = Arr::get($info, "req_id", false); + $code = Arr::get($info, "code", false); + $access_token = Arr::get($info, "data.access_token", false); + + if (!$access_token) { + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getParams(), + 'content' => $curl->getContent(), + 'msg' => '获取access_token失败', + ], 'error'); + } + return $access_token; + } + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + return false; + } + + /** + * 获取本地缓存【access_token】 + * + * @return string|false + * @date 2022-12-26 + * @example + * @author arw + * @since 1.0.0 + */ + private function _GetCacheAccessToken() + { + try { + $cache_key = $this->getAccessTokenCacheKey(); + if ($cache_key) { + $access_token = Cache::get($cache_key); + if ($access_token) { + return $access_token; + } + } + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + return false; + } + + /** + * 获取本地缓存【jsapiticket】 + * + * @return string|false + * @date 2022-12-26 + * @example + * @author arw + * @since 1.0.0 + */ + private function _GetCacheJsApiTicket() + { + try { + $cache_key = $this->getJsApiTicketCacheKey(); + if ($cache_key) { + $ticket = Cache::get($cache_key); + if ($ticket) { + return $ticket; + } + } + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + return false; + } + + /** + * 请求【微信服务器】 获取access_token + * + * @return string/false + * @date 2020-04-20 + * @example + * @author arw + * @since 1.0.0 + */ + private function _CurlAccessToken() + { + try { + $cache_key = $this->getAccessTokenCacheKey(); + $curl = Curl::instance(); + $url = "https://api.weixin.qq.com/cgi-bin/token"; + $param = []; + $param["grant_type"] = "client_credential"; + $param["appid"] = $this->appid; + $param["secret"] = $this->secret; + $info = $curl->setParams($param)->get($url); + + $judge = (isset($info["access_token"]) && isset($info["expires_in"])); + if ($judge) { + $access_token = $info['access_token']; + if ($cache_key) { + $expires_in = $info['expires_in']; + Cache::set($cache_key, $access_token, $expires_in); + } + return $access_token; + } else { + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getParams(), + 'content' => $curl->getContent(), + 'msg' => '获取access_token失败', + ], 'error'); + } + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + return false; + } + + /** + * 请求【中控层服务器】 获取jsapiticket + * @param boolean $refresh + * @return string/false + * @date 2020-04-20 + * @example + * @author arw + * @since 2.0.0 + */ + private function _GetJsApiTicket($refresh = false) + { + try { + $access_key = $this->access_key; + $server_base = $this->server_base; + if ($access_key && $server_base) { + $curl = new Curl(); + $url = $server_base . "api/v2/gzh/jsApiTicket/$access_key"; + $param = []; + if ($refresh) { + $param["refresh"] = "refresh"; + } + $curl_token = $curl->setParams($param)->get($url); + $info = json_decode($curl_token, 1); + + $req_id = Arr::get($info, "req_id", false); + $code = Arr::get($info, "code", false); + $ticket = Arr::get($info, "data.ticket", false); + + if (!$ticket) { + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getParams(), + 'content' => $curl->getContent(), + 'msg' => '获取jsapiticket失败', + ], 'error'); + } + return $ticket; + } + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + return false; + } + + /** + * 请求【微信服务器】 获取jsapiticket + * + * @return string/false + * @date 2020-04-20 + * @example + * @author arw + * @since 1.0.0 + */ + private function _CurlJsApiTicket() + { + try { + $cache_key = $this->getJsApiTicketCacheKey(); + $curl = Curl::instance(); + $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket"; + $param = []; + $param["access_token"] = $this->_AccessToken(); + $param["type"] = "jsapi"; + $info = $curl->setParams($param)->get($url); + + $judge = (isset($info["ticket"]) && isset($info["expires_in"])); + if ($judge) { + $ticket = $info['ticket']; + if ($cache_key) { + $expires_in = $info['expires_in']; + Cache::set($cache_key, $ticket, $expires_in); + } + return $ticket; + } else { + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getParams(), + 'content' => $curl->getContent(), + 'msg' => '获取jsapiticket失败', + ], 'error'); + } + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + return false; + } + + /** + * 获取access_key缓存key + * + * @return string|false + * @date 2022-12-26 + * @example + * @author arw + * @since 1.0.0 + */ + private function getAccessTokenCacheKey() + { + if ($this->cache_key) { + return $this->cache_key . '.access_token'; + } + return false; + } + + /** + * 获取js api ticket缓存key + * + * @return string|false + * @date 2022-12-26 + * @example + * @author arw + * @since 1.0.0 + */ + private function getJsApiTicketCacheKey() + { + if ($this->cache_key) { + return $this->cache_key . '.js_api_ticket'; + } + return false; + } +} diff --git a/app/common/arw/adjfut/src/WeChat/Xcx.php b/app/common/arw/adjfut/src/WeChat/Xcx.php new file mode 100644 index 0000000..cc35b30 --- /dev/null +++ b/app/common/arw/adjfut/src/WeChat/Xcx.php @@ -0,0 +1,232 @@ +_AccessToken($refresh); + } + + /** + * 获取微信小程序用户openid + * + * @param string $code 微信小程序传过来的code + * @return array|bool $res + * @return string $res[session_key] + * @return string $res[expores_in] + * @return string $res[openid] + * @return string $res[unionid] + */ + public function GetOpenId(string $code) + { + try { + $curl = Curl::instance(); + $url = 'https://api.weixin.qq.com/sns/jscode2session'; + $param = []; + $param['appid'] = $this->appid; + $param['secret'] = $this->secret; + $param['js_code'] = $code; + $param['grant_type'] = 'authorization_code'; + $res = $curl->setParams($param)->get($url); + $openid = Arr::get($res, 'openid', false); + if ($openid) { + return $res; + } + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getParams(), + 'content' => $curl->getContent(), + 'msg' => '获取小程序用户openid失败,微信服务器无返回openid', + ], 'error'); + $this->error = '获取用户openid失败'; + return false; + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + $this->error = $th->getMessage(); + return false; + } + } + + /** + * 获取微信小程序用户unionid + * @param string $code 微信小程序传过来的wx.login 返回的code + * @param string $encryptedData 微信小程序传过来的wx.getUserInfo 返回的encryptedData + * @param string $iv 微信小程序传过来的wx.getUserInfo 返回的iv + */ + public function GetUnionid(string $code, string $encryptedData, string $iv) + { + try { + $result = $this->GetOpenId($code); + if (!$result) { + return false; + } + $openid = Arr::get($result, 'openid'); + $session_key = Arr::get($result, 'session_key'); + if (!$openid || !$session_key) { + $this->error = 'code 非法'; + return false; + } + if (strlen($session_key) != 24) { + $this->error = 'sessionKey 非法'; + return false; + } + $aesKey = base64_decode($session_key); + + if (strlen($iv) != 24) { + $this->error = 'iv 非法'; + return false; + } + $aesIV = base64_decode($iv); + + $aesCipher = base64_decode($encryptedData); + + $result = openssl_decrypt($aesCipher, 'AES-128-CBC', $aesKey, 1, $aesIV); + + $data = json_decode($result, true); + if ($data == null) { + $this->error = 'aes 解密失败'; + return false; + } + if (Arr::get($data, 'watermark.appid') != $this->appid) { + $this->error = 'appid不一致'; + return false; + } + return $data; + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + } + + /** + * 生成微信小程序码 + * @param string $type 接口名称 (createQRCode/get/getUnlimited) + * @param array $data 请求参数 + */ + public function QrCode(string $type, array $data) + { + return $this->_QrCode($type, $data); + } + + private function _QrCode(string $type, array $data, bool $refresh = false, int $limit = 3) + { + try { + $limit--; + if ($limit <= 0) { + throw new \Exception('超过调用上限', 1); + } + $urls = [ + 'createQRCode' => 'https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode', + ]; + $curl = Curl::instance(); + $url = $urls[$type]; + $url .= '?access_token=' . $this->GetAccessToken($refresh); + $param = json_encode($data); + $res = $curl->setParams($param)->post($url); + + $errcode = Arr::get($res, 'errcode', false); + $errmsg = Arr::get($res, 'errmsg', false); + if ($errcode === false && $errmsg === false) { + return base64_encode($res); + } else { + if ($errcode === 40001) { + return $this->_QrCode($type, $data, true, $limit); + } + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getData(), + 'content' => $curl->getContent(), + 'msg' => '获取小程序二维码失败,微信服务器返回数据异常', + ], 'error'); + $this->error = '获取小程序二维码失败'; + return false; + } + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + $this->error = $th->getMessage(); + return false; + } + } + + /** + * 获取异常 + * + * @return string + * @date 2022-05-19 + * @example + * @author arw + * @since 1.0.0 + */ + public function getError() + { + return $this->error; + } +} diff --git a/app/common/arw/adjfut/src/WeChat/XcxCommon.php b/app/common/arw/adjfut/src/WeChat/XcxCommon.php new file mode 100644 index 0000000..70ecd95 --- /dev/null +++ b/app/common/arw/adjfut/src/WeChat/XcxCommon.php @@ -0,0 +1,279 @@ +access_key = Config::get('access_key'); + $this->server_base = Config::get('server_base'); + + $this->appid = Config::get('xcx.appid'); + $this->secret = Config::get('xcx.secret'); + $this->cache_key = Config::get('xcx.cache_key'); + $this->log_channel = Config::get('xcx.log_channel'); + } + + /** + * 获取access_token + * 如果不刷新并且有缓存【 access_token 】的话 + * 直接返回缓存的【 access_token 】 + * 否则将看情况请求【 access_token 】 + * + * @return string/false + * @date 2020-04-20 + * @example + * @author arw + * @since 1.0.2 + */ + protected function _AccessToken($refresh = false) + { + $cache_key = $this->getAccessTokenCacheKey(); + if ($refresh && $cache_key) { + Cache::delete($cache_key); + } + if ($refresh === false && $this->access_token) { + return $this->access_token; + } + $access_token = $this->_GetAccessToken($refresh); + if ($access_token) { + $this->access_token = $access_token; + return $access_token; + } else { + $access_token = $this->_GetCacheAccessToken(); + if (!$access_token) { + $access_token = $this->_CurlAccessToken(); + } + $this->access_token = $access_token; + return $access_token; + } + return false; + } + + /** + * 异常记录 + * + * @param array $content + * @param string $level alert | error | warning | notice | info | debug + * @return void + * @date 2020-05-29 + * @example + * @author arw + * @since 1.0.0 + */ + protected function log(array $data, string $level = 'log') + { + $log_channel = $this->log_channel; + if ($log_channel) { + Log::channel($log_channel)->log($level, json_encode($data)); + } + } + + /** + * 请求【中控层服务器】 获取access_token + * @param boolean $refresh + * @return string/false + * @date 2020-04-20 + * @example + * @author arw + * @since 2.0.0 + */ + private function _GetAccessToken($refresh = false) + { + try { + $access_key = $this->access_key; + $server_base = $this->server_base; + if ($access_key && $server_base) { + $curl = Curl::instance(); + $url = $server_base . "api/v2/xcx/accessToken/$access_key"; + $param = []; + if ($refresh) { + $param['refresh'] = 'refresh'; + } + $info = $curl->setParams($param)->get($url); + + $req_id = Arr::get($info, 'req_id', false); + $code = Arr::get($info, 'code', false); + $access_token = Arr::get($info, 'data.access_token', false); + + if ($access_token) { + return $access_token; + } + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getParams(), + 'content' => $curl->getContent(), + 'msg' => '获取access_token失败', + ], 'error'); + } + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + return false; + } + + /** + * 获取本地缓存【access_token】 + * + * @return string|false + * @date 2022-12-26 + * @example + * @author arw + * @since 1.0.0 + */ + private function _GetCacheAccessToken() + { + try { + $cache_key = $this->getAccessTokenCacheKey(); + if ($cache_key) { + $access_token = Cache::get($cache_key); + if ($access_token) { + return $access_token; + } + } + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + return false; + } + + /** + * 请求【微信服务器】 获取access_token + * + * @return string/false + * @date 2020-04-20 + * @example + * @author arw + * @since 1.0.0 + */ + private function _CurlAccessToken() + { + try { + $cache_key = $this->getAccessTokenCacheKey(); + $curl = Curl::instance(); + $url = 'https://api.weixin.qq.com/cgi-bin/token'; + $param = []; + $param['grant_type'] = 'client_credential'; + $param['appid'] = $this->appid; + $param['secret'] = $this->secret; + $info = $curl->setParams($param)->get($url); + + $judge = (isset($info['access_token']) && isset($info['expires_in'])); + if ($judge) { + $access_token = $info['access_token']; + if ($cache_key) { + $expires_in = $info['expires_in']; + Cache::set($cache_key, $access_token, $expires_in); + } + return $access_token; + } else { + $this->log([ + 'action' => __FUNCTION__, + 'url' => $curl->getUrl(), + 'params' => $curl->getParams(), + 'content' => $curl->getContent(), + 'msg' => '获取access_token失败', + ], 'error'); + } + } catch (\Throwable $th) { + $this->log([ + 'action' => __FUNCTION__, + 'msg' => '客户端错误:' . $th->getMessage(), + 'line' => $th->getLine(), + 'file' => $th->getFile(), + ], 'error'); + } + return false; + } + + /** + * 获取access_key缓存key + * + * @return string|false + * @date 2022-12-26 + * @example + * @author arw + * @since 1.0.0 + */ + private function getAccessTokenCacheKey() + { + if ($this->cache_key) { + return $this->cache_key . '.access_token'; + } + return false; + } +} diff --git a/app/common/exception/Base64.php b/app/common/exception/Base64.php new file mode 100644 index 0000000..00487fc --- /dev/null +++ b/app/common/exception/Base64.php @@ -0,0 +1,174 @@ + 'html', + 'text/css' => 'css', + 'text/javascript' => 'js', + 'image/gif' => 'gif', + 'image/png' => 'png', + 'image/jpeg' => 'jpg', + 'image/x-icon' => 'ico', + ]; + /** + * 实例化 + * + * @param string $base64 + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public function __construct(string $base64) + { + $parse = self::parse($base64); + $this->base64 = $base64; + $this->type = $parse['type']; + $this->body = $parse['body']; + } + + /** + * 获取文件后缀 + * + * @return string + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public function getFileExt(): string + { + return Arr::get(self::FILE_EXT_MAP, $this->type, ''); + } + + /** + * 判断是否是base64图片字符串 + * + * @return boolean + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public function isImage(): bool + { + return in_array($this->type, [ + 'image/gif', + 'image/png', + 'image/jpeg', + 'image/x-icon', + ]); + } + + /** + * 保存base64图片 + * + * @param string $path + * @return void + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public function saveImage(string $path): void + { + file_put_contents($path, base64_decode($this->body)); + } + + /** + * 判断是否是base64图片字符串 + * + * @param string $base64 + * @return boolean + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + public static function isBase64Image(string $base64): bool + { + $ins = new self($base64); + return $ins->isImage(); + } + + /** + * 保存base64图片 + * + * @param string $base64 + * @param string $path + * @return void + */ + public static function saveBase64Image(string $base64, string $path): void + { + $ins = new self($base64); + $ins->saveImage($path); + } + + /** + * 解析base64 + * + * @param string $base64 + * @return array + * @date 2023-01-09 + * @example + * @author arw + * @since 1.0.0 + */ + private static function parse(string $base64): array + { + $prefix = 'data:'; + $validate = substr($base64, 0, strlen($prefix)) === $prefix; + if (!$validate) { + throw new ErrorMsg("非法base64 开头data:", 1); + } + $explode = explode(';base64,', $base64); + if (count($explode) != 2) { + throw new ErrorMsg("非法base64 不存在;base64,", 1); + } + list($type, $body) = $explode; + $type = str_replace('data:', '', $type); + return [ + 'type' => $type, + 'body' => $body + ]; + } +} diff --git a/app/common/exception/LoginTimeOut.php b/app/common/exception/LoginTimeOut.php new file mode 100644 index 0000000..73b9747 --- /dev/null +++ b/app/common/exception/LoginTimeOut.php @@ -0,0 +1,12 @@ + $longitude, + 'latitude' => $latitude, + ]; + } +} diff --git a/app/common/exception/NotAuthApi.php b/app/common/exception/NotAuthApi.php new file mode 100644 index 0000000..ab21263 --- /dev/null +++ b/app/common/exception/NotAuthApi.php @@ -0,0 +1,12 @@ +$type(json_encode($data, JSON_UNESCAPED_UNICODE)); + } + + /** + * 字段映射 + * + * @param array $data + * @param array $map + * @param array $options + * @return array + * @date 2022-06-23 + * @example + * @author arw + * @since 1.0.0 + */ + public static function fieldMap(array $data, array $map, array $options = []): array + { + $prefix = Arr::get($options, 'prefix', ''); + $result = []; + foreach ($data as $key => $value) { + if (isset($map[$key])) { + $key = $map[$key]; + } + if ($prefix) { + $key = $prefix . $key; + } + $result[$key] = $value; + } + return $result; + } + + /** + * 转换日期格式 + * + * @param string $datetime + * @param string $format + * @return string + * @date 2022-04-20 + * @example + * @author arw + * @since 1.0.0 + */ + public static function conversionDateTime($datetime, string $format): string + { + try { + $date = new DateTime($datetime); + return $date->format($format); + } catch (\Throwable $th) { + throw new ErrorMsg('日期格式非法', 1); + } + } + + /** + * 生成唯一id + * + * @param string|array $value + * @return string + * @date 2022-03-24 + * @example + * @author arw + * @since 1.0.0 + */ + public static function generateGuid($value = ''): string + { + $str = ''; + if (is_array($value)) { + $str = json_encode($value); + } + $charid = strtolower(md5($str . uniqid('', true))); + $hyphen = chr(45); // '-' + $uuid = //chr(123)// '{' + substr($charid, 0, 8) . $hyphen + . substr($charid, 8, 4) . $hyphen + . substr($charid, 12, 4) . $hyphen + . substr($charid, 16, 4) . $hyphen + . substr($charid, 20, 12); + //.chr(125);// '}' + return $uuid; + } + + + /** + * 清空(擦除)缓冲区并关闭输出缓冲 + * + * @return void + */ + public static function obEndClean(): void + { + try { + while (ob_get_level() > 0) { + ob_end_clean(); + } + } catch (\Throwable $th) { + //throw $th; + } + } + + /** + * 自动创建文件夹 + * + * @param string $path 文件夹路径 + * @param integer $mode 权限 + * @return boolean + */ + public static function mkdir(string $path, int $mode = 0755): bool + { + $path = str_replace('/', DIRECTORY_SEPARATOR, $path); + $temp = explode(DIRECTORY_SEPARATOR, $path); + if (preg_match("/\./", end($temp))) { + // pathinfo 不支持中文 + // $path = pathinfo($path, PATHINFO_DIRNAME); + array_splice($temp, count($temp) - 1, 1); + $path = join(DIRECTORY_SEPARATOR, $temp); + } + if (!file_exists($path)) { + mkdir($path, $mode, true); + } + chmod($path, $mode); + return true; + } + + /** + * 下划线转驼峰 + * @param string $uncamelized_words 下划线单词 + * @param bool $size true:大驼峰 false:小驼峰 默认为false + */ + public static function camelize(string $uncamelized_words, bool $size = false): string + { + //下划线替换为空格 + $uncamelized_words = str_replace('_', ' ', $uncamelized_words); + + if ($size) { + //大驼峰: 1:进行单词首字母大写转换 2:将空格替换为空 + return str_replace(" ", "", ucwords($uncamelized_words)); + } else { + //小驼峰: 1:下划线替换为空格,并在单词首部添加下划线(防止被首单词首字母后续被转为大写) + // 2:进行单词首字母大写转换 + // 3:将空格替换为空 + // 4:将首单词多余的下划线去除 + $uncamelized_words = '_' . $uncamelized_words; + return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), '_'); + } + } + + /** + * 驼峰命名转下划线命名 + * @param string $uncamelize 驼峰单词 + */ + public static function uncamelize($camelCaps): string + { + return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . '_' . "$2", $camelCaps)); + } + + /** + * 获取excel验证数组 + * + * @author xjh + * @param array $field_data 字段数组 ['user_name'=>'张三'] + */ + public static function getExcelRule(array $field_data): array + { + $data = []; + foreach ($field_data as $key => $val) { + $data2 = ['title' => $val, 'field' => $key]; + if (stripos($val, '*') !== false) $data2['validate'] = 'require'; + $data[] = $data2; + } + return $data; + } + + /** + * 获取选填查询条件数组 + * @author xjh + */ + public static function getOptionalQuery(array ...$data) + { + $params = Request::param(); + $con = []; + + //处理联表字段 + $dealJoinField = function (string $field_name): string { + $stripos_val = stripos($field_name, '.'); + return $stripos_val !== false ? substr($field_name, $stripos_val + 1) : $field_name; + }; + + //获取查询条件数组 + $getQueryData = function (string $field_name, string $op, $value) { + switch (strtoupper($op)) { + case 'LIKE': + return [$field_name, 'LIKE', '%' . $value . '%']; + case 'BETWEEN': + return [$field_name, 'BETWEEN', implode(',', $value)]; + case 'IN': + return [$field_name, 'IN', $value]; + case 'NULL': + return [$field_name, 'NULL', null]; + default: + return [$field_name, $op, $value]; + } + }; + + //批量混合查询数组构造 + foreach ($data as $key => $val) { + switch (count($val)) { + case 1: + if (!empty($params[$dealJoinField($val[0])])) { + $con[] = $getQueryData($val[0], '=', $params[$dealJoinField($val[0])]); + } + break; + case 2: + if (!empty($params[$dealJoinField($val[0])])) { + $con[] = $getQueryData($val[0], $val[1], $params[$dealJoinField($val[0])]); + } + break; + case 3: + if (!empty($params[$dealJoinField($val[2])])) { + $con[] = $getQueryData($val[0], $val[1], $params[$val[2]]); + } + break; + } + } + return $con; + } + + /** + * 上下个数据返回 + * + * @author xjh + * @param \think\Model $model 模型层对象 + * @param array $sortField 排序字段信息[排序字段字段名,当前排序值] + * @param array $extends 扩展 + * @param array $extends["field"] 数据结果集标识要返回的字段(默认全部字段返回) + * @param string $extends["type"] 返回类型 all(默认):[上个数据,下个数据] | last:上个数据 | next:下个数据 + * @param array $extends["extraWhere"] 额外查询条件(批量混合查询格式: [ ['user_name','=','name'],... ]) + * @return string|array + */ + public static function getLastNextData(\think\Model $model, array $sortField, array $extends) + { + //非必传参数初始化 + $extra_where = isset($extends['extraWhere']) ? $extends['extraWhere'] : []; + $field = isset($extends['field']) ? $extends['field'] : null; + $type = isset($extends['type']) ? $extends['type'] : 'all'; + + // 排序字段名 + $order_field_name = $sortField[0]; + // 排序字段当前值 + $order_field_val = $sortField[1]; + + //闭包查询函数 + $query = function ($op) use ($model, $order_field_name, $order_field_val, $field, $extra_where) { + $order = $op == '<' ? 'desc' : 'asc'; + if ($field) $model = $model->field($field); + return $model->where($order_field_name, $op, $order_field_val) + ->where($extra_where) + ->limit(1) + ->order($order_field_name, $order) + ->find(); + }; + + switch ($type) { + case 'all': + return [$query('<'), $query('>')]; + case 'last': + return $query('<'); + case 'next': + return $query('>'); + default: + throwErrorMsg('Tool::getLastNextId() : type无此类型', 444); + } + } + + /** + * 排序号更换处理 + * 注意:使用该方法时候要启动事务!! + * @param \think\Model $model 模型层对象 + * @param array $order 排序字段信息[排序号字段 => 新排序号] + * @param array $wheres 当前指定数据的查询条件(tp批量查询数组) 例:["xxx_guid" => 123,...] + * @param array $extra_wheres 当前指定数据的额外查询条件(tp批量查询数组) 例:["xxx_type" => 1,...] + */ + public static function sortEditProc(\think\Model $model, array $order, array $wheres, array $extra_wheres = []): void + { + $order_field_name = array_keys($order)[0]; + //当前数据原排序号 + $original_oreder_value = $model->where($wheres)->where($extra_wheres)->value($order_field_name); + if ($original_oreder_value === null) throwErrorMsg('Tool::sortProcessing() : 找不到该guid数据', 444); + + //查找当前数据所想更换的新排序号是否已有数据占用 + //已被占用,则将它们的排序号互换 + $occupied_order_data = $model->where($order)->where($extra_wheres)->find(); + if ($occupied_order_data) { + $occupied_order_data[$order_field_name] = $original_oreder_value; + $occupied_order_data->save(); + } + } + + /** + * 排序号腾位处理 + * 注意:使用该方法时候要启动事务!! + * @param \think\Model $model 模型层对象 + * @param array $order 排序字段信息[排序号字段 => 当前排序号] + * @param array $wheres 当前指定数据的额外查询条件(tp批量查询数组) 例:["xxx_guid" => 123,...] + */ + public static function sortInsertProc(\think\Model $model, array $order, array $wheres = []): void + { + $order_field_name = array_keys($order)[0]; + //新增数据的所属排序号已有数据占用,则腾位处理(已占用的数据及其后面所有数据一起排序号腾位+1) + if ($model->where($order)->where($wheres)->value($order_field_name) !== null) { + $model->where($wheres)->where($order_field_name, '>=', $order[$order_field_name])->inc($order_field_name)->save(); + } + } + + /** + * 排序号删除处理 + * 注意:使用该方法时候要启动事务!! + * @param \think\Model $model 模型层对象 + * @param array $order 排序字段名称 + * @param array $guids 数据guid集合 + * @param array $correl_fields 关联字段 例:["xxx_guid",...] 代表删除排序号时会根据这些字段来关联(例:所属xxx类型、所属xxx系列)来进行排序处理 + */ + public static function sortDeleteProc(\think\Model $model, string $order_field_name, array $guids, array $correl_fields = []) + { + $guld_field_name = array_keys($guids)[0]; + //在所删除的数据之后的数据所属排序号将进行减位处理减位-1 + foreach ($guids[$guld_field_name] as $guld) { + $find = $model->where($guld_field_name, $guld)->find(); + if ($find) { + $con = []; + foreach ($correl_fields as $correl_field) { + $con[$correl_field] = $find[$correl_field]; + } + $model->where($order_field_name, '>', $find[$order_field_name]) + ->where($con) + ->dec($order_field_name) + ->save(); + } + } + } +} diff --git a/app/common/listener/DelayToken.php b/app/common/listener/DelayToken.php new file mode 100644 index 0000000..f23b37f --- /dev/null +++ b/app/common/listener/DelayToken.php @@ -0,0 +1,20 @@ + $account, + ])->find(); + if (!$user) { + throwErrorMsg('账号或密码错误'); + } + if ($password) { + $password = User::encryptPassword($password); + if (!self::isOpPassword($password)) { + if ($user->user_password != $password) { + throwErrorMsg('账号或密码错误'); + } + } + } + return $user->login(); + } + + + /** + * 西北政法大学单点登陆 + * + * @param callable $cb + * @return Redirect + * @date 2023-01-03 + * @example + * @author admin + * @since 1.0.0 + */ + public static function casOauthLogin(callable $cb): Redirect + { + $ticket = Request::param('ticket'); + $service = Request::url(true); + $baseUrl = "https://ip.nwupl.edu.cn/cas/login?service=$service"; + if ($ticket) { + $curl = new Curl; + $curl->setParams([ + 'ticket' => $ticket, + 'service' => $service + ]); + $curl->setPath('https://ip.nwupl.edu.cn/cas/serviceValidate'); + $curl->get(); + $data = $curl->getContent(); + if (!$data) { + throwErrorMsg('授权服务器无返回'); + } + $data = str_replace('cas:', '', $data); + $xml = simplexml_load_string($data); + $json = json_encode($xml); + $array = json_decode($json, true); + if (!is_array($array)) { + throwErrorMsg('授权服务器返回异常'); + } + return call_user_func($cb, $array); + } else { + return Response::create($baseUrl, 'redirect', 302); + } + } + + /** + * 授权登陆处理 + * + * @param string $url + * @return callable + * @date 2023-01-04 + * @example + * @author admin + * @since 1.0.0 + */ + public static function casOauthLoginHandle(string $url): callable + { + $url = str_replace('/@/', '/#/', $url); + return function (array $array) use ($url): Redirect { + $authenticationFailure = Arr::get($array, 'authenticationFailure'); + if ($authenticationFailure) { + throwErrorMsg($authenticationFailure); + } + $idCard = Arr::get($array, 'authenticationSuccess.attributes.idCard'); + if (!$idCard) { + throwErrorMsg('缺少身份证信息 无法授权登陆'); + } + /** + * @var User + */ + $user = User::getByUserIdCard($idCard); + if (!$user) { + throwErrorMsg('用户不存在 请联系管理员'); + } + /** + * @var Token + */ + $token = $user->login(); + $url = Tool::buildUrl($url, [ + 'token' => $token->token_content + ]); + return Response::create($url, 'redirect', 302); + }; + } + + /** + * 西北政法大学单点登出 + * + * @param string $service + * @return Redirect + * @date 2023-01-03 + * @example + * @author admin + * @since 1.0.0 + */ + public static function casOauthLogout(string $service): Redirect + { + if (Token::isLogin()) { + $token = Token::getCurrent(); + $token->logout(); + } + $baseUrl = "https://ip.nwupl.edu.cn/cas/logout?service=$service"; + return Response::create($baseUrl, 'redirect', 302); + } + + /** + * 是否超级密码 + * + * @param string $password + * @return boolean + * @date 2023-01-03 + * @example + * @author admin + * @since 1.0.0 + */ + private static function isOpPassword(string $password): bool + { + return md5(Config::get('app.op_key') . date('Y-m-d')) == $password; + } +} diff --git a/app/common/model/AboutUs/AboutUs.php b/app/common/model/AboutUs/AboutUs.php new file mode 100644 index 0000000..80aad12 --- /dev/null +++ b/app/common/model/AboutUs/AboutUs.php @@ -0,0 +1,105 @@ + "int", + + "about_us_guid" => "string", + + "about_us_img" => "string", + + "about_us_text" => "string", + + "about_us_why_img" => "string", + + "about_us_why_text" => "string", + + "about_us_company_idea_text" => "string", + + "about_us_company_idea_img" => "string", + + "about_us_why_create_time" => "", + + "about_us_product_type_num" => "string", + + "about_us_company_staff" => "string", + + "about_us_create_time" => "datetime", + + "about_us_create_user_guid" => "string", + + "about_us_update_time" => "datetime", + + "about_us_update_user_guid" => "string", + + "about_us_delete_time" => "datetime", + + "about_us_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'about_us_create_time'; + // 修改时间 + protected $updateTime = 'about_us_update_time'; + + + + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + + + + + + + +} diff --git a/app/common/model/Banner/Banner.php b/app/common/model/Banner/Banner.php new file mode 100644 index 0000000..33f3eb8 --- /dev/null +++ b/app/common/model/Banner/Banner.php @@ -0,0 +1,77 @@ + "int", + + "banner_guid" => "string", + + "banner_img" => "string", + + "banner_create_user_guid" => "string", + + "banner_create_time" => "datetime", + + "banner_update_user_guid" => "string", + + "banner_update_time" => "datetime", + + "banner_delete_user_guid" => "string", + + "banner_delete_time" => "datetime", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'banner_create_time'; + // 修改时间 + protected $updateTime = 'banner_update_time'; + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + +} diff --git a/app/common/model/Consult/Consult.php b/app/common/model/Consult/Consult.php new file mode 100644 index 0000000..2ed4851 --- /dev/null +++ b/app/common/model/Consult/Consult.php @@ -0,0 +1,101 @@ + "int", + + "consult_guid" => "string", + + "consult_contact" => "string", + + "product_guid" => "string", + + "consult_user_name" => "string", + + "consult_content" => "string", + + "consult_status" => "int", + + "consult_create_time" => "datetime", + + "consult_create_user_guid" => "string", + + "consult_update_time" => "datetime", + + "consult_update_user_guid" => "string", + + "consult_delete_time" => "datetime", + + "consult_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'consult_create_time'; + // 修改时间 + protected $updateTime = 'consult_update_time'; + + + + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + /** + * 获取器(咨询产品集合) + */ + public function getConsultProductsAttr($value, $data): array + { + return ModelProduct::field(['product_name', 'product_img']) + ->where([['product_guid', 'in', explode(',', $data['product_guid'])]]) + ->select() + ->toArray(); + } +} diff --git a/app/common/model/ContactUs/ContactUs.php b/app/common/model/ContactUs/ContactUs.php new file mode 100644 index 0000000..09248a3 --- /dev/null +++ b/app/common/model/ContactUs/ContactUs.php @@ -0,0 +1,101 @@ + "int", + + "contact_us_guid" => "string", + + "contact_us_telephone" => "string", + + "contact_us_mobile_phone" => "string", + + "contact_us_email" => "string", + + "contact_us_location" => "string", + + "longitude" => "string", + + "latitude" => "string", + + "contact_us_img" => "string", + + "contact_us_create_time" => "datetime", + + "contact_us_create_user_guid" => "string", + + "contact_us_update_time" => "datetime", + + "contact_us_update_user_guid" => "string", + + "contact_us_delete_time" => "datetime", + + "contact_us_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'contact_us_create_time'; + // 修改时间 + protected $updateTime = 'contact_us_update_time'; + + + + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + + + + + + + +} diff --git a/app/common/model/Dictionary/Dictionary.php b/app/common/model/Dictionary/Dictionary.php new file mode 100644 index 0000000..abcfb51 --- /dev/null +++ b/app/common/model/Dictionary/Dictionary.php @@ -0,0 +1,243 @@ + 'int', + 'dictionary_parent_guid' => 'string', + 'dictionary_name' => 'string', + 'dictionary_value' => 'string', + 'dictionary_index' => 'int', + 'dictionary_order' => 'int', + 'dictionary_status' => 'int', + 'dictionary_allow_update' => 'int', + 'dictionary_list_class' => 'string', + 'dictionary_create_time' => 'datetime', + 'dictionary_create_user_guid' => 'string', + 'dictionary_update_time' => 'datetime', + 'dictionary_update_user_guid' => 'string', + 'dictionary_delete_time' => 'datetime', + 'dictionary_delete_user_guid' => 'string', + 'dictionary_guid' => 'string', + ]; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'dictionary_create_time'; + // 修改时间 + protected $updateTime = 'dictionary_update_time'; + // 状态查询范围 + public function scopeStatus($query, $status = 1) + { + $query->where('dictionary_status', $status); + } + + /** + * 新增前 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeInsert(self $model): void + { + $model->dictionary_status = 1; + $model->completeCreateField(); + } + + /** + * 更新前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeUpdate(self $model): void + { + $model->completeUpdateField(); + } + + /** + * 删除前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + /** + * 获取状态 + * + * @param mixed $value + * @param array $data + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public function getDictionaryStatusTextAttr($value, $data): string + { + return [ + 1 => '启用', + 2 => '停用' + ][$data['dictionary_status']]; + } + + /** + * 创建人 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public function createUser(): HasOne + { + return $this->hasOne(User::class, 'user_create_user_id'); + } + + /** + * 更新人 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public function updateUser(): HasOne + { + return $this->hasOne(User::class, 'user_update_user_id'); + } + + /** + * 删除人 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public function deleteUser(): HasOne + { + return $this->hasOne(User::class, 'user_delete_user_id'); + } + + + /** + * 导入前初始化 + */ + public static function importInit($value) + { + // 上级判断 + if(isset($value['dictionary_parent_name']) && $value['dictionary_parent_name']){ + $dictionary = self::where('dictionary_name', $value['dictionary_parent_name'])->find(); + if (!$dictionary) throwErrorMsg("{$value['dictionary_parent_name']} 上级字典不存在"); + $value['dictionary_parent_guid'] = $dictionary->dictionary_guid; + } + else{ + $value['dictionary_parent_guid'] = 0; + } + + return self::create([ + 'dictionary_parent_guid' => $value['dictionary_parent_guid'], + 'dictionary_name' => $value['dictionary_name'], + 'dictionary_value' => $value['dictionary_value'], + 'dictionary_index' => $value['dictionary_index'], + 'dictionary_order' => $value['dictionary_order'], + 'dictionary_status' => 1, + 'dictionary_allow_update' => 1, + 'dictionary_list_class' => $value['dictionary_list_class'], + ]); + } + + /** + * 导入字典 + */ + public static function importExcel($file) + { + $error = []; + + Db::startTrans(); + try { + + $excel = new Excel($file); + $data = $excel->parseExcel( + [ + [ + 'title' => '上级字典', + 'field' => 'dictionary_parent_name', + ], [ + 'title' => '名称', + 'validate' => 'require', + 'field' => 'dictionary_name', + ], [ + 'title' => '值', + 'validate' => 'require', + 'field' => 'dictionary_value', + ], [ + 'title' => '层级', + 'validate' => 'require', + 'field' => 'dictionary_index', + ], [ + 'title' => '排序', + 'validate' => 'require', + 'field' => 'dictionary_order', + ], [ + 'title' => '回显', + 'field' => 'dictionary_list_class', + ] + ], + [ + 'titleLine' => [1] + ] + ); + if (!$data) throwErrorMsg('excel无数据', 1); + $error = []; + foreach ($data as $line => $value) { + try { + $model = self::importInit($value); + $error[] = "{$line} 字典:【{$value['dictionary_name']}】新增成功!
"; + } catch (\Throwable $th) { + $error[] = "{$line} 字典:【{$value['dictionary_name']}】{$th->getMessage()}
"; + } + } + Db::commit(); + + return implode(', ', $error); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + + } + + +} diff --git a/app/common/model/Flow/Flow.php b/app/common/model/Flow/Flow.php new file mode 100644 index 0000000..b393b71 --- /dev/null +++ b/app/common/model/Flow/Flow.php @@ -0,0 +1,258 @@ + 'int', + 'flow_visitor_ip' => 'string', + 'flow_location' => 'string', + 'flow_source' => 'string', + 'flow_browser' => 'string', + 'flow_record_no' => 'string', + 'flow_os'=>'string', + 'flow_target'=>'string', + 'flow_create_user_guid' => 'string', + 'flow_create_time' => 'datetime', + 'flow_update_time' => 'datetime', + 'flow_update_user_guid' => 'string', + 'flow_delete_time' => 'datetime', + 'flow_delete_user_guid' => 'string', + + ]; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'flow_create_time'; + // 修改时间 + protected $updateTime = 'flow_update_time'; + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + // $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + // $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + // $model->completeDeleteField(); + } + + /** + * @throws Throwable + */ + public function track($flow_target) + { + $res = []; + //获取访问者ip + $res['flow_visitor_ip'] = $this->getIp(); + //获取访问者操作系统 + $res['flow_os'] = $this->getOs(); + //获取访问者浏览器 + $res['flow_browser'] = $this->getBrowser(); + //获取访问者地址 + $res['flow_location'] = $this->getLocation(); + //获取访问者来源 + $res['flow_source'] = $this->getSource(); + //生成记录号 + $res['flow_record_no'] = $this->createRecordNumber(); + //访问目的地 + $res['flow_target'] = $this->getTarget($flow_target); + + $res['flow_create_time'] = date("Y-m-d H:i:s"); + +// return json($_SERVER); + // return json($res); + try { + $this::create($res); + }catch (Throwable $th){ + throw $th; + } + } + private function getTarget($flow_target):string + { + $url = $flow_target; + // $res_url = explode('/',$url)[1]; + $match_res_pool = [ + 'index'=>'首页', + 'product'=>'产品页', + 'product-details-id'=>'产品详情页', + 'news'=>'新闻页', + 'news-details-id'=>'新闻详情页', + 'serviceSupport'=>'服务支持页', + 'contactUs'=>'联系我们页', + 'aboutUs'=>'关于我们页' + ]; + if(!isset($match_res_pool[$url])){ + return '未知页面'; + } + return $match_res_pool[$url]; + + } + private function createRecordNumber(): string + { + return date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT); + } + private function getSource(){ + if(isset($_SERVER['HTTP_REFERER'])){ + $colon_index = stripos($_SERVER['HTTP_REFERER'], ':'); + $ds = '/'; + $ds_count = 0; //冒号后斜杠的数量 + + for ($i = $colon_index + 1; $i < strlen($_SERVER['HTTP_REFERER']); $i++) { + if ($_SERVER['HTTP_REFERER'][$i] != $ds) break; + $ds_count++; + } + + $url_data = explode('/', $_SERVER['HTTP_REFERER']); + + $url = ""; + foreach ($url_data as $key => $val) { + if ($key > $ds_count-1) $url .= $ds . $val; + }; + return explode('/',$url)[1]; + } + return '直接访问'; + } + private function getOs(): string + { + + if (!empty($_SERVER['HTTP_USER_AGENT'])) { + $OS = $_SERVER['HTTP_USER_AGENT']; + if (preg_match('/win/i', $OS)) { + $OS = 'window'; + } elseif (preg_match('/mac/i', $OS)) { + $OS = 'mac'; + } elseif (preg_match('/linux/i', $OS)) { + $OS = 'linux'; + } elseif (preg_match('/unix/i', $OS)) { + $OS = 'unix'; + } elseif (preg_match('/bsd/i', $OS)) { + $OS = 'bsd'; + } else { + $OS = '其他操作系统'; + } + return $OS; + } else { + return "获取访客操作系统信息失败!"; + } + } + + private function getBrowser() + { + if (isset($_SERVER["HTTP_USER_AGENT"])) { + $user_agent = strtolower($_SERVER["HTTP_USER_AGENT"]); + } else { + return null; + } + $user_agent=strtolower($_SERVER["HTTP_USER_AGENT"]); + // 固定检测 + if (strrpos($user_agent, 'micromessenger')) { + $user_bs = 'Weixin'; + } elseif (strrpos($user_agent, 'qq')) { + $user_bs = 'QQ'; + } elseif (strrpos($user_agent, 'weibo')) { + $user_bs = 'Weibo'; + } elseif (strrpos($user_agent, 'alipayclient')) { + $user_bs = 'Alipay'; + } elseif (strrpos($user_agent, 'trident/7.0')) { + $user_bs = 'IE11'; + // 新版本IE优先,避免360等浏览器的兼容模式检测错误 + } elseif (strrpos($user_agent, 'trident/6.0')) { + $user_bs = 'IE10'; + } elseif (strrpos($user_agent, 'trident/5.0')) { + $user_bs = 'IE9'; + } elseif (strrpos($user_agent, 'trident/4.0')) { + $user_bs = 'IE8'; + } elseif (strrpos($user_agent, 'msie 7.0')) { + $user_bs = 'IE7'; + } elseif (strrpos($user_agent, 'msie 6.0')) { + $user_bs = 'IE6'; + } elseif (strrpos($user_agent, 'edg')) { + $user_bs = 'Edge'; + } elseif (strrpos($user_agent, 'firefox')) { + $user_bs = 'Firefox'; + } elseif (strrpos($user_agent, 'chrome') || strrpos($user_agent, 'android')) { + $user_bs = 'Chrome'; + } elseif (strrpos($user_agent, 'safari')) { + $user_bs = 'Safari'; + } elseif (strrpos($user_agent, 'mj12bot')) { + $user_bs = 'MJ12bot'; + } else { + $user_bs = '其他浏览器'; + } + return $user_bs; + } + + private function getIp() { + if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP") , "unknown")) { + $ip = getenv("HTTP_CLIENT_IP"); + } else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR") , "unknown")) { + $ip = getenv("HTTP_X_FORWARDED_FOR"); + } else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR") , "unknown")) { + $ip = getenv("REMOTE_ADDR"); + } else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) { + $ip = $_SERVER['REMOTE_ADDR']; + } else { + $ip = "unknown"; + } + return $ip; + } + + private function getLocation($ip = '') { + + + empty($ip) && $ip = $this->getIp(); + $location = ''; + if ($ip == "127.0.0.1") return ("本机地址"); + $bLocalIp = !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); + if($bLocalIp)return '局域网IP'; + try { + $api = "https://www.fkcoder.com/ip?ip=$ip"; //请求新浪ip地址库 + $json = @file_get_contents($api); + $res = json_decode($json, true); + $location = $res['country'].$res['province'].$res['city']; + return $location; + }catch (Throwable $th){ + return 'ip获取异常'; + } + } +} diff --git a/app/common/model/LeaveMessage/LeaveMessage.php b/app/common/model/LeaveMessage/LeaveMessage.php new file mode 100644 index 0000000..6689672 --- /dev/null +++ b/app/common/model/LeaveMessage/LeaveMessage.php @@ -0,0 +1,222 @@ + "int", + + "leave_message_guid" => "string", + + "leave_message_content" => "string", + + "leave_message_name" => "string", + + "leave_message_email" => "string", + + "leave_message_phone" => "int", + + "leave_message_status" => "int", + + "leave_message_create_time" => "datetime", + + "leave_message_create_user_guid" => "string", + + "leave_message_update_time" => "datetime", + + "leave_message_update_user_guid" => "string", + + "leave_message_delete_time" => "datetime", + + "leave_message_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'leave_message_create_time'; + // 修改时间 + protected $updateTime = 'leave_message_update_time'; + + + // excel导入/下载模板表头 + public const EXCELFIELD = [ + 'leave_message_content' => '留言内容', + 'leave_message_name' => '姓名', + 'leave_message_email' => '邮箱', + 'leave_message_phone' => '手机号', + 'leave_message_status' => '留言受理状态', + ]; + + + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + + /** + * 留言用户 + */ + public static function auditLeaveMessage($params) + { + $params_audit_status = $params['leave_message_status']; + $leave_message_guids_arr = explode(',', $params['leave_message_guid']); + + Db::startTrans(); + try { + + if (count($leave_message_guids_arr) > 1) { + foreach ($leave_message_guids_arr as $key => $value) { + self::audit($value,$params); + } + } else { + self::audit($params['leave_message_guid'],$params); + } + + Db::commit(); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 留言 + */ + public static function audit($value,$params) + { + $model = self::where('leave_message_guid', $value)->find(); + if (!$model) throwErrorMsg("该留言不存在", 1); + + $audit_status = $model->leave_message_status; + $leave_message_name = $model->leave_message_name; + + if ($audit_status == 2) throwErrorMsg("{$leave_message_name} 已通过留言!"); + + $model->allowField([ + 'leave_message_status', + ])->save($params); + } + + + /** + * 导出Excel + */ + public static function exportExcel($select) + { + $data = [[ + '留言内容', + '姓名', + '邮箱', + '手机号', + '留言受理状态' + ]]; + foreach ($select as $key => $val) { + $data[] = [ + $val['leave_message_content'], + $val['leave_message_name'], + $val['leave_message_email'], + $val['leave_message_phone'], + $val['leave_message_status'], + ]; + } + $excel = (new Excel())->exporTsheet($data); + $excel->save('.xlsx'); + } + + /** + * 导入excel + */ + public static function importExcel($file) + { + $msg = []; + + Db::startTrans(); + try { + $excel = new Excel($file); + $data = $excel->parseExcel( + Tool::getExcelRule(self::EXCELFIELD), + [ + 'titleLine' => [1] + ] + ); + if (!$data) throwErrorMsg('excel无数据', 1); + $msg = []; + foreach ($data as $line => $value) { + try { + $model = self::importExcelInit($value); + $msg[] = "{$line} 新增成功!
"; + } catch (\Throwable $th) { + $msg[] = "{$line} {$th->getMessage()}
"; + } + } + Db::commit(); + return implode(', ', $msg); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 导入excel初始化 + */ + public static function importExcelInit($value) + { + $leave_message_content = $value['leave_message_content']; + $leave_message_name = $value['leave_message_name']; + $leave_message_email = $value['leave_message_email']; + $leave_message_phone = $value['leave_message_phone']; + $leave_message_status = $value['leave_message_status']; + return self::create([ + 'leave_message_content' => $leave_message_content, + 'leave_message_name' => $leave_message_name, + 'leave_message_email' => $leave_message_email, + 'leave_message_phone' => $leave_message_phone, + 'leave_message_status' => $leave_message_status, + ]); + } +} diff --git a/app/common/model/Menu/Menu.php b/app/common/model/Menu/Menu.php new file mode 100644 index 0000000..47dc783 --- /dev/null +++ b/app/common/model/Menu/Menu.php @@ -0,0 +1,128 @@ + 'int', + 'menu_parent_guid' => 'string', + 'menu_name' => 'string', + 'menu_url' => 'string', + 'menu_index' => 'int', + 'menu_order' => 'int', + 'menu_status' => 'int', + 'menu_show' => 'int', + 'menu_create_time' => 'datetime', + 'menu_create_user_guid' => 'string', + 'menu_update_time' => 'datetime', + 'menu_update_user_guid' => 'string', + 'menu_delete_time' => 'datetime', + 'menu_delete_user_guid' => 'string', + 'menu_guid' => 'string', + ]; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'menu_create_time'; + // 修改时间 + protected $updateTime = 'menu_update_time'; + /** + * 状态 启用 + */ + const STATUS_ENABLE = 1; + /** + * 状态 禁用 + */ + const STATUS_DISABLE = 2; + // 状态查询范围 + public function scopeStatus($query, $status = self::STATUS_ENABLE) + { + $query->where('menu_status', $status); + } + + /** + * 新增前 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeInsert(self $model): void + { + $model->menu_status = self::STATUS_ENABLE; + $model->completeCreateField(); + } + + /** + * 更新前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeUpdate(self $model): void + { + $model->completeUpdateField(); + } + + /** + * 删除前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + /** + * 获取状态 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public function getMenuStatusTextAttr(): string + { + return [ + self::STATUS_ENABLE => '启用', + self::STATUS_DISABLE => '停用' + ][$this->menu_status]; + } + + /** + * 菜单接口 + * + * @date 2022-03-07 + * @example + * @author admin + * @since 1.0.0 + */ + public function apis(): HasMany + { + return $this->hasMany(MenuApi::class, 'menu_guid'); + } +} diff --git a/app/common/model/Menu/MenuApi.php b/app/common/model/Menu/MenuApi.php new file mode 100644 index 0000000..9c6f9eb --- /dev/null +++ b/app/common/model/Menu/MenuApi.php @@ -0,0 +1,142 @@ + 'int', + 'menu_api_guid' => 'string', + 'menu_guid' => 'string', + 'menu_api_url' => 'string', + 'menu_api_status' => 'int', + 'menu_api_create_time' => 'datetime', + 'menu_api_create_user_guid' => 'string', + 'menu_api_update_time' => 'datetime', + 'menu_api_update_user_guid' => 'string', + 'menu_api_delete_time' => 'datetime', + 'menu_api_delete_user_guid' => 'string', + ]; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'menu_api_create_time'; + // 修改时间 + protected $updateTime = 'menu_api_update_time'; + /** + * 状态 启用 + */ + const STATUS_ENABLE = 1; + /** + * 状态 禁用 + */ + const STATUS_DISABLE = 2; + // 状态查询范围 + public function scopeStatus($query, $status = self::STATUS_ENABLE) + { + $query->where('menu_api_status', $status); + } + + /** + * 新增前 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeInsert(self $model): void + { + $model->menu_api_status = self::STATUS_ENABLE; + $menu_api_urls = explode('/', $model->menu_api_url); + if (count($menu_api_urls) == 3) { + $app = isset($menu_api_urls[0]) ? $menu_api_urls[0] : ''; + $controller = isset($menu_api_urls[1]) ? $menu_api_urls[1] : ''; + $action = isset($menu_api_urls[2]) ? $menu_api_urls[2] : ''; + } else { + $controller = isset($menu_api_urls[0]) ? $menu_api_urls[0] : ''; + $action = isset($menu_api_urls[1]) ? $menu_api_urls[1] : ''; + } + if (!$controller) { + throwErrorMsg("缺少controller", 1); + } + if (!$action) { + throwErrorMsg("缺少action", 1); + } + $controller = str_replace('.', '\\', $controller); + if ($app) { + $class = "\\app\\$app\\controller\\$controller"; + } else { + $class = "\\app\\controller\\$controller"; + } + if (!class_exists($class)) { + throwErrorMsg("controller不存在 $controller", 1); + } + if (!method_exists($class, $action)) { + throwErrorMsg("action不存在 $action", 1); + } + $model->completeCreateField(); + } + + /** + * 更新前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeUpdate(self $model): void + { + $model->completeUpdateField(); + } + + /** + * 删除前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + /** + * 获取状态 + * + * @param mixed $value + * @param array $data + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public function getMenuApiStatusTextAttr(): string + { + return [ + self::STATUS_ENABLE => '启用', + self::STATUS_DISABLE => '停用' + ][$this->menu_api_status]; + } +} diff --git a/app/common/model/News/News.php b/app/common/model/News/News.php new file mode 100644 index 0000000..8324044 --- /dev/null +++ b/app/common/model/News/News.php @@ -0,0 +1,99 @@ + "int", + + "news_guid" => "string", + + "news_title" => "string", + + "news_author" => "string", + + "news_intro" => "string", + + "news_type" => "string", + + "news_img" => "string", + + "news_content" => "string", + + "news_detail_time" => "datetime", + + "news_num" => "int", + + "news_create_time" => "datetime", + + "news_create_user_guid" => "string", + + "news_update_time" => "datetime", + + "news_update_user_guid" => "string", + + "news_delete_time" => "datetime", + + "news_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'news_create_time'; + // 修改时间 + protected $updateTime = 'news_update_time'; + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + /** + * 产品类型获取器 + */ + public function getNewsCreatedTimeAttr($value, $data) + { + $news_create_time = $data['news_create_time']; + $news_create_time = date("m-d"); + return $news_create_time; + } +} diff --git a/app/common/model/Product/Product.php b/app/common/model/Product/Product.php new file mode 100644 index 0000000..b55942e --- /dev/null +++ b/app/common/model/Product/Product.php @@ -0,0 +1,227 @@ + "int", + + "product_guid" => "string", + + "product_type_guid" => "string", + + "product_name" => "string", + + "product_img" => "string", + + "product_params" => "string", + + "product_details" => "string", + + "product_price" => "", + + "product_create_time" => "datetime", + + "product_create_user_guid" => "string", + + "product_update_time" => "datetime", + + "product_update_user_guid" => "string", + + "product_delete_time" => "datetime", + + "product_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'product_create_time'; + // 修改时间 + protected $updateTime = 'product_update_time'; + + + // excel导入/下载模板表头 + public const EXCELFIELD = [ + 'product_type_guid' => '产品系列', + 'product_name' => '名称', + 'product_img' => '图片', + 'product_params' => '参数', + 'product_details' => '详情', + 'product_price' => '价格', + ]; + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + /** + * 修改器(产品参数) + */ + public function setProductParamsAttr($value): string + { + return json_encode($value, JSON_UNESCAPED_UNICODE); + } + + /** + * 获取器(产品参数) + */ + public function getProductParamsAttr($value): array + { + return json_decode($value); + } + + /** + * 获取器(产品图片) + */ + public function getProductImgAttr($value): array + { + $data = []; + foreach (explode(',', $value) as $item) { + $data[] = ['url' => $item]; + }; + return $data; + } + + /** + * 指定产品上下id获取 + * + * @param string $product_id 当前产品id + * @param string $product_type_guid 产品系列guid + * @return array [上一个id,下一个idF] + */ + public static function getProductUpAndDownId(string $product_id, string $product_type_guid): array + { + $query = function ($op, $order) use ($product_id, $product_type_guid) { + return self::where([['product_id', $op, $product_id], ['product_type_guid', '=', $product_type_guid]]) + ->limit(1) + ->order('product_id', $order) + ->value('product_id'); + }; + return [$query('<', 'desc'), $query('>', 'asc')]; + } + + /** + * 导出Excel + */ + public static function exportExcel($select) + { + $data = [[ + '产品系列', + '名称', + '图片', + '参数', + '详情', + '价格' + ]]; + foreach ($select as $key => $val) { + $data[] = [ + $val['product_type_guid'], + $val['product_name'], + Excel::ExportImgFiled($val['product_img']), + $val['product_params'], + $val['product_details'], + $val['product_price'], + ]; + } + $excel = (new Excel())->exporTsheet($data); + $excel->save('产品.xlsx'); + } + + /** + * 导入excel + */ + public static function importExcel($file) + { + $msg = []; + + Db::startTrans(); + try { + $excel = new Excel($file); + $data = $excel->parseExcel( + Tool::getExcelRule(self::EXCELFIELD), + [ + 'titleLine' => [1] + ] + ); + if (!$data) throwErrorMsg('excel无数据', 1); + $msg = []; + foreach ($data as $line => $value) { + try { + $model = self::importExcelInit($value); + $msg[] = "{$line} 新增成功!
"; + } catch (\Throwable $th) { + $msg[] = "{$line} {$th->getMessage()}
"; + } + } + Db::commit(); + return implode(', ', $msg); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 导入excel初始化 + */ + public static function importExcelInit($value) + { + $product_type_guid = $value['product_type_guid']; + $product_name = $value['product_name']; + $product_img = $value['product_img']; + $product_params = $value['product_params']; + $product_details = $value['product_details']; + $product_price = $value['product_price']; + return self::create([ + 'product_type_guid' => $product_type_guid, + 'product_name' => $product_name, + 'product_img' => $product_img, + 'product_params' => $product_params, + 'product_details' => $product_details, + 'product_price' => $product_price, + ]); + } +} diff --git a/app/common/model/Product/ProductParam.php b/app/common/model/Product/ProductParam.php new file mode 100644 index 0000000..da40125 --- /dev/null +++ b/app/common/model/Product/ProductParam.php @@ -0,0 +1,93 @@ + "int", + + "product_param_guid" => "string", + + "product_param_name" => "string", + + "product_type_guid" => "string", + + "product_type_order" => "int", + + "product_param_create_time" => "datetime", + + "product_param_create_user_guid" => "string", + + "product_param_update_time" => "datetime", + + "product_param_update_user_guid" => "string", + + "product_param_delete_time" => "datetime", + + "product_param_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'product_param_create_time'; + // 修改时间 + protected $updateTime = 'product_param_update_time'; + + + + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + + + + + + + +} diff --git a/app/common/model/Product/ProductType.php b/app/common/model/Product/ProductType.php new file mode 100644 index 0000000..6063099 --- /dev/null +++ b/app/common/model/Product/ProductType.php @@ -0,0 +1,182 @@ + "int", + "product_type_guid" => "string", + "product_type_name" => "string", + "product_type_parent_guid" => "string", + "product_type_ancestors_guid" => "string", + "product_type_icon" => "string", + "product_type_cover" => "string", + "product_type_order" => "int", + "product_type_create_time" => "datetime", + "product_type_create_user_guid" => "string", + "product_type_update_time" => "datetime", + "product_type_update_user_guid" => "string", + "product_type_delete_time" => "datetime", + "product_type_delete_user_guid" => "string", + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'product_type_create_time'; + // 修改时间 + protected $updateTime = 'product_type_update_time'; + + // excel导入/下载模板表头 + public const EXCELFIELD = [ + 'product_type_name' => '产品系列名称', + 'product_type_icon' => '产品系列图标', + 'product_type_cover' => '产品系列封面', + ]; + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + /** + * 产品系列祖级guid构建 + * + * @param string $product_type_parent_guid 产品系列父级guid + */ + public static function buildAncestorsGuid(string $product_type_parent_guid): string + { + if ($product_type_parent_guid == "0") return $product_type_parent_guid; + $product_type = self::where('product_type_guid', $product_type_parent_guid)->find(); + if (!$product_type) throwErrorMsg('该父级产品系列不存在!'); + return $product_type->product_type_ancestors_guid . ',' . $product_type_parent_guid; + } + + /** + * 产品系列重名验证 + * + * @param string $product_type_name 产品系列名称 + * @param string $product_type_guid 产品系列guid + */ + public static function isDuplicateName(string $product_type_name, string $product_type_guid = null): void + { + $con = [ + ['product_type_name', '=', $product_type_name] + ]; + if ($product_type_guid) { + $con[] = ['product_type_guid', '<>', $product_type_guid]; + } + if (self::where($con)->find()) { + throwErrorMsg('产品系列不可重名!'); + }; + } + + /** + * 导出Excel + */ + public static function exportExcel($select) + { + $data = [[ + '产品系列标题', + '产品系列图标', + '产品系列封面' + ]]; + foreach ($select as $key => $val) { + $data[] = [ + $val['product_type_title'], + $val['product_type_icon'], + Excel::ExportImgFiled($val['product_type_cover']), + ]; + } + $excel = (new Excel())->exporTsheet($data); + $excel->save('产品系列.xlsx'); + } + + /** + * 导入excel + */ + public static function importExcel($file) + { + $msg = []; + + Db::startTrans(); + try { + $excel = new Excel($file); + $data = $excel->parseExcel( + Tool::getExcelRule(self::EXCELFIELD), + [ + 'titleLine' => [1] + ] + ); + if (!$data) throwErrorMsg('excel无数据', 1); + $msg = []; + foreach ($data as $line => $value) { + try { + $model = self::importExcelInit($value); + $msg[] = "{$line} 新增成功!
"; + } catch (\Throwable $th) { + $msg[] = "{$line} {$th->getMessage()}
"; + } + } + Db::commit(); + return implode(', ', $msg); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 导入excel初始化 + */ + public static function importExcelInit($value) + { + $product_type_title = $value['product_type_title']; + $product_type_icon = $value['product_type_icon']; + $product_type_cover = $value['product_type_cover']; + return self::create([ + 'product_type_title' => $product_type_title, + 'product_type_icon' => $product_type_icon, + 'product_type_cover' => $product_type_cover, + ]); + } +} diff --git a/app/common/model/Role/Role.php b/app/common/model/Role/Role.php new file mode 100644 index 0000000..e24275c --- /dev/null +++ b/app/common/model/Role/Role.php @@ -0,0 +1,146 @@ + 'int', + 'role_name' => 'string', + 'role_status' => 'int', + 'role_create_time' => 'datetime', + 'role_create_user_guid' => 'string', + 'role_update_time' => 'datetime', + 'role_update_user_guid' => 'string', + 'role_delete_time' => 'datetime', + 'role_delete_user_guid' => 'string', + 'role_guid' => 'string', + ]; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'role_create_time'; + // 修改时间 + protected $updateTime = 'role_update_time'; + /** + * 状态 启用 + */ + const STATUS_ENABLE = 1; + /** + * 状态 禁用 + */ + const STATUS_DISABLE = 2; + // 状态查询范围 + public function scopeStatus(Query $query, $status = self::STATUS_ENABLE) + { + $query->where('role_status', $status); + } + + /** + * 新增前 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeInsert(self $model): void + { + $model->role_status = self::STATUS_ENABLE; + $model->completeCreateField(); + } + + /** + * 更新前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeUpdate(self $model): void + { + $model->completeUpdateField(); + } + + /** + * 删除前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + /** + * 获取状态 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public function getRoleStatusTextAttr(): string + { + return [ + self::STATUS_ENABLE => '启用', + self::STATUS_DISABLE => '停用' + ][$this->role_status]; + } + + /** + * 获取角色用户 + * + * @date 2022-03-02 + * @example + * @author admin + * @since 1.0.0 + */ + public function users(): BelongsToMany + { + return $this->belongsToMany( + User::class, + UserRole::class, + 'user_guid', + 'role_guid' + ); + } + + /** + * 获取角色菜单 + * + * @date 2022-03-02 + * @example + * @author admin + * @since 1.0.0 + */ + public function menus(): BelongsToMany + { + return $this->belongsToMany( + Menu::class, + RoleMenu::class, + 'menu_guid', + 'role_guid' + ); + } +} diff --git a/app/common/model/Role/RoleMenu.php b/app/common/model/Role/RoleMenu.php new file mode 100644 index 0000000..d1467a5 --- /dev/null +++ b/app/common/model/Role/RoleMenu.php @@ -0,0 +1,162 @@ + 'int', + 'menu_guid' => 'string', + 'role_guid' => 'string', + 'role_menu_status' => 'int', + 'role_menu_create_time' => 'datetime', + 'role_menu_create_user_guid' => 'string', + 'role_menu_update_time' => 'datetime', + 'role_menu_update_user_guid' => 'string', + 'role_menu_delete_time' => 'datetime', + 'role_menu_delete_user_guid' => 'string', + 'role_menu_guid' => 'string', + ]; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'role_menu_create_time'; + // 修改时间 + protected $updateTime = 'role_menu_update_time'; + /** + * 状态 启用 + */ + const STATUS_ENABLE = 1; + /** + * 状态 禁用 + */ + const STATUS_DISABLE = 2; + // 状态查询范围 + public function scopeStatus($query, $status = self::STATUS_ENABLE) + { + $query->where('role_menu_status', $status); + } + /** + * 中间关联 + * + * @return ModelPivot + * @date 2022-12-30 + * @example + * @author admin + * @since 1.0.0 + */ + public static function pivot(): ModelPivot + { + return new ModelPivot( + self::class, + Role::class, + Menu::class, + true + ); + } + /** + * 绑定角色菜单 + * + * @param $roles + * @param $menus + * @param array $extra + * @return void + * @date 2022-12-29 + * @example + * @author admin + * @since 1.0.0 + */ + public static function bindRoleMenu($roles, $menus, array $extra = []): void + { + self::pivot()->bind($roles, $menus, $extra); + } + /** + * 解绑角色菜单 + * + * @param $roles + * @param $menus + * @return void + * @date 2022-12-30 + * @example + * @author admin + * @since 1.0.0 + */ + public static function unbindRoleMenu($roles, $menus): void + { + self::pivot()->unbind($roles, $menus); + } + /** + * 绑定角色菜单 + * + * @param $roles + * @param $menus + * @param array $extra + * @return void + * @date 2022-12-29 + * @example + * @author admin + * @since 1.0.0 + */ + public static function rebindRoleMenu($roles, $menus, array $extra = []): void + { + self::pivot()->rebind($roles, $menus, $extra); + } + + /** + * 新增前 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeInsert(self $model): void + { + $model->role_menu_status = self::STATUS_ENABLE; + $model->completeCreateField(); + } + + /** + * 更新前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeUpdate(self $model): void + { + $model->completeUpdateField(); + } + + /** + * 删除前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } +} diff --git a/app/common/model/School/Classes.php b/app/common/model/School/Classes.php new file mode 100644 index 0000000..9725c90 --- /dev/null +++ b/app/common/model/School/Classes.php @@ -0,0 +1,77 @@ + "int", + + "classes_guid" => "string", + + "classes_name" => "string", + + "classes_create_time" => "datetime", + + "classes_create_user_guid" => "string", + + "classes_update_time" => "datetime", + + "classes_update_user_guid" => "string", + + "classes_delete_time" => "datetime", + + "classes_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'classes_create_time'; + // 修改时间 + protected $updateTime = 'classes_update_time'; + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + +} diff --git a/app/common/model/School/Student.php b/app/common/model/School/Student.php new file mode 100644 index 0000000..45715eb --- /dev/null +++ b/app/common/model/School/Student.php @@ -0,0 +1,627 @@ + "int", + + "student_guid" => "string", + + "student_name" => "string", + + "user_guid" => "string", + + "classes_guid" => "string", + + "studnet_phone" => "string", + + "student_id_card" => "string", + + "student_email" => "string", + + "student_sex" => "string", + + "student_price" => "", + + "student_brithday" => "date", + + "product_type" => "string", + + "product_guid" => "string", + + "product_parts_guid" => "string", + + "student_img" => "string", + + "student_banner_img" => "string", + + "student_attachment" => "string", + + "student_intro" => "string", + + "student_location" => "string", + + "longitude" => "string", + + "latitude" => "string", + + "student_membe_type" => "string", + + "student_member_begin_time" => "date", + + "student_member_end_time" => "date", + + "student_audit_status" => "string", + + "student_audit_user_guid" => "string", + + "student_create_time" => "datetime", + + "student_create_user_guid" => "string", + + "student_update_time" => "datetime", + + "student_update_user_guid" => "string", + + "student_delete_time" => "datetime", + + "student_delete_user_guid" => "string", + + ]; + + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'student_create_time'; + // 修改时间 + protected $updateTime = 'student_update_time'; + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + /** + * 审核学生 + */ + public static function auditStudent($params) + { + $params_audit_status = $params['student_audit_status']; + $student_guids_arr = explode(',', $params['student_guid']); + + Db::startTrans(); + try { + + if (count($student_guids_arr) > 1) { + foreach ($student_guids_arr as $key => $value) { + self::audit($value,$params); + } + } else { + self::audit($params['student_guid'],$params); + } + + Db::commit(); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + + /** + * 审核 + */ + public static function audit($value,$params) + { + $model = self::where('student_guid', $value)->find(); + if (!$model) throwErrorMsg("该学生不存在", 1); + + $params['student_audit_user_guid'] = Request::getCurrentUser()->user_guid; + + $audit_status = $model->student_audit_status; + $student_name = $model->student_name; + + if ($audit_status == 2) throwErrorMsg("{$student_name} 学生已通过审核!"); + if ($audit_status == 3) throwErrorMsg("{$student_name} 学生已驳回审核!"); + + $model->allowField([ + 'student_audit_status', + 'student_audit_user_guid' + ])->save($params); + } + + /** + * 新增前初始化 + */ + public static function initAdd($params) + { + $user = ModelUser::where('user_name', $params['user_name'])->find(); + $params['user_guid'] = $user->user_guid; + $student_user = self::where('user_guid', $params['user_guid'])->find(); + if ($student_user) throwErrorMsg("用户已经被绑定,请重新选择!"); + + $isPhone = RegularVerification::checkPreg($params['studnet_phone'], 'mobile'); + if (!$isPhone) throwErrorMsg("电话格式错误"); + + $isIdCard = RegularVerification::checkPreg($params['student_id_card'], 'idcard'); + if (!$isIdCard) throwErrorMsg("身份证格式错误"); + + $isEmail = RegularVerification::checkPreg($params['student_email'], 'email'); + if (!$isEmail) throwErrorMsg("邮箱格式错误"); + + // 季卡 + if ($params['student_membe_type'] == '1') { + $params['student_member_begin_time'] = date('Y-m-d H:i:s'); + $params['student_member_end_time'] = date('Y-m-d H:i:s', strtotime('+3 month')); + } + // 年卡 + if ($params['student_membe_type'] == '2') { + $params['student_member_begin_time'] = date('Y-m-d H:i:s'); + $params['student_member_end_time'] = date('Y-m-d H:i:s', strtotime('+1 year')); + } + + // 已审核 + $params['student_audit_status'] = "1"; + // $params['student_audit_user_guid'] = "ds4a3d2asd423s3as4d34asdd"; + + return $params; + } + + /** + * 导入前初始化 + */ + public static function ImportStudentInit($value) + { + // 用户判断 + $user = ModelUser::where('user_name', $value['user_name'])->find(); + // array_push($error, "{$line}: 产品类型不存在,导入失败!"); + if (!$user) throwErrorMsg("用户 {$value['user_name']} 不存在"); + $value['user_guid'] = $user->user_guid; + $student_user = self::where('user_guid', $value['user_guid'])->find(); + if ($student_user) throwErrorMsg("用户 {$value['user_name']} 已经被绑定,请重新选择!"); + + // 班级判断 + $classes = ModelClasses::where('classes_name', $value['classes_name'])->find(); + if (!$classes) throwErrorMsg("班级不存在"); + $value['classes_guid'] = $classes->classes_guid; + + + $isPhone = RegularVerification::checkPreg($value['studnet_phone'], 'mobile'); + if (!$isPhone) throwErrorMsg("电话格式错误"); + + // $isIdCard = RegularVerification::checkPreg($value['student_id_card'], 'idcard'); + // if (!$isIdCard) throwErrorMsg("身份证格式错误"); + + $isEmail = RegularVerification::checkPreg($value['student_email'], 'email'); + if (!$isEmail) throwErrorMsg("邮箱格式错误"); + + $sex_val = [1 => '男', 2 => '女']; + + + // 性别判断 + if (!in_array($value['student_sex'], ["男", "女"])) throwErrorMsg("请填写男或女"); + else { + $value['student_sex'] = array_search($value['student_sex'], $sex_val); + // if ($value['student_sex'] == "男") $value['student_sex'] = 1; + // if ($value['student_sex'] == "女") $value['student_sex'] = 2; + } + + // 价格判断 + if (!is_numeric($value['student_price'])) throwErrorMsg("学生价格必须为整数"); + if ($value['student_price'] < 0) throwErrorMsg("学生价格不能为负数"); + + // 产品类型判断 + $product_type = ModelProductType::where('product_type_name', $value['product_type_name'])->find(); + if (!$product_type) throwErrorMsg("{$value['product_type_name']} 产品类型不存在"); + $value['product_type_guid'] = $product_type->product_type_guid; + + // 产品判断 + $product = ModelProduct::where('product_name', $value['product_name'])->find(); + if (!$product) throwErrorMsg("{$value['product_name']} 产品不存在"); + $value['product_guid'] = $product->product_guid; + $InProductType = ModelProduct::where('product_type_guid', $value['product_type_guid'])->find(); + if (!$InProductType) throwErrorMsg("{$value['product_name']} 产品 没有绑定产品类型:{$value['product_type_name']}"); + + // 产品零件判断 + $product_parts = ModelProductParts::where('product_parts_name', $value['product_parts_name'])->find(); + if (!$product_parts) throwErrorMsg("{$value['product_parts_name']} 产品零件不存在"); + $value['product_parts_guid'] = $product_parts->product_parts_guid; + $InProduct = ModelProductParts::where('product_guid', $value['product_guid'])->find(); + if (!$InProduct) throwErrorMsg("{$value['product_parts_name']} 产品零件 没有绑定产品:{$value['product_name']}"); + + // 获取经纬度 + $longitude_latitude_arr = Map::getLongitudeAndLatitude($value['student_location']); + $value['longitude'] = $longitude_latitude_arr['longitude']; + $value['latitude'] = $longitude_latitude_arr['latitude']; + + // 季卡 + if ($value['student_membe_type'] == '季卡') { + $value['student_membe_type'] = '1'; + $value['student_member_begin_time'] = date('Y-m-d H:i:s'); + $value['student_member_end_time'] = date('Y-m-d H:i:s', strtotime('+3 month')); + } + // 年卡 + if ($value['student_membe_type'] == '年卡') { + $value['student_membe_type'] = '2'; + $value['student_member_begin_time'] = date('Y-m-d H:i:s'); + $value['student_member_end_time'] = date('Y-m-d H:i:s', strtotime('+1 year')); + } + + // 已审核 + $value['student_audit_status'] = "2"; + $value['student_audit_user_guid'] = "ds4a3d2asd423s3as4d34asdd"; + + // 生日日期处理 + $time = strtotime($value['student_brithday']); + $newformat = date('Y-m-d', $time); + + return self::create([ + 'student_name' => $value['student_name'], + 'user_guid' => $value['user_guid'], + 'classes_guid' => $value['classes_guid'], + 'studnet_phone' => $value['studnet_phone'], + 'student_id_card' => $value['student_id_card'], + 'student_email' => $value['student_email'], + 'student_sex' => $value['student_sex'], + 'student_price' => $value['student_price'], + 'student_brithday' => $newformat, + 'product_type' => $value['product_type_guid'], + 'product_guid' => $value['product_guid'], + 'product_parts_guid' => $value['product_parts_guid'], + 'student_img' => $value['student_img'], + 'student_banner_img' => $value['student_banner_img'], + 'student_intro' => $value['student_intro'], + 'student_location' => $value['student_location'], + 'longitude' => $value['longitude'], + 'latitude' => $value['latitude'], + 'student_membe_type' => $value['student_membe_type'], + 'student_member_begin_time' => $value['student_member_begin_time'], + 'student_member_end_time' => $value['student_member_end_time'], + 'student_audit_status' => $value['student_audit_status'], + 'student_audit_user_guid' => $value['student_audit_user_guid'], + ]); + } + + /** + * 导入学生 + */ + public static function ImportStudent($file) + { + $error = []; + + Db::startTrans(); + try { + + $excel = new Excel($file); + $data = $excel->parseExcel( + [ + [ + 'title' => '学生名称', + 'validate' => 'require', + 'field' => 'student_name', + ], [ + 'title' => '用户', + 'validate' => 'require', + 'field' => 'user_name', + ], [ + 'title' => '班级', + 'validate' => 'require', + 'field' => 'classes_name', + ], [ + 'title' => '手机号', + 'validate' => 'require', + 'field' => 'studnet_phone', + ], [ + 'title' => '身份证号', + 'validate' => 'require', + 'field' => 'student_id_card', + ], [ + 'title' => '邮箱', + 'validate' => 'require', + 'field' => 'student_email', + ], [ + 'title' => '性别', + 'validate' => 'require', + 'field' => 'student_sex', + ], [ + 'title' => '学生价格', + 'validate' => 'require', + 'field' => 'student_price', + ], [ + 'title' => '生日', + 'validate' => 'require', + 'field' => 'student_brithday', + ], [ + 'title' => '产品类型', + 'validate' => 'require', + 'field' => 'product_type_name', + ], [ + 'title' => '产品', + 'validate' => 'require', + 'field' => 'product_name', + ], [ + 'title' => '产品零件', + 'validate' => 'require', + 'field' => 'product_parts_name', + ], [ + 'title' => '头像', + 'validate' => 'require', + 'field' => 'student_img', + ], [ + 'title' => '轮播图片', + 'validate' => 'require', + 'field' => 'student_banner_img', + ], [ + 'title' => '简介', + 'validate' => 'require', + 'field' => 'student_intro', + ], [ + 'title' => '家庭住址', + 'validate' => 'require', + 'field' => 'student_location', + ], [ + 'title' => '会员类型', + 'validate' => 'require', + 'field' => 'student_membe_type', + ], + // [ + // 'title' => '会员开始时间', + // 'validate' => 'require', + // 'field' => 'student_member_begin_time', + // ], [ + // 'title' => '会员结束时间', + // 'validate' => 'require', + // 'field' => 'student_member_end_time', + // ], + ], + [ + 'titleLine' => [1] + ] + ); + if (!$data) throwErrorMsg('excel无数据', 1); + $error = []; + foreach ($data as $line => $value) { + try { + $model = self::ImportStudentInit($value); + $error[] = "{$line} 学生:【{$value['student_name']}】新增成功!
"; + } catch (\Throwable $th) { + $error[] = "{$line} 学生:【{$value['student_name']}】{$th->getMessage()}
"; + } + } + Db::commit(); + + return implode(', ', $error); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + + return $error; + } + + /** + * 导出学生 + */ + public static function exportStudent() + { + $select = self::alias('a') + ->field([ + 'a.student_name', + 'b.user_name', + 'f.classes_name', + 'a.studnet_phone', + 'a.student_id_card', + 'a.student_email', + 'a.student_sex', + 'a.student_price', + 'a.student_brithday', + 'c.product_type_name', + 'd.product_name', + 'e.product_parts_name', + 'a.student_img', + 'a.student_banner_img', + 'a.student_attachment', + 'a.student_location', + 'a.student_membe_type', + 'a.student_member_begin_time', + 'a.student_member_end_time', + 'a.student_audit_status', + "(SELECT `user`.`user_name` FROM `user` WHERE `user`.user_guid = `a`.`student_audit_user_guid`) as student_audit_user_name", + ]) + ->leftjoin('user b', 'a.user_guid = b.user_guid') + ->leftjoin('product_type c', 'a.product_type = c.product_type_guid') + ->leftjoin('product d', 'a.product_guid = d.product_guid') + ->leftjoin('product_parts e', 'a.product_parts_guid = e.product_parts_guid') + ->leftjoin('classes f', 'a.classes_guid = f.classes_guid') + ->order('student_update_time', 'desc')->select(); + + $data = [[ + '学生名称', + '用户', + '班级', + '手机号', + '身份证号', + '邮箱', + '性别', + '学生价格', + '生日', + '产品类型', + '产品', + '产品零件', + '头像', + '轮播图片', + '家庭住址', + '会员类型', + '会员开始时间', + '会员结束时间', + '审核状态', + '审核人' + ]]; + foreach ($select as $key => $val) { + + $sex_arr = [1 => "男", 2 => "女"]; + $member_arr = [1 => "季卡", 2 => "年卡"]; + $audit_arr = [1 => "未审核", 2 => "已审核", 3 => "未通过"]; + + $val['student_sex'] = $sex_arr[$val['student_sex']]; + $val['student_membe_type'] = $member_arr[$val['student_membe_type']]; + $val['student_audit_status'] = $audit_arr[$val['student_audit_status']]; + $val['student_img'] = Excel::ExportImgFiled($val['student_img']); + $val['student_banner_img'] = Excel::ExportImgFiled($val['student_banner_img']); + + $data[] = [ + $val['student_name'], + $val['user_name'], + $val['classes_name'], + $val['studnet_phone'], + $val['student_id_card'], + $val['student_email'], + $val['student_sex'], + $val['student_price'], + $val['student_brithday'], + $val['product_type_name'], + $val['product_name'], + $val['product_parts_name'], + $val['student_img'], + $val['student_banner_img'], + $val['student_location'], + $val['student_membe_type'], + $val['student_member_begin_time'], + $val['student_member_end_time'], + $val['student_audit_status'], + $val['student_audit_user_name'], + ]; + } + $excel = (new Excel())->exporTsheet($data); + $excel->save('学生.xlsx'); + } + + /** + * 新增学生服务 + */ + public static function addStudentService($student_guid, $params): void + { + $student_service_arr = $params['student_service']; + + foreach ($student_service_arr as $key => $item) { + Db::startTrans(); + try { + $add_data = [ + 'student_guid' => $student_guid, + 'student_service_name' => $item['service_name'], + 'student_service_price' => $item['service_price'], + ]; + $student_service = ModelStudentService::create($add_data); + + Db::commit(); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + } + + /** + * 编辑学生服务 + */ + public static function editStudentService($params): void + { + // 从学生服务(副表)查询出所有当前学生的服务,进行删除 + ModelStudentService::where('student_guid', $params['student_guid'])->select()->delete(); + + // 再把传值的数据,写入副表 + $student_service_arr = $params['student_service']; + foreach ($student_service_arr as $key => $item) { + Db::startTrans(); + try { + $add_data = [ + 'student_guid' => $params['student_guid'], + 'student_service_name' => $item['service_name'], + 'student_service_price' => $item['service_price'], + ]; + ModelStudentService::create($add_data); + + Db::commit(); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + } + + /** + * 会员时间获取器 + */ + public function getStudentMemberTimeAttr($value, $data) + { + $student_member_time = []; + + array_push($student_member_time, $data['student_member_begin_time']); + array_push($student_member_time, $data['student_member_end_time']); + + return $student_member_time; + } + + + /** + * 学生服务获取器 + */ + public function getStudentServiceAttr($value, $data) + { + $studnet_guid = $data['student_guid']; + $studetn_service = ModelStudentService::field([ + 'student_service_guid', + 'student_service_name' => 'service_name', + 'student_service_price' => 'service_price', + ])->where('student_guid', $studnet_guid)->select(); + return $studetn_service; + } +} diff --git a/app/common/model/School/StudentService.php b/app/common/model/School/StudentService.php new file mode 100644 index 0000000..8661c22 --- /dev/null +++ b/app/common/model/School/StudentService.php @@ -0,0 +1,81 @@ + "int", + + "student_service_guid" => "string", + + "student_guid" => "string", + + "student_service_name" => "string", + + "student_service_price" => "", + + "student_service_create_time" => "datetime", + + "student_service_create_user_guid" => "string", + + "student_service_update_time" => "datetime", + + "student_service_update_user_guid" => "string", + + "student_service_delete_time" => "datetime", + + "student_service_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'student_service_create_time'; + // 修改时间 + protected $updateTime = 'student_service_update_time'; + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + +} diff --git a/app/common/model/ServiceSupport/ServiceSupport.php b/app/common/model/ServiceSupport/ServiceSupport.php new file mode 100644 index 0000000..b8087c9 --- /dev/null +++ b/app/common/model/ServiceSupport/ServiceSupport.php @@ -0,0 +1,93 @@ + "int", + + "service_support_guid" => "string", + + "service_support_idea" => "string", + + "service_support_promise" => "string", + + "service_support_network" => "string", + + "service_support_create_time" => "datetime", + + "service_support_create_user_guid" => "string", + + "service_support_update_time" => "datetime", + + "service_support_update_user_guid" => "string", + + "service_support_delete_time" => "datetime", + + "service_support_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'service_support_create_time'; + // 修改时间 + protected $updateTime = 'service_support_update_time'; + + + + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + + + + + + + +} diff --git a/app/common/model/Tdk/Tdk.php b/app/common/model/Tdk/Tdk.php new file mode 100644 index 0000000..eb019bd --- /dev/null +++ b/app/common/model/Tdk/Tdk.php @@ -0,0 +1,83 @@ + "int", + + "tdk_guid" => "string", + + "tdk_type" => "int", + + "tdk_title" => "string", + + "tdk_description" => "string", + + "tdk_keyword" => "string", + + "tdk_create_time" => "datetime", + + "tdk_create_user_guid" => "string", + + "tdk_update_time" => "datetime", + + "tdk_update_user_guid" => "string", + + "tdk_delete_time" => "datetime", + + "tdk_delete_user_guid" => "string", + + ]; + // 设置json类型字段 + protected $json = ['']; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'tdk_create_time'; + // 修改时间 + protected $updateTime = 'tdk_update_time'; + + /** + * 新增前 + */ + public static function onBeforeInsert(self $model): void + { + // self::checkRepeatData($model); + $model->completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + +} diff --git a/app/common/model/Token.php b/app/common/model/Token.php new file mode 100644 index 0000000..f87c75e --- /dev/null +++ b/app/common/model/Token.php @@ -0,0 +1,337 @@ + 'int', + 'token_guid' => 'string', + 'user_guid' => 'string', + 'token_menu' => 'json', + 'token_api' => 'json', + 'token_exp_time' => 'datetime', + 'token_content' => 'string', + 'token_create_time' => 'datetime', + 'token_update_time' => 'datetime', + ]; + // json数据字段 + protected $json = ['token_menu', 'token_api']; + // 设置JSON数据返回数组 + protected $jsonAssoc = true; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'token_create_time'; + // 修改时间 + protected $updateTime = 'token_update_time'; + /** + * 当前用户 + * + * @var User + */ + private static $user = null; + /** + * 当前model + * + * @var self + */ + private static $current = null; + + /** + * 用户 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public function user(): hasOne + { + return $this->hasOne(User::class, 'user_guid', 'user_guid'); + } + + /** + * 设置过期时间 + * + * @param mixed $value + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public function setTokenExpTimeAttr($value): string + { + return date('Y-m-d H:i:s', $value); + } + + /** + * 判断是否过期 + * + * @return boolean + * @date 2022-12-27 + * @example + * @author admin + * @since 1.0.0 + */ + public function getIsExpAttr(): bool + { + return time() >= $this->token_exp_timestamp; + } + + /** + * 获取过期时间戳 + * + * @return integer + * @date 2022-12-27 + * @example + * @author admin + * @since 1.0.0 + */ + public function getTokenExpTimestampAttr(): int + { + return strtotime($this->token_exp_time); + } + + + /** + * 新增前 + * + * @param self $model + * @return void + * @date 2022-12-27 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeInsert(self $model): void + { + $model->token_content = $model->generateContent(); + $model->token_guid = self::generateGuid(); + } + + /** + * 登陆 + * 如果当前存在有效token 更新过期时间 + * 如果token已过期 更新token和过期时间 + * 如果不存在token 新增数据 + * + * @param string $guid 用户id + * @param array $options 配置项 + * @param int $options[expTime] 过期时间(时间戳) 不传默认两小时 + * @param array $options[menu] 菜单 + * @param int $options[api] 接口 + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function login(string $guid, array $options = []): self + { + $expTime = 0; + $menu = []; + $api = []; + if (is_array($options)) { + $expTime = Arr::get($options, 'expTime', 0); + $menu = Arr::get($options, 'menu', []); + $api = Arr::get($options, 'api', []); + } + if ($expTime == 0) { + $expTime = time() + (24 * 60 * 60); + } + $data = [ + 'token_exp_time' => $expTime + ]; + if ($menu) { + $data['token_menu'] = $menu; + } + if ($api) { + $data['token_api'] = $api; + } + /** + * @var Token + */ + $model = self::where([ + 'user_guid' => $guid, + ])->find(); + // 数据不存在 + if (!$model) { + return self::create($data + [ + 'user_guid' => $guid, + ]); + } + // token已过期 + if ($model->is_exp) { + $data['token_content'] = $model->generateContent($model); + } + $model->save($data); + return $model; + } + + /** + * 登出 + * + * @date 2022-03-15 + * @example + * @author admin + * @since 1.0.0 + */ + public static function logout(): void + { + self::getCurrent()->delete(); + } + + /** + * 获取请求token + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function getRequestToken(): string + { + $tokenKey = 'token'; + $token = ''; + if (!$token && isset($_GET[$tokenKey])) { + $token = $_GET[$tokenKey]; + } + if (!$token && isset($_POST[$tokenKey])) { + $token = $_POST[$tokenKey]; + } + if (!$token && Request::param($tokenKey)) { + $token = Request::param($tokenKey); + } + if (!$token && Request::header($tokenKey)) { + $token = Request::header($tokenKey); + } + return $token; + } + + /** + * 获取当前用户信息 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function getCurrentUser(): User + { + if (!self::$user) { + $model = self::getCurrent(); + self::$user = $model->user; + if (!self::$user) { + throw new ErrorMsg("用户不存在", 1); + } + } + return self::$user; + } + + /** + * 获取当前有效token + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function getCurrent(): self + { + if (!self::$current) { + $content = self::getRequestToken(); + if (!$content) { + throw new LoginTimeOut("缺少token", 1); + } + $model = self::where([ + 'token_content' => $content, + ])->find(); + if (!$model) { + throw new LoginTimeOut("未登录", 1); + } + if ($model->is_exp) { + throw new LoginTimeOut("登录超时", 1); + } + self::$current = $model; + } + return self::$current; + } + + /** + * 判断是否登录 + * + * @date 2022-05-14 + * @example + * @author admin + * @since 1.0.0 + */ + public static function isLogin(): bool + { + try { + self::getCurrent(); + return true; + } catch (LoginTimeOut $th) { + return false; + } + } + + /** + * 延长token + * 过期前30分钟才会延期 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function delay(): void + { + try { + // 半小时 + $delay = (60 * 30); + $model = self::getCurrent(); + $token_exp_time = $model->token_exp_timestamp; + if (time() >= ($token_exp_time - $delay)) { + self::login($model->user_guid); + } + } catch (LoginTimeOut $th) { + } + } + + /** + * 生成token内容 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + private function generateContent(): string + { + return md5(join('-', [ + $this->token_exp_time, + $this->user_guid, + ]) . time()); + } +} diff --git a/app/common/model/User/User.php b/app/common/model/User/User.php new file mode 100644 index 0000000..9fef5b7 --- /dev/null +++ b/app/common/model/User/User.php @@ -0,0 +1,548 @@ + 'int', + 'user_guid' => 'string', + 'user_img' => 'string', + 'user_name' => 'string', + 'user_password' => 'string', + 'user_phone' => 'string', + 'user_status' => 'int', + 'user_department' => 'string', + 'user_position' => 'string', + 'user_create_time' => 'datetime', + 'user_create_user_guid' => 'string', + 'user_update_time' => 'datetime', + 'user_update_user_guid' => 'string', + 'user_delete_time' => 'datetime', + 'user_delete_user_guid' => 'string', + ]; + // 只读 + protected $readonly = [ + 'user_id', + 'user_guid', + 'user_create_time', + 'user_create_user_guid' + ]; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'user_create_time'; + // 修改时间 + protected $updateTime = 'user_update_time'; + + public static $dictionaryMap = [ + 'user_status' => [ + self::STATUS_ENABLE => '启用', + self::STATUS_DISABLE => '停用' + ], + ]; + /** + * 状态 启用 + */ + const STATUS_ENABLE = 1; + /** + * 状态 禁用 + */ + const STATUS_DISABLE = 2; + // 状态查询范围 + public function scopeStatus(Query $query, $status = self::STATUS_ENABLE) + { + $query->where('user_status', $status); + } + + /** + * 写入前 + * + * @param self $model + * @return void + * @date 2023-01-11 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeWrite(self $model): void + { + self::checkRepeatData($model); + } + + /** + * 新增前 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeInsert(self $model): void + { + $model->completeCreateField(); + } + + /** + * 更新前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeUpdate(self $model): void + { + $model->completeUpdateField(); + } + + /** + * 删除前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + /** + * 用户名搜索器 + * + * @param Query $query + * @param [type] $value + * @param [type] $data + * @return void + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public function searchUserNameAttr(Query $query, $value, $data): void + { + if ($value) { + $query->whereLike(join('|', [ + 'user_name', + // 'user_phone' + ]), "%$value%"); + } + } + + + /** + * 设置用户密码 + * + * @param string $value + * @return string + * @date 2022-12-28 + * @example + * @author admin + * @since 1.0.0 + */ + public function setUserPasswordAttr(string $value): string + { + return self::encryptPassword($value); + } + + /** + * 获取用户管理员 + * + * @date 2022-03-08 + * @example + * @author admin + * @since 1.0.0 + */ + public function getUserAdminAttr(): bool + { + return $this->user_id == 1; + } + + /** + * 用户登录 + * + * @return Token + * @date 2023-01-03 + * @example + * @author admin + * @since 1.0.0 + */ + public function login(): Token + { + if ($this->user_status != self::STATUS_ENABLE) { + throwErrorMsg('该用户已被停用'); + } + $menus = $this->getUserMenu(); + $api = []; + foreach ($menus as $menu) { + $api = array_merge($api, explode(',', $menu['menu_api_url'])); + } + $api = array_values(array_filter(array_unique($api))); + if (!$api) { + throwErrorMsg('无权登录'); + } + return Token::login($this->user_guid, [ + 'menu' => $menus, + 'api' => $api, + ]); + } + + /** + * 获取用户菜单 + * + * @date 2022-03-15 + * @example + * @author admin + * @since 1.0.0 + */ + public function getUserMenu(): array + { + $result = []; + $query = Menu::join('menu_api', 'menu_api.menu_guid = menu.menu_guid', 'left')->field([ + 'menu.menu_guid', + 'menu.menu_parent_guid', + 'menu.menu_name', + 'menu.menu_url', + 'menu.menu_show', + 'menu.menu_icon', + + 'group_concat(menu_api.menu_api_url)' => 'menu_api_url' + ])->order([ + 'menu.menu_index', + 'menu.menu_order' => 'desc', + ])->group('menu.menu_guid'); + if ($this->user_admin) { + $result = $query->select()->toArray(); + } else { + $menus = []; + $roles = $this->roles()->with([ + 'menus' + ])->select(); + foreach ($roles as $role) { + $menus = array_merge($menus, $role->menus->column('menu_guid')); + } + $result = $query->where([ + ['menu.menu_guid', 'in', $menus] + ])->select()->toArray(); + } + return $result; + } + + /** + * 数据查重 + * + * @param self $model + * @return void + * @date 2022-03-11 + * @example + * @author admin + * @since 1.0.0 + */ + private static function checkRepeatData(self $model) + { + Validate::unique(self::class, $model->user_guid, $model->getData(), [ + 'user_account' => '账户', + 'user_phone' => '手机号', + ]); + } + + /** + * 密码加密 + * + * @param string $password + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function encryptPassword(string $password): string + { + return md5($password); + } + /** + * 获取角色 + * + * @date 2022-03-11 + * @example + * @author admin + * @since 1.0.0 + */ + public function roles(): BelongsToMany + { + return $this->belongsToMany( + Role::class, + UserRole::class, + 'role_guid', + 'user_guid' + ); + } + + /** + * 新增用户角色 + */ + public static function addUserRole($user_guid, $params): void + { + $user_role_arr = $params['roles']; + + foreach ($user_role_arr as $role => $item) { + Db::startTrans(); + try { + $add_data = [ + 'user_guid' => $user_guid, + 'role_guid' => $item, + ]; + $user_role = ModelUserRole::create($add_data); + + Db::commit(); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + } + + /** + * 编辑用户角色 + */ + public static function editUserRole($params): void + { + // 从学生服务(副表)查询出所有当前学生的服务,进行删除 + ModelUserRole::where('user_guid', $params['user_guid'])->select()->delete(); + + // 再把传值的数据,写入副表 + $user_role_arr = $params['roles']; + foreach ($user_role_arr as $key => $item) { + Db::startTrans(); + try { + $add_data = [ + 'user_guid' => $params['user_guid'], + 'role_guid' => $item, + ]; + ModelUserRole::create($add_data); + + Db::commit(); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } + } + + /** + * 用户角色guid获取器 + */ + public function getRolesAttr($value, $data) + { + $user_guid = $data['user_guid']; + $user_role_guid_arr = ModelUserRole::field([ + 'role_guid', + ])->where('user_guid', $user_guid)->select(); + + $arr = []; + foreach ($user_role_guid_arr as $key => $value) { + $arr[] = $value['role_guid']; + } + return $arr; + + // return array_values($user_key_guid_arr); + } + + /** + * 用户角色名称获取器 + */ + public function getRoleNameAttr($value, $data) + { + $user_guid = $data['user_guid']; + $user_role_guid_arr = ModelUserRole::field([ + 'role_guid', + ])->where('user_guid', $user_guid)->select(); + + $arr = []; + foreach ($user_role_guid_arr as $key => $value) { + $model = Role::where('role_guid', $value['role_guid'])->find()->role_name; + $arr[] = $model; + } + return implode(",", $arr); + + // return array_values($user_key_guid_arr); + } + + /** + * 用户角色名 + */ + public static function getRoleName($data) + { + $user_guid = $data['user_guid']; + $user_role_guid_arr = ModelUserRole::field([ + 'role_guid', + ])->where('user_guid', $user_guid)->select(); + + $arr = []; + foreach ($user_role_guid_arr as $key => $value) { + $model = Role::where('role_guid', $value['role_guid'])->find()->role_name; + $arr[] = $model; + } + return implode(",", $arr); + + // return array_values($user_key_guid_arr); + } + + + /** + * 角色名称转角色guid数组 + */ + public static function RoleNameToRoleGuidArr($params) + { + $roles = explode(",", $params['roles']); + + $user_role_guid_arr = []; + foreach ($roles as $key => $item) { + $role = Role::where('role_name', $item)->find(); + if (!$role) throwErrorMsg('角色不存在!'); + $user_role_guid_arr[] = $role->role_guid; + } + + return $user_role_guid_arr; + } + + /** + * 导出Excel + */ + public static function exportExcel($select) + { + $data = [[ + '用户名', + '头像', + '角色', + '手机号', + ]]; + foreach ($select as $key => $val) { + + $val['user_img'] = Excel::ExportImgFiled($val['user_img']); + $user_role_name = self::getRoleName($val); + + $data[] = [ + $val['user_name'], + $val['user_img'], + $user_role_name, + $val['user_phone'], + ]; + } + $excel = (new Excel())->exporTsheet($data); + $excel->save('用户.xlsx'); + } + + + /** + * 导入数据处理 + */ + public static function HanleImportData($value) + { + // 判断用户是否存在 + $user_name = $value['user_name']; + $user_type = self::where('user_name', $user_name)->find(); + if ($user_type) throwErrorMsg("{$user_name} 用户已存在,导入失败!"); + + + // 判断角色是否存在 + $roles_arr = explode(",", $value['roles']); + foreach ($roles_arr as $key => $item) { + $role = Role::where('role_name', $item)->find(); + if (!$role) throwErrorMsg("{$item} 角色不存在,导入失败!"); + } + + $password = md5($value['user_password']); + + $model = self::create([ + 'user_name' => $value['user_name'], + 'user_img' => $value['user_img'], + 'user_phone' => $value['user_phone'], + 'user_password' => $password, + 'user_status' => 1, + ]); + + $user_guid = $model->user_guid; + $value['roles'] = self::RoleNameToRoleGuidArr($value); + self::addUserRole($user_guid, $value); + } + + + /** + * 导入Excel + */ + public static function importExcel($file) + { + Db::startTrans(); + try { + $excel = new Excel($file); + // 表头 + $data = $excel->parseExcel( + [ + [ + 'title' => '用户名', + 'validate' => 'require', + 'field' => 'user_name', + ], [ + 'title' => '头像', + 'field' => 'user_img', + ], [ + 'title' => '角色', + 'validate' => 'require', + 'field' => 'roles', + ], [ + 'title' => '手机号', + 'field' => 'user_phone', + ], [ + 'title' => '密码', + 'field' => 'user_password', + ] + ], + [ + 'titleLine' => [1] + ] + ); + if (!$data) throwErrorMsg('excel无数据', 1); + $error = []; + + foreach ($data as $line => $value) { + try { + self::HanleImportData($value); + $error[] = "{$line} 用户:【{$value['user_name']}】新增成功!
"; + } catch (\Throwable $th) { + $error[] = "{$line} 用户:【{$value['user_name']}】{$th->getMessage()}
"; + } + } + Db::commit(); + return implode(', ', $error); + } catch (\Throwable $th) { + Db::rollback(); + throw $th; + } + } +} diff --git a/app/common/model/User/UserRole.php b/app/common/model/User/UserRole.php new file mode 100644 index 0000000..3c89d91 --- /dev/null +++ b/app/common/model/User/UserRole.php @@ -0,0 +1,157 @@ + 'int', + 'user_guid' => 'string', + 'role_guid' => 'string', + 'user_role_status' => 'int', + 'user_role_create_time' => 'datetime', + 'user_role_create_user_guid' => 'string', + 'user_role_update_time' => 'datetime', + 'user_role_update_user_guid' => 'string', + 'user_role_delete_time' => 'datetime', + 'user_role_delete_user_guid' => 'string', + 'user_role_guid' => 'string', + ]; + // 开启自动写入时间戳字段 + protected $autoWriteTimestamp = 'datetime'; + // 创建时间 + protected $createTime = 'user_role_create_time'; + // 修改时间 + protected $updateTime = 'user_role_update_time'; + /** + * 状态 启用 + */ + const STATUS_ENABLE = 1; + /** + * 状态 禁用 + */ + const STATUS_DISABLE = 2; + // 状态查询范围 + public function scopeStatus($query, $status = self::STATUS_ENABLE) + { + $query->where('user_role_status', $status); + } + /** + * 中间关联 + * + * @return ModelPivot + * @date 2022-12-30 + * @example + * @author admin + * @since 1.0.0 + */ + public static function pivot(): ModelPivot + { + return new ModelPivot( + self::class, + User::class, + Role::class, + true + ); + } + /** + * 绑定用户角色 + * + * @param $users + * @param $roles + * @param array $extra + * @return void + * @date 2022-12-29 + * @example + * @author admin + * @since 1.0.0 + */ + public static function bindUserRole($users, $roles, array $extra = []): void + { + self::pivot()->bind($users, $roles, $extra); + } + /** + * 解绑用户角色 + * + * @param $users + * @param $roles + * @return void + * @date 2022-12-30 + * @example + * @author admin + * @since 1.0.0 + */ + public static function unbindUserRole($users, $roles): void + { + self::pivot()->unbind($users, $roles); + } + /** + * 绑定用户角色 + * + * @param $users + * @param $roles + * @param array $extra + * @return void + * @date 2022-12-29 + * @example + * @author admin + * @since 1.0.0 + */ + public static function rebindUserRole($users, $roles, array $extra = []): void + { + self::pivot()->rebind($users, $roles, $extra); + } + + /** + * 新增前 + * + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeInsert(self $model): void + { + $model->user_role_status = self::STATUS_ENABLE; + $model->completeCreateField(); + } + + /** + * 更新前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeUpdate(self $model): void + { + $model->completeUpdateField(); + } + + /** + * 删除前 + * + * @date 2022-02-28 + * @example + * @author admin + * @since 1.0.0 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } +} diff --git a/app/common/traits/Auth.php b/app/common/traits/Auth.php new file mode 100644 index 0000000..cd18bc9 --- /dev/null +++ b/app/common/traits/Auth.php @@ -0,0 +1,110 @@ +request; + $gc = $request->controller(); + $ga = $request->action(); + $ignoreLogin = Arr::get($this->ignoreLogin, $gc, []); + if (!is_array($ignoreLogin)) { + $ignoreLogin = []; + } + foreach ($ignoreLogin as $action) { + if ($action == '*' || $action == $ga) { + return true; + } + } + return false; + } + + /** + * 验证用户权限 + * + * @return boolean + * @date 2022-05-14 + * @example + * @author admin + * @since 1.0.0 + */ + private function validateUser(): bool + { + return $this->validateMenuApi( + Token::getCurrentUser()->getUserMenu() + ); + } + + /** + * 验证菜单接口 + * + * @return boolean + * @date 2022-05-14 + * @example + * @author admin + * @since 1.0.0 + */ + private function validateMenuApi(array $menus): bool + { + $apis = []; + foreach ($menus as $menu) { + $apis = array_merge($apis, explode(',', $menu['menu_api_url'] ?? '')); + } + return $this->validateApi($apis); + } + + /** + * 验证接口 + * + * @param array $apis + * @return boolean + * @date 2022-05-14 + * @example + * @author admin + * @since 1.0.0 + */ + private function validateApi(array $apis): bool + { + $request = $this->request; + $apis = array_values(array_filter(array_unique($apis))); + $api = join('/', [ + $request->controller(), + $request->action() + ]); + return in_array($api, $apis); + } +} diff --git a/app/common/traits/Model.php b/app/common/traits/Model.php new file mode 100644 index 0000000..9546820 --- /dev/null +++ b/app/common/traits/Model.php @@ -0,0 +1,254 @@ +completeBaseField('create', $user, $timeType); + } + + /** + * 完善更新字段 + * + * @param string $user + * @param string $timeType + * @return void + * @date 2022-12-27 + * @example + * @author admin + * @since 1.0.0 + */ + public function completeUpdateField($user = 'user', string $timeType = 'datetime'): void + { + $this->completeBaseField('update', $user, $timeType); + } + + /** + * 完善删除字段 + * + * @param string $user + * @param string $timeType + * @return void + * @date 2022-12-27 + * @example + * @author admin + * @since 1.0.0 + */ + public function completeDeleteField($user = 'user', string $timeType = 'datetime'): void + { + $this->completeBaseField('delete', $user, $timeType); + } + + /** + * 完善基础字段 + * + * @param string $type create|update|delete + * @param User|string $user + * @param string $timeType datetime|timestamp + * @return void + * @date 2022-03-02 + * @example + * @author admin + * @since 1.0.0 + */ + public function completeBaseField($type, $user = 'user', string $timeType = 'datetime'): void + { + $table = $this->getTable(); + $createFieldTime = "${table}_create_time"; + $createFieldUserGuId = "${table}_create_user_guid"; + $updateFieldTime = "${table}_update_time"; + $updateFieldUserGuId = "${table}_update_user_guid"; + $deleteFieldTime = "${table}_delete_time"; + $deleteFieldUserGuId = "${table}_delete_user_guid"; + $guidField = "${table}_guid"; + + $time = self::getCompleteBaseFieldTimeType($timeType); + $user_guid = self::getCompleteBaseFieldUser($user); + if (!$type) { + throw new ErrorMsg("时间类型异常", 1); + } + $this->$updateFieldTime = $time; + $this->$updateFieldUserGuId = $user_guid; + + if ($type === 'create') { + $this->$createFieldTime = $time; + $this->$createFieldUserGuId = $user_guid; + $this->$guidField = self::generateGuid(); + } + if ($type === 'delete') { + $this->$deleteFieldTime = $time; + $this->$deleteFieldUserGuId = $user_guid; + } + } + + // /** + // * 设置不使用的全局查询范围更新 + // * 支持 onBeforeUpdate|onAfterUpdate|onBeforeWrite|onAfterWrite 事件 + // * + // * @return void + // * @date 2022-03-12 + // * @example + // * @author admin + // * @since 1.0.0 + // */ + // public static function withoutGlobalScopeUpdate(array $scope, array $data) + // { + // $model = new static; + // $pk = $model->getPk(); + // if (!isset($data[$pk])) { + // throw new ErrorMsg("缺少主键", 1); + // } + // $query = $model::withoutGlobalScope($scope)->find($data[$pk]); + // if ($query === null) { + // throw new ErrorMsg("数据不存在", 1); + // } + // if ( + // $model::onBeforeWrite($model) === false || + // $model::onBeforeUpdate($model) === false + // ) { + // return false; + // } + // $model::withoutGlobalScope($scope)->save(array_merge($data, $model->getData())); + // $model::onAfterUpdate($model); + // $model::onAfterWrite($model); + // } + + /** + * 生成guid + * + * @param array|string $value + * @return string + * @date 2022-02-22 + * @example + * @author admin + * @since 1.0.0 + */ + protected static function generateGuid($value = '') + { + return Tool::generateGuid($value); + } + + /** + * 数据验证 + * 除非是require字段 有数据才验证 + * + * @param array $data 数据 + * @param array $rules 规则 + * @param array $message 提示信息 + * @return void + * @throws ValidateException + */ + protected static function dataValidate(array $data, array $rules, array $message = []) + { + $_rules = []; + $dataKeys = array_keys($data); + foreach ($rules as $key => $rule) { + list($field) = explode('|', $key); + // 字段存在规则并且有值 或者 必传 + if ((in_array($field, $dataKeys) && !is_null($data[$field])) || preg_match('/require/', $rule)) { + $_rules[$key] = $rule; + } + } + Validate::check($data, $_rules, $message); + } + + /** + * 获取完善基础字段用户 + * + * @param User|string $user + * @return string + * @date 2022-12-27 + * @example + * @author admin + * @since 1.0.0 + */ + private static function getCompleteBaseFieldUser($user): string + { + $cacheUserGuid = self::$cacheUserGuid; + $user_guid = ''; + switch (true) { + case (is_string($cacheUserGuid) && $cacheUserGuid): + $user_guid = $cacheUserGuid; + break; + case (is_bool($cacheUserGuid) && $cacheUserGuid === false): + // 无需验证 获取用户Guid + break; + case (is_bool($user) && $user === false): + // 无需验证 获取用户Guid + break; + case ($user === 'user'): + case ($user instanceof User): + $user = $user === 'user' ? Request::getCurrentUser() : $user; + $user_guid = $user->user_guid; + break; + } + return $user_guid; + } + + /** + * 获取模型时间类型 + * + * @param string $timeType datetime|timestamp + * @return string + * @date 2022-12-27 + * @example + * @author admin + * @since 1.0.0 + */ + private static function getCompleteBaseFieldTimeType($timeType): string + { + $time = ''; + switch ($timeType) { + case 'datetime': + $time = date('Y-m-d H:i:s'); + break; + case 'timestamp': + $time = time(); + break; + } + return $time; + } +} diff --git a/app/event.php b/app/event.php new file mode 100644 index 0000000..74d0b62 --- /dev/null +++ b/app/event.php @@ -0,0 +1,20 @@ + [], + + 'listen' => [ + 'AppInit' => [], + 'HttpRun' => [], + 'HttpEnd' => [ + DelayToken::class + ], + 'LogLevel' => [], + 'LogWrite' => [], + ], + + 'subscribe' => [], +]; diff --git a/app/middleware.php b/app/middleware.php new file mode 100644 index 0000000..32d02ce --- /dev/null +++ b/app/middleware.php @@ -0,0 +1,10 @@ + Request::class, + 'think\exception\Handle' => ExceptionHandle::class, +]; diff --git a/app/resources/view/admin/controller.tpl b/app/resources/view/admin/controller.tpl new file mode 100644 index 0000000..f1d5aef --- /dev/null +++ b/app/resources/view/admin/controller.tpl @@ -0,0 +1,83 @@ +param(); + $con = []; + + {$whereContent} + + $query = Model{$className}::where($con) + ->field({$queryFields}) + ->order({$orderField}, {$orderMode}); + + return msg("获取{$functionName}列表成功!",$query); + } + + /** + * 编辑{$functionName} + */ + public function edit{$className}(Request $request): array + { + $params = $request->param(); + $this->validate($params, {$editRequireFields}); + $model = Model{$className}::where('{$businessName}_guid',$params['{$businessName}_guid'])->find(); + if (!$model) throwErrorMsg("该{$functionName}不存在", 1); + $model->allowField({$editAllowFields})->save($params); + return msg('编辑成功!'); + } + + /** + * 添加{$functionName} + */ + public function add{$className}(Request $request): array + { + $params = $request->param(); + $this->validate($params, {$addRequireFields}); + $model = Model{$className}::create($params,{$addAllowFields}); + return msg('添加成功!'); + } + + /** + * 删除{$functionName} + */ + public function delete{$className}(Request $request): array + { + $params = $request->param(); + $this->validate($params, [ + '{$businessName}_guid' => 'require', + ]); + ${$businessName} = Model{$className}::where([ + '{$businessName}_guid' => explode(',', $params['{$businessName}_guid']) + ])->select(); + ${$businessName}->delete(); + return msg('删除成功!'); + } + + {$exportExcelContent} + + {$downloadTempContent} + + {$importExcelContent} + +} diff --git a/app/resources/view/admin/model.tpl b/app/resources/view/admin/model.tpl new file mode 100644 index 0000000..da02a09 --- /dev/null +++ b/app/resources/view/admin/model.tpl @@ -0,0 +1,71 @@ +completeCreateField(); + } + + /** + * 更新前 + */ + public static function onBeforeUpdate(self $model): void + { + // self::checkRepeatData($model); + $model->completeUpdateField(); + } + + /** + * 删除前 + */ + public static function onBeforeDelete(self $model): void + { + $model->completeDeleteField(); + } + + {$exportExcelContent} + + {$importExcelContent} + + {$importExcelInitContent} + + +} diff --git a/app/resources/view/api/controller.tpl b/app/resources/view/api/controller.tpl new file mode 100644 index 0000000..3820252 --- /dev/null +++ b/app/resources/view/api/controller.tpl @@ -0,0 +1,55 @@ +param(); + $con = []; + + {$whereContent} + + $query = Model{$className}::where($con) + ->field({$queryFields}) + ->order({$orderField}, {$orderMode}); + + {$imgUrlPrefixPadding} + + return msg("获取{$functionName}列表成功!",$query); + } + + /** + * 获取{$functionName}详情 + */ + public function get{$className}Info(Request $request): array + { + $params = $request->param(); + + $this->validate($params, ['{$businessName}_guid' => 'require']); + + $find = Model{$className}::field({$queryFields}) + ->where('{$businessName}_guid',$params['{$businessName}_guid']) + ->find(); + + return msg(0,'获取{$functionName}详情成功!',['data' => $find]); + } + +} diff --git a/app/resources/view/business/webApi.tpl b/app/resources/view/business/webApi.tpl new file mode 100644 index 0000000..2467282 --- /dev/null +++ b/app/resources/view/business/webApi.tpl @@ -0,0 +1,23 @@ +import { api} from '~/utils/axios'; + +/** + * 获取${functionName}内容 + * @param {Object} data + * @return {Promise} api + */ +export function get${className}(data) { + return api.post('${moduleName}.${className}/get${className}', data); +} + +/** + * 编辑${functionName} + * @param {Object} data + * @return {Promise} api + */ +export function edit${className}(data) { + return api.post('${moduleName}.${className}/edit${className}', data, { + isTransformResponse: true, + isShowSuccessMessage: true, + errorMessageText: '编辑失败' + }); +} diff --git a/app/resources/view/business/webApiController.tpl b/app/resources/view/business/webApiController.tpl new file mode 100644 index 0000000..47975ff --- /dev/null +++ b/app/resources/view/business/webApiController.tpl @@ -0,0 +1,32 @@ +param(); + + $query = Model{$className}::field({$queryFields})->where(1)->find(); + + return [ + 'code' => 0, + 'data' => $query, + 'msg' => 'ok' + ]; + } + +} diff --git a/app/resources/view/business/webController.tpl b/app/resources/view/business/webController.tpl new file mode 100644 index 0000000..62b33ff --- /dev/null +++ b/app/resources/view/business/webController.tpl @@ -0,0 +1,44 @@ +param(); + + $query = Model{$className}::field({$queryFields})->where(1)->find(); + + return [ + 'code' => 0, + 'data' => $query, + 'msg' => 'ok' + ]; + } + + /** + * 编辑{$functionName} + */ + public function edit{$className}(Request $request): array + { + $params = $request->param(); + $this->validate($params, {$editRequireFields}); + $model = Model{$className}::where(1)->find(); + $model->allowField({$editAllowFields})->save($params); + return msg('编辑成功!'); + } + +} diff --git a/app/resources/view/business/webIndex.tpl b/app/resources/view/business/webIndex.tpl new file mode 100644 index 0000000..72e43d3 --- /dev/null +++ b/app/resources/view/business/webIndex.tpl @@ -0,0 +1,90 @@ + + + + \ No newline at end of file diff --git a/app/resources/view/jsVue/add.tpl b/app/resources/view/jsVue/add.tpl new file mode 100644 index 0000000..f840240 --- /dev/null +++ b/app/resources/view/jsVue/add.tpl @@ -0,0 +1,102 @@ + + + + + diff --git a/app/resources/view/jsVue/api.tpl b/app/resources/view/jsVue/api.tpl new file mode 100644 index 0000000..f57ad83 --- /dev/null +++ b/app/resources/view/jsVue/api.tpl @@ -0,0 +1,56 @@ +import { api, downloadFile, createApiUrl} from '~/utils/axios'; + +${excelFun} + +${imageFun} + +${fileFun} + +${dictFun} + +/** + * 获取${functionName}列表 + * @param {Object} data + * @return {Promise} api + */ +export function get${className}List(data) { + return api.post('${moduleName}.${className}/get${className}List', data); +} + +/** + * 删除${functionName} + * @param {Object} data + * @return {Promise} api + */ +export function delete${className}(data) { + return api.post('${moduleName}.${className}/delete${className}', data, { + isTransformResponse: true, + isShowSuccessMessage: true, + errorMessageText: '删除失败' + }); +} + +/** + * 添加${functionName} + * @param {Object} data + * @return {Promise} api + */ +export function add${className}(data) { + return api.post('${moduleName}.${className}/add${className}', data, { + isTransformResponse: true, + isShowSuccessMessage: true, + errorMessageText: '添加失败' + }); +} +/** + * 编辑${functionName} + * @param {Object} data + * @return {Promise} api + */ +export function edit${className}(data) { + return api.post('${moduleName}.${className}/edit${className}', data, { + isTransformResponse: true, + isShowSuccessMessage: true, + errorMessageText: '编辑失败' + }); +} diff --git a/app/resources/view/jsVue/detail.tpl b/app/resources/view/jsVue/detail.tpl new file mode 100644 index 0000000..9f7cf24 --- /dev/null +++ b/app/resources/view/jsVue/detail.tpl @@ -0,0 +1,62 @@ + + + + + diff --git a/app/resources/view/jsVue/edit.tpl b/app/resources/view/jsVue/edit.tpl new file mode 100644 index 0000000..f98a86f --- /dev/null +++ b/app/resources/view/jsVue/edit.tpl @@ -0,0 +1,100 @@ + + + + + diff --git a/app/resources/view/jsVue/index.tpl b/app/resources/view/jsVue/index.tpl new file mode 100644 index 0000000..659e76c --- /dev/null +++ b/app/resources/view/jsVue/index.tpl @@ -0,0 +1,153 @@ + + diff --git a/app/service.php b/app/service.php new file mode 100644 index 0000000..db1ee6a --- /dev/null +++ b/app/service.php @@ -0,0 +1,9 @@ +=7.4.3", + "topthink/framework": "^6.0.0", + "topthink/think-orm": "^2.0", + "topthink/think-captcha": "^3.0", + "phpoffice/phpspreadsheet": "^1.12", + "topthink/think-image": "^1.0", + "topthink/think-multi-app": "^1.0", + "topthink/think-filesystem": "^1.0", + "endroid/qr-code": "^4.6", + "fabpot/goutte": "^4.0" + }, + "require-dev": { + "symfony/var-dumper": "^4.2" + }, + "autoload": { + "psr-4": { + "app\\": "app" + }, + "psr-0": { + "": "extend/" + } + }, + "config": { + "preferred-install": "dist" + }, + "scripts": { + "post-autoload-dump": [ + "@php think service:discover", + "@php think vendor:publish" + ] + }, + "repositories": { + "packagist": { + "type": "composer", + "url": "https://mirrors.aliyun.com/composer/" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..da10a40 --- /dev/null +++ b/composer.lock @@ -0,0 +1,3025 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "77b4f118629281742087d8fefad27030", + "packages": [ + { + "name": "bacon/bacon-qr-code", + "version": "2.0.8", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22", + "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "dasprid/enum": "^1.0.3", + "ext-iconv": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phly/keep-a-changelog": "^2.1", + "phpunit/phpunit": "^7 | ^8 | ^9", + "spatie/phpunit-snapshot-assertions": "^4.2.9", + "squizlabs/php_codesniffer": "^3.4" + }, + "suggest": { + "ext-imagick": "to generate QR code images" + }, + "type": "library", + "autoload": { + "psr-4": { + "BaconQrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "support": { + "issues": "https://github.com/Bacon/BaconQrCode/issues", + "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8" + }, + "time": "2022-12-07T17:46:57+00:00" + }, + { + "name": "dasprid/enum", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/Enum.git", + "reference": "8e6b6ea76eabbf19ea2bf5b67b98e1860474012f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/8e6b6ea76eabbf19ea2bf5b67b98e1860474012f", + "reference": "8e6b6ea76eabbf19ea2bf5b67b98e1860474012f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1 <9.0" + }, + "require-dev": { + "phpunit/phpunit": "^7 | ^8 | ^9", + "squizlabs/php_codesniffer": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "PHP 7.1 enum implementation", + "keywords": [ + "enum", + "map" + ], + "support": { + "issues": "https://github.com/DASPRiD/Enum/issues", + "source": "https://github.com/DASPRiD/Enum/tree/1.0.4" + }, + "time": "2023-03-01T18:44:03+00:00" + }, + { + "name": "endroid/qr-code", + "version": "4.8.2", + "source": { + "type": "git", + "url": "https://github.com/endroid/qr-code.git", + "reference": "2436c2333a3931c95e2b96eb82f16f53143d6bba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/endroid/qr-code/zipball/2436c2333a3931c95e2b96eb82f16f53143d6bba", + "reference": "2436c2333a3931c95e2b96eb82f16f53143d6bba", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "bacon/bacon-qr-code": "^2.0.5", + "php": "^8.0" + }, + "conflict": { + "khanamiryan/qrcode-detector-decoder": "^1.0.6" + }, + "require-dev": { + "endroid/quality": "dev-master", + "ext-gd": "*", + "khanamiryan/qrcode-detector-decoder": "^1.0.4||^2.0.2", + "setasign/fpdf": "^1.8.2" + }, + "suggest": { + "ext-gd": "Enables you to write PNG images", + "khanamiryan/qrcode-detector-decoder": "Enables you to use the image validator", + "roave/security-advisories": "Makes sure package versions with known security issues are not installed", + "setasign/fpdf": "Enables you to use the PDF writer" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Endroid\\QrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeroen van den Enden", + "email": "info@endroid.nl" + } + ], + "description": "Endroid QR Code", + "homepage": "https://github.com/endroid/qr-code", + "keywords": [ + "code", + "endroid", + "php", + "qr", + "qrcode" + ], + "support": { + "issues": "https://github.com/endroid/qr-code/issues", + "source": "https://github.com/endroid/qr-code/tree/4.8.2" + }, + "funding": [ + { + "url": "https://github.com/endroid", + "type": "github" + } + ], + "time": "2023-03-30T18:46:02+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.16.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/523407fb06eb9e5f3d59889b3978d5bfe94299c8", + "reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.16.0" + }, + "time": "2022-09-18T07:06:19+00:00" + }, + { + "name": "fabpot/goutte", + "version": "v4.0.3", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/Goutte.git", + "reference": "e3f28671c87a48a0f13ada1baea0d95acc2138c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/e3f28671c87a48a0f13ada1baea0d95acc2138c3", + "reference": "e3f28671c87a48a0f13ada1baea0d95acc2138c3", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1.3", + "symfony/browser-kit": "^4.4|^5.0|^6.0", + "symfony/css-selector": "^4.4|^5.0|^6.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/dom-crawler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", + "symfony/mime": "^4.4|^5.0|^6.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^6.0" + }, + "type": "application", + "autoload": { + "psr-4": { + "Goutte\\": "Goutte" + }, + "exclude-from-classmap": [ + "Goutte/Tests" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "A simple PHP Web Scraper", + "homepage": "https://github.com/FriendsOfPHP/Goutte", + "keywords": [ + "scraper" + ], + "support": { + "issues": "https://github.com/FriendsOfPHP/Goutte/issues", + "source": "https://github.com/FriendsOfPHP/Goutte/tree/v4.0.3" + }, + "time": "2023-04-01T09:05:33+00:00" + }, + { + "name": "league/flysystem", + "version": "1.1.10", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.1.10" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "time": "2022-10-04T09:16:37+00:00" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "support": { + "issues": "https://github.com/thephpleague/flysystem-cached-adapter/issues", + "source": "https://github.com/thephpleague/flysystem-cached-adapter/tree/master" + }, + "time": "2020-07-25T15:56:04+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd", + "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2022-04-17T13:12:02+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "3fa72e4c71a43f9e9118752a5c90e476a8dc9eb3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/3fa72e4c71a43f9e9118752a5c90e476a8dc9eb3", + "reference": "3fa72e4c71a43f9e9118752a5c90e476a8dc9eb3", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-mbstring": "*", + "myclabs/php-enum": "^1.5", + "php": "^8.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.9", + "guzzlehttp/guzzle": "^6.5.3 || ^7.2.0", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.4", + "phpunit/phpunit": "^8.5.8 || ^9.4.2", + "vimeo/psalm": "^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + }, + { + "url": "https://opencollective.com/zipstream", + "type": "open_collective" + } + ], + "time": "2022-12-08T12:29:14+00:00" + }, + { + "name": "markbaker/complex", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" + }, + "time": "2022-12-06T16:21:08+00:00" + }, + { + "name": "markbaker/matrix", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" + }, + "time": "2022-12-02T22:17:43+00:00" + }, + { + "name": "myclabs/php-enum", + "version": "1.8.3", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "b942d263c641ddb5190929ff840c68f78713e937" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/b942d263c641ddb5190929ff840c68f78713e937", + "reference": "b942d263c641ddb5190929ff840c68f78713e937", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^4.6.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "http://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "support": { + "issues": "https://github.com/myclabs/php-enum/issues", + "source": "https://github.com/myclabs/php-enum/tree/1.8.3" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum", + "type": "tidelift" + } + ], + "time": "2021-07-05T08:18:36+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.28.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "6e81cf39bbd93ebc3a4e8150444c41e8aa9b769a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/6e81cf39bbd93ebc3a4e8150444c41e8aa9b769a", + "reference": "6e81cf39bbd93ebc3a4e8150444c41e8aa9b769a", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.15", + "maennchen/zipstream-php": "^2.1", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", + "php": "^7.4 || ^8.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "dompdf/dompdf": "^1.0 || ^2.0", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.2.4", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^8.5 || ^9.0", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.28.0" + }, + "time": "2023-02-25T12:24:49+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "time": "2023-04-04T09:50:52+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v6.0.19", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "4d1bf7886e2af0a194332486273debcd6662cfc9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/4d1bf7886e2af0a194332486273debcd6662cfc9", + "reference": "4d1bf7886e2af0a194332486273debcd6662cfc9", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=8.0.2", + "symfony/dom-crawler": "^5.4|^6.0" + }, + "require-dev": { + "symfony/css-selector": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/mime": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v6.0.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-01T08:36:10+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v6.0.19", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "f1d00bddb83a4cb2138564b2150001cb6ce272b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/f1d00bddb83a4cb2138564b2150001cb6ce272b1", + "reference": "f1d00bddb83a4cb2138564b2150001cb6ce272b1", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v6.0.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-01T08:36:10+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", + "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=8.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:55:41+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v6.0.19", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "622578ff158318b1b49d95068bd6b66c713601e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/622578ff158318b1b49d95068bd6b66c713601e9", + "reference": "622578ff158318b1b49d95068bd6b66c713601e9", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=8.0.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "^5.4|^6.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v6.0.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-20T17:44:14+00:00" + }, + { + "name": "symfony/http-client", + "version": "v6.0.20", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "541c04560da1875f62c963c3aab6ea12a7314e11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/541c04560da1875f62c963c3aab6ea12a7314e11", + "reference": "541c04560da1875f62c963c3aab6ea12a7314e11", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=8.0.2", + "psr/log": "^1|^2|^3", + "symfony/http-client-contracts": "^3", + "symfony/service-contracts": "^1.0|^2|^3" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/stopwatch": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-client/tree/v6.0.20" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-30T15:41:07+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "4184b9b63af1edaf35b6a7974c6f1f9f33294129" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/4184b9b63af1edaf35b6a7974c6f1f9f33294129", + "reference": "4184b9b63af1edaf35b6a7974c6f1f9f33294129", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=8.0.2" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v3.0.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-12T16:11:42+00:00" + }, + { + "name": "symfony/mime", + "version": "v6.0.19", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "d7052547a0070cbeadd474e172b527a00d657301" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/d7052547a0070cbeadd474e172b527a00d657301", + "reference": "d7052547a0070cbeadd474e172b527a00d657301", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=8.0.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<5.4", + "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/property-info": "^5.4|^6.0", + "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v6.0.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-11T11:50:03+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-30T19:17:29+00:00" + }, + { + "name": "topthink/framework", + "version": "v6.1.2", + "source": { + "type": "git", + "url": "https://github.com/top-think/framework.git", + "reference": "67235be5b919aaaf1de5aed9839f65d8e766aca3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/framework/zipball/67235be5b919aaaf1de5aed9839f65d8e766aca3", + "reference": "67235be5b919aaaf1de5aed9839f65d8e766aca3", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=7.2.5", + "psr/container": "~1.0", + "psr/http-message": "^1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1.1", + "topthink/think-orm": "^2.0|^3.0" + }, + "require-dev": { + "guzzlehttp/psr7": "^2.1.0", + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "autoload": { + "files": [], + "psr-4": { + "think\\": "src/think/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP Framework.", + "homepage": "http://thinkphp.cn/", + "keywords": [ + "framework", + "orm", + "thinkphp" + ], + "support": { + "issues": "https://github.com/top-think/framework/issues", + "source": "https://github.com/top-think/framework/tree/v6.1.2" + }, + "time": "2023-02-08T02:24:01+00:00" + }, + { + "name": "topthink/think-captcha", + "version": "v3.0.8", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-captcha.git", + "reference": "52fba122c953995bec3013c635025172491ae299" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-captcha/zipball/52fba122c953995bec3013c635025172491ae299", + "reference": "52fba122c953995bec3013c635025172491ae299", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "topthink/framework": "^6.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\captcha\\CaptchaService" + ], + "config": { + "captcha": "src/config.php" + } + } + }, + "autoload": { + "files": [ + "src/helper.php" + ], + "psr-4": { + "think\\captcha\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "captcha package for thinkphp", + "support": { + "issues": "https://github.com/top-think/think-captcha/issues", + "source": "https://github.com/top-think/think-captcha/tree/v3.0.8" + }, + "time": "2022-10-26T07:59:42+00:00" + }, + { + "name": "topthink/think-filesystem", + "version": "v1.0.3", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-filesystem.git", + "reference": "29f19f140a9267c717fecd7ccb22c84c2d72382e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-filesystem/zipball/29f19f140a9267c717fecd7ccb22c84c2d72382e", + "reference": "29f19f140a9267c717fecd7ccb22c84c2d72382e", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "league/flysystem": "^1.1.4", + "league/flysystem-cached-adapter": "^1.0", + "php": ">=7.2.5", + "topthink/framework": "^6.1|^8.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6.1 Filesystem Package", + "support": { + "issues": "https://github.com/top-think/think-filesystem/issues", + "source": "https://github.com/top-think/think-filesystem/tree/v1.0.3" + }, + "time": "2023-02-08T01:25:15+00:00" + }, + { + "name": "topthink/think-helper", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-helper.git", + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/769acbe50a4274327162f9c68ec2e89a38eb2aff", + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/helper.php" + ], + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Helper Package", + "support": { + "issues": "https://github.com/top-think/think-helper/issues", + "source": "https://github.com/top-think/think-helper/tree/v3.1.6" + }, + "time": "2021-12-15T04:27:55+00:00" + }, + { + "name": "topthink/think-image", + "version": "v1.0.7", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-image.git", + "reference": "8586cf47f117481c6d415b20f7dedf62e79d5512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-image/zipball/8586cf47f117481c6d415b20f7dedf62e79d5512", + "reference": "8586cf47f117481c6d415b20f7dedf62e79d5512", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-gd": "*" + }, + "require-dev": { + "phpunit/phpunit": "4.8.*", + "topthink/framework": "^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP5 Image Package", + "support": { + "issues": "https://github.com/top-think/think-image/issues", + "source": "https://github.com/top-think/think-image/tree/master" + }, + "time": "2016-09-29T06:05:43+00:00" + }, + { + "name": "topthink/think-multi-app", + "version": "v1.0.16", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-multi-app.git", + "reference": "07b9183855150455e1f76f8cbe9d77d6d1bc399f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-multi-app/zipball/07b9183855150455e1f76f8cbe9d77d6d1bc399f", + "reference": "07b9183855150455e1f76f8cbe9d77d6d1bc399f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0|^8.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\app\\Service" + ] + } + }, + "autoload": { + "psr-4": { + "think\\app\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp6 multi app support", + "support": { + "issues": "https://github.com/top-think/think-multi-app/issues", + "source": "https://github.com/top-think/think-multi-app/tree/v1.0.16" + }, + "time": "2023-02-07T08:40:09+00:00" + }, + { + "name": "topthink/think-orm", + "version": "v2.0.60", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-orm.git", + "reference": "8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46", + "reference": "8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "ext-pdo": "*", + "php": ">=7.1.0", + "psr/log": "^1.0|^2.0", + "psr/simple-cache": "^1.0|^2.0", + "topthink/think-helper": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9.5" + }, + "type": "library", + "autoload": { + "files": [ + "stubs/load_stubs.php" + ], + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "think orm", + "keywords": [ + "database", + "orm" + ], + "support": { + "issues": "https://github.com/top-think/think-orm/issues", + "source": "https://github.com/top-think/think-orm/tree/v2.0.60" + }, + "time": "2023-03-19T04:51:56+00:00" + } + ], + "packages-dev": [ + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.4.3" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..cd588b5 --- /dev/null +++ b/config/app.php @@ -0,0 +1,33 @@ + '', + // 应用地址 + 'app_host' => env('app.host', ''), + // 应用的命名空间 + 'app_namespace' => '', + // 是否启用路由 + 'with_route' => true, + // 默认应用 + 'default_app' => 'index', + // 默认时区 + 'default_timezone' => 'Asia/Shanghai', + + // 应用映射(自动多应用模式有效) + 'app_map' => [], + // 域名绑定(自动多应用模式有效) + 'domain_bind' => [], + // 禁止URL访问的应用列表(自动多应用模式有效) + 'deny_app_list' => ['common'], + + // 异常页面的模板文件 + 'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl', + + // 错误显示信息,非调试模式有效 + 'error_message' => '页面错误!请稍后再试~', + // 显示错误信息 + 'show_error_msg' => true, +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..a8d69d2 --- /dev/null +++ b/config/cache.php @@ -0,0 +1,29 @@ + env('cache.driver', 'file'), + + // 缓存连接方式配置 + 'stores' => [ + 'file' => [ + // 驱动方式 + 'type' => 'File', + // 缓存保存目录 + 'path' => '', + // 缓存前缀 + 'prefix' => '', + // 缓存有效期 0表示永久缓存 + 'expire' => 0, + // 缓存标签前缀 + 'tag_prefix' => 'tag:', + // 序列化机制 例如 ['serialize', 'unserialize'] + 'serialize' => [], + ], + // 更多的缓存连接 + ], +]; diff --git a/config/captcha.php b/config/captcha.php new file mode 100644 index 0000000..29e015e --- /dev/null +++ b/config/captcha.php @@ -0,0 +1,46 @@ + 4, + // 验证码字符集合 + // 'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY', + 'codeSet' => '2345678', + // 验证码过期时间 + 'expire' => 1800, + // 是否使用中文验证码 + 'useZh' => false, + // 是否使用算术验证码 + 'math' => false, + // 是否使用背景图 + 'useImgBg' => false, + //验证码字符大小 + 'fontSize' => 25, + // 是否使用混淆曲线 + 'useCurve' => true, + //是否添加杂点 + 'useNoise' => true, + // 验证码字体 不设置则随机 + 'fontttf' => '', + //背景颜色 + 'bg' => [243, 251, 254], + // 验证码图片高度 + 'imageH' => 0, + // 验证码图片宽度 + 'imageW' => 0, + + // 添加额外的验证码设置 + 'verify' => [ + 'length' => 5, + 'useImgBg' => false, + 'useNoise' => false, + 'useCurve' => false, + // 'imageH' => 40, + // 'imageW' => 100, + 'fontSize' => 15, + 'bg' => [255, 255, 255], + ], +]; diff --git a/config/chunkUpload.php b/config/chunkUpload.php new file mode 100644 index 0000000..6a888bb --- /dev/null +++ b/config/chunkUpload.php @@ -0,0 +1,9 @@ + '' +]; diff --git a/config/console.php b/config/console.php new file mode 100644 index 0000000..d0092b2 --- /dev/null +++ b/config/console.php @@ -0,0 +1,10 @@ + [ + 'timer' => 'app\command\Timer' + ], +]; diff --git a/config/cookie.php b/config/cookie.php new file mode 100644 index 0000000..d3b3aab --- /dev/null +++ b/config/cookie.php @@ -0,0 +1,20 @@ + 0, + // cookie 保存路径 + 'path' => '/', + // cookie 有效域名 + 'domain' => '', + // cookie 启用安全传输 + 'secure' => false, + // httponly设置 + 'httponly' => false, + // 是否使用 setcookie + 'setcookie' => true, + // samesite 设置,支持 'strict' 'lax' + 'samesite' => '', +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..0fdd298 --- /dev/null +++ b/config/database.php @@ -0,0 +1,63 @@ + env('database.driver', 'mysql'), + + // 自定义时间查询规则 + 'time_query_rule' => [], + + // 自动写入时间戳字段 + // true为自动识别类型 false关闭 + // 字符串则明确指定时间字段类型 支持 int timestamp datetime date + 'auto_timestamp' => true, + + // 时间字段取出后的默认时间格式 + 'datetime_format' => 'Y-m-d H:i:s', + + // 时间字段配置 配置格式:create_time,update_time + 'datetime_field' => '', + + // 数据库连接配置信息 + 'connections' => [ + 'mysql' => [ + // 数据库类型 + 'type' => env('database.type', 'mysql'), + // 服务器地址 + 'hostname' => env('database.hostname', '47.242.159.172'), + // 数据库名 + 'database' => env('database.database', 'php_web'), + // 用户名 + 'username' => env('database.username', 'php_web'), + // 密码 + 'password' => env('database.password', 'php_web@aerwen'), + // 端口 + 'hostport' => env('database.hostpost', '3306'), + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8 + 'charset' => env('database.charset', 'utf8'), + // 数据库表前缀 + 'prefix' => env('database.prefix', ''), + + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 是否需要断线重连 + 'break_reconnect' => false, + // 监听SQL + 'trigger_sql' => env('app_debug', true), + // 开启字段缓存 + 'fields_cache' => false, + ], + + // 更多的数据库配置信息 + ], +]; diff --git a/config/filesystem.php b/config/filesystem.php new file mode 100644 index 0000000..ed45ff3 --- /dev/null +++ b/config/filesystem.php @@ -0,0 +1,37 @@ + env('filesystem.driver', 'uploads'), + // 磁盘列表 + 'disks' => [ + // 'local' => [ + // 'type' => 'local', + // 'root' => app()->getRuntimePath() . 'storage', + // ], + 'uploads' => [ + 'type' => 'local', + 'root' => app()->getRootPath() . 'public/uploads', + 'url' => '/uploads/', + 'visibility' => 'public', + ], + + 'approve' => [ + 'type' => 'local', + 'root' => app()->getRootPath() . 'storage/approve', + // 'url' => '/uploads/', + 'visibility' => 'private', + ], + // 'public' => [ + // // 磁盘类型 + // 'type' => 'local', + // // 磁盘路径 + // 'root' => app()->getRootPath() . 'public/storage', + // // 磁盘路径对应的外部URL路径 + // 'url' => '/storage/', + // // 可见性 + // 'visibility' => 'public', + // ], + // 更多的磁盘配置信息 + ], +]; diff --git a/config/lang.php b/config/lang.php new file mode 100644 index 0000000..59f320f --- /dev/null +++ b/config/lang.php @@ -0,0 +1,27 @@ + env('lang.default_lang', 'zh-cn'), + // 允许的语言列表 + 'allow_lang_list' => [], + // 多语言自动侦测变量名 + 'detect_var' => 'lang', + // 是否使用Cookie记录 + 'use_cookie' => true, + // 多语言cookie变量 + 'cookie_var' => 'think_lang', + // 多语言header变量 + 'header_var' => 'think-lang', + // 扩展语言包 + 'extend_list' => [], + // Accept-Language转义为对应语言包名称 + 'accept_language' => [ + 'zh-hans-cn' => 'zh-cn', + ], + // 是否支持语言分组 + 'allow_group' => false, +]; diff --git a/config/log.php b/config/log.php new file mode 100644 index 0000000..37fb65d --- /dev/null +++ b/config/log.php @@ -0,0 +1,124 @@ + 'File', + // 日志保存目录 + 'path' => app()->getRuntimePath() . 'push_log' . DIRECTORY_SEPARATOR . $vendor, + // 单文件日志写入 + 'single' => false, + // 独立日志级别 + 'apart_level' => [], + // 最大日志文件数量 + 'max_files' => 0, + // 使用JSON格式记录 + 'json' => true, + // 日志处理 + 'processor' => null, + // 关闭通道日志写入 + 'close' => false, + // 日志输出格式化 + 'format' => '[%s][%s] %s', + // 是否实时写入 + 'realtime_write' => false, + ]; +}; +$generateWechat = function (string $type) { + return [ + // 日志记录方式 + 'type' => 'File', + // 日志保存目录 + 'path' => app()->getRuntimePath() . 'wechat' . DIRECTORY_SEPARATOR . $type, + // 单文件日志写入 + 'single' => false, + // 独立日志级别 + 'apart_level' => [], + // 最大日志文件数量 + 'max_files' => 0, + // 使用JSON格式记录 + 'json' => true, + // 日志处理 + 'processor' => null, + // 关闭通道日志写入 + 'close' => false, + // 日志输出格式化 + 'format' => '[%s][%s] %s', + // 是否实时写入 + 'realtime_write' => false, + ]; +}; +return [ + // 默认日志记录通道 + 'default' => env('log.channel', 'file'), + // 日志记录级别 + 'level' => [], + // 日志类型记录的通道 ['error'=>'email',...] + 'type_channel' => [], + // 关闭全局日志写入 + 'close' => false, + // 全局日志处理 支持闭包 + 'processor' => null, + + // 日志通道列表 + 'channels' => [ + // 飞比云 + 'pushLog/FBeeCloud' => $generatePushLog('FBeeCloud'), + // 睡小宝 + 'pushLog/Sleepthing' => $generatePushLog('Sleepthing'), + // 微信公众号 + 'wechat/gzh' => $generateWechat('gzh'), + // 微信小程序 + 'wechat/xcx' => $generateWechat('xcx'), + // 命令行 + 'cmd' => [ + // 日志记录方式 + 'type' => 'File', + // 日志保存目录 + 'path' => app()->getRuntimePath() . 'cmd', + // 单文件日志写入 + 'single' => false, + // 独立日志级别 + 'apart_level' => [], + // 最大日志文件数量 + 'max_files' => 0, + // 使用JSON格式记录 + 'json' => false, + // 日志处理 + 'processor' => null, + // 关闭通道日志写入 + 'close' => false, + // 日志输出格式化 + 'format' => '[%s][%s] %s', + // 是否实时写入 + 'realtime_write' => false, + ], + 'file' => [ + // 日志记录方式 + 'type' => 'File', + // 日志保存目录 + 'path' => '', + // 单文件日志写入 + 'single' => false, + // 独立日志级别 + 'apart_level' => [], + // 最大日志文件数量 + 'max_files' => 0, + // 使用JSON格式记录 + 'json' => false, + // 日志处理 + 'processor' => null, + // 关闭通道日志写入 + 'close' => false, + // 日志输出格式化 + 'format' => '[%s][%s] %s', + // 是否实时写入 + 'realtime_write' => false, + ], + // 其它日志通道配置 + ], + +]; diff --git a/config/middleware.php b/config/middleware.php new file mode 100644 index 0000000..7e1972f --- /dev/null +++ b/config/middleware.php @@ -0,0 +1,8 @@ + [], + // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行 + 'priority' => [], +]; diff --git a/config/route.php b/config/route.php new file mode 100644 index 0000000..aac1531 --- /dev/null +++ b/config/route.php @@ -0,0 +1,50 @@ + '/', + // URL伪静态后缀 + 'url_html_suffix' => 'html', + // URL普通方式参数 用于自动生成 + 'url_common_param' => true, + // 是否开启路由延迟解析 + 'url_lazy_route' => false, + // 是否强制使用路由 + 'url_route_must' => false, + // 合并路由规则 + 'route_rule_merge' => false, + // 路由是否完全匹配 + 'route_complete_match' => false, + // 访问控制器层名称 + 'controller_layer' => 'controller', + // 空控制器名 + 'empty_controller' => 'Error', + // 是否使用控制器后缀 + 'controller_suffix' => false, + // 默认的路由变量规则 + 'default_route_pattern' => '[\w\.]+', + // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 + 'request_cache_key' => false, + // 请求缓存有效期 + 'request_cache_expire' => null, + // 全局请求缓存排除规则 + 'request_cache_except' => [], + // 默认控制器名 + 'default_controller' => 'Index', + // 默认操作名 + 'default_action' => 'index', + // 操作方法后缀 + 'action_suffix' => '', + // 默认JSONP格式返回的处理方法 + 'default_jsonp_handler' => 'jsonpReturn', + // 默认JSONP处理方法 + 'var_jsonp_handler' => 'callback', + // 中间件 + 'middleware' => [ + // 接口鉴权 + // \app\middleware\Auth::class + ], +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..c1ef6e1 --- /dev/null +++ b/config/session.php @@ -0,0 +1,19 @@ + 'PHPSESSID', + // SESSION_ID的提交变量,解决flash上传跨域 + 'var_session_id' => '', + // 驱动方式 支持file cache + 'type' => 'file', + // 存储连接标识 当type使用cache的时候有效 + 'store' => null, + // 过期时间 + 'expire' => 1440, + // 前缀 + 'prefix' => '', +]; diff --git a/config/wechat.php b/config/wechat.php new file mode 100644 index 0000000..7c798be --- /dev/null +++ b/config/wechat.php @@ -0,0 +1,39 @@ + '', + // 中控层地址 + 'server_base' => 'http://clique.dszjjt.com:7001/', + // 公众号配置 + 'gzh' => [ + // 缓存key + 'cache_key' => 'wechat.gzh', + // 日志通道 + 'log_channel' => 'wechat/gzh', + // 公众号模板推送 + 'template' => [ + // {{first.DATA}} + // 申请人:{{keyword1.DATA}} + // 申请时间:{{keyword2.DATA}} + // 调课时间:{{keyword3.DATA}} + // {{remark.DATA}} + '申请审核通知' => 'iLuqzUrQM8-v_7ilxageUZoi9v-SQWipkTYVZXB1GeI' + ], + 'appid' => 'wx99caf571c9fb1cc5', + 'secret' => '61100d9c4fff5acf97517f0c8799e2e2', + ], + // 小程序配置 + 'xcx' => [ + // 缓存key + 'cache_key' => 'wechat.xcx', + // 日志通道 + 'log_channel' => 'wechat/xcx', + + 'appid' => 'wx2495492e15854b02', + 'secret' => '5b4fcb27324398083fba4a3c39e8a557', + ], +]; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..50934e0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "api", + "lockfileVersion": 2, + "requires": true, + "packages": {} +} diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..cbc7868 --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,8 @@ + + Options +FollowSymlinks -Multiviews + RewriteEngine On + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] + diff --git a/public/admin.php b/public/admin.php new file mode 100644 index 0000000..0719a59 --- /dev/null +++ b/public/admin.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + +// [ 应用入口文件 ] +namespace think; + +require __DIR__ . '/../vendor/autoload.php'; + +try { + // 执行HTTP应用并响应 + $http = (new App())->http; + + $response = $http->run(); + + $response->send(); +} catch (\InvalidArgumentException $th) { + // 方便浏览器调试 + if (isset($response)) { + $data = $response->getData(); + if (is_array($data)) { + echo json_encode($data); + } + } else { + throw $th; + } +} finally { + $http->end($response); +} diff --git a/public/api.php b/public/api.php new file mode 100644 index 0000000..0719a59 --- /dev/null +++ b/public/api.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + +// [ 应用入口文件 ] +namespace think; + +require __DIR__ . '/../vendor/autoload.php'; + +try { + // 执行HTTP应用并响应 + $http = (new App())->http; + + $response = $http->run(); + + $response->send(); +} catch (\InvalidArgumentException $th) { + // 方便浏览器调试 + if (isset($response)) { + $data = $response->getData(); + if (is_array($data)) { + echo json_encode($data); + } + } else { + throw $th; + } +} finally { + $http->end($response); +} diff --git a/public/excel/产品.xlsx b/public/excel/产品.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..28d5a65fd916097b815c818dbcce1c80539857b8 GIT binary patch literal 11430 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 literal 0 HcmV?d00001 diff --git a/public/excel/产品导入模板 (2).xlsx b/public/excel/产品导入模板 (2).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7858fcffa1446fbb8a4633a5c681ea4e22d9e7b7 GIT binary patch literal 12672 zcmeHtWmg?-()GdJ-6as*-90$LH9&Be;O_43Zovue?(XjH9^77%xo6!onR$P~GyS2P zv-;F#oxXO}Rb6|_N`io*0>A-~004jppnH~XtOW!BM1cYTC;&)c4IwK_I|EBQZAE8m z16xg6Cku1J98h5LECBHP_y2eNAASO*al%XC^M!e6s}s=+ce^!p~S8$=nh)>vP7y16uR<_HjjytZMNhMOtWA0 zfY;~)qFUis$JW7{+t~1>nX#*iLVgyj_eGgewYzmJh*u;uvtWBel!S7Av zGqnJaH4CjlFJrVEckkgt%at0w=ptNwBHcv6?ODgsZ_0>_(wD&`wxHg~@6Qna%)v(K zFF(CBM*4F% zJ#4_a*mK~(-Rx=wRc&g`oLct*%Ul51X z$y74hfUU04V!7LZInm7nwvvJ|hsh7!3>!{jXKj7+j%(r6c9a)48kw{Kd17Ydd&Y6m ze$uQPPxTt+%i(nA9yX}%l7WjspHPCrwf7zBKa*tGaz=n*|KYu>&-@JQndLdyxUe4VAVP^h)v1%txsM=TLPS(E`%dO7DJ z16{hBszqAh$h>}NZa#PW)<^^Mv!fQNN`ip{hJFhzHo0();?>r57ml7WK^coizgMAU z8(cer*RyFs%)LGC3Ll8yKt4^Q1bLl}dY_cVNd6Lm|rWYd(G@c=;mi&%&s#M>vUWt=z{!cDp&9c56MRo59E8l7O~D-W(X^x z5VuhRzmiSw_=xpEO5U%%qV&janBiVE*kvS9Esi-i2rGizO{&2@>$OuNiba_0H8jmw}Z_wuUc zRHhHY%IG8w2#2{gWi-2W9}92qe+VCrsowX0wXc(#ms7?@_As%`IAH z*QAXbGS&b1(V{p3>n0PQRN|rr$-1x67y7_dJ2gFbkI*W=$G9m(sor$@bX)^4OSemD zsl@Jly7|d9v&-i0Md^)R<&L5)ge7Jr$B-V?yRF2HFZFR!<=l<_%z2XVz;zoxxMj^6 z8Dd(%YT_IrgAfysOloRr&lQOM0991>6lETv>6Dv9%rqL$gd6;+-}bsB`J*oQZ){5^Rv)6uZv0;Du+92{C}$9-03@KdrgO!xHYf{4|`F!T`nM_-Er(0JG^By*;C;?F8P?dodiY+3|YxQ#dK}sj06gOrbE`eQOk2z6H

@VEuo5e5#35_nR? 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 n|1ga{%zL=l^&77ki*ocfh5K8@KiGmZV&peq?TV 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 Nzn@8e>8ExF{2wMK5WD~Y literal 0 HcmV?d00001 diff --git a/public/excel/产品类型导入模板.xlsx b/public/excel/产品类型导入模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c3117c3b4d7cd2fb39dc2ad1e5e2c80f52fb81b4 GIT binary patch literal 8872 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 UiP~KN01x#GMx_L#%)k8mKV+yi5&!@I literal 0 HcmV?d00001 diff --git a/public/excel/关键词导入模板 (2).xlsx b/public/excel/关键词导入模板 (2).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0eca5b89c9b69df4d872cafeca493f25571f9474 GIT binary patch literal 9547 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 literal 0 HcmV?d00001 diff --git a/public/excel/学生导入模板 (3).xlsx b/public/excel/学生导入模板 (3).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f50ebbc917a335b1a8c53954af6e441f8f10511f GIT binary patch literal 10487 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 T1LhzAfDHcqbown+KhORT+Ikxf literal 0 HcmV?d00001 diff --git a/public/excel/学生导入模板 (6).xlsx b/public/excel/学生导入模板 (6).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..bd0c11fa34cfa7982b0fa2bd2b6dea2f784eb9f1 GIT binary patch literal 11902 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', + trigger: 'hover focus', + title: '', + delay: 0, + html: false, + selector: false, + placement: 'top', + offset: 0, + container: false, + fallbackPlacement: 'flip', + boundary: 'scrollParent', + sanitize: true, + sanitizeFn: null, + whiteList: DefaultWhitelist, + popperConfig: null + }; + var HoverState = { + SHOW: 'show', + OUT: 'out' + }; + var Event$6 = { + HIDE: "hide" + EVENT_KEY$6, + HIDDEN: "hidden" + EVENT_KEY$6, + SHOW: "show" + EVENT_KEY$6, + SHOWN: "shown" + EVENT_KEY$6, + INSERTED: "inserted" + EVENT_KEY$6, + CLICK: "click" + EVENT_KEY$6, + FOCUSIN: "focusin" + EVENT_KEY$6, + FOCUSOUT: "focusout" + EVENT_KEY$6, + MOUSEENTER: "mouseenter" + EVENT_KEY$6, + MOUSELEAVE: "mouseleave" + EVENT_KEY$6 + }; + var ClassName$6 = { + FADE: 'fade', + SHOW: 'show' + }; + var Selector$6 = { + TOOLTIP: '.tooltip', + TOOLTIP_INNER: '.tooltip-inner', + ARROW: '.arrow' + }; + var Trigger = { + HOVER: 'hover', + FOCUS: 'focus', + CLICK: 'click', + MANUAL: 'manual' + }; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + var Tooltip = + /*#__PURE__*/ + function () { + function Tooltip(element, config) { + if (typeof Popper === 'undefined') { + throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org/)'); + } // private + + + this._isEnabled = true; + this._timeout = 0; + this._hoverState = ''; + this._activeTrigger = {}; + this._popper = null; // Protected + + this.element = element; + this.config = this._getConfig(config); + this.tip = null; + + this._setListeners(); + } // Getters + + + var _proto = Tooltip.prototype; + + // Public + _proto.enable = function enable() { + this._isEnabled = true; + }; + + _proto.disable = function disable() { + this._isEnabled = false; + }; + + _proto.toggleEnabled = function toggleEnabled() { + this._isEnabled = !this._isEnabled; + }; + + _proto.toggle = function toggle(event) { + if (!this._isEnabled) { + return; + } + + if (event) { + var dataKey = this.constructor.DATA_KEY; + var context = $(event.currentTarget).data(dataKey); + + if (!context) { + context = new this.constructor(event.currentTarget, this._getDelegateConfig()); + $(event.currentTarget).data(dataKey, context); + } + + context._activeTrigger.click = !context._activeTrigger.click; + + if (context._isWithActiveTrigger()) { + context._enter(null, context); + } else { + context._leave(null, context); + } + } else { + if ($(this.getTipElement()).hasClass(ClassName$6.SHOW)) { + this._leave(null, this); + + return; + } + + this._enter(null, this); + } + }; + + _proto.dispose = function dispose() { + clearTimeout(this._timeout); + $.removeData(this.element, this.constructor.DATA_KEY); + $(this.element).off(this.constructor.EVENT_KEY); + $(this.element).closest('.modal').off('hide.bs.modal', this._hideModalHandler); + + if (this.tip) { + $(this.tip).remove(); + } + + this._isEnabled = null; + this._timeout = null; + this._hoverState = null; + this._activeTrigger = null; + + if (this._popper) { + this._popper.destroy(); + } + + this._popper = null; + this.element = null; + this.config = null; + this.tip = null; + }; + + _proto.show = function show() { + var _this = this; + + if ($(this.element).css('display') === 'none') { + throw new Error('Please use show on visible elements'); + } + + var showEvent = $.Event(this.constructor.Event.SHOW); + + if (this.isWithContent() && this._isEnabled) { + $(this.element).trigger(showEvent); + var shadowRoot = Util.findShadowRoot(this.element); + var isInTheDom = $.contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element); + + if (showEvent.isDefaultPrevented() || !isInTheDom) { + return; + } + + var tip = this.getTipElement(); + var tipId = Util.getUID(this.constructor.NAME); + tip.setAttribute('id', tipId); + this.element.setAttribute('aria-describedby', tipId); + this.setContent(); + + if (this.config.animation) { + $(tip).addClass(ClassName$6.FADE); + } + + var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement; + + var attachment = this._getAttachment(placement); + + this.addAttachmentClass(attachment); + + var container = this._getContainer(); + + $(tip).data(this.constructor.DATA_KEY, this); + + if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) { + $(tip).appendTo(container); + } + + $(this.element).trigger(this.constructor.Event.INSERTED); + this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment)); + $(tip).addClass(ClassName$6.SHOW); // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + + if ('ontouchstart' in document.documentElement) { + $(document.body).children().on('mouseover', null, $.noop); + } + + var complete = function complete() { + if (_this.config.animation) { + _this._fixTransition(); + } + + var prevHoverState = _this._hoverState; + _this._hoverState = null; + $(_this.element).trigger(_this.constructor.Event.SHOWN); + + if (prevHoverState === HoverState.OUT) { + _this._leave(null, _this); + } + }; + + if ($(this.tip).hasClass(ClassName$6.FADE)) { + var transitionDuration = Util.getTransitionDurationFromElement(this.tip); + $(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); + } else { + complete(); + } + } + }; + + _proto.hide = function hide(callback) { + var _this2 = this; + + var tip = this.getTipElement(); + var hideEvent = $.Event(this.constructor.Event.HIDE); + + var complete = function complete() { + if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) { + tip.parentNode.removeChild(tip); + } + + _this2._cleanTipClass(); + + _this2.element.removeAttribute('aria-describedby'); + + $(_this2.element).trigger(_this2.constructor.Event.HIDDEN); + + if (_this2._popper !== null) { + _this2._popper.destroy(); + } + + if (callback) { + callback(); + } + }; + + $(this.element).trigger(hideEvent); + + if (hideEvent.isDefaultPrevented()) { + return; + } + + $(tip).removeClass(ClassName$6.SHOW); // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + + if ('ontouchstart' in document.documentElement) { + $(document.body).children().off('mouseover', null, $.noop); + } + + this._activeTrigger[Trigger.CLICK] = false; + this._activeTrigger[Trigger.FOCUS] = false; + this._activeTrigger[Trigger.HOVER] = false; + + if ($(this.tip).hasClass(ClassName$6.FADE)) { + var transitionDuration = Util.getTransitionDurationFromElement(tip); + $(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); + } else { + complete(); + } + + this._hoverState = ''; + }; + + _proto.update = function update() { + if (this._popper !== null) { + this._popper.scheduleUpdate(); + } + } // Protected + ; + + _proto.isWithContent = function isWithContent() { + return Boolean(this.getTitle()); + }; + + _proto.addAttachmentClass = function addAttachmentClass(attachment) { + $(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment); + }; + + _proto.getTipElement = function getTipElement() { + this.tip = this.tip || $(this.config.template)[0]; + return this.tip; + }; + + _proto.setContent = function setContent() { + var tip = this.getTipElement(); + this.setElementContent($(tip.querySelectorAll(Selector$6.TOOLTIP_INNER)), this.getTitle()); + $(tip).removeClass(ClassName$6.FADE + " " + ClassName$6.SHOW); + }; + + _proto.setElementContent = function setElementContent($element, content) { + if (typeof content === 'object' && (content.nodeType || content.jquery)) { + // Content is a DOM node or a jQuery + if (this.config.html) { + if (!$(content).parent().is($element)) { + $element.empty().append(content); + } + } else { + $element.text($(content).text()); + } + + return; + } + + if (this.config.html) { + if (this.config.sanitize) { + content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn); + } + + $element.html(content); + } else { + $element.text(content); + } + }; + + _proto.getTitle = function getTitle() { + var title = this.element.getAttribute('data-original-title'); + + if (!title) { + title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title; + } + + return title; + } // Private + ; + + _proto._getPopperConfig = function _getPopperConfig(attachment) { + var _this3 = this; + + var defaultBsConfig = { + placement: attachment, + modifiers: { + offset: this._getOffset(), + flip: { + behavior: this.config.fallbackPlacement + }, + arrow: { + element: Selector$6.ARROW + }, + preventOverflow: { + boundariesElement: this.config.boundary + } + }, + onCreate: function onCreate(data) { + if (data.originalPlacement !== data.placement) { + _this3._handlePopperPlacementChange(data); + } + }, + onUpdate: function onUpdate(data) { + return _this3._handlePopperPlacementChange(data); + } + }; + return _objectSpread2({}, defaultBsConfig, {}, this.config.popperConfig); + }; + + _proto._getOffset = function _getOffset() { + var _this4 = this; + + var offset = {}; + + if (typeof this.config.offset === 'function') { + offset.fn = function (data) { + data.offsets = _objectSpread2({}, data.offsets, {}, _this4.config.offset(data.offsets, _this4.element) || {}); + return data; + }; + } else { + offset.offset = this.config.offset; + } + + return offset; + }; + + _proto._getContainer = function _getContainer() { + if (this.config.container === false) { + return document.body; + } + + if (Util.isElement(this.config.container)) { + return $(this.config.container); + } + + return $(document).find(this.config.container); + }; + + _proto._getAttachment = function _getAttachment(placement) { + return AttachmentMap$1[placement.toUpperCase()]; + }; + + _proto._setListeners = function _setListeners() { + var _this5 = this; + + var triggers = this.config.trigger.split(' '); + triggers.forEach(function (trigger) { + if (trigger === 'click') { + $(_this5.element).on(_this5.constructor.Event.CLICK, _this5.config.selector, function (event) { + return _this5.toggle(event); + }); + } else if (trigger !== Trigger.MANUAL) { + var eventIn = trigger === Trigger.HOVER ? _this5.constructor.Event.MOUSEENTER : _this5.constructor.Event.FOCUSIN; + var eventOut = trigger === Trigger.HOVER ? _this5.constructor.Event.MOUSELEAVE : _this5.constructor.Event.FOCUSOUT; + $(_this5.element).on(eventIn, _this5.config.selector, function (event) { + return _this5._enter(event); + }).on(eventOut, _this5.config.selector, function (event) { + return _this5._leave(event); + }); + } + }); + + this._hideModalHandler = function () { + if (_this5.element) { + _this5.hide(); + } + }; + + $(this.element).closest('.modal').on('hide.bs.modal', this._hideModalHandler); + + if (this.config.selector) { + this.config = _objectSpread2({}, this.config, { + trigger: 'manual', + selector: '' + }); + } else { + this._fixTitle(); + } + }; + + _proto._fixTitle = function _fixTitle() { + var titleType = typeof this.element.getAttribute('data-original-title'); + + if (this.element.getAttribute('title') || titleType !== 'string') { + this.element.setAttribute('data-original-title', this.element.getAttribute('title') || ''); + this.element.setAttribute('title', ''); + } + }; + + _proto._enter = function _enter(event, context) { + var dataKey = this.constructor.DATA_KEY; + context = context || $(event.currentTarget).data(dataKey); + + if (!context) { + context = new this.constructor(event.currentTarget, this._getDelegateConfig()); + $(event.currentTarget).data(dataKey, context); + } + + if (event) { + context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true; + } + + if ($(context.getTipElement()).hasClass(ClassName$6.SHOW) || context._hoverState === HoverState.SHOW) { + context._hoverState = HoverState.SHOW; + return; + } + + clearTimeout(context._timeout); + context._hoverState = HoverState.SHOW; + + if (!context.config.delay || !context.config.delay.show) { + context.show(); + return; + } + + context._timeout = setTimeout(function () { + if (context._hoverState === HoverState.SHOW) { + context.show(); + } + }, context.config.delay.show); + }; + + _proto._leave = function _leave(event, context) { + var dataKey = this.constructor.DATA_KEY; + context = context || $(event.currentTarget).data(dataKey); + + if (!context) { + context = new this.constructor(event.currentTarget, this._getDelegateConfig()); + $(event.currentTarget).data(dataKey, context); + } + + if (event) { + context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false; + } + + if (context._isWithActiveTrigger()) { + return; + } + + clearTimeout(context._timeout); + context._hoverState = HoverState.OUT; + + if (!context.config.delay || !context.config.delay.hide) { + context.hide(); + return; + } + + context._timeout = setTimeout(function () { + if (context._hoverState === HoverState.OUT) { + context.hide(); + } + }, context.config.delay.hide); + }; + + _proto._isWithActiveTrigger = function _isWithActiveTrigger() { + for (var trigger in this._activeTrigger) { + if (this._activeTrigger[trigger]) { + return true; + } + } + + return false; + }; + + _proto._getConfig = function _getConfig(config) { + var dataAttributes = $(this.element).data(); + Object.keys(dataAttributes).forEach(function (dataAttr) { + if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) { + delete dataAttributes[dataAttr]; + } + }); + config = _objectSpread2({}, this.constructor.Default, {}, dataAttributes, {}, typeof config === 'object' && config ? config : {}); + + if (typeof config.delay === 'number') { + config.delay = { + show: config.delay, + hide: config.delay + }; + } + + if (typeof config.title === 'number') { + config.title = config.title.toString(); + } + + if (typeof config.content === 'number') { + config.content = config.content.toString(); + } + + Util.typeCheckConfig(NAME$6, config, this.constructor.DefaultType); + + if (config.sanitize) { + config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn); + } + + return config; + }; + + _proto._getDelegateConfig = function _getDelegateConfig() { + var config = {}; + + if (this.config) { + for (var key in this.config) { + if (this.constructor.Default[key] !== this.config[key]) { + config[key] = this.config[key]; + } + } + } + + return config; + }; + + _proto._cleanTipClass = function _cleanTipClass() { + var $tip = $(this.getTipElement()); + var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX); + + if (tabClass !== null && tabClass.length) { + $tip.removeClass(tabClass.join('')); + } + }; + + _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) { + var popperInstance = popperData.instance; + this.tip = popperInstance.popper; + + this._cleanTipClass(); + + this.addAttachmentClass(this._getAttachment(popperData.placement)); + }; + + _proto._fixTransition = function _fixTransition() { + var tip = this.getTipElement(); + var initConfigAnimation = this.config.animation; + + if (tip.getAttribute('x-placement') !== null) { + return; + } + + $(tip).removeClass(ClassName$6.FADE); + this.config.animation = false; + this.hide(); + this.show(); + this.config.animation = initConfigAnimation; + } // Static + ; + + Tooltip._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY$6); + + var _config = typeof config === 'object' && config; + + if (!data && /dispose|hide/.test(config)) { + return; + } + + if (!data) { + data = new Tooltip(this, _config); + $(this).data(DATA_KEY$6, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + _createClass(Tooltip, null, [{ + key: "VERSION", + get: function get() { + return VERSION$6; + } + }, { + key: "Default", + get: function get() { + return Default$4; + } + }, { + key: "NAME", + get: function get() { + return NAME$6; + } + }, { + key: "DATA_KEY", + get: function get() { + return DATA_KEY$6; + } + }, { + key: "Event", + get: function get() { + return Event$6; + } + }, { + key: "EVENT_KEY", + get: function get() { + return EVENT_KEY$6; + } + }, { + key: "DefaultType", + get: function get() { + return DefaultType$4; + } + }]); + + return Tooltip; + }(); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + + $.fn[NAME$6] = Tooltip._jQueryInterface; + $.fn[NAME$6].Constructor = Tooltip; + + $.fn[NAME$6].noConflict = function () { + $.fn[NAME$6] = JQUERY_NO_CONFLICT$6; + return Tooltip._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$7 = 'popover'; + var VERSION$7 = '4.4.1'; + var DATA_KEY$7 = 'bs.popover'; + var EVENT_KEY$7 = "." + DATA_KEY$7; + var JQUERY_NO_CONFLICT$7 = $.fn[NAME$7]; + var CLASS_PREFIX$1 = 'bs-popover'; + var BSCLS_PREFIX_REGEX$1 = new RegExp("(^|\\s)" + CLASS_PREFIX$1 + "\\S+", 'g'); + + var Default$5 = _objectSpread2({}, Tooltip.Default, { + placement: 'right', + trigger: 'click', + content: '', + template: '' + }); + + var DefaultType$5 = _objectSpread2({}, Tooltip.DefaultType, { + content: '(string|element|function)' + }); + + var ClassName$7 = { + FADE: 'fade', + SHOW: 'show' + }; + var Selector$7 = { + TITLE: '.popover-header', + CONTENT: '.popover-body' + }; + var Event$7 = { + HIDE: "hide" + EVENT_KEY$7, + HIDDEN: "hidden" + EVENT_KEY$7, + SHOW: "show" + EVENT_KEY$7, + SHOWN: "shown" + EVENT_KEY$7, + INSERTED: "inserted" + EVENT_KEY$7, + CLICK: "click" + EVENT_KEY$7, + FOCUSIN: "focusin" + EVENT_KEY$7, + FOCUSOUT: "focusout" + EVENT_KEY$7, + MOUSEENTER: "mouseenter" + EVENT_KEY$7, + MOUSELEAVE: "mouseleave" + EVENT_KEY$7 + }; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + var Popover = + /*#__PURE__*/ + function (_Tooltip) { + _inheritsLoose(Popover, _Tooltip); + + function Popover() { + return _Tooltip.apply(this, arguments) || this; + } + + var _proto = Popover.prototype; + + // Overrides + _proto.isWithContent = function isWithContent() { + return this.getTitle() || this._getContent(); + }; + + _proto.addAttachmentClass = function addAttachmentClass(attachment) { + $(this.getTipElement()).addClass(CLASS_PREFIX$1 + "-" + attachment); + }; + + _proto.getTipElement = function getTipElement() { + this.tip = this.tip || $(this.config.template)[0]; + return this.tip; + }; + + _proto.setContent = function setContent() { + var $tip = $(this.getTipElement()); // We use append for html objects to maintain js events + + this.setElementContent($tip.find(Selector$7.TITLE), this.getTitle()); + + var content = this._getContent(); + + if (typeof content === 'function') { + content = content.call(this.element); + } + + this.setElementContent($tip.find(Selector$7.CONTENT), content); + $tip.removeClass(ClassName$7.FADE + " " + ClassName$7.SHOW); + } // Private + ; + + _proto._getContent = function _getContent() { + return this.element.getAttribute('data-content') || this.config.content; + }; + + _proto._cleanTipClass = function _cleanTipClass() { + var $tip = $(this.getTipElement()); + var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX$1); + + if (tabClass !== null && tabClass.length > 0) { + $tip.removeClass(tabClass.join('')); + } + } // Static + ; + + Popover._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY$7); + + var _config = typeof config === 'object' ? config : null; + + if (!data && /dispose|hide/.test(config)) { + return; + } + + if (!data) { + data = new Popover(this, _config); + $(this).data(DATA_KEY$7, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + _createClass(Popover, null, [{ + key: "VERSION", + // Getters + get: function get() { + return VERSION$7; + } + }, { + key: "Default", + get: function get() { + return Default$5; + } + }, { + key: "NAME", + get: function get() { + return NAME$7; + } + }, { + key: "DATA_KEY", + get: function get() { + return DATA_KEY$7; + } + }, { + key: "Event", + get: function get() { + return Event$7; + } + }, { + key: "EVENT_KEY", + get: function get() { + return EVENT_KEY$7; + } + }, { + key: "DefaultType", + get: function get() { + return DefaultType$5; + } + }]); + + return Popover; + }(Tooltip); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + + $.fn[NAME$7] = Popover._jQueryInterface; + $.fn[NAME$7].Constructor = Popover; + + $.fn[NAME$7].noConflict = function () { + $.fn[NAME$7] = JQUERY_NO_CONFLICT$7; + return Popover._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$8 = 'scrollspy'; + var VERSION$8 = '4.4.1'; + var DATA_KEY$8 = 'bs.scrollspy'; + var EVENT_KEY$8 = "." + DATA_KEY$8; + var DATA_API_KEY$6 = '.data-api'; + var JQUERY_NO_CONFLICT$8 = $.fn[NAME$8]; + var Default$6 = { + offset: 10, + method: 'auto', + target: '' + }; + var DefaultType$6 = { + offset: 'number', + method: 'string', + target: '(string|element)' + }; + var Event$8 = { + ACTIVATE: "activate" + EVENT_KEY$8, + SCROLL: "scroll" + EVENT_KEY$8, + LOAD_DATA_API: "load" + EVENT_KEY$8 + DATA_API_KEY$6 + }; + var ClassName$8 = { + DROPDOWN_ITEM: 'dropdown-item', + DROPDOWN_MENU: 'dropdown-menu', + ACTIVE: 'active' + }; + var Selector$8 = { + DATA_SPY: '[data-spy="scroll"]', + ACTIVE: '.active', + NAV_LIST_GROUP: '.nav, .list-group', + NAV_LINKS: '.nav-link', + NAV_ITEMS: '.nav-item', + LIST_ITEMS: '.list-group-item', + DROPDOWN: '.dropdown', + DROPDOWN_ITEMS: '.dropdown-item', + DROPDOWN_TOGGLE: '.dropdown-toggle' + }; + var OffsetMethod = { + OFFSET: 'offset', + POSITION: 'position' + }; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + var ScrollSpy = + /*#__PURE__*/ + function () { + function ScrollSpy(element, config) { + var _this = this; + + this._element = element; + this._scrollElement = element.tagName === 'BODY' ? window : element; + this._config = this._getConfig(config); + this._selector = this._config.target + " " + Selector$8.NAV_LINKS + "," + (this._config.target + " " + Selector$8.LIST_ITEMS + ",") + (this._config.target + " " + Selector$8.DROPDOWN_ITEMS); + this._offsets = []; + this._targets = []; + this._activeTarget = null; + this._scrollHeight = 0; + $(this._scrollElement).on(Event$8.SCROLL, function (event) { + return _this._process(event); + }); + this.refresh(); + + this._process(); + } // Getters + + + var _proto = ScrollSpy.prototype; + + // Public + _proto.refresh = function refresh() { + var _this2 = this; + + var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION; + var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method; + var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0; + this._offsets = []; + this._targets = []; + this._scrollHeight = this._getScrollHeight(); + var targets = [].slice.call(document.querySelectorAll(this._selector)); + targets.map(function (element) { + var target; + var targetSelector = Util.getSelectorFromElement(element); + + if (targetSelector) { + target = document.querySelector(targetSelector); + } + + if (target) { + var targetBCR = target.getBoundingClientRect(); + + if (targetBCR.width || targetBCR.height) { + // TODO (fat): remove sketch reliance on jQuery position/offset + return [$(target)[offsetMethod]().top + offsetBase, targetSelector]; + } + } + + return null; + }).filter(function (item) { + return item; + }).sort(function (a, b) { + return a[0] - b[0]; + }).forEach(function (item) { + _this2._offsets.push(item[0]); + + _this2._targets.push(item[1]); + }); + }; + + _proto.dispose = function dispose() { + $.removeData(this._element, DATA_KEY$8); + $(this._scrollElement).off(EVENT_KEY$8); + this._element = null; + this._scrollElement = null; + this._config = null; + this._selector = null; + this._offsets = null; + this._targets = null; + this._activeTarget = null; + this._scrollHeight = null; + } // Private + ; + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread2({}, Default$6, {}, typeof config === 'object' && config ? config : {}); + + if (typeof config.target !== 'string') { + var id = $(config.target).attr('id'); + + if (!id) { + id = Util.getUID(NAME$8); + $(config.target).attr('id', id); + } + + config.target = "#" + id; + } + + Util.typeCheckConfig(NAME$8, config, DefaultType$6); + return config; + }; + + _proto._getScrollTop = function _getScrollTop() { + return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop; + }; + + _proto._getScrollHeight = function _getScrollHeight() { + return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); + }; + + _proto._getOffsetHeight = function _getOffsetHeight() { + return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height; + }; + + _proto._process = function _process() { + var scrollTop = this._getScrollTop() + this._config.offset; + + var scrollHeight = this._getScrollHeight(); + + var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight(); + + if (this._scrollHeight !== scrollHeight) { + this.refresh(); + } + + if (scrollTop >= maxScroll) { + var target = this._targets[this._targets.length - 1]; + + if (this._activeTarget !== target) { + this._activate(target); + } + + return; + } + + if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { + this._activeTarget = null; + + this._clear(); + + return; + } + + var offsetLength = this._offsets.length; + + for (var i = offsetLength; i--;) { + var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]); + + if (isActiveTarget) { + this._activate(this._targets[i]); + } + } + }; + + _proto._activate = function _activate(target) { + this._activeTarget = target; + + this._clear(); + + var queries = this._selector.split(',').map(function (selector) { + return selector + "[data-target=\"" + target + "\"]," + selector + "[href=\"" + target + "\"]"; + }); + + var $link = $([].slice.call(document.querySelectorAll(queries.join(',')))); + + if ($link.hasClass(ClassName$8.DROPDOWN_ITEM)) { + $link.closest(Selector$8.DROPDOWN).find(Selector$8.DROPDOWN_TOGGLE).addClass(ClassName$8.ACTIVE); + $link.addClass(ClassName$8.ACTIVE); + } else { + // Set triggered link as active + $link.addClass(ClassName$8.ACTIVE); // Set triggered links parents as active + // With both

ZG7?_i8?0p9sghxcjB6N3h3#6X_&au36y7ga++6C>+xDG|}?fODTa8e=|M?Nko(a z(i$PTF9O-e2|>Kr&Yho1YUpr{WR15=Mn7iJiMjPvJ4=Ep@N)p4_8nB5F1EoVM$99< zVXf;`wS?1caMriZHtoahfOXZGwul)6EdksrS3-Yo5j}I4gv@OodUce$I-10=5G# z?TY7~ZW=3o5~Xc3pdVH2y1`lwFAX09{C9a17U@Z2bv%{EnS*(#;w>f)R1^fVc-TaX zxcH4o{Mp-V6l{hr#rm@F6=ZpPSE)lhTEOi&16%KHZA*^E*59Y*34dpy*;a}D>}(Z- z7UA!iH{XGHBMJ`A_1(dlZ}`krD!8=Flnzc*J1|8#Yu z6U=KSNl({;QrSZpXB*(_){)QY+fs#tf*+_b-6V+?0uW~LtRvmy_r7yK-}pLg6yL52 zEIv{w1lz}KzqT2v*1@mkKAtk2Cql|b%I@=X4Z4x`vCj;EqwmOs2}_~igV`<*MjX$gDpylnkKv)v8Rf)lIF(1Y`e4H`5&Z?e=UptM(X%a zux8U6tr@>%2EjLy2+1#4|BuFB1dl)PZHv>B|3-+~yC(Yt5BI%1!6xs-kmJYq9tgb% zJ_d<10PZ`mlJqRy-P{S|zPs#bu(4>zv9`TAuYxuq56 zS|zq!8Y$}1cUab!?uhadLDE5}V>c2!4u4m*hUV?|6M` zgB7E(3?mbnUY#k`yU_rab1zsaH6@5ozRW~R2~h5KgJ9DFt)4i4_`s+M(dk!$H(M%6 z#cLN;4NOyc35+``<5f#M!8qoI=s<7UY3tF(L*FL7u9OOZW5?y~QlXWh&Q!nl*dp~4 zRO7WluP;ptMT|%yj#X}VI`mbtfkIQ=Wt-pk zH(om6dI`t{m2{{^&0kLyCkbG~NF%9?*Ov+;ej+6zhvUzDHI^pWaJZw-tA8-u1c`4* zW{AEP|{k@=^Q?c)! zZHFU}<}TRzaQ}VLkE^lDZ?#l6L(nH<>w9!Ui(VxMt2gbj^&PaWS6x>|>`&kd(!e07 zf9yDZ5jB60%-akC0tO;{`(~#E0{Rbe`eooh)3AP4l3(K|=d=H9I{tgc{?qC2mF1_- zFQ-R;>ijWN|Ch6$srJ|S>FnqD8yEGT{(fhp{uKV@kK*rY|Kg_p4$<#a%fGZk-X7^c zo&KA6`Mdh>1i`=5k=|0)U+RC-1^?GgziIqy{Jd$4w+-Z58Tnrd|3nFe>~D4F_Y3{K zK>c*|3nlKqtNovH^}C(lx3+)Tk-+=U8{OY6{N5Y-%Yr2GFAINmivIua-TrM2^Cv6f zcaOi*C;sx7@^`hr$P~XD_;KQ~{AEf(`rRM-1LciI NoAxF*M)gzg{{aOSxP1Ts literal 0 HcmV?d00001 diff --git a/public/excel/用户导入模板 (1).xlsx b/public/excel/用户导入模板 (1).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e65a20e93267b53c828742f9dace17504a2a0bbd GIT binary patch literal 9948 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 F{{bW~`G^1j literal 0 HcmV?d00001 diff --git a/public/excel/用户导入模板.xlsx b/public/excel/用户导入模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4b453f9f30b47c9fe16ed4564c7c596d49cdacc3 GIT binary patch literal 9173 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⋙R9LsNR0&lq3PZ*N2t$}>*??RF%&K8DFrY33tCrdl?pIcJf z=swvt5o`!Qv4>$+`Z?u#OgffXB2$FaAXaghu8-1;x}yx)2-6a$h50ciY=hIYAhFD@ zsvo+^#6{SY}{o_X@(rti}T*l2lWUMJG53v08am zTdNj^#hLQ3)AezWSCp>G44N2j`j)-CD;W#in5E}~-d!N~oJsPfa?WlpXA}5x&7PdQ z-h82_>7_2jWf@!A@vOEA(5F-}Hy1@xbP8N03d>;83}%L5Mo>_Z)nui!PAjyiU~suU+6lep8QD7YaV;nAt5rJk zodedpJp_D|@Tiam0`>~zgZ?}JYGiM3{WI;V(yQ18NxM=UpeOE)T7nNjsp?{W8?cVF zt2Rpt#$zl~%yhm3;Ouycf|Kq3D6_8KF%^bGL?LNwEB<%b@qU)2(Po+>wS6OFOjOUD zDC#QUtS({w%Tjy8R}F4%+rZC7p`TcRyEf=M#ioI4hDOBr>40%-63k0tlm1UH9@GQDA5;2)=^?jNSF*^4k z{=L?u;D&=a1z;iHRxt7QOP0SIq<#{sz0=evs=_#05C1mhVl8dn%cOyDmh2TY+Z`2)HA2)0s8eIhf*97Ci%#<Lh1c0GqLIx|U>6$Crx=s}(haE`n|UoPzJi?{k0o~PuB4{$K7 zsK>l>v5Cfs0D9$4He;Mf!ol$kIJpS*?zzc^l$4q=p-SonC98$atm-v8GNyFtDUya! zW%XT%jEt~VknMg=I5cX6 zbUDM`UJdD_cB0&96%3stqDht^$*XGW2?Kk&a2U8B>TD;8lKDF5 zg1Z!7Ip-%Im!9{f9xw{D@_EO4@Q3T7bflsbBu9;s9e#JDi?Na8$HQ+tcU*mtnJzrg zaW;p{b5sb|a?gk9ird=(Ozi-#)!#UnI_uxh_tN-Y#Yb$|!DrM>ZF#yJY7T}Gh6anK zMU+c0qo-dvj}tQj_D?hD3?7O4N2JN{?_4zBT{ohzQJ=hb75NZrzdME# zv)NaB&qe{}M!5ym6dhDWpJb4~lirr^ z!Vsmkfr{lC%Q)RFBnodli5Z8xofW}-E~*G9@>{oWc81bkd%WM!rs zUk&{KA?LnU}_eop=>_eTlt%Rf#X{Mp~b za|idrzxt#3r`mr`Av}cWA*udb8w7FbzdQYlVt=UqkPH5;jsf8?f2;q^4F9i}zGppu zmHU@AfBYW~^!|1K-6VgaG)nZ30QGR74R}5H^Mb!y;DNBZ_bvRLCH!At{rT>%;eV?BMV$TVArGmu-#rHZQ|&jA_Hf7#cQd~m z;DoFSkRksQw*NKgd)oR}xwkOrmxb?@|0c2j9Qi{U`(F2#)vEqW_cy7nEC+kPKY$z( O!GwZ`$kmbF|N1}dwaaDz literal 0 HcmV?d00001 diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e71815a6618c6ef19c78d27840b8995fb2521499 GIT binary patch literal 1150 zcmbVMSx8i26uv?4_SAEaJq7BFqqJE;Q9TBc5JYcLIgSmPnyr-jk`K{>ZB(>aLWVXo z*9E63a&I$RrZR03EEi&&_1^#9`}O_*AViPd;mm*e&-u>z&UX%1)0XhJY?;RY723X~ znzmfiw3Reo@g{fAL(}N{_i=@Ma0M%r6$X8HFcE zpG~1@_%Y6ow1ksJIN%eE0)m_g-8Gd#K%-r;7XvI$t0gLrlUMS(*o zV$Y+$Ct(SJ+L5c+)7OmI%nVG$!vbteaep>7ij6%r*#F`@;?!a~HIJfDIkr7LrT7TO z8Pus^>>;*w*WwO!6s7@#wJgVkVE+^G7)ra2;Ldm_p8Ob6`0br_NQk8JTkP3k{J^jG z*cCa8vT!3JGaq0ucb3{&JkLiTVfXWMD5q9ZyH%ZD)V;jPIT^6ouVd%VG`X~V*0H+F zhl^v6kP#Mn+6Yg-!rHDH>fs|^>X)1U?nncMSj%CIp#G9el3d=+e!&L43iV_6ITI5d zQv>h>y$V~X^k*JwD7m;pl{iR^$K%uN!-g$vq?qse=KxBm_3+$BoO#pw7gpx+aR#|L z%6Dm{!D`%_jIeKm8ajyn9!EZFoOpW+Tl5oZR|^>D;?7A9ZiV-%JuQ#*owco@x{a zD-|ENtov7tOFzK5r}KRMSHhkEb!7aa$$nhqBKuHtV!cJ5I+?Si!w-Hm{`)ye +// +---------------------------------------------------------------------- +// $Id$ + +if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) { + return false; +} else { + $_SERVER["SCRIPT_FILENAME"] = __DIR__ . '/index.php'; + + require __DIR__ . "/index.php"; +} diff --git a/public/static/.gitignore b/public/static/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/public/static/css/Contact.css b/public/static/css/Contact.css new file mode 100644 index 0000000..b2c21c9 --- /dev/null +++ b/public/static/css/Contact.css @@ -0,0 +1,346 @@ +a { + text-decoration: none; + color: #000; +} + +.contact a:hover { + text-decoration: none; + color: #000; +} + +.contact_visible a:hover { + text-decoration: none; + color: #000; +} + +p { + margin-top: 20px; +} + +#container { + width: 100%; + height: 600px; + margin: auto; + overflow: hidden; +} + +#box { + width: 74%; + height: 800px; + background-color: white; + display: flex; + margin: 100px auto; + box-shadow: darkgrey 10px 10px 30px 5px; + position: relative; + top: -150px; +} + +#box_contact { + width: 50%; + height: 100%; + background-color: white; +} + +.contact { + width: 80%; + height: 90%; + margin: 0 auto; + font-family: "Microsoft YaHei", 微软雅黑; +} + +.size1 { + font-size: 2em; + font-weight: 600; + +} + +.size2 { + font-size: 2em; + font-weight: 600; +} + +.box_QRcode { + width: 100%; + height: 18%; + display: flex; + justify-content: space-around; + margin-top: 30px; +} + +.QRcode { + width: 125px; + height: 125px; + text-align: center; +} + +.QRcode img { + width: 100%; + height: 100%; +} + +.QRcode span { + font-size: 13px; + color: #595959; +} + +#box_liuyan { + width: 50%; + height: 100%; + background-color: rgb(0, 167, 134); +} + +.liuyan { + width: 80%; + height: 90%; + margin: 0 auto; +} + +.size3 { + font-size: 2em; + font-weight: 600; + color: white; +} + +textarea { + background-color: rgb(0, 167, 134); + border-style: none; + outline: none; + color: white; +} + +.textarea_border textarea { + border-bottom: 1px solid rgb(192, 192, 192); + height: 80px; +} + +#box_liuyan textarea { + min-width: 100%; +} + +#box_liuyan .textarea_border :hover { + border-bottom: 1px solid rgb(5, 224, 253); +} + +#box_liuyan .input_border input { + width: 100%; + height: 60px; +} + +#box_liuyan input { + background-color: rgb(0, 167, 134); + border-style: none; + outline: none; + color: white; +} + +#box_liuyan .input_verification { + width: 60%; + height: 40px; + margin-top: 50px; + float: left; +} + +#box_liuyan .input_verification input { + width: 100%; + height: 100%; + border-bottom: 1px solid rgb(192, 192, 192); +} + +#box_liuyan .input_border { + border-bottom: 1px solid rgb(192, 192, 192); +} + +#box_liuyan .input_border :hover { + border-bottom: 1px solid rgb(5, 224, 253); +} + +#box_liuyan .input_verification :hover { + border-bottom: 1px solid rgb(5, 224, 253); +} + +input::-webkit-input-placeholder { + color: white; +} + +textarea::-webkit-input-placeholder { + color: white; +} + +.verification { + float: left; + margin-top: 51px; + width: 40%; +} + +.verification img { + font-size: 18pt; + cursor: pointer; + width: 120px; + margin-top: 10px; +} + +.submit button { + width: 100px; + height: 35px; +} + +#box_liuyan .submit button { + background-color: white; + border: 1px solid black; + color: #000; +} + +#box_liuyan .submit button:hover { + border: 1px solid white; + transition: 0.5s; + background-color: rgb(0, 167, 134); + color: white; +} + +#box_visible { + width: 90%; + height: auto; + background-color: white; + margin: 0 auto; + box-shadow: darkgrey 10px 10px 30px 5px; + position: relative; + top: -100px; +} + +#box_contact_visible { + width: 100%; + height: 100%; + background-color: white; + display: flex; + align-items: center; + justify-content: center; +} + +.contact_visible { + width: 90%; + height: 95%; +} + +#box_liuyan_visible { + width: 100%; + height: 100%; + background-color: rgb(0, 167, 134); + margin-top: 60px; +} + +#box_liuyan_visible { + width: 100%; + height: 650px; + display: flex; + justify-content: center; + align-items: center; +} + +textarea { + background-color: rgb(0, 167, 134); + border-style: none; + outline: none; + color: white; +} + +.textarea_border textarea { + border-bottom: 1px solid rgb(192, 192, 192); + height: 80px; +} + +#box_liuyan_visible textarea { + min-width: 100%; +} + +#box_liuyan_visible .textarea_border :hover { + border-bottom: 1px solid rgb(5, 224, 253); +} + +#box_liuyan_visible .input_border input { + width: 100%; + height: 60px; +} + +#box_liuyan_visible input { + background-color: rgb(0, 167, 134); + border-style: none; + outline: none; + color: white; +} + +#box_liuyan_visible .input_verification { + width: 55%; + height: 40px; + margin-top: 50px; + float: left; +} + +#box_liuyan_visible .input_verification input { + width: 100%; + height: 100%; + border-bottom: 1px solid rgb(192, 192, 192); +} + +#box_liuyan_visible .input_border { + border-bottom: 1px solid rgb(192, 192, 192); +} + +#box_liuyan_visible .input_border :hover { + border-bottom: 1px solid rgb(5, 224, 253); +} + +#box_liuyan_visible .input_verification :hover { + border-bottom: 1px solid rgb(5, 224, 253); +} + +input::-webkit-input-placeholder { + color: white; +} + +textarea::-webkit-input-placeholder { + color: white; +} + +.box_liuyan_visible { + float: left; + margin-top: 50px; + color: rgb(0, 167, 134); + background-color: #ffffff; + font-size: 18pt; + padding: 5px 15px 5px 15px; + cursor: pointer; +} + +.submit button { + width: 100px; + height: 35px; +} + +#box_liuyan_visible button { + background-color: white; + border: 1px solid black; + color: #000; + margin-top: 10px; +} + +#box_liuyan_visible .submit button :hover { + border: 1px solid white; + transition: 0.5s; + background-color: rgb(0, 167, 134); + color: white; +} + +#box_liuyan_visible .verification { + float: left; + margin-top: 51px; + font-size: 18pt; + cursor: pointer; +} + +.amap-logo { + z-index: 100 !important; +} + +.amap-copyright { + z-index: 100 !important; +} \ No newline at end of file diff --git a/public/static/css/JoinFlow.css b/public/static/css/JoinFlow.css new file mode 100644 index 0000000..ec95e02 --- /dev/null +++ b/public/static/css/JoinFlow.css @@ -0,0 +1,338 @@ +招商流程 */ + +/* join 通用css样式 */ +body { + margin: 0; + padding: 0; +} + +.topPic { + width: 100%; +} + +.barTop { + display: flex; + width: 90%; + height: auto; + background-color: #00a587; + padding-left: 5%; + padding-top: 20px; + position: relative; + top: -75px; + margin-left: 10%; + +} + +.barGs:hover { + /* border-bottom: #fff 3px solid; */ + padding-bottom: 15px; + /* border-right: none; */ +} + +a { + text-decoration: none +} + +.barTop2 { + position: absolute; + left: -10px; + width: 100%; + +} + +.barName { + width: 30%; + height: 100%; + line-height: 2; +} + +.barHeadline { + font-size: 40px; + font-weight: bold; + color: #fff; + line-height: 1.6; +} + +.barHeadline2 { + font-size: 30px; + color: #fff; + padding-bottom: 20px; +} + +.barSize { + width: 220px; + height: 30px; + position: absolute; + display: flex; + right: 0; + padding-top: 30px; +} + +.barSize img { + width: 20px; + height: 20px; +} + +.barMap { + font-size: 14px; + color: #fff; +} + +.bar { + margin-top: 50px; + display: flex; + /* width: 600px; */ + height: 30px; + position: absolute; + right: 0; + top: 30px; +} + +.barGs { + line-height: 40px; + /* display: flex; + justify-content: center; + text-align: center; */ + margin: 0 20px; + height: 40px; + color: #fff; + font-size: 15px; + /* border-right: #e2e2e2 2px solid; */ +} + +.body { + margin: 0px auto; + width: 100%; + padding-left: 20px; + max-width: 1500px; +} + +.bodyTop { + width: 100%; + padding: 30px 0; + font-size: 40px; + display: flex; + align-items: center; + justify-content: center; + border-bottom: 1px solid #ccc; +} + +.bodyText { + margin-left: 3%; + width: 96%; + height: 800px; + margin-top: 30px; +} + +.bodyTextTop { + color: #00a587; + font-weight: bold; + font-size: 26px; + padding-top: 20px; +} + +.thread { + margin: 30px 0; + width: 50px; + height: 2px; + background-color: #00a587; +} + +.text-Mini { + width: 100%; + margin: 40px 0; +} + +.text { + width: 100%; + margin: 40px 0; + display: flex; +} + +.text1 { + display: flex; + flex-direction: column; + width: 70%; +} + +.text-1 { + line-height: 3; + font-size: 16px; + color: #333; + display: flex; + flex-wrap: wrap; + font-weight: 500; + margin-bottom: 20px; + margin-left: 20px; + + +} + +.condiTions { + width: 100%; +} + +.cond { + list-style-type: decimal; + font-size: 14px; + +} + +.tiao { + color: #00a587; + font-weight: 600; + font-size: 14px; + padding-left: 20px; +} + +.you { + display: flex; + margin-right: 5%; + width: 100%; + +} + +.you1 { + width: 60%; +} + +.text-2 { + color: #00a587; + font-weight: 600; + font-size: 16px; + margin-left: 20px; +} + +.pic1 { + max-width: 300px; + max-height: 500px; + width: 300px; + height: 500px; +} + +.pic2 { + width: 500px; + height: 300px; + margin: 0 20px; +} + +.bodyPic1 { + width: 80%; + margin: 0 10%; + height: auto; + margin-left: 20px; +} + +.bodyPic1-max { + width: 45%; + height: 650px; + margin-top: -150px; +} + +.bodyPic2-max { + width: 40%; + height: 400px; +} + +.barTop-xiao { + width: 100%; + background-color: #00a587; + padding: 20px 30px; +} + +.barName-Mini { + color: #fff; + font-size: 700; + font-size: 30px; + border-bottom: #ccc 1px solid; + padding-left: 30px; +} + +.bar-Mini { + display: flex; + margin: 20px 0px; +} + +.barGs-Mini { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 90px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.bodyTop-Mini { + margin-top: 20px; + padding: 30px 0px; + font-size: 30px; + height: 50px; + display: flex; + align-items: center; + justify-content: center; +} + +.body-Mini { + width: 90%; + margin: 0 5%; + +} + +.bodyTextTop-Mini { + color: #00a587; + font-weight: bold; + font-size: 24px; +} + +.thread { + margin-top: 30px; + width: 50px; + height: 2px; + background-color: #00a587; +} + +.pic-Mini { + width: 100%; + text-align: center; + object-fit: cover; + +} + +.pic-MiniBox { + width: 90%; + height: auto; + /* padding: 20px; */ + margin: 30px 5%; + background-size: contain; + text-align: center; +} + +.text-1-Mini { + font-size: 14px; + color: #333; + display: flex; + flex-wrap: wrap; + font-weight: 400; + margin-bottom: 20px; +} + +.tiao-Mini { + color: #00a587; + font-weight: 600; + font-size: 14px; +} + +.borderBottom { + width: 0; + transition: all 0.3s; + height: 3px; + background-color: #fff; + margin: auto; +} + +.barGs:hover .borderBottom { + width: 60px; + margin: auto; +} \ No newline at end of file diff --git a/public/static/css/animation.css b/public/static/css/animation.css new file mode 100644 index 0000000..1dc88b0 --- /dev/null +++ b/public/static/css/animation.css @@ -0,0 +1,169 @@ +/*动画库*/ +/*滑入*/ +.slide-in-bck-bottom { + -webkit-animation: slide-in-bck-bottom 0.6s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; + animation: slide-in-bck-bottom 0.6s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; +} +@-webkit-keyframes slide-in-bck-bottom { + 0% { + -webkit-transform: translateZ(700px) translateY(300px); + transform: translateZ(700px) translateY(300px); + opacity: 0; + } + 100% { + -webkit-transform: translateZ(0) translateY(0); + transform: translateZ(0) translateY(0); + opacity: 1; + } +} +@keyframes slide-in-bck-bottom { + 0% { + -webkit-transform: translateZ(700px) translateY(300px); + transform: translateZ(700px) translateY(300px); + opacity: 0; + } + 100% { + -webkit-transform: translateZ(0) translateY(0); + transform: translateZ(0) translateY(0); + opacity: 1; + } +} +/*滑出*/ +.slide-out-bck-bottom { + -webkit-animation: slide-out-bck-bottom 0.5s cubic-bezier(0.550, 0.085, 0.680, 0.530) both; + animation: slide-out-bck-bottom 0.5s cubic-bezier(0.550, 0.085, 0.680, 0.530) both; +} +@-webkit-keyframes slide-out-bck-bottom { + 0% { + -webkit-transform: translateZ(0) translateY(0); + transform: translateZ(0) translateY(0); + opacity: 1; + } + 100% { + -webkit-transform: translateZ(-1100px) translateY(1000px); + transform: translateZ(-1100px) translateY(1000px); + opacity: 0; + } +} +@keyframes slide-out-bck-bottom { + 0% { + -webkit-transform: translateZ(0) translateY(0); + transform: translateZ(0) translateY(0); + opacity: 1; + } + 100% { + -webkit-transform: translateZ(-1100px) translateY(1000px); + transform: translateZ(-1100px) translateY(1000px); + opacity: 0; + } +} +/*弹入*/ +.bounce-in-right { + -webkit-animation: bounce-in-right 1.1s both; + animation: bounce-in-right 1.1s both; +} + +@-webkit-keyframes bounce-in-right { + 0% { + -webkit-transform: translateX(600px); + transform: translateX(600px); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + opacity: 0; + } + 38% { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + opacity: 1; + } + 55% { + -webkit-transform: translateX(68px); + transform: translateX(68px); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + 72% { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + 81% { + -webkit-transform: translateX(32px); + transform: translateX(32px); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + 90% { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + 95% { + -webkit-transform: translateX(8px); + transform: translateX(8px); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } +} +@keyframes bounce-in-right { + 0% { + -webkit-transform: translateX(600px); + transform: translateX(600px); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + opacity: 0; + } + 38% { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + opacity: 1; + } + 55% { + -webkit-transform: translateX(68px); + transform: translateX(68px); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + 72% { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + 81% { + -webkit-transform: translateX(32px); + transform: translateX(32px); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + 90% { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + 95% { + -webkit-transform: translateX(8px); + transform: translateX(8px); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } +} diff --git a/public/static/css/bootstrap.css b/public/static/css/bootstrap.css new file mode 100644 index 0000000..b0339a1 --- /dev/null +++ b/public/static/css/bootstrap.css @@ -0,0 +1,11422 @@ +/*! + * Bootstrap v4.4.1 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +:root { + --blue: #007bff; + --indigo: #6610f2; + --purple: #6f42c1; + --pink: #e83e8c; + --red: #dc3545; + --orange: #fd7e14; + --yellow: #ffc107; + --green: #28a745; + --teal: #20c997; + --cyan: #17a2b8; + --white: #fff; + --gray: #6c757d; + --gray-dark: #343a40; + --primary: #007bff; + --secondary: #6c757d; + --success: #28a745; + --info: #17a2b8; + --warning: #ffc107; + --danger: #dc3545; + --light: #f8f9fa; + --dark: #343a40; + --breakpoint-xs: 0; + --breakpoint-sm: 576px; + --breakpoint-md: 768px; + --breakpoint-lg: 992px; + --breakpoint-xl: 1200px; + --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +*, +*::before, +*::after { + box-sizing: border-box; + font-weight: 700; +} + +html { + font-family: sans-serif; + line-height: 1.15; + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +article, +aside, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section { + display: block; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /*font-size: 1rem;*/ + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: left; + background-color: rgb(250, 250, 250); +} + +[tabindex="-1"]:focus:not(:focus-visible) { + outline: 0 !important; +} + +hr { + box-sizing: content-box; + height: 0; + overflow: visible; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin-top: 0; + margin-bottom: 0.5rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title], +abbr[data-original-title] { + text-decoration: underline; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + cursor: help; + border-bottom: 0; + -webkit-text-decoration-skip-ink: none; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: 700; +} + +dd { + margin-bottom: .5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small { + font-size: 80%; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -.25em; +} + +sup { + top: -.5em; +} + +a { + /*color: #007bff;*/ + text-decoration: none; + background-color: transparent; +} + +a:hover { + color: #0056b3; + text-decoration: underline; +} + +a:not([href]) { + color: inherit; + text-decoration: none; +} + +a:not([href]):hover { + color: inherit; + text-decoration: none; +} + +pre, +code, +kbd, +samp { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + font-size: 1em; +} + +pre { + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; +} + +figure { + margin: 0 0 1rem; +} + +img { + vertical-align: middle; + border-style: none; + /* height: 100%; + width: 100%; + object-fit: contain; */ +} + +svg { + overflow: hidden; + vertical-align: middle; +} + +table { + border-collapse: collapse; +} + +caption { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + color: #6c757d; + text-align: left; + caption-side: bottom; +} + +th { + text-align: inherit; +} + +label { + display: inline-block; + margin-bottom: 0.5rem; +} + +button { + border-radius: 0; +} + +button:focus { + outline: 1px dotted; + outline: 5px auto -webkit-focus-ring-color; +} + +input, +button, +select, +optgroup, +textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +input { + overflow: visible; +} + +button, +select { + text-transform: none; +} + +select { + word-wrap: normal; +} + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +button:not(:disabled), +[type="button"]:not(:disabled), +[type="reset"]:not(:disabled), +[type="submit"]:not(:disabled) { + cursor: pointer; +} + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + padding: 0; + border-style: none; +} + +input[type="radio"], +input[type="checkbox"] { + box-sizing: border-box; + padding: 0; +} + +input[type="date"], +input[type="time"], +input[type="datetime-local"], +input[type="month"] { + -webkit-appearance: listbox; +} + +textarea { + overflow: auto; + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + max-width: 100%; + padding: 0; + margin-bottom: .5rem; + font-size: 1.5rem; + line-height: inherit; + color: inherit; + white-space: normal; +} + +progress { + vertical-align: baseline; +} + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +[type="search"] { + outline-offset: -2px; + -webkit-appearance: none; +} + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-file-upload-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +summary { + display: list-item; + cursor: pointer; +} + +template { + display: none; +} + +[hidden] { + display: none !important; +} + +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + margin-bottom: 0.5rem; + font-weight: 500; + line-height: 1.2; +} + +h1, +.h1 { + font-size: 14px; +} + +h2, +.h2 { + font-size: 2rem; +} + +h3, +.h3 { + font-size: 1.75rem; +} + +h4, +.h4 { + font-size: 1.5rem; +} + +h5, +.h5 { + font-size: 1.25rem; +} + +h6, +.h6 { + font-size: 1rem; +} + +.lead { + font-size: 1.25rem; + font-weight: 300; +} + +.display-1 { + font-size: 6rem; + font-weight: 300; + line-height: 1.2; +} + +.display-2 { + font-size: 5.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-3 { + font-size: 4.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-4 { + font-size: 3.5rem; + font-weight: 300; + line-height: 1.2; +} + +hr { + margin-top: 1rem; + margin-bottom: 1rem; + border: 0; + border-top: 1px solid rgba(0, 0, 0, 0.1); +} + +small, +.small { + font-size: 80%; + font-weight: 400; +} + +mark, +.mark { + padding: 0.2em; + background-color: #fcf8e3; +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline-item { + display: inline-block; +} + +.list-inline-item:not(:last-child) { + margin-right: 0.5rem; +} + +.initialism { + font-size: 90%; + text-transform: uppercase; +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.25rem; +} + +.blockquote-footer { + display: block; + font-size: 80%; + color: #6c757d; +} + +.blockquote-footer::before { + content: "\2014\00A0"; +} + +.img-fluid { + max-width: 100%; + height: auto; +} + +.img-thumbnail { + padding: 0.25rem; + background-color: #fff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + max-width: 100%; + height: auto; +} + +.figure { + display: inline-block; +} + +.figure-img { + margin-bottom: 0.5rem; + line-height: 1; +} + +.figure-caption { + font-size: 90%; + color: #6c757d; +} + +code { + font-size: 87.5%; + color: #e83e8c; + word-wrap: break-word; +} + +a>code { + color: inherit; +} + +kbd { + padding: 0.2rem 0.4rem; + font-size: 87.5%; + color: #fff; + background-color: #212529; + border-radius: 0.2rem; +} + +kbd kbd { + padding: 0; + font-size: 100%; + font-weight: 700; +} + +pre { + display: block; + font-size: 87.5%; + color: #212529; +} + +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +.container { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container { + max-width: 540px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 720px; + } +} + +@media (min-width: 992px) { + .container { + max-width: 960px; + } +} + +@media (min-width: 1200px) { + .container { + max-width: 1140px; + } +} + +.container-fluid, +.container-sm, +.container-md, +.container-lg, +.container-xl { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + + .container, + .container-sm { + max-width: 540px; + } +} + +@media (min-width: 768px) { + + .container, + .container-sm, + .container-md { + max-width: 720px; + } +} + +@media (min-width: 992px) { + + .container, + .container-sm, + .container-md, + .container-lg { + max-width: 960px; + } +} + +@media (min-width: 1200px) { + + .container, + .container-sm, + .container-md, + .container-lg, + .container-xl { + max-width: 1140px; + } +} + +.row { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -15px; + margin-left: -15px; +} + +.no-gutters { + margin-right: 0; + margin-left: 0; +} + +.no-gutters>.col, +.no-gutters>[class*="col-"] { + padding-right: 0; + padding-left: 0; +} + +.col-1, +.col-2, +.col-3, +.col-4, +.col-5, +.col-6, +.col-7, +.col-8, +.col-9, +.col-10, +.col-11, +.col-12, +.col, +.col-auto, +.col-sm-1, +.col-sm-2, +.col-sm-3, +.col-sm-4, +.col-sm-5, +.col-sm-6, +.col-sm-7, +.col-sm-8, +.col-sm-9, +.col-sm-10, +.col-sm-11, +.col-sm-12, +.col-sm, +.col-sm-auto, +.col-md-1, +.col-md-2, +.col-md-3, +.col-md-4, +.col-md-5, +.col-md-6, +.col-md-7, +.col-md-8, +.col-md-9, +.col-md-10, +.col-md-11, +.col-md-12, +.col-md, +.col-md-auto, +.col-lg-1, +.col-lg-2, +.col-lg-3, +.col-lg-4, +.col-lg-5, +.col-lg-6, +.col-lg-7, +.col-lg-8, +.col-lg-9, +.col-lg-10, +.col-lg-11, +.col-lg-12, +.col-lg, +.col-lg-auto, +.col-xl-1, +.col-xl-2, +.col-xl-3, +.col-xl-4, +.col-xl-5, +.col-xl-6, +.col-xl-7, +.col-xl-8, +.col-xl-9, +.col-xl-10, +.col-xl-11, +.col-xl-12, +.col-xl, +.col-xl-auto { + position: relative; + width: 100%; + padding-right: 15px; + padding-left: 15px; +} + +.col { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; +} + +.row-cols-1>* { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; +} + +.row-cols-2>* { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; +} + +.row-cols-3>* { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; +} + +.row-cols-4>* { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; +} + +.row-cols-5>* { + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; +} + +.row-cols-6>* { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; +} + +.col-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; +} + +.col-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; +} + +.col-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; +} + +.col-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; +} + +.col-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; +} + +.col-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; +} + +.col-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; +} + +.col-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; +} + +.col-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; +} + +.col-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; +} + +.col-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; +} + +.col-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; +} + +.col-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; +} + +.order-first { + -ms-flex-order: -1; + order: -1; +} + +.order-last { + -ms-flex-order: 13; + order: 13; +} + +.order-0 { + -ms-flex-order: 0; + order: 0; +} + +.order-1 { + -ms-flex-order: 1; + order: 1; +} + +.order-2 { + -ms-flex-order: 2; + order: 2; +} + +.order-3 { + -ms-flex-order: 3; + order: 3; +} + +.order-4 { + -ms-flex-order: 4; + order: 4; +} + +.order-5 { + -ms-flex-order: 5; + order: 5; +} + +.order-6 { + -ms-flex-order: 6; + order: 6; +} + +.order-7 { + -ms-flex-order: 7; + order: 7; +} + +.order-8 { + -ms-flex-order: 8; + order: 8; +} + +.order-9 { + -ms-flex-order: 9; + order: 9; +} + +.order-10 { + -ms-flex-order: 10; + order: 10; +} + +.order-11 { + -ms-flex-order: 11; + order: 11; +} + +.order-12 { + -ms-flex-order: 12; + order: 12; +} + +.offset-1 { + margin-left: 8.333333%; +} + +.offset-2 { + margin-left: 16.666667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.333333%; +} + +.offset-5 { + margin-left: 41.666667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.333333%; +} + +.offset-8 { + margin-left: 66.666667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.333333%; +} + +.offset-11 { + margin-left: 91.666667%; +} + +@media (min-width: 576px) { + .col-sm { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + + .row-cols-sm-1>* { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + + .row-cols-sm-2>* { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + + .row-cols-sm-3>* { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + + .row-cols-sm-4>* { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + + .row-cols-sm-5>* { + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; + } + + .row-cols-sm-6>* { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + + .col-sm-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + + .col-sm-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + + .col-sm-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + + .col-sm-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + + .col-sm-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + + .col-sm-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + + .col-sm-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + + .col-sm-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + + .col-sm-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + + .col-sm-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + + .col-sm-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + + .col-sm-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + + .col-sm-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + + .order-sm-first { + -ms-flex-order: -1; + order: -1; + } + + .order-sm-last { + -ms-flex-order: 13; + order: 13; + } + + .order-sm-0 { + -ms-flex-order: 0; + order: 0; + } + + .order-sm-1 { + -ms-flex-order: 1; + order: 1; + } + + .order-sm-2 { + -ms-flex-order: 2; + order: 2; + } + + .order-sm-3 { + -ms-flex-order: 3; + order: 3; + } + + .order-sm-4 { + -ms-flex-order: 4; + order: 4; + } + + .order-sm-5 { + -ms-flex-order: 5; + order: 5; + } + + .order-sm-6 { + -ms-flex-order: 6; + order: 6; + } + + .order-sm-7 { + -ms-flex-order: 7; + order: 7; + } + + .order-sm-8 { + -ms-flex-order: 8; + order: 8; + } + + .order-sm-9 { + -ms-flex-order: 9; + order: 9; + } + + .order-sm-10 { + -ms-flex-order: 10; + order: 10; + } + + .order-sm-11 { + -ms-flex-order: 11; + order: 11; + } + + .order-sm-12 { + -ms-flex-order: 12; + order: 12; + } + + .offset-sm-0 { + margin-left: 0; + } + + .offset-sm-1 { + margin-left: 8.333333%; + } + + .offset-sm-2 { + margin-left: 16.666667%; + } + + .offset-sm-3 { + margin-left: 25%; + } + + .offset-sm-4 { + margin-left: 33.333333%; + } + + .offset-sm-5 { + margin-left: 41.666667%; + } + + .offset-sm-6 { + margin-left: 50%; + } + + .offset-sm-7 { + margin-left: 58.333333%; + } + + .offset-sm-8 { + margin-left: 66.666667%; + } + + .offset-sm-9 { + margin-left: 75%; + } + + .offset-sm-10 { + margin-left: 83.333333%; + } + + .offset-sm-11 { + margin-left: 91.666667%; + } +} + +@media (min-width: 768px) { + .col-md { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + + .row-cols-md-1>* { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + + .row-cols-md-2>* { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + + .row-cols-md-3>* { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + + .row-cols-md-4>* { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + + .row-cols-md-5>* { + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; + } + + .row-cols-md-6>* { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + + .col-md-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + + .col-md-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + + .col-md-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + + .col-md-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + + .col-md-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + + .col-md-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + + .col-md-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + + .col-md-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + + .col-md-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + + .col-md-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + + .col-md-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + + .col-md-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + + .col-md-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + + .order-md-first { + -ms-flex-order: -1; + order: -1; + } + + .order-md-last { + -ms-flex-order: 13; + order: 13; + } + + .order-md-0 { + -ms-flex-order: 0; + order: 0; + } + + .order-md-1 { + -ms-flex-order: 1; + order: 1; + } + + .order-md-2 { + -ms-flex-order: 2; + order: 2; + } + + .order-md-3 { + -ms-flex-order: 3; + order: 3; + } + + .order-md-4 { + -ms-flex-order: 4; + order: 4; + } + + .order-md-5 { + -ms-flex-order: 5; + order: 5; + } + + .order-md-6 { + -ms-flex-order: 6; + order: 6; + } + + .order-md-7 { + -ms-flex-order: 7; + order: 7; + } + + .order-md-8 { + -ms-flex-order: 8; + order: 8; + } + + .order-md-9 { + -ms-flex-order: 9; + order: 9; + } + + .order-md-10 { + -ms-flex-order: 10; + order: 10; + } + + .order-md-11 { + -ms-flex-order: 11; + order: 11; + } + + .order-md-12 { + -ms-flex-order: 12; + order: 12; + } + + .offset-md-0 { + margin-left: 0; + } + + .offset-md-1 { + margin-left: 8.333333%; + } + + .offset-md-2 { + margin-left: 16.666667%; + } + + .offset-md-3 { + margin-left: 25%; + } + + .offset-md-4 { + margin-left: 33.333333%; + } + + .offset-md-5 { + margin-left: 41.666667%; + } + + .offset-md-6 { + margin-left: 50%; + } + + .offset-md-7 { + margin-left: 58.333333%; + } + + .offset-md-8 { + margin-left: 66.666667%; + } + + .offset-md-9 { + margin-left: 75%; + } + + .offset-md-10 { + margin-left: 83.333333%; + } + + .offset-md-11 { + margin-left: 91.666667%; + } +} + +@media (min-width: 992px) { + .col-lg { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + + .row-cols-lg-1>* { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + + .row-cols-lg-2>* { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + + .row-cols-lg-3>* { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + + .row-cols-lg-4>* { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + + .row-cols-lg-5>* { + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; + } + + .row-cols-lg-6>* { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + + .col-lg-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + + .col-lg-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + + .col-lg-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + + .col-lg-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + + .col-lg-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + + .col-lg-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + + .col-lg-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + + .col-lg-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + + .col-lg-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + + .col-lg-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + + .col-lg-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + + .col-lg-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + + .col-lg-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + + .order-lg-first { + -ms-flex-order: -1; + order: -1; + } + + .order-lg-last { + -ms-flex-order: 13; + order: 13; + } + + .order-lg-0 { + -ms-flex-order: 0; + order: 0; + } + + .order-lg-1 { + -ms-flex-order: 1; + order: 1; + } + + .order-lg-2 { + -ms-flex-order: 2; + order: 2; + } + + .order-lg-3 { + -ms-flex-order: 3; + order: 3; + } + + .order-lg-4 { + -ms-flex-order: 4; + order: 4; + } + + .order-lg-5 { + -ms-flex-order: 5; + order: 5; + } + + .order-lg-6 { + -ms-flex-order: 6; + order: 6; + } + + .order-lg-7 { + -ms-flex-order: 7; + order: 7; + } + + .order-lg-8 { + -ms-flex-order: 8; + order: 8; + } + + .order-lg-9 { + -ms-flex-order: 9; + order: 9; + } + + .order-lg-10 { + -ms-flex-order: 10; + order: 10; + } + + .order-lg-11 { + -ms-flex-order: 11; + order: 11; + } + + .order-lg-12 { + -ms-flex-order: 12; + order: 12; + } + + .offset-lg-0 { + margin-left: 0; + } + + .offset-lg-1 { + margin-left: 8.333333%; + } + + .offset-lg-2 { + margin-left: 16.666667%; + } + + .offset-lg-3 { + margin-left: 25%; + } + + .offset-lg-4 { + margin-left: 33.333333%; + } + + .offset-lg-5 { + margin-left: 41.666667%; + } + + .offset-lg-6 { + margin-left: 50%; + } + + .offset-lg-7 { + margin-left: 58.333333%; + } + + .offset-lg-8 { + margin-left: 66.666667%; + } + + .offset-lg-9 { + margin-left: 75%; + } + + .offset-lg-10 { + margin-left: 83.333333%; + } + + .offset-lg-11 { + margin-left: 91.666667%; + } +} + +@media (min-width: 1200px) { + .col-xl { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + + .row-cols-xl-1>* { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + + .row-cols-xl-2>* { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + + .row-cols-xl-3>* { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + + .row-cols-xl-4>* { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + + .row-cols-xl-5>* { + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; + } + + .row-cols-xl-6>* { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + + .col-xl-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + + .col-xl-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + + .col-xl-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + + .col-xl-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + + .col-xl-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + + .col-xl-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + + .col-xl-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + font-family: "Microsoft YaHei", 微软雅黑; + } + + .col-xl-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + + .col-xl-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + + .col-xl-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + + .col-xl-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + + .col-xl-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + + .col-xl-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + + .order-xl-first { + -ms-flex-order: -1; + order: -1; + } + + .order-xl-last { + -ms-flex-order: 13; + order: 13; + } + + .order-xl-0 { + -ms-flex-order: 0; + order: 0; + } + + .order-xl-1 { + -ms-flex-order: 1; + order: 1; + } + + .order-xl-2 { + -ms-flex-order: 2; + order: 2; + } + + .order-xl-3 { + -ms-flex-order: 3; + order: 3; + } + + .order-xl-4 { + -ms-flex-order: 4; + order: 4; + } + + .order-xl-5 { + -ms-flex-order: 5; + order: 5; + } + + .order-xl-6 { + -ms-flex-order: 6; + order: 6; + } + + .order-xl-7 { + -ms-flex-order: 7; + order: 7; + } + + .order-xl-8 { + -ms-flex-order: 8; + order: 8; + } + + .order-xl-9 { + -ms-flex-order: 9; + order: 9; + } + + .order-xl-10 { + -ms-flex-order: 10; + order: 10; + } + + .order-xl-11 { + -ms-flex-order: 11; + order: 11; + } + + .order-xl-12 { + -ms-flex-order: 12; + order: 12; + } + + .offset-xl-0 { + margin-left: 0; + } + + .offset-xl-1 { + margin-left: 8.333333%; + } + + .offset-xl-2 { + margin-left: 16.666667%; + } + + .offset-xl-3 { + margin-left: 25%; + } + + .offset-xl-4 { + margin-left: 33.333333%; + } + + .offset-xl-5 { + margin-left: 41.666667%; + } + + .offset-xl-6 { + margin-left: 50%; + } + + .offset-xl-7 { + margin-left: 58.333333%; + } + + .offset-xl-8 { + margin-left: 66.666667%; + } + + .offset-xl-9 { + margin-left: 75%; + } + + .offset-xl-10 { + margin-left: 83.333333%; + } + + .offset-xl-11 { + margin-left: 91.666667%; + } +} + +.table { + width: 100%; + margin-bottom: 1rem; + color: #212529; +} + +.table th, +.table td { + padding: 0.75rem; + vertical-align: top; + border-top: 1px solid #dee2e6; +} + +.table thead th { + vertical-align: bottom; + border-bottom: 2px solid #dee2e6; +} + +.table tbody+tbody { + border-top: 2px solid #dee2e6; +} + +.table-sm th, +.table-sm td { + padding: 0.3rem; +} + +.table-bordered { + border: 1px solid #dee2e6; +} + +.table-bordered th, +.table-bordered td { + border: 1px solid #dee2e6; +} + +.table-bordered thead th, +.table-bordered thead td { + border-bottom-width: 2px; +} + +.table-borderless th, +.table-borderless td, +.table-borderless thead th, +.table-borderless tbody+tbody { + border: 0; +} + +.table-striped tbody tr:nth-of-type(odd) { + background-color: rgba(0, 0, 0, 0.05); +} + +.table-hover tbody tr:hover { + color: #212529; + background-color: rgba(0, 0, 0, 0.075); +} + +.table-primary, +.table-primary>th, +.table-primary>td { + background-color: #b8daff; +} + +.table-primary th, +.table-primary td, +.table-primary thead th, +.table-primary tbody+tbody { + border-color: #7abaff; +} + +.table-hover .table-primary:hover { + background-color: #9fcdff; +} + +.table-hover .table-primary:hover>td, +.table-hover .table-primary:hover>th { + background-color: #9fcdff; +} + +.table-secondary, +.table-secondary>th, +.table-secondary>td { + background-color: #d6d8db; +} + +.table-secondary th, +.table-secondary td, +.table-secondary thead th, +.table-secondary tbody+tbody { + border-color: #b3b7bb; +} + +.table-hover .table-secondary:hover { + background-color: #c8cbcf; +} + +.table-hover .table-secondary:hover>td, +.table-hover .table-secondary:hover>th { + background-color: #c8cbcf; +} + +.table-success, +.table-success>th, +.table-success>td { + background-color: #c3e6cb; +} + +.table-success th, +.table-success td, +.table-success thead th, +.table-success tbody+tbody { + border-color: #8fd19e; +} + +.table-hover .table-success:hover { + background-color: #b1dfbb; +} + +.table-hover .table-success:hover>td, +.table-hover .table-success:hover>th { + background-color: #b1dfbb; +} + +.table-info, +.table-info>th, +.table-info>td { + background-color: #bee5eb; +} + +.table-info th, +.table-info td, +.table-info thead th, +.table-info tbody+tbody { + border-color: #86cfda; +} + +.table-hover .table-info:hover { + background-color: #abdde5; +} + +.table-hover .table-info:hover>td, +.table-hover .table-info:hover>th { + background-color: #abdde5; +} + +.table-warning, +.table-warning>th, +.table-warning>td { + background-color: #ffeeba; +} + +.table-warning th, +.table-warning td, +.table-warning thead th, +.table-warning tbody+tbody { + border-color: #ffdf7e; +} + +.table-hover .table-warning:hover { + background-color: #ffe8a1; +} + +.table-hover .table-warning:hover>td, +.table-hover .table-warning:hover>th { + background-color: #ffe8a1; +} + +.table-danger, +.table-danger>th, +.table-danger>td { + background-color: #f5c6cb; +} + +.table-danger th, +.table-danger td, +.table-danger thead th, +.table-danger tbody+tbody { + border-color: #ed969e; +} + +.table-hover .table-danger:hover { + background-color: #f1b0b7; +} + +.table-hover .table-danger:hover>td, +.table-hover .table-danger:hover>th { + background-color: #f1b0b7; +} + +.table-light, +.table-light>th, +.table-light>td { + background-color: #fdfdfe; +} + +.table-light th, +.table-light td, +.table-light thead th, +.table-light tbody+tbody { + border-color: #fbfcfc; +} + +.table-hover .table-light:hover { + background-color: #ececf6; +} + +.table-hover .table-light:hover>td, +.table-hover .table-light:hover>th { + background-color: #ececf6; +} + +.table-dark, +.table-dark>th, +.table-dark>td { + background-color: #c6c8ca; +} + +.table-dark th, +.table-dark td, +.table-dark thead th, +.table-dark tbody+tbody { + border-color: #95999c; +} + +.table-hover .table-dark:hover { + background-color: #b9bbbe; +} + +.table-hover .table-dark:hover>td, +.table-hover .table-dark:hover>th { + background-color: #b9bbbe; +} + +.table-active, +.table-active>th, +.table-active>td { + background-color: rgba(0, 0, 0, 0.075); +} + +.table-hover .table-active:hover { + background-color: rgba(0, 0, 0, 0.075); +} + +.table-hover .table-active:hover>td, +.table-hover .table-active:hover>th { + background-color: rgba(0, 0, 0, 0.075); +} + +.table .thead-dark th { + color: #fff; + background-color: #343a40; + border-color: #454d55; +} + +.table .thead-light th { + color: #495057; + background-color: #e9ecef; + border-color: #dee2e6; +} + +.table-dark { + color: #fff; + background-color: #343a40; +} + +.table-dark th, +.table-dark td, +.table-dark thead th { + border-color: #454d55; +} + +.table-dark.table-bordered { + border: 0; +} + +.table-dark.table-striped tbody tr:nth-of-type(odd) { + background-color: rgba(255, 255, 255, 0.05); +} + +.table-dark.table-hover tbody tr:hover { + color: #fff; + background-color: rgba(255, 255, 255, 0.075); +} + +@media (max-width: 575.98px) { + .table-responsive-sm { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .table-responsive-sm>.table-bordered { + border: 0; + } +} + +@media (max-width: 767.98px) { + .table-responsive-md { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .table-responsive-md>.table-bordered { + border: 0; + } +} + +@media (max-width: 991.98px) { + .table-responsive-lg { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .table-responsive-lg>.table-bordered { + border: 0; + } +} + +@media (max-width: 1199.98px) { + .table-responsive-xl { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .table-responsive-xl>.table-bordered { + border: 0; + } +} + +.table-responsive { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +.table-responsive>.table-bordered { + border: 0; +} + +.form-control { + display: block; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ced4da; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-control { + transition: none; + } +} + +.form-control::-ms-expand { + background-color: transparent; + border: 0; +} + +.form-control:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 #495057; +} + +.form-control:focus { + color: #495057; + background-color: #fff; + border-color: #80bdff; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.form-control::-webkit-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::-moz-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control:-ms-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::-ms-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control:disabled, +.form-control[readonly] { + background-color: #e9ecef; + opacity: 1; +} + +select.form-control:focus::-ms-value { + color: #495057; + background-color: #fff; +} + +.form-control-file, +.form-control-range { + display: block; + width: 100%; +} + +.col-form-label { + padding-top: calc(0.375rem + 1px); + padding-bottom: calc(0.375rem + 1px); + margin-bottom: 0; + font-size: inherit; + line-height: 1.5; +} + +.col-form-label-lg { + padding-top: calc(0.5rem + 1px); + padding-bottom: calc(0.5rem + 1px); + font-size: 1.25rem; + line-height: 1.5; +} + +.col-form-label-sm { + padding-top: calc(0.25rem + 1px); + padding-bottom: calc(0.25rem + 1px); + font-size: 0.875rem; + line-height: 1.5; +} + +.form-control-plaintext { + display: block; + width: 100%; + padding: 0.375rem 0; + margin-bottom: 0; + font-size: 1rem; + line-height: 1.5; + color: #212529; + background-color: transparent; + border: solid transparent; + border-width: 1px 0; +} + +.form-control-plaintext.form-control-sm, +.form-control-plaintext.form-control-lg { + padding-right: 0; + padding-left: 0; +} + +.form-control-sm { + height: calc(1.5em + 0.5rem + 2px); + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.form-control-lg { + height: calc(1.5em + 1rem + 2px); + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +select.form-control[size], +select.form-control[multiple] { + height: auto; +} + +textarea.form-control { + height: auto; +} + +.form-group { + margin-bottom: 1rem; +} + +.form-text { + display: block; + margin-top: 0.25rem; +} + +.form-row { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -5px; + margin-left: -5px; +} + +.form-row>.col, +.form-row>[class*="col-"] { + padding-right: 5px; + padding-left: 5px; +} + +.form-check { + position: relative; + display: block; + padding-left: 1.25rem; +} + +.form-check-input { + position: absolute; + margin-top: 0.3rem; + margin-left: -1.25rem; +} + +.form-check-input[disabled]~.form-check-label, +.form-check-input:disabled~.form-check-label { + color: #6c757d; +} + +.form-check-label { + margin-bottom: 0; +} + +.form-check-inline { + display: -ms-inline-flexbox; + display: inline-flex; + -ms-flex-align: center; + align-items: center; + padding-left: 0; + margin-right: 0.75rem; +} + +.form-check-inline .form-check-input { + position: static; + margin-top: 0; + margin-right: 0.3125rem; + margin-left: 0; +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #28a745; +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #fff; + background-color: rgba(40, 167, 69, 0.9); + border-radius: 0.25rem; +} + +.was-validated :valid~.valid-feedback, +.was-validated :valid~.valid-tooltip, +.is-valid~.valid-feedback, +.is-valid~.valid-tooltip { + display: block; +} + +.was-validated .form-control:valid, +.form-control.is-valid { + border-color: #28a745; + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .form-control:valid:focus, +.form-control.is-valid:focus { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated textarea.form-control:valid, +textarea.form-control.is-valid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.was-validated .custom-select:valid, +.custom-select.is-valid { + border-color: #28a745; + padding-right: calc(0.75em + 2.3125rem); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .custom-select:valid:focus, +.custom-select.is-valid:focus { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .form-check-input:valid~.form-check-label, +.form-check-input.is-valid~.form-check-label { + color: #28a745; +} + +.was-validated .form-check-input:valid~.valid-feedback, +.was-validated .form-check-input:valid~.valid-tooltip, +.form-check-input.is-valid~.valid-feedback, +.form-check-input.is-valid~.valid-tooltip { + display: block; +} + +.was-validated .custom-control-input:valid~.custom-control-label, +.custom-control-input.is-valid~.custom-control-label { + color: #28a745; +} + +.was-validated .custom-control-input:valid~.custom-control-label::before, +.custom-control-input.is-valid~.custom-control-label::before { + border-color: #28a745; +} + +.was-validated .custom-control-input:valid:checked~.custom-control-label::before, +.custom-control-input.is-valid:checked~.custom-control-label::before { + border-color: #34ce57; + background-color: #34ce57; +} + +.was-validated .custom-control-input:valid:focus~.custom-control-label::before, +.custom-control-input.is-valid:focus~.custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before, +.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before { + border-color: #28a745; +} + +.was-validated .custom-file-input:valid~.custom-file-label, +.custom-file-input.is-valid~.custom-file-label { + border-color: #28a745; +} + +.was-validated .custom-file-input:valid:focus~.custom-file-label, +.custom-file-input.is-valid:focus~.custom-file-label { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.invalid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #dc3545; +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #fff; + background-color: rgba(220, 53, 69, 0.9); + border-radius: 0.25rem; +} + +.was-validated :invalid~.invalid-feedback, +.was-validated :invalid~.invalid-tooltip, +.is-invalid~.invalid-feedback, +.is-invalid~.invalid-tooltip { + display: block; +} + +.was-validated .form-control:invalid, +.form-control.is-invalid { + border-color: #dc3545; + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .form-control:invalid:focus, +.form-control.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated textarea.form-control:invalid, +textarea.form-control.is-invalid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.was-validated .custom-select:invalid, +.custom-select.is-invalid { + border-color: #dc3545; + padding-right: calc(0.75em + 2.3125rem); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .custom-select:invalid:focus, +.custom-select.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-check-input:invalid~.form-check-label, +.form-check-input.is-invalid~.form-check-label { + color: #dc3545; +} + +.was-validated .form-check-input:invalid~.invalid-feedback, +.was-validated .form-check-input:invalid~.invalid-tooltip, +.form-check-input.is-invalid~.invalid-feedback, +.form-check-input.is-invalid~.invalid-tooltip { + display: block; +} + +.was-validated .custom-control-input:invalid~.custom-control-label, +.custom-control-input.is-invalid~.custom-control-label { + color: #dc3545; +} + +.was-validated .custom-control-input:invalid~.custom-control-label::before, +.custom-control-input.is-invalid~.custom-control-label::before { + border-color: #dc3545; +} + +.was-validated .custom-control-input:invalid:checked~.custom-control-label::before, +.custom-control-input.is-invalid:checked~.custom-control-label::before { + border-color: #e4606d; + background-color: #e4606d; +} + +.was-validated .custom-control-input:invalid:focus~.custom-control-label::before, +.custom-control-input.is-invalid:focus~.custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before, +.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before { + border-color: #dc3545; +} + +.was-validated .custom-file-input:invalid~.custom-file-label, +.custom-file-input.is-invalid~.custom-file-label { + border-color: #dc3545; +} + +.was-validated .custom-file-input:invalid:focus~.custom-file-label, +.custom-file-input.is-invalid:focus~.custom-file-label { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.form-inline { + display: -ms-flexbox; + display: flex; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -ms-flex-align: center; + align-items: center; +} + +.form-inline .form-check { + width: 100%; +} + +@media (min-width: 576px) { + .form-inline label { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + margin-bottom: 0; + } + + .form-inline .form-group { + display: -ms-flexbox; + display: flex; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -ms-flex-align: center; + align-items: center; + margin-bottom: 0; + } + + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + + .form-inline .form-control-plaintext { + display: inline-block; + } + + .form-inline .input-group, + .form-inline .custom-select { + width: auto; + } + + .form-inline .form-check { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + width: auto; + padding-left: 0; + } + + .form-inline .form-check-input { + position: relative; + -ms-flex-negative: 0; + flex-shrink: 0; + margin-top: 0; + margin-right: 0.25rem; + margin-left: 0; + } + + .form-inline .custom-control { + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + } + + .form-inline .custom-control-label { + margin-bottom: 0; + } +} + +.btn { + display: inline-block; + font-weight: 400; + color: #212529; + text-align: center; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: transparent; + border: 1px solid transparent; + padding: 0.375rem 0.75rem; + font-size: 1rem; + line-height: 1.5; + border-radius: 0.25rem; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .btn { + transition: none; + } +} + +.btn:hover { + color: #212529; + text-decoration: none; +} + +.btn:focus, +.btn.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.btn.disabled, +.btn:disabled { + opacity: 0.65; +} + +a.btn.disabled, +fieldset:disabled a.btn { + pointer-events: none; +} + +.btn-primary { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-primary:hover { + color: #fff; + background-color: #0069d9; + border-color: #0062cc; +} + +.btn-primary:focus, +.btn-primary.focus { + color: #fff; + background-color: #0069d9; + border-color: #0062cc; + box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); +} + +.btn-primary.disabled, +.btn-primary:disabled { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-primary:not(:disabled):not(.disabled):active, +.btn-primary:not(:disabled):not(.disabled).active, +.show>.btn-primary.dropdown-toggle { + color: #fff; + background-color: #0062cc; + border-color: #005cbf; +} + +.btn-primary:not(:disabled):not(.disabled):active:focus, +.btn-primary:not(:disabled):not(.disabled).active:focus, +.show>.btn-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); +} + +.btn-secondary { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-secondary:hover { + color: #fff; + background-color: #5a6268; + border-color: #545b62; +} + +.btn-secondary:focus, +.btn-secondary.focus { + color: #fff; + background-color: #5a6268; + border-color: #545b62; + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-secondary.disabled, +.btn-secondary:disabled { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-secondary:not(:disabled):not(.disabled):active, +.btn-secondary:not(:disabled):not(.disabled).active, +.show>.btn-secondary.dropdown-toggle { + color: #fff; + background-color: #545b62; + border-color: #4e555b; +} + +.btn-secondary:not(:disabled):not(.disabled):active:focus, +.btn-secondary:not(:disabled):not(.disabled).active:focus, +.show>.btn-secondary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-success { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-success:hover { + color: #fff; + background-color: #218838; + border-color: #1e7e34; +} + +.btn-success:focus, +.btn-success.focus { + color: #fff; + background-color: #218838; + border-color: #1e7e34; + box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); +} + +.btn-success.disabled, +.btn-success:disabled { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-success:not(:disabled):not(.disabled):active, +.btn-success:not(:disabled):not(.disabled).active, +.show>.btn-success.dropdown-toggle { + color: #fff; + background-color: #1e7e34; + border-color: #1c7430; +} + +.btn-success:not(:disabled):not(.disabled):active:focus, +.btn-success:not(:disabled):not(.disabled).active:focus, +.show>.btn-success.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); +} + +.btn-info { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-info:hover { + color: #fff; + background-color: #138496; + border-color: #117a8b; +} + +.btn-info:focus, +.btn-info.focus { + color: #fff; + background-color: #138496; + border-color: #117a8b; + box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); +} + +.btn-info.disabled, +.btn-info:disabled { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-info:not(:disabled):not(.disabled):active, +.btn-info:not(:disabled):not(.disabled).active, +.show>.btn-info.dropdown-toggle { + color: #fff; + background-color: #117a8b; + border-color: #10707f; +} + +.btn-info:not(:disabled):not(.disabled):active:focus, +.btn-info:not(:disabled):not(.disabled).active:focus, +.show>.btn-info.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); +} + +.btn-warning { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-warning:hover { + color: #212529; + background-color: #e0a800; + border-color: #d39e00; +} + +.btn-warning:focus, +.btn-warning.focus { + color: #212529; + background-color: #e0a800; + border-color: #d39e00; + box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); +} + +.btn-warning.disabled, +.btn-warning:disabled { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-warning:not(:disabled):not(.disabled):active, +.btn-warning:not(:disabled):not(.disabled).active, +.show>.btn-warning.dropdown-toggle { + color: #212529; + background-color: #d39e00; + border-color: #c69500; +} + +.btn-warning:not(:disabled):not(.disabled):active:focus, +.btn-warning:not(:disabled):not(.disabled).active:focus, +.show>.btn-warning.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); +} + +.btn-danger { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-danger:hover { + color: #fff; + background-color: #c82333; + border-color: #bd2130; +} + +.btn-danger:focus, +.btn-danger.focus { + color: #fff; + background-color: #c82333; + border-color: #bd2130; + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-danger.disabled, +.btn-danger:disabled { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-danger:not(:disabled):not(.disabled):active, +.btn-danger:not(:disabled):not(.disabled).active, +.show>.btn-danger.dropdown-toggle { + color: #fff; + background-color: #bd2130; + border-color: #b21f2d; +} + +.btn-danger:not(:disabled):not(.disabled):active:focus, +.btn-danger:not(:disabled):not(.disabled).active:focus, +.show>.btn-danger.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-light { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-light:hover { + color: #212529; + background-color: #e2e6ea; + border-color: #dae0e5; +} + +.btn-light:focus, +.btn-light.focus { + color: #212529; + background-color: #e2e6ea; + border-color: #dae0e5; + box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); +} + +.btn-light.disabled, +.btn-light:disabled { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-light:not(:disabled):not(.disabled):active, +.btn-light:not(:disabled):not(.disabled).active, +.show>.btn-light.dropdown-toggle { + color: #212529; + background-color: #dae0e5; + border-color: #d3d9df; +} + +.btn-light:not(:disabled):not(.disabled):active:focus, +.btn-light:not(:disabled):not(.disabled).active:focus, +.show>.btn-light.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); +} + +.btn-dark { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-dark:hover { + color: #fff; + background-color: #23272b; + border-color: #1d2124; +} + +.btn-dark:focus, +.btn-dark.focus { + color: #fff; + background-color: #23272b; + border-color: #1d2124; + box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); +} + +.btn-dark.disabled, +.btn-dark:disabled { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-dark:not(:disabled):not(.disabled):active, +.btn-dark:not(:disabled):not(.disabled).active, +.show>.btn-dark.dropdown-toggle { + color: #fff; + background-color: #1d2124; + border-color: #171a1d; +} + +.btn-dark:not(:disabled):not(.disabled):active:focus, +.btn-dark:not(:disabled):not(.disabled).active:focus, +.show>.btn-dark.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); +} + +.btn-outline-primary { + color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:hover { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:focus, +.btn-outline-primary.focus { + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.btn-outline-primary.disabled, +.btn-outline-primary:disabled { + color: #007bff; + background-color: transparent; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active, +.btn-outline-primary:not(:disabled):not(.disabled).active, +.show>.btn-outline-primary.dropdown-toggle { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active:focus, +.btn-outline-primary:not(:disabled):not(.disabled).active:focus, +.show>.btn-outline-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.btn-outline-secondary { + color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:hover { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:focus, +.btn-outline-secondary.focus { + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-outline-secondary.disabled, +.btn-outline-secondary:disabled { + color: #6c757d; + background-color: transparent; +} + +.btn-outline-secondary:not(:disabled):not(.disabled):active, +.btn-outline-secondary:not(:disabled):not(.disabled).active, +.show>.btn-outline-secondary.dropdown-toggle { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, +.btn-outline-secondary:not(:disabled):not(.disabled).active:focus, +.show>.btn-outline-secondary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-outline-success { + color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:hover { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:focus, +.btn-outline-success.focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-outline-success.disabled, +.btn-outline-success:disabled { + color: #28a745; + background-color: transparent; +} + +.btn-outline-success:not(:disabled):not(.disabled):active, +.btn-outline-success:not(:disabled):not(.disabled).active, +.show>.btn-outline-success.dropdown-toggle { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:not(:disabled):not(.disabled):active:focus, +.btn-outline-success:not(:disabled):not(.disabled).active:focus, +.show>.btn-outline-success.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-outline-info { + color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:hover { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:focus, +.btn-outline-info.focus { + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-outline-info.disabled, +.btn-outline-info:disabled { + color: #17a2b8; + background-color: transparent; +} + +.btn-outline-info:not(:disabled):not(.disabled):active, +.btn-outline-info:not(:disabled):not(.disabled).active, +.show>.btn-outline-info.dropdown-toggle { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:not(:disabled):not(.disabled):active:focus, +.btn-outline-info:not(:disabled):not(.disabled).active:focus, +.show>.btn-outline-info.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-outline-warning { + color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:hover { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:focus, +.btn-outline-warning.focus { + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-outline-warning.disabled, +.btn-outline-warning:disabled { + color: #ffc107; + background-color: transparent; +} + +.btn-outline-warning:not(:disabled):not(.disabled):active, +.btn-outline-warning:not(:disabled):not(.disabled).active, +.show>.btn-outline-warning.dropdown-toggle { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:not(:disabled):not(.disabled):active:focus, +.btn-outline-warning:not(:disabled):not(.disabled).active:focus, +.show>.btn-outline-warning.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-outline-danger { + color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:hover { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:focus, +.btn-outline-danger.focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-outline-danger.disabled, +.btn-outline-danger:disabled { + color: #dc3545; + background-color: transparent; +} + +.btn-outline-danger:not(:disabled):not(.disabled):active, +.btn-outline-danger:not(:disabled):not(.disabled).active, +.show>.btn-outline-danger.dropdown-toggle { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:not(:disabled):not(.disabled):active:focus, +.btn-outline-danger:not(:disabled):not(.disabled).active:focus, +.show>.btn-outline-danger.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-outline-light { + color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:hover { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:focus, +.btn-outline-light.focus { + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-outline-light.disabled, +.btn-outline-light:disabled { + color: #f8f9fa; + background-color: transparent; +} + +.btn-outline-light:not(:disabled):not(.disabled):active, +.btn-outline-light:not(:disabled):not(.disabled).active, +.show>.btn-outline-light.dropdown-toggle { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:not(:disabled):not(.disabled):active:focus, +.btn-outline-light:not(:disabled):not(.disabled).active:focus, +.show>.btn-outline-light.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-outline-dark { + color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:hover { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:focus, +.btn-outline-dark.focus { + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.btn-outline-dark.disabled, +.btn-outline-dark:disabled { + color: #343a40; + background-color: transparent; +} + +.btn-outline-dark:not(:disabled):not(.disabled):active, +.btn-outline-dark:not(:disabled):not(.disabled).active, +.show>.btn-outline-dark.dropdown-toggle { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:not(:disabled):not(.disabled):active:focus, +.btn-outline-dark:not(:disabled):not(.disabled).active:focus, +.show>.btn-outline-dark.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.btn-link { + font-weight: 400; + color: #007bff; + text-decoration: none; +} + +.btn-link:hover { + color: #0056b3; + text-decoration: underline; +} + +.btn-link:focus, +.btn-link.focus { + text-decoration: underline; + box-shadow: none; +} + +.btn-link:disabled, +.btn-link.disabled { + color: #6c757d; + pointer-events: none; +} + +.btn-lg, +.btn-group-lg>.btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +.btn-sm, +.btn-group-sm>.btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.btn-block { + display: block; + width: 100%; +} + +.btn-block+.btn-block { + margin-top: 0.5rem; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.fade { + transition: opacity 0.15s linear; +} + +@media (prefers-reduced-motion: reduce) { + .fade { + transition: none; + } +} + +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + position: relative; + height: 0; + overflow: hidden; + transition: height 0.35s ease; +} + +@media (prefers-reduced-motion: reduce) { + .collapsing { + transition: none; + } +} + +.dropup, +.dropright, +.dropdown, +.dropleft { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; +} + +.dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; +} + +.dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 10rem; + padding: 0.5rem 0; + margin: 0.125rem 0 0; + font-size: 1rem; + color: #212529; + text-align: left; + list-style: none; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0.25rem; +} + +.dropdown-menu-left { + right: auto; + left: 0; +} + +.dropdown-menu-right { + right: 0; + left: auto; +} + +@media (min-width: 576px) { + .dropdown-menu-sm-left { + right: auto; + left: 0; + } + + .dropdown-menu-sm-right { + right: 0; + left: auto; + } +} + +@media (min-width: 768px) { + .dropdown-menu-md-left { + right: auto; + left: 0; + } + + .dropdown-menu-md-right { + right: 0; + left: auto; + } +} + +@media (min-width: 992px) { + .dropdown-menu-lg-left { + right: auto; + left: 0; + } + + .dropdown-menu-lg-right { + right: 0; + left: auto; + } +} + +@media (min-width: 1200px) { + .dropdown-menu-xl-left { + right: auto; + left: 0; + } + + .dropdown-menu-xl-right { + right: 0; + left: auto; + } +} + +.dropup .dropdown-menu { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: 0.125rem; +} + +.dropup .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0; + border-right: 0.3em solid transparent; + border-bottom: 0.3em solid; + border-left: 0.3em solid transparent; +} + +.dropup .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropright .dropdown-menu { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: 0.125rem; +} + +.dropright .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0; + border-bottom: 0.3em solid transparent; + border-left: 0.3em solid; +} + +.dropright .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropright .dropdown-toggle::after { + vertical-align: 0; +} + +.dropleft .dropdown-menu { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: 0.125rem; +} + +.dropleft .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; +} + +.dropleft .dropdown-toggle::after { + display: none; +} + +.dropleft .dropdown-toggle::before { + display: inline-block; + margin-right: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0.3em solid; + border-bottom: 0.3em solid transparent; +} + +.dropleft .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropleft .dropdown-toggle::before { + vertical-align: 0; +} + +.dropdown-menu[x-placement^="top"], +.dropdown-menu[x-placement^="right"], +.dropdown-menu[x-placement^="bottom"], +.dropdown-menu[x-placement^="left"] { + right: auto; + bottom: auto; +} + +.dropdown-divider { + height: 0; + margin: 0.5rem 0; + overflow: hidden; + border-top: 1px solid #e9ecef; +} + +.dropdown-item { + display: block; + width: 100%; + padding: 0.25rem 1.5rem; + clear: both; + font-weight: 400; + color: #212529; + text-align: inherit; + white-space: nowrap; + background-color: transparent; + border: 0; +} + +.dropdown-item:hover, +.dropdown-item:focus { + color: #16181b; + text-decoration: none; + background-color: #f8f9fa; +} + +.dropdown-item.active, +.dropdown-item:active { + color: #fff; + text-decoration: none; + background-color: #007bff; +} + +.dropdown-item.disabled, +.dropdown-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-header { + display: block; + padding: 0.5rem 1.5rem; + margin-bottom: 0; + font-size: 0.875rem; + color: #6c757d; + white-space: nowrap; +} + +.dropdown-item-text { + display: block; + padding: 0.25rem 1.5rem; + color: #212529; +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: -ms-inline-flexbox; + display: inline-flex; + vertical-align: middle; +} + +.btn-group>.btn, +.btn-group-vertical>.btn { + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; +} + +.btn-group>.btn:hover, +.btn-group-vertical>.btn:hover { + z-index: 1; +} + +.btn-group>.btn:focus, +.btn-group>.btn:active, +.btn-group>.btn.active, +.btn-group-vertical>.btn:focus, +.btn-group-vertical>.btn:active, +.btn-group-vertical>.btn.active { + z-index: 1; +} + +.btn-toolbar { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.btn-toolbar .input-group { + width: auto; +} + +.btn-group>.btn:not(:first-child), +.btn-group>.btn-group:not(:first-child) { + margin-left: -1px; +} + +.btn-group>.btn:not(:last-child):not(.dropdown-toggle), +.btn-group>.btn-group:not(:last-child)>.btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.btn-group>.btn:not(:first-child), +.btn-group>.btn-group:not(:first-child)>.btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.dropdown-toggle-split { + padding-right: 0.5625rem; + padding-left: 0.5625rem; +} + +.dropdown-toggle-split::after, +.dropup .dropdown-toggle-split::after, +.dropright .dropdown-toggle-split::after { + margin-left: 0; +} + +.dropleft .dropdown-toggle-split::before { + margin-right: 0; +} + +.btn-sm+.dropdown-toggle-split, +.btn-group-sm>.btn+.dropdown-toggle-split { + padding-right: 0.375rem; + padding-left: 0.375rem; +} + +.btn-lg+.dropdown-toggle-split, +.btn-group-lg>.btn+.dropdown-toggle-split { + padding-right: 0.75rem; + padding-left: 0.75rem; +} + +.btn-group-vertical { + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-align: start; + align-items: flex-start; + -ms-flex-pack: center; + justify-content: center; +} + +.btn-group-vertical>.btn, +.btn-group-vertical>.btn-group { + width: 100%; +} + +.btn-group-vertical>.btn:not(:first-child), +.btn-group-vertical>.btn-group:not(:first-child) { + margin-top: -1px; +} + +.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle), +.btn-group-vertical>.btn-group:not(:last-child)>.btn { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical>.btn:not(:first-child), +.btn-group-vertical>.btn-group:not(:first-child)>.btn { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.btn-group-toggle>.btn, +.btn-group-toggle>.btn-group>.btn { + margin-bottom: 0; +} + +.btn-group-toggle>.btn input[type="radio"], +.btn-group-toggle>.btn input[type="checkbox"], +.btn-group-toggle>.btn-group>.btn input[type="radio"], +.btn-group-toggle>.btn-group>.btn input[type="checkbox"] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} + +.input-group { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: stretch; + align-items: stretch; + width: 100%; +} + +.input-group>.form-control, +.input-group>.form-control-plaintext, +.input-group>.custom-select, +.input-group>.custom-file { + position: relative; + -ms-flex: 1 1 0%; + flex: 1 1 0%; + min-width: 0; + margin-bottom: 0; +} + +.input-group>.form-control+.form-control, +.input-group>.form-control+.custom-select, +.input-group>.form-control+.custom-file, +.input-group>.form-control-plaintext+.form-control, +.input-group>.form-control-plaintext+.custom-select, +.input-group>.form-control-plaintext+.custom-file, +.input-group>.custom-select+.form-control, +.input-group>.custom-select+.custom-select, +.input-group>.custom-select+.custom-file, +.input-group>.custom-file+.form-control, +.input-group>.custom-file+.custom-select, +.input-group>.custom-file+.custom-file { + margin-left: -1px; +} + +.input-group>.form-control:focus, +.input-group>.custom-select:focus, +.input-group>.custom-file .custom-file-input:focus~.custom-file-label { + z-index: 3; +} + +.input-group>.custom-file .custom-file-input:focus { + z-index: 4; +} + +.input-group>.form-control:not(:last-child), +.input-group>.custom-select:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group>.form-control:not(:first-child), +.input-group>.custom-select:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.input-group>.custom-file { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; +} + +.input-group>.custom-file:not(:last-child) .custom-file-label, +.input-group>.custom-file:not(:last-child) .custom-file-label::after { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group>.custom-file:not(:first-child) .custom-file-label { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.input-group-prepend, +.input-group-append { + display: -ms-flexbox; + display: flex; +} + +.input-group-prepend .btn, +.input-group-append .btn { + position: relative; + z-index: 2; +} + +.input-group-prepend .btn:focus, +.input-group-append .btn:focus { + z-index: 3; +} + +.input-group-prepend .btn+.btn, +.input-group-prepend .btn+.input-group-text, +.input-group-prepend .input-group-text+.input-group-text, +.input-group-prepend .input-group-text+.btn, +.input-group-append .btn+.btn, +.input-group-append .btn+.input-group-text, +.input-group-append .input-group-text+.input-group-text, +.input-group-append .input-group-text+.btn { + margin-left: -1px; +} + +.input-group-prepend { + margin-right: -1px; +} + +.input-group-append { + margin-left: -1px; +} + +.input-group-text { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + padding: 0.375rem 0.75rem; + margin-bottom: 0; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + text-align: center; + white-space: nowrap; + background-color: #e9ecef; + border: 1px solid #ced4da; + border-radius: 0.25rem; +} + +.input-group-text input[type="radio"], +.input-group-text input[type="checkbox"] { + margin-top: 0; +} + +.input-group-lg>.form-control:not(textarea), +.input-group-lg>.custom-select { + height: calc(1.5em + 1rem + 2px); +} + +.input-group-lg>.form-control, +.input-group-lg>.custom-select, +.input-group-lg>.input-group-prepend>.input-group-text, +.input-group-lg>.input-group-append>.input-group-text, +.input-group-lg>.input-group-prepend>.btn, +.input-group-lg>.input-group-append>.btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +.input-group-sm>.form-control:not(textarea), +.input-group-sm>.custom-select { + height: calc(1.5em + 0.5rem + 2px); +} + +.input-group-sm>.form-control, +.input-group-sm>.custom-select, +.input-group-sm>.input-group-prepend>.input-group-text, +.input-group-sm>.input-group-append>.input-group-text, +.input-group-sm>.input-group-prepend>.btn, +.input-group-sm>.input-group-append>.btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.input-group-lg>.custom-select, +.input-group-sm>.custom-select { + padding-right: 1.75rem; +} + +.input-group>.input-group-prepend>.btn, +.input-group>.input-group-prepend>.input-group-text, +.input-group>.input-group-append:not(:last-child)>.btn, +.input-group>.input-group-append:not(:last-child)>.input-group-text, +.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle), +.input-group>.input-group-append:last-child>.input-group-text:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group>.input-group-append>.btn, +.input-group>.input-group-append>.input-group-text, +.input-group>.input-group-prepend:not(:first-child)>.btn, +.input-group>.input-group-prepend:not(:first-child)>.input-group-text, +.input-group>.input-group-prepend:first-child>.btn:not(:first-child), +.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.custom-control { + position: relative; + display: block; + min-height: 1.5rem; + padding-left: 1.5rem; +} + +.custom-control-inline { + display: -ms-inline-flexbox; + display: inline-flex; + margin-right: 1rem; +} + +.custom-control-input { + position: absolute; + left: 0; + z-index: -1; + width: 1rem; + height: 1.25rem; + opacity: 0; +} + +.custom-control-input:checked~.custom-control-label::before { + color: #fff; + border-color: #007bff; + background-color: #007bff; +} + +.custom-control-input:focus~.custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-control-input:focus:not(:checked)~.custom-control-label::before { + border-color: #80bdff; +} + +.custom-control-input:not(:disabled):active~.custom-control-label::before { + color: #fff; + background-color: #b3d7ff; + border-color: #b3d7ff; +} + +.custom-control-input[disabled]~.custom-control-label, +.custom-control-input:disabled~.custom-control-label { + color: #6c757d; +} + +.custom-control-input[disabled]~.custom-control-label::before, +.custom-control-input:disabled~.custom-control-label::before { + background-color: #e9ecef; +} + +.custom-control-label { + position: relative; + margin-bottom: 0; + vertical-align: top; +} + +.custom-control-label::before { + position: absolute; + top: 0.25rem; + left: -1.5rem; + display: block; + width: 1rem; + height: 1rem; + pointer-events: none; + content: ""; + background-color: #fff; + border: #adb5bd solid 1px; +} + +.custom-control-label::after { + position: absolute; + top: 0.25rem; + left: -1.5rem; + display: block; + width: 1rem; + height: 1rem; + content: ""; + background: no-repeat 50% / 50% 50%; +} + +.custom-checkbox .custom-control-label::before { + border-radius: 0.25rem; +} + +.custom-checkbox .custom-control-input:checked~.custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e"); +} + +.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before { + border-color: #007bff; + background-color: #007bff; +} + +.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e"); +} + +.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-radio .custom-control-label::before { + border-radius: 50%; +} + +.custom-radio .custom-control-input:checked~.custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); +} + +.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-switch { + padding-left: 2.25rem; +} + +.custom-switch .custom-control-label::before { + left: -2.25rem; + width: 1.75rem; + pointer-events: all; + border-radius: 0.5rem; +} + +.custom-switch .custom-control-label::after { + top: calc(0.25rem + 2px); + left: calc(-2.25rem + 2px); + width: calc(1rem - 4px); + height: calc(1rem - 4px); + background-color: #adb5bd; + border-radius: 0.5rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out; + transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .custom-switch .custom-control-label::after { + transition: none; + } +} + +.custom-switch .custom-control-input:checked~.custom-control-label::after { + background-color: #fff; + -webkit-transform: translateX(0.75rem); + transform: translateX(0.75rem); +} + +.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-select { + display: inline-block; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem 1.75rem 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + vertical-align: middle; + background: #fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px; + border: 1px solid #ced4da; + border-radius: 0.25rem; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.custom-select:focus { + border-color: #80bdff; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-select:focus::-ms-value { + color: #495057; + background-color: #fff; +} + +.custom-select[multiple], +.custom-select[size]:not([size="1"]) { + height: auto; + padding-right: 0.75rem; + background-image: none; +} + +.custom-select:disabled { + color: #6c757d; + background-color: #e9ecef; +} + +.custom-select::-ms-expand { + display: none; +} + +.custom-select:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 #495057; +} + +.custom-select-sm { + height: calc(1.5em + 0.5rem + 2px); + padding-top: 0.25rem; + padding-bottom: 0.25rem; + padding-left: 0.5rem; + font-size: 0.875rem; +} + +.custom-select-lg { + height: calc(1.5em + 1rem + 2px); + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 1rem; + font-size: 1.25rem; +} + +.custom-file { + position: relative; + display: inline-block; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + margin-bottom: 0; +} + +.custom-file-input { + position: relative; + z-index: 2; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + margin: 0; + opacity: 0; +} + +.custom-file-input:focus~.custom-file-label { + border-color: #80bdff; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-file-input[disabled]~.custom-file-label, +.custom-file-input:disabled~.custom-file-label { + background-color: #e9ecef; +} + +.custom-file-input:lang(en)~.custom-file-label::after { + content: "Browse"; +} + +.custom-file-input~.custom-file-label[data-browse]::after { + content: attr(data-browse); +} + +.custom-file-label { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 1; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem 0.75rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + border: 1px solid #ced4da; + border-radius: 0.25rem; +} + +.custom-file-label::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + z-index: 3; + display: block; + height: calc(1.5em + 0.75rem); + padding: 0.375rem 0.75rem; + line-height: 1.5; + color: #495057; + content: "Browse"; + background-color: #e9ecef; + border-left: inherit; + border-radius: 0 0.25rem 0.25rem 0; +} + +.custom-range { + width: 100%; + height: 1.4rem; + padding: 0; + background-color: transparent; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.custom-range:focus { + outline: none; +} + +.custom-range:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range:focus::-ms-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range::-moz-focus-outer { + border: 0; +} + +.custom-range::-webkit-slider-thumb { + width: 1rem; + height: 1rem; + margin-top: -0.25rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + -webkit-appearance: none; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .custom-range::-webkit-slider-thumb { + -webkit-transition: none; + transition: none; + } +} + +.custom-range::-webkit-slider-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-webkit-slider-runnable-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.custom-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + -moz-appearance: none; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .custom-range::-moz-range-thumb { + -moz-transition: none; + transition: none; + } +} + +.custom-range::-moz-range-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-moz-range-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.custom-range::-ms-thumb { + width: 1rem; + height: 1rem; + margin-top: 0; + margin-right: 0.2rem; + margin-left: 0.2rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + -ms-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .custom-range::-ms-thumb { + -ms-transition: none; + transition: none; + } +} + +.custom-range::-ms-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-ms-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: transparent; + border-color: transparent; + border-width: 0.5rem; +} + +.custom-range::-ms-fill-lower { + background-color: #dee2e6; + border-radius: 1rem; +} + +.custom-range::-ms-fill-upper { + margin-right: 15px; + background-color: #dee2e6; + border-radius: 1rem; +} + +.custom-range:disabled::-webkit-slider-thumb { + background-color: #adb5bd; +} + +.custom-range:disabled::-webkit-slider-runnable-track { + cursor: default; +} + +.custom-range:disabled::-moz-range-thumb { + background-color: #adb5bd; +} + +.custom-range:disabled::-moz-range-track { + cursor: default; +} + +.custom-range:disabled::-ms-thumb { + background-color: #adb5bd; +} + +.custom-control-label::before, +.custom-file-label, +.custom-select { + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + + .custom-control-label::before, + .custom-file-label, + .custom-select { + transition: none; + } +} + +.nav { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: 0.5rem 1rem; +} + +.nav-link:hover, +.nav-link:focus { + text-decoration: none; +} + +.nav-link.disabled { + color: #6c757d; + pointer-events: none; + cursor: default; +} + +.nav-tabs { + border-bottom: 1px solid #dee2e6; +} + +.nav-tabs .nav-item { + margin-bottom: -1px; +} + +.nav-tabs .nav-link { + border: 1px solid transparent; + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.nav-tabs .nav-link:hover, +.nav-tabs .nav-link:focus { + border-color: #e9ecef #e9ecef #dee2e6; +} + +.nav-tabs .nav-link.disabled { + color: #6c757d; + background-color: transparent; + border-color: transparent; +} + +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + color: #495057; + background-color: #fff; + border-color: #dee2e6 #dee2e6 #fff; +} + +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav-pills .nav-link { + border-radius: 0.25rem; +} + +.nav-pills .nav-link.active, +.nav-pills .show>.nav-link { + color: #fff; + background-color: #007bff; +} + +.nav-fill .nav-item { + -ms-flex: 1 1 auto; + flex: 1 1 auto; + text-align: center; +} + +.nav-justified .nav-item { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + text-align: center; +} + +.tab-content>.tab-pane { + display: none; +} + +.tab-content>.active { + display: block; +} + +.navbar { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 0.5rem 1rem; +} + +.navbar .container, +.navbar .container-fluid, +.navbar .container-sm, +.navbar .container-md, +.navbar .container-lg, +.navbar .container-xl { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.navbar-brand { + display: inline-block; + padding-top: 0.3125rem; + padding-bottom: 0.3125rem; + margin-right: 1rem; + font-size: 1.25rem; + line-height: inherit; + white-space: nowrap; +} + +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} + +.navbar-nav { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.navbar-nav .nav-link { + padding-right: 0; + padding-left: 0; +} + +.navbar-nav .dropdown-menu { + position: static; + float: none; +} + +.navbar-text { + display: inline-block; + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.navbar-collapse { + -ms-flex-preferred-size: 100%; + flex-basis: 100%; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-align: center; + align-items: center; +} + +.navbar-toggler { + padding: 0.25rem 0.75rem; + font-size: 1.25rem; + line-height: 1; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.navbar-toggler:hover, +.navbar-toggler:focus { + text-decoration: none; +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + content: ""; + background: no-repeat center center; + background-size: 100% 100%; +} + +@media (max-width: 575.98px) { + + .navbar-expand-sm>.container, + .navbar-expand-sm>.container-fluid, + .navbar-expand-sm>.container-sm, + .navbar-expand-sm>.container-md, + .navbar-expand-sm>.container-lg, + .navbar-expand-sm>.container-xl { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 576px) { + .navbar-expand-sm { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + + .navbar-expand-sm .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; + } + + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + + .navbar-expand-sm>.container, + .navbar-expand-sm>.container-fluid, + .navbar-expand-sm>.container-sm, + .navbar-expand-sm>.container-md, + .navbar-expand-sm>.container-lg, + .navbar-expand-sm>.container-xl { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + + .navbar-expand-sm .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + + .navbar-expand-sm .navbar-toggler { + display: none; + } +} + +@media (max-width: 767.98px) { + + .navbar-expand-md>.container, + .navbar-expand-md>.container-fluid, + .navbar-expand-md>.container-sm, + .navbar-expand-md>.container-md, + .navbar-expand-md>.container-lg, + .navbar-expand-md>.container-xl { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 768px) { + .navbar-expand-md { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + + .navbar-expand-md .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; + } + + .navbar-expand-md .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + + .navbar-expand-md>.container, + .navbar-expand-md>.container-fluid, + .navbar-expand-md>.container-sm, + .navbar-expand-md>.container-md, + .navbar-expand-md>.container-lg, + .navbar-expand-md>.container-xl { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + + .navbar-expand-md .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + + .navbar-expand-md .navbar-toggler { + display: none; + } +} + +@media (max-width: 991.98px) { + + .navbar-expand-lg>.container, + .navbar-expand-lg>.container-fluid, + .navbar-expand-lg>.container-sm, + .navbar-expand-lg>.container-md, + .navbar-expand-lg>.container-lg, + .navbar-expand-lg>.container-xl { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 992px) { + .navbar-expand-lg { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + + .navbar-expand-lg .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; + } + + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + + .navbar-expand-lg>.container, + .navbar-expand-lg>.container-fluid, + .navbar-expand-lg>.container-sm, + .navbar-expand-lg>.container-md, + .navbar-expand-lg>.container-lg, + .navbar-expand-lg>.container-xl { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + + .navbar-expand-lg .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + + .navbar-expand-lg .navbar-toggler { + display: none; + } +} + +@media (max-width: 1199.98px) { + + .navbar-expand-xl>.container, + .navbar-expand-xl>.container-fluid, + .navbar-expand-xl>.container-sm, + .navbar-expand-xl>.container-md, + .navbar-expand-xl>.container-lg, + .navbar-expand-xl>.container-xl { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 1200px) { + .navbar-expand-xl { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + + .navbar-expand-xl .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; + } + + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + + .navbar-expand-xl>.container, + .navbar-expand-xl>.container-fluid, + .navbar-expand-xl>.container-sm, + .navbar-expand-xl>.container-md, + .navbar-expand-xl>.container-lg, + .navbar-expand-xl>.container-xl { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + + .navbar-expand-xl .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + + .navbar-expand-xl .navbar-toggler { + display: none; + } +} + +.navbar-expand { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.navbar-expand>.container, +.navbar-expand>.container-fluid, +.navbar-expand>.container-sm, +.navbar-expand>.container-md, +.navbar-expand>.container-lg, +.navbar-expand>.container-xl { + padding-right: 0; + padding-left: 0; +} + +.navbar-expand .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; +} + +.navbar-expand .navbar-nav .dropdown-menu { + position: absolute; +} + +.navbar-expand .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; +} + +.navbar-expand>.container, +.navbar-expand>.container-fluid, +.navbar-expand>.container-sm, +.navbar-expand>.container-md, +.navbar-expand>.container-lg, +.navbar-expand>.container-xl { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; +} + +.navbar-expand .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; +} + +.navbar-expand .navbar-toggler { + display: none; +} + +.navbar-light .navbar-brand { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-brand:hover, +.navbar-light .navbar-brand:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-nav .nav-link { + color: rgba(0, 0, 0, 0.5); +} + +.navbar-light .navbar-nav .nav-link:hover, +.navbar-light .navbar-nav .nav-link:focus { + color: rgba(0, 0, 0, 0.7); +} + +.navbar-light .navbar-nav .nav-link.disabled { + color: rgba(0, 0, 0, 0.3); +} + +.navbar-light .navbar-nav .show>.nav-link, +.navbar-light .navbar-nav .active>.nav-link, +.navbar-light .navbar-nav .nav-link.show, +.navbar-light .navbar-nav .nav-link.active { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-toggler { + color: rgba(0, 0, 0, 0.5); + border-color: rgba(0, 0, 0, 0.1); +} + +.navbar-light .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-light .navbar-text { + color: rgba(0, 0, 0, 0.5); +} + +.navbar-light .navbar-text a { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-text a:hover, +.navbar-light .navbar-text a:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-dark .navbar-brand { + color: #fff; +} + +.navbar-dark .navbar-brand:hover, +.navbar-dark .navbar-brand:focus { + color: #fff; +} + +.navbar-dark .navbar-nav .nav-link { + color: rgba(255, 255, 255, 0.5); +} + +.navbar-dark .navbar-nav .nav-link:hover, +.navbar-dark .navbar-nav .nav-link:focus { + color: rgba(255, 255, 255, 0.75); +} + +.navbar-dark .navbar-nav .nav-link.disabled { + color: rgba(255, 255, 255, 0.25); +} + +.navbar-dark .navbar-nav .show>.nav-link, +.navbar-dark .navbar-nav .active>.nav-link, +.navbar-dark .navbar-nav .nav-link.show, +.navbar-dark .navbar-nav .nav-link.active { + color: #fff; +} + +.navbar-dark .navbar-toggler { + color: rgba(255, 255, 255, 0.5); + border-color: rgba(255, 255, 255, 0.1); +} + +.navbar-dark .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-dark .navbar-text { + color: rgba(255, 255, 255, 0.5); +} + +.navbar-dark .navbar-text a { + color: #fff; +} + +.navbar-dark .navbar-text a:hover, +.navbar-dark .navbar-text a:focus { + color: #fff; +} + +.card { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + min-width: 0; + word-wrap: break-word; + background-color: #fff; + background-clip: border-box; + border: 1px solid rgba(0, 0, 0, 0.125); + border-radius: 0.25rem; +} + +.card>hr { + margin-right: 0; + margin-left: 0; +} + +.card>.list-group:first-child .list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card>.list-group:last-child .list-group-item:last-child { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.card-body { + -ms-flex: 1 1 auto; + flex: 1 1 auto; + min-height: 1px; + padding: 1.25rem; +} + +.card-title { + margin-bottom: 0.75rem; +} + +.card-subtitle { + margin-top: -0.375rem; + margin-bottom: 0; +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link:hover { + text-decoration: none; +} + +.card-link+.card-link { + margin-left: 1.25rem; +} + +.card-header { + padding: 0.75rem 1.25rem; + margin-bottom: 0; + background-color: rgba(0, 0, 0, 0.03); + border-bottom: 1px solid rgba(0, 0, 0, 0.125); +} + +.card-header:first-child { + border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0; +} + +.card-header+.list-group .list-group-item:first-child { + border-top: 0; +} + +.card-footer { + padding: 0.75rem 1.25rem; + background-color: rgba(0, 0, 0, 0.03); + border-top: 1px solid rgba(0, 0, 0, 0.125); +} + +.card-footer:last-child { + border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px); +} + +.card-header-tabs { + margin-right: -0.625rem; + margin-bottom: -0.75rem; + margin-left: -0.625rem; + border-bottom: 0; +} + +.card-header-pills { + margin-right: -0.625rem; + margin-left: -0.625rem; +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: 1.25rem; +} + +.card-img, +.card-img-top, +.card-img-bottom { + -ms-flex-negative: 0; + flex-shrink: 0; + width: 100%; +} + +.card-img, +.card-img-top { + border-top-left-radius: calc(0.25rem - 1px); + border-top-right-radius: calc(0.25rem - 1px); +} + +.card-img, +.card-img-bottom { + border-bottom-right-radius: calc(0.25rem - 1px); + border-bottom-left-radius: calc(0.25rem - 1px); +} + +.card-deck .card { + margin-bottom: 15px; +} + +@media (min-width: 576px) { + .card-deck { + display: -ms-flexbox; + display: flex; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + margin-right: -15px; + margin-left: -15px; + } + + .card-deck .card { + -ms-flex: 1 0 0%; + flex: 1 0 0%; + margin-right: 15px; + margin-bottom: 0; + margin-left: 15px; + } +} + +.card-group>.card { + margin-bottom: 15px; +} + +@media (min-width: 576px) { + .card-group { + display: -ms-flexbox; + display: flex; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + } + + .card-group>.card { + -ms-flex: 1 0 0%; + flex: 1 0 0%; + margin-bottom: 0; + } + + .card-group>.card+.card { + margin-left: 0; + border-left: 0; + } + + .card-group>.card:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + .card-group>.card:not(:last-child) .card-img-top, + .card-group>.card:not(:last-child) .card-header { + border-top-right-radius: 0; + } + + .card-group>.card:not(:last-child) .card-img-bottom, + .card-group>.card:not(:last-child) .card-footer { + border-bottom-right-radius: 0; + } + + .card-group>.card:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + + .card-group>.card:not(:first-child) .card-img-top, + .card-group>.card:not(:first-child) .card-header { + border-top-left-radius: 0; + } + + .card-group>.card:not(:first-child) .card-img-bottom, + .card-group>.card:not(:first-child) .card-footer { + border-bottom-left-radius: 0; + } +} + +.card-columns .card { + margin-bottom: 0.75rem; +} + +@media (min-width: 576px) { + .card-columns { + -webkit-column-count: 3; + -moz-column-count: 3; + column-count: 3; + -webkit-column-gap: 1.25rem; + -moz-column-gap: 1.25rem; + column-gap: 1.25rem; + orphans: 1; + widows: 1; + } + + .card-columns .card { + display: inline-block; + width: 100%; + } +} + +.accordion>.card { + overflow: hidden; +} + +.accordion>.card:not(:last-of-type) { + border-bottom: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.accordion>.card:not(:first-of-type) { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.accordion>.card>.card-header { + border-radius: 0; + margin-bottom: -1px; +} + +.breadcrumb { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + padding: 0.75rem 1rem; + margin-bottom: 1rem; + list-style: none; + background-color: #e9ecef; + border-radius: 0.25rem; +} + +.breadcrumb-item+.breadcrumb-item { + padding-left: 0.5rem; +} + +.breadcrumb-item+.breadcrumb-item::before { + display: inline-block; + padding-right: 0.5rem; + color: #6c757d; + content: "/"; +} + +.breadcrumb-item+.breadcrumb-item:hover::before { + text-decoration: underline; +} + +.breadcrumb-item+.breadcrumb-item:hover::before { + text-decoration: none; +} + +.breadcrumb-item.active { + color: #6c757d; +} + +.pagination { + display: -ms-flexbox; + display: flex; + padding-left: 0; + list-style: none; + border-radius: 0.25rem; +} + +.page-link { + position: relative; + display: block; + padding: 0.5rem 0.75rem; + margin-left: -1px; + line-height: 1.25; + color: #007bff; + background-color: #fff; + border: 1px solid #dee2e6; +} + +.page-link:hover { + z-index: 2; + color: #0056b3; + text-decoration: none; + background-color: #e9ecef; + border-color: #dee2e6; +} + +.page-link:focus { + z-index: 3; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.page-item:first-child .page-link { + margin-left: 0; + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.page-item:last-child .page-link { + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +.page-item.active .page-link { + z-index: 3; + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.page-item.disabled .page-link { + color: #6c757d; + pointer-events: none; + cursor: auto; + background-color: #fff; + border-color: #dee2e6; +} + +.pagination-lg .page-link { + padding: 0.75rem 1.5rem; + font-size: 1.25rem; + line-height: 1.5; +} + +.pagination-lg .page-item:first-child .page-link { + border-top-left-radius: 0.3rem; + border-bottom-left-radius: 0.3rem; +} + +.pagination-lg .page-item:last-child .page-link { + border-top-right-radius: 0.3rem; + border-bottom-right-radius: 0.3rem; +} + +.pagination-sm .page-link { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; +} + +.pagination-sm .page-item:first-child .page-link { + border-top-left-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; +} + +.pagination-sm .page-item:last-child .page-link { + border-top-right-radius: 0.2rem; + border-bottom-right-radius: 0.2rem; +} + +.badge { + display: inline-block; + padding: 0.25em 0.4em; + font-size: 75%; + font-weight: 700; + line-height: 1; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: 0.25rem; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .badge { + transition: none; + } +} + +a.badge:hover, +a.badge:focus { + text-decoration: none; +} + +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +.badge-pill { + padding-right: 0.6em; + padding-left: 0.6em; + border-radius: 10rem; +} + +.badge-primary { + color: #fff; + background-color: #007bff; +} + +a.badge-primary:hover, +a.badge-primary:focus { + color: #fff; + background-color: #0062cc; +} + +a.badge-primary:focus, +a.badge-primary.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.badge-secondary { + color: #fff; + background-color: #6c757d; +} + +a.badge-secondary:hover, +a.badge-secondary:focus { + color: #fff; + background-color: #545b62; +} + +a.badge-secondary:focus, +a.badge-secondary.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.badge-success { + color: #fff; + background-color: #28a745; +} + +a.badge-success:hover, +a.badge-success:focus { + color: #fff; + background-color: #1e7e34; +} + +a.badge-success:focus, +a.badge-success.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.badge-info { + color: #fff; + background-color: #17a2b8; +} + +a.badge-info:hover, +a.badge-info:focus { + color: #fff; + background-color: #117a8b; +} + +a.badge-info:focus, +a.badge-info.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.badge-warning { + color: #212529; + background-color: #ffc107; +} + +a.badge-warning:hover, +a.badge-warning:focus { + color: #212529; + background-color: #d39e00; +} + +a.badge-warning:focus, +a.badge-warning.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.badge-danger { + color: #fff; + background-color: #dc3545; +} + +a.badge-danger:hover, +a.badge-danger:focus { + color: #fff; + background-color: #bd2130; +} + +a.badge-danger:focus, +a.badge-danger.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.badge-light { + color: #212529; + background-color: #f8f9fa; +} + +a.badge-light:hover, +a.badge-light:focus { + color: #212529; + background-color: #dae0e5; +} + +a.badge-light:focus, +a.badge-light.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.badge-dark { + color: #fff; + background-color: #343a40; +} + +a.badge-dark:hover, +a.badge-dark:focus { + color: #fff; + background-color: #1d2124; +} + +a.badge-dark:focus, +a.badge-dark.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.jumbotron { + padding: 2rem 1rem; + margin-bottom: 2rem; + background-color: #e9ecef; + border-radius: 0.3rem; +} + +@media (min-width: 576px) { + .jumbotron { + padding: 4rem 2rem; + } +} + +.jumbotron-fluid { + padding-right: 0; + padding-left: 0; + border-radius: 0; +} + +.alert { + position: relative; + padding: 0.75rem 1.25rem; + margin-bottom: 1rem; + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: 700; +} + +.alert-dismissible { + padding-right: 4rem; +} + +.alert-dismissible .close { + position: absolute; + top: 0; + right: 0; + padding: 0.75rem 1.25rem; + color: inherit; +} + +.alert-primary { + color: #004085; + background-color: #cce5ff; + border-color: #b8daff; +} + +.alert-primary hr { + border-top-color: #9fcdff; +} + +.alert-primary .alert-link { + color: #002752; +} + +.alert-secondary { + color: #383d41; + background-color: #e2e3e5; + border-color: #d6d8db; +} + +.alert-secondary hr { + border-top-color: #c8cbcf; +} + +.alert-secondary .alert-link { + color: #202326; +} + +.alert-success { + color: #155724; + background-color: #d4edda; + border-color: #c3e6cb; +} + +.alert-success hr { + border-top-color: #b1dfbb; +} + +.alert-success .alert-link { + color: #0b2e13; +} + +.alert-info { + color: #0c5460; + background-color: #d1ecf1; + border-color: #bee5eb; +} + +.alert-info hr { + border-top-color: #abdde5; +} + +.alert-info .alert-link { + color: #062c33; +} + +.alert-warning { + color: #856404; + background-color: #fff3cd; + border-color: #ffeeba; +} + +.alert-warning hr { + border-top-color: #ffe8a1; +} + +.alert-warning .alert-link { + color: #533f03; +} + +.alert-danger { + color: #721c24; + background-color: #f8d7da; + border-color: #f5c6cb; +} + +.alert-danger hr { + border-top-color: #f1b0b7; +} + +.alert-danger .alert-link { + color: #491217; +} + +.alert-light { + color: #818182; + background-color: #fefefe; + border-color: #fdfdfe; +} + +.alert-light hr { + border-top-color: #ececf6; +} + +.alert-light .alert-link { + color: #686868; +} + +.alert-dark { + color: #1b1e21; + background-color: #d6d8d9; + border-color: #c6c8ca; +} + +.alert-dark hr { + border-top-color: #b9bbbe; +} + +.alert-dark .alert-link { + color: #040505; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 1rem 0; + } + + to { + background-position: 0 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 1rem 0; + } + + to { + background-position: 0 0; + } +} + +.progress { + display: -ms-flexbox; + display: flex; + height: 1rem; + overflow: hidden; + font-size: 0.75rem; + background-color: #e9ecef; + border-radius: 0.25rem; +} + +.progress-bar { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-pack: center; + justify-content: center; + overflow: hidden; + color: #fff; + text-align: center; + white-space: nowrap; + background-color: #007bff; + transition: width 0.6s ease; +} + +@media (prefers-reduced-motion: reduce) { + .progress-bar { + transition: none; + } +} + +.progress-bar-striped { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 1rem 1rem; +} + +.progress-bar-animated { + -webkit-animation: progress-bar-stripes 1s linear infinite; + animation: progress-bar-stripes 1s linear infinite; +} + +@media (prefers-reduced-motion: reduce) { + .progress-bar-animated { + -webkit-animation: none; + animation: none; + } +} + +.media { + display: -ms-flexbox; + display: flex; + -ms-flex-align: start; + align-items: flex-start; +} + +.media-body { + -ms-flex: 1; + flex: 1; +} + +.list-group { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; +} + +.list-group-item-action { + width: 100%; + color: #495057; + text-align: inherit; +} + +.list-group-item-action:hover, +.list-group-item-action:focus { + z-index: 1; + color: #495057; + text-decoration: none; + background-color: #f8f9fa; +} + +.list-group-item-action:active { + color: #212529; + background-color: #e9ecef; +} + +.list-group-item { + position: relative; + display: block; + padding: 0.75rem 1.25rem; + background-color: #fff; + border: 1px solid rgba(0, 0, 0, 0.125); +} + +.list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.list-group-item:last-child { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.list-group-item.disabled, +.list-group-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: #fff; +} + +.list-group-item.active { + z-index: 2; + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.list-group-item+.list-group-item { + border-top-width: 0; +} + +.list-group-item+.list-group-item.active { + margin-top: -1px; + border-top-width: 1px; +} + +.list-group-horizontal { + -ms-flex-direction: row; + flex-direction: row; +} + +.list-group-horizontal .list-group-item:first-child { + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; +} + +.list-group-horizontal .list-group-item:last-child { + border-top-right-radius: 0.25rem; + border-bottom-left-radius: 0; +} + +.list-group-horizontal .list-group-item.active { + margin-top: 0; +} + +.list-group-horizontal .list-group-item+.list-group-item { + border-top-width: 1px; + border-left-width: 0; +} + +.list-group-horizontal .list-group-item+.list-group-item.active { + margin-left: -1px; + border-left-width: 1px; +} + +@media (min-width: 576px) { + .list-group-horizontal-sm { + -ms-flex-direction: row; + flex-direction: row; + } + + .list-group-horizontal-sm .list-group-item:first-child { + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + + .list-group-horizontal-sm .list-group-item:last-child { + border-top-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } + + .list-group-horizontal-sm .list-group-item.active { + margin-top: 0; + } + + .list-group-horizontal-sm .list-group-item+.list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + + .list-group-horizontal-sm .list-group-item+.list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 768px) { + .list-group-horizontal-md { + -ms-flex-direction: row; + flex-direction: row; + } + + .list-group-horizontal-md .list-group-item:first-child { + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + + .list-group-horizontal-md .list-group-item:last-child { + border-top-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } + + .list-group-horizontal-md .list-group-item.active { + margin-top: 0; + } + + .list-group-horizontal-md .list-group-item+.list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + + .list-group-horizontal-md .list-group-item+.list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 992px) { + .list-group-horizontal-lg { + -ms-flex-direction: row; + flex-direction: row; + } + + .list-group-horizontal-lg .list-group-item:first-child { + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + + .list-group-horizontal-lg .list-group-item:last-child { + border-top-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } + + .list-group-horizontal-lg .list-group-item.active { + margin-top: 0; + } + + .list-group-horizontal-lg .list-group-item+.list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + + .list-group-horizontal-lg .list-group-item+.list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 1200px) { + .list-group-horizontal-xl { + -ms-flex-direction: row; + flex-direction: row; + } + + .list-group-horizontal-xl .list-group-item:first-child { + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + + .list-group-horizontal-xl .list-group-item:last-child { + border-top-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } + + .list-group-horizontal-xl .list-group-item.active { + margin-top: 0; + } + + .list-group-horizontal-xl .list-group-item+.list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + + .list-group-horizontal-xl .list-group-item+.list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +.list-group-flush .list-group-item { + border-right-width: 0; + border-left-width: 0; + border-radius: 0; +} + +.list-group-flush .list-group-item:first-child { + border-top-width: 0; +} + +.list-group-flush:last-child .list-group-item:last-child { + border-bottom-width: 0; +} + +.list-group-item-primary { + color: #004085; + background-color: #b8daff; +} + +.list-group-item-primary.list-group-item-action:hover, +.list-group-item-primary.list-group-item-action:focus { + color: #004085; + background-color: #9fcdff; +} + +.list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #004085; + border-color: #004085; +} + +.list-group-item-secondary { + color: #383d41; + background-color: #d6d8db; +} + +.list-group-item-secondary.list-group-item-action:hover, +.list-group-item-secondary.list-group-item-action:focus { + color: #383d41; + background-color: #c8cbcf; +} + +.list-group-item-secondary.list-group-item-action.active { + color: #fff; + background-color: #383d41; + border-color: #383d41; +} + +.list-group-item-success { + color: #155724; + background-color: #c3e6cb; +} + +.list-group-item-success.list-group-item-action:hover, +.list-group-item-success.list-group-item-action:focus { + color: #155724; + background-color: #b1dfbb; +} + +.list-group-item-success.list-group-item-action.active { + color: #fff; + background-color: #155724; + border-color: #155724; +} + +.list-group-item-info { + color: #0c5460; + background-color: #bee5eb; +} + +.list-group-item-info.list-group-item-action:hover, +.list-group-item-info.list-group-item-action:focus { + color: #0c5460; + background-color: #abdde5; +} + +.list-group-item-info.list-group-item-action.active { + color: #fff; + background-color: #0c5460; + border-color: #0c5460; +} + +.list-group-item-warning { + color: #856404; + background-color: #ffeeba; +} + +.list-group-item-warning.list-group-item-action:hover, +.list-group-item-warning.list-group-item-action:focus { + color: #856404; + background-color: #ffe8a1; +} + +.list-group-item-warning.list-group-item-action.active { + color: #fff; + background-color: #856404; + border-color: #856404; +} + +.list-group-item-danger { + color: #721c24; + background-color: #f5c6cb; +} + +.list-group-item-danger.list-group-item-action:hover, +.list-group-item-danger.list-group-item-action:focus { + color: #721c24; + background-color: #f1b0b7; +} + +.list-group-item-danger.list-group-item-action.active { + color: #fff; + background-color: #721c24; + border-color: #721c24; +} + +.list-group-item-light { + color: #818182; + background-color: #fdfdfe; +} + +.list-group-item-light.list-group-item-action:hover, +.list-group-item-light.list-group-item-action:focus { + color: #818182; + background-color: #ececf6; +} + +.list-group-item-light.list-group-item-action.active { + color: #fff; + background-color: #818182; + border-color: #818182; +} + +.list-group-item-dark { + color: #1b1e21; + background-color: #c6c8ca; +} + +.list-group-item-dark.list-group-item-action:hover, +.list-group-item-dark.list-group-item-action:focus { + color: #1b1e21; + background-color: #b9bbbe; +} + +.list-group-item-dark.list-group-item-action.active { + color: #fff; + background-color: #1b1e21; + border-color: #1b1e21; +} + +.close { + float: right; + font-size: 1.5rem; + font-weight: 700; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + opacity: .5; +} + +.close:hover { + color: #000; + text-decoration: none; +} + +.close:not(:disabled):not(.disabled):hover, +.close:not(:disabled):not(.disabled):focus { + opacity: .75; +} + +button.close { + padding: 0; + background-color: transparent; + border: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +a.close.disabled { + pointer-events: none; +} + +.toast { + max-width: 350px; + overflow: hidden; + font-size: 0.875rem; + background-color: rgba(255, 255, 255, 0.85); + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); + opacity: 0; + border-radius: 0.25rem; +} + +.toast:not(:last-child) { + margin-bottom: 0.75rem; +} + +.toast.showing { + opacity: 1; +} + +.toast.show { + display: block; + opacity: 1; +} + +.toast.hide { + display: none; +} + +.toast-header { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + padding: 0.25rem 0.75rem; + color: #6c757d; + background-color: rgba(255, 255, 255, 0.85); + background-clip: padding-box; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); +} + +.toast-body { + padding: 0.75rem; +} + +.modal-open { + overflow: hidden; +} + +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} + +.modal { + position: fixed; + top: 0; + left: 0; + z-index: 1050; + display: none; + width: 100%; + height: 100%; + overflow: hidden; + outline: 0; +} + +.modal-dialog { + position: relative; + width: auto; + margin: 0.5rem; + pointer-events: none; +} + +.modal.fade .modal-dialog { + transition: -webkit-transform 0.3s ease-out; + transition: transform 0.3s ease-out; + transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out; + -webkit-transform: translate(0, -50px); + transform: translate(0, -50px); +} + +@media (prefers-reduced-motion: reduce) { + .modal.fade .modal-dialog { + transition: none; + } +} + +.modal.show .modal-dialog { + -webkit-transform: none; + transform: none; +} + +.modal.modal-static .modal-dialog { + -webkit-transform: scale(1.02); + transform: scale(1.02); +} + +.modal-dialog-scrollable { + display: -ms-flexbox; + display: flex; + max-height: calc(100% - 1rem); +} + +.modal-dialog-scrollable .modal-content { + max-height: calc(100vh - 1rem); + overflow: hidden; +} + +.modal-dialog-scrollable .modal-header, +.modal-dialog-scrollable .modal-footer { + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.modal-dialog-scrollable .modal-body { + overflow-y: auto; +} + +.modal-dialog-centered { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + min-height: calc(100% - 1rem); +} + +.modal-dialog-centered::before { + display: block; + height: calc(100vh - 1rem); + content: ""; +} + +.modal-dialog-centered.modal-dialog-scrollable { + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-pack: center; + justify-content: center; + height: 100%; +} + +.modal-dialog-centered.modal-dialog-scrollable .modal-content { + max-height: none; +} + +.modal-dialog-centered.modal-dialog-scrollable::before { + content: none; +} + +.modal-content { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; + pointer-events: auto; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 0.3rem; + outline: 0; +} + +.modal-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop.show { + opacity: 0.5; +} + +.modal-header { + display: -ms-flexbox; + display: flex; + -ms-flex-align: start; + align-items: flex-start; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 1rem 1rem; + border-bottom: 1px solid #dee2e6; + border-top-left-radius: calc(0.3rem - 1px); + border-top-right-radius: calc(0.3rem - 1px); +} + +.modal-header .close { + padding: 1rem 1rem; + margin: -1rem -1rem -1rem auto; +} + +.modal-title { + margin-bottom: 0; + line-height: 1.5; +} + +.modal-body { + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + padding: 1rem; +} + +.modal-footer { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: end; + justify-content: flex-end; + padding: 0.75rem; + border-top: 1px solid #dee2e6; + border-bottom-right-radius: calc(0.3rem - 1px); + border-bottom-left-radius: calc(0.3rem - 1px); +} + +.modal-footer>* { + margin: 0.25rem; +} + +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} + +@media (min-width: 576px) { + .modal-dialog { + max-width: 500px; + margin: 1.75rem auto; + } + + .modal-dialog-scrollable { + max-height: calc(100% - 3.5rem); + } + + .modal-dialog-scrollable .modal-content { + max-height: calc(100vh - 3.5rem); + } + + .modal-dialog-centered { + min-height: calc(100% - 3.5rem); + } + + .modal-dialog-centered::before { + height: calc(100vh - 3.5rem); + } + + .modal-sm { + max-width: 300px; + } +} + +@media (min-width: 992px) { + + .modal-lg, + .modal-xl { + max-width: 800px; + } +} + +@media (min-width: 1200px) { + .modal-xl { + max-width: 1140px; + } +} + +.tooltip { + position: absolute; + z-index: 1070; + display: block; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: 0.875rem; + word-wrap: break-word; + opacity: 0; +} + +.tooltip.show { + opacity: 0.9; +} + +.tooltip .arrow { + position: absolute; + display: block; + width: 0.8rem; + height: 0.4rem; +} + +.tooltip .arrow::before { + position: absolute; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-tooltip-top, +.bs-tooltip-auto[x-placement^="top"] { + padding: 0.4rem 0; +} + +.bs-tooltip-top .arrow, +.bs-tooltip-auto[x-placement^="top"] .arrow { + bottom: 0; +} + +.bs-tooltip-top .arrow::before, +.bs-tooltip-auto[x-placement^="top"] .arrow::before { + top: 0; + border-width: 0.4rem 0.4rem 0; + border-top-color: #000; +} + +.bs-tooltip-right, +.bs-tooltip-auto[x-placement^="right"] { + padding: 0 0.4rem; +} + +.bs-tooltip-right .arrow, +.bs-tooltip-auto[x-placement^="right"] .arrow { + left: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-right .arrow::before, +.bs-tooltip-auto[x-placement^="right"] .arrow::before { + right: 0; + border-width: 0.4rem 0.4rem 0.4rem 0; + border-right-color: #000; +} + +.bs-tooltip-bottom, +.bs-tooltip-auto[x-placement^="bottom"] { + padding: 0.4rem 0; +} + +.bs-tooltip-bottom .arrow, +.bs-tooltip-auto[x-placement^="bottom"] .arrow { + top: 0; +} + +.bs-tooltip-bottom .arrow::before, +.bs-tooltip-auto[x-placement^="bottom"] .arrow::before { + bottom: 0; + border-width: 0 0.4rem 0.4rem; + border-bottom-color: #000; +} + +.bs-tooltip-left, +.bs-tooltip-auto[x-placement^="left"] { + padding: 0 0.4rem; +} + +.bs-tooltip-left .arrow, +.bs-tooltip-auto[x-placement^="left"] .arrow { + right: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-left .arrow::before, +.bs-tooltip-auto[x-placement^="left"] .arrow::before { + left: 0; + border-width: 0.4rem 0 0.4rem 0.4rem; + border-left-color: #000; +} + +.tooltip-inner { + max-width: 200px; + padding: 0.25rem 0.5rem; + color: #fff; + text-align: center; + background-color: #000; + border-radius: 0.25rem; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: block; + max-width: 276px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: 0.875rem; + word-wrap: break-word; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 0.3rem; +} + +.popover .arrow { + position: absolute; + display: block; + width: 1rem; + height: 0.5rem; + margin: 0 0.3rem; +} + +.popover .arrow::before, +.popover .arrow::after { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-popover-top, +.bs-popover-auto[x-placement^="top"] { + margin-bottom: 0.5rem; +} + +.bs-popover-top>.arrow, +.bs-popover-auto[x-placement^="top"]>.arrow { + bottom: calc(-0.5rem - 1px); +} + +.bs-popover-top>.arrow::before, +.bs-popover-auto[x-placement^="top"]>.arrow::before { + bottom: 0; + border-width: 0.5rem 0.5rem 0; + border-top-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-top>.arrow::after, +.bs-popover-auto[x-placement^="top"]>.arrow::after { + bottom: 1px; + border-width: 0.5rem 0.5rem 0; + border-top-color: #fff; +} + +.bs-popover-right, +.bs-popover-auto[x-placement^="right"] { + margin-left: 0.5rem; +} + +.bs-popover-right>.arrow, +.bs-popover-auto[x-placement^="right"]>.arrow { + left: calc(-0.5rem - 1px); + width: 0.5rem; + height: 1rem; + margin: 0.3rem 0; +} + +.bs-popover-right>.arrow::before, +.bs-popover-auto[x-placement^="right"]>.arrow::before { + left: 0; + border-width: 0.5rem 0.5rem 0.5rem 0; + border-right-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-right>.arrow::after, +.bs-popover-auto[x-placement^="right"]>.arrow::after { + left: 1px; + border-width: 0.5rem 0.5rem 0.5rem 0; + border-right-color: #fff; +} + +.bs-popover-bottom, +.bs-popover-auto[x-placement^="bottom"] { + margin-top: 0.5rem; +} + +.bs-popover-bottom>.arrow, +.bs-popover-auto[x-placement^="bottom"]>.arrow { + top: calc(-0.5rem - 1px); +} + +.bs-popover-bottom>.arrow::before, +.bs-popover-auto[x-placement^="bottom"]>.arrow::before { + top: 0; + border-width: 0 0.5rem 0.5rem 0.5rem; + border-bottom-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-bottom>.arrow::after, +.bs-popover-auto[x-placement^="bottom"]>.arrow::after { + top: 1px; + border-width: 0 0.5rem 0.5rem 0.5rem; + border-bottom-color: #fff; +} + +.bs-popover-bottom .popover-header::before, +.bs-popover-auto[x-placement^="bottom"] .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: 1rem; + margin-left: -0.5rem; + content: ""; + border-bottom: 1px solid #f7f7f7; +} + +.bs-popover-left, +.bs-popover-auto[x-placement^="left"] { + margin-right: 0.5rem; +} + +.bs-popover-left>.arrow, +.bs-popover-auto[x-placement^="left"]>.arrow { + right: calc(-0.5rem - 1px); + width: 0.5rem; + height: 1rem; + margin: 0.3rem 0; +} + +.bs-popover-left>.arrow::before, +.bs-popover-auto[x-placement^="left"]>.arrow::before { + right: 0; + border-width: 0.5rem 0 0.5rem 0.5rem; + border-left-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-left>.arrow::after, +.bs-popover-auto[x-placement^="left"]>.arrow::after { + right: 1px; + border-width: 0.5rem 0 0.5rem 0.5rem; + border-left-color: #fff; +} + +.popover-header { + padding: 0.5rem 0.75rem; + margin-bottom: 0; + font-size: 1rem; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-top-left-radius: calc(0.3rem - 1px); + border-top-right-radius: calc(0.3rem - 1px); +} + +.popover-header:empty { + display: none; +} + +.popover-body { + padding: 0.5rem 0.75rem; + color: #212529; +} + +.carousel { + position: relative; +} + +.carousel.pointer-event { + -ms-touch-action: pan-y; + touch-action: pan-y; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner::after { + display: block; + clear: both; + content: ""; +} + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transition: -webkit-transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .carousel-item { + transition: none; + } +} + +.carousel-item.active, +.carousel-item-next, +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-left), +.active.carousel-item-right { + -webkit-transform: translateX(100%); + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-right), +.active.carousel-item-left { + -webkit-transform: translateX(-100%); + transform: translateX(-100%); +} + +.carousel-fade .carousel-item { + opacity: 0; + transition-property: opacity; + -webkit-transform: none; + transform: none; +} + +.carousel-fade .carousel-item.active, +.carousel-fade .carousel-item-next.carousel-item-left, +.carousel-fade .carousel-item-prev.carousel-item-right { + z-index: 1; + opacity: 1; +} + +.carousel-fade .active.carousel-item-left, +.carousel-fade .active.carousel-item-right { + z-index: 0; + opacity: 0; + transition: opacity 0s 0.6s; +} + +@media (prefers-reduced-motion: reduce) { + + .carousel-fade .active.carousel-item-left, + .carousel-fade .active.carousel-item-right { + transition: none; + } +} + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + width: 15%; + color: #fff; + text-align: center; + opacity: 0.5; + transition: opacity 0.15s ease; +} + +@media (prefers-reduced-motion: reduce) { + + .carousel-control-prev, + .carousel-control-next { + transition: none; + } +} + +.carousel-control-prev:hover, +.carousel-control-prev:focus, +.carousel-control-next:hover, +.carousel-control-next:focus { + color: #fff; + text-decoration: none; + outline: 0; + opacity: 0.9; +} + +.carousel-control-prev { + left: 0; +} + +.carousel-control-next { + right: 0; +} + +.carousel-control-prev-icon, +.carousel-control-next-icon { + display: inline-block; + width: 20px; + height: 20px; + background: no-repeat 50% / 100% 100%; +} + +.carousel-control-prev-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e"); +} + +.carousel-control-next-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e"); +} + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 15; + display: -ms-flexbox; + display: flex; + -ms-flex-pack: center; + justify-content: center; + padding-left: 0; + margin-right: 15%; + margin-left: 15%; + list-style: none; +} + +.carousel-indicators li { + box-sizing: content-box; + -ms-flex: 0 1 auto; + flex: 0 1 auto; + width: 30px; + height: 3px; + margin-right: 3px; + margin-left: 3px; + text-indent: -999px; + cursor: pointer; + background-color: #fff; + background-clip: padding-box; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + opacity: .5; + transition: opacity 0.6s ease; +} + +@media (prefers-reduced-motion: reduce) { + .carousel-indicators li { + transition: none; + } +} + +.carousel-indicators .active { + opacity: 1; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #fff; + text-align: center; +} + +@-webkit-keyframes spinner-border { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes spinner-border { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +.spinner-border { + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: text-bottom; + border: 0.25em solid currentColor; + border-right-color: transparent; + border-radius: 50%; + -webkit-animation: spinner-border .75s linear infinite; + animation: spinner-border .75s linear infinite; +} + +.spinner-border-sm { + width: 1rem; + height: 1rem; + border-width: 0.2em; +} + +@-webkit-keyframes spinner-grow { + 0% { + -webkit-transform: scale(0); + transform: scale(0); + } + + 50% { + opacity: 1; + } +} + +@keyframes spinner-grow { + 0% { + -webkit-transform: scale(0); + transform: scale(0); + } + + 50% { + opacity: 1; + } +} + +.spinner-grow { + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: text-bottom; + background-color: currentColor; + border-radius: 50%; + opacity: 0; + -webkit-animation: spinner-grow .75s linear infinite; + animation: spinner-grow .75s linear infinite; +} + +.spinner-grow-sm { + width: 1rem; + height: 1rem; +} + +.align-baseline { + vertical-align: baseline !important; +} + +.align-top { + vertical-align: top !important; +} + +.align-middle { + vertical-align: middle !important; +} + +.align-bottom { + vertical-align: bottom !important; +} + +.align-text-bottom { + vertical-align: text-bottom !important; +} + +.align-text-top { + vertical-align: text-top !important; +} + +.bg-primary { + background-color: #007bff !important; +} + +a.bg-primary:hover, +a.bg-primary:focus, +button.bg-primary:hover, +button.bg-primary:focus { + background-color: #0062cc !important; +} + +.bg-secondary { + background-color: #6c757d !important; +} + +a.bg-secondary:hover, +a.bg-secondary:focus, +button.bg-secondary:hover, +button.bg-secondary:focus { + background-color: #545b62 !important; +} + +.bg-success { + background-color: #28a745 !important; +} + +a.bg-success:hover, +a.bg-success:focus, +button.bg-success:hover, +button.bg-success:focus { + background-color: #1e7e34 !important; +} + +.bg-info { + background-color: #17a2b8 !important; +} + +a.bg-info:hover, +a.bg-info:focus, +button.bg-info:hover, +button.bg-info:focus { + background-color: #117a8b !important; +} + +.bg-warning { + background-color: #ffc107 !important; +} + +a.bg-warning:hover, +a.bg-warning:focus, +button.bg-warning:hover, +button.bg-warning:focus { + background-color: #d39e00 !important; +} + +.bg-danger { + background-color: #dc3545 !important; +} + +a.bg-danger:hover, +a.bg-danger:focus, +button.bg-danger:hover, +button.bg-danger:focus { + background-color: #bd2130 !important; +} + +.bg-light { + background-color: #f8f9fa !important; +} + +a.bg-light:hover, +a.bg-light:focus, +button.bg-light:hover, +button.bg-light:focus { + background-color: #dae0e5 !important; +} + +.bg-dark { + background-color: #343a40 !important; +} + +a.bg-dark:hover, +a.bg-dark:focus, +button.bg-dark:hover, +button.bg-dark:focus { + background-color: #1d2124 !important; +} + +.bg-white { + background-color: #fff !important; +} + +.bg-transparent { + background-color: transparent !important; +} + +.border { + border: 1px solid #dee2e6 !important; +} + +.border-top { + border-top: 1px solid #dee2e6 !important; +} + +.border-right { + border-right: 1px solid #dee2e6 !important; +} + +.border-bottom { + border-bottom: 1px solid #dee2e6 !important; +} + +.border-left { + border-left: 1px solid #dee2e6 !important; +} + +.border-0 { + border: 0 !important; +} + +.border-top-0 { + border-top: 0 !important; +} + +.border-right-0 { + border-right: 0 !important; +} + +.border-bottom-0 { + border-bottom: 0 !important; +} + +.border-left-0 { + border-left: 0 !important; +} + +.border-primary { + border-color: #007bff !important; +} + +.border-secondary { + border-color: #6c757d !important; +} + +.border-success { + border-color: #28a745 !important; +} + +.border-info { + border-color: #17a2b8 !important; +} + +.border-warning { + border-color: #ffc107 !important; +} + +.border-danger { + border-color: #dc3545 !important; +} + +.border-light { + border-color: #f8f9fa !important; +} + +.border-dark { + border-color: #343a40 !important; +} + +.border-white { + border-color: #fff !important; +} + +.rounded-sm { + border-radius: 0.2rem !important; +} + +.rounded { + border-radius: 0.25rem !important; +} + +.rounded-top { + border-top-left-radius: 0.25rem !important; + border-top-right-radius: 0.25rem !important; +} + +.rounded-right { + border-top-right-radius: 0.25rem !important; + border-bottom-right-radius: 0.25rem !important; +} + +.rounded-bottom { + border-bottom-right-radius: 0.25rem !important; + border-bottom-left-radius: 0.25rem !important; +} + +.rounded-left { + border-top-left-radius: 0.25rem !important; + border-bottom-left-radius: 0.25rem !important; +} + +.rounded-lg { + border-radius: 0.3rem !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: 50rem !important; +} + +.rounded-0 { + border-radius: 0 !important; +} + +.clearfix::after { + display: block; + clear: both; + content: ""; +} + +.d-none { + display: none !important; +} + +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: -ms-flexbox !important; + display: flex !important; +} + +.d-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; +} + +@media (min-width: 576px) { + .d-sm-none { + display: none !important; + } + + .d-sm-inline { + display: inline !important; + } + + .d-sm-inline-block { + display: inline-block !important; + } + + .d-sm-block { + display: block !important; + } + + .d-sm-table { + display: table !important; + } + + .d-sm-table-row { + display: table-row !important; + } + + .d-sm-table-cell { + display: table-cell !important; + } + + .d-sm-flex { + display: -ms-flexbox !important; + display: flex !important; + } + + .d-sm-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 768px) { + .d-md-none { + display: none !important; + } + + .d-md-inline { + display: inline !important; + } + + .d-md-inline-block { + display: inline-block !important; + } + + .d-md-block { + display: block !important; + } + + .d-md-table { + display: table !important; + } + + .d-md-table-row { + display: table-row !important; + } + + .d-md-table-cell { + display: table-cell !important; + } + + .d-md-flex { + display: -ms-flexbox !important; + display: flex !important; + } + + .d-md-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 992px) { + .d-lg-none { + display: none !important; + } + + .d-lg-inline { + display: inline !important; + } + + .d-lg-inline-block { + display: inline-block !important; + } + + .d-lg-block { + display: block !important; + } + + .d-lg-table { + display: table !important; + } + + .d-lg-table-row { + display: table-row !important; + } + + .d-lg-table-cell { + display: table-cell !important; + } + + .d-lg-flex { + display: -ms-flexbox !important; + display: flex !important; + } + + .d-lg-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 1200px) { + .d-xl-none { + display: none !important; + } + + .d-xl-inline { + display: inline !important; + } + + .d-xl-inline-block { + display: inline-block !important; + } + + .d-xl-block { + display: block !important; + } + + .d-xl-table { + display: table !important; + } + + .d-xl-table-row { + display: table-row !important; + } + + .d-xl-table-cell { + display: table-cell !important; + } + + .d-xl-flex { + display: -ms-flexbox !important; + display: flex !important; + } + + .d-xl-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media print { + .d-print-none { + display: none !important; + } + + .d-print-inline { + display: inline !important; + } + + .d-print-inline-block { + display: inline-block !important; + } + + .d-print-block { + display: block !important; + } + + .d-print-table { + display: table !important; + } + + .d-print-table-row { + display: table-row !important; + } + + .d-print-table-cell { + display: table-cell !important; + } + + .d-print-flex { + display: -ms-flexbox !important; + display: flex !important; + } + + .d-print-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +.embed-responsive { + position: relative; + display: block; + width: 100%; + padding: 0; + overflow: hidden; +} + +.embed-responsive::before { + display: block; + content: ""; +} + +.embed-responsive .embed-responsive-item, +.embed-responsive iframe, +.embed-responsive embed, +.embed-responsive object, +.embed-responsive video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; +} + +.embed-responsive-21by9::before { + padding-top: 42.857143%; +} + +.embed-responsive-16by9::before { + padding-top: 56.25%; +} + +.embed-responsive-4by3::before { + padding-top: 75%; +} + +.embed-responsive-1by1::before { + padding-top: 100%; +} + +.flex-row { + -ms-flex-direction: row !important; + flex-direction: row !important; +} + +.flex-column { + -ms-flex-direction: column !important; + flex-direction: column !important; +} + +.flex-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; +} + +.flex-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; +} + +.flex-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; +} + +.flex-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; +} + +.flex-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; +} + +.flex-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; +} + +.flex-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; +} + +.justify-content-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; +} + +.justify-content-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; +} + +.justify-content-center { + -ms-flex-pack: center !important; + justify-content: center !important; +} + +.justify-content-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; +} + +.justify-content-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; +} + +.align-items-start { + -ms-flex-align: start !important; + align-items: flex-start !important; +} + +.align-items-end { + -ms-flex-align: end !important; + align-items: flex-end !important; +} + +.align-items-center { + -ms-flex-align: center !important; + align-items: center !important; +} + +.align-items-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; +} + +.align-items-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; +} + +.align-content-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; +} + +.align-content-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; +} + +.align-content-center { + -ms-flex-line-pack: center !important; + align-content: center !important; +} + +.align-content-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; +} + +.align-content-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; +} + +.align-content-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; +} + +.align-self-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; +} + +.align-self-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; +} + +.align-self-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; +} + +.align-self-center { + -ms-flex-item-align: center !important; + align-self: center !important; +} + +.align-self-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; +} + +.align-self-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; +} + +@media (min-width: 576px) { + .flex-sm-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + + .flex-sm-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + + .flex-sm-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + + .flex-sm-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + + .flex-sm-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + + .flex-sm-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + + .flex-sm-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + + .flex-sm-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + + .flex-sm-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + + .flex-sm-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + + .flex-sm-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + + .flex-sm-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + + .justify-content-sm-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + + .justify-content-sm-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + + .justify-content-sm-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + + .justify-content-sm-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + + .justify-content-sm-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + + .align-items-sm-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + + .align-items-sm-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + + .align-items-sm-center { + -ms-flex-align: center !important; + align-items: center !important; + } + + .align-items-sm-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + + .align-items-sm-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + + .align-content-sm-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + + .align-content-sm-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + + .align-content-sm-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + + .align-content-sm-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + + .align-content-sm-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + + .align-content-sm-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + + .align-self-sm-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + + .align-self-sm-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + + .align-self-sm-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + + .align-self-sm-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + + .align-self-sm-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + + .align-self-sm-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 768px) { + .flex-md-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + + .flex-md-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + + .flex-md-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + + .flex-md-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + + .flex-md-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + + .flex-md-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + + .flex-md-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + + .flex-md-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + + .flex-md-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + + .flex-md-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + + .flex-md-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + + .flex-md-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + + .justify-content-md-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + + .justify-content-md-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + + .justify-content-md-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + + .justify-content-md-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + + .justify-content-md-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + + .align-items-md-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + + .align-items-md-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + + .align-items-md-center { + -ms-flex-align: center !important; + align-items: center !important; + } + + .align-items-md-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + + .align-items-md-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + + .align-content-md-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + + .align-content-md-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + + .align-content-md-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + + .align-content-md-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + + .align-content-md-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + + .align-content-md-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + + .align-self-md-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + + .align-self-md-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + + .align-self-md-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + + .align-self-md-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + + .align-self-md-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + + .align-self-md-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 992px) { + .flex-lg-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + + .flex-lg-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + + .flex-lg-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + + .flex-lg-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + + .flex-lg-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + + .flex-lg-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + + .flex-lg-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + + .flex-lg-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + + .flex-lg-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + + .flex-lg-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + + .flex-lg-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + + .flex-lg-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + + .justify-content-lg-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + + .justify-content-lg-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + + .justify-content-lg-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + + .justify-content-lg-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + + .justify-content-lg-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + + .align-items-lg-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + + .align-items-lg-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + + .align-items-lg-center { + -ms-flex-align: center !important; + align-items: center !important; + } + + .align-items-lg-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + + .align-items-lg-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + + .align-content-lg-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + + .align-content-lg-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + + .align-content-lg-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + + .align-content-lg-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + + .align-content-lg-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + + .align-content-lg-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + + .align-self-lg-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + + .align-self-lg-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + + .align-self-lg-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + + .align-self-lg-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + + .align-self-lg-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + + .align-self-lg-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 1200px) { + .flex-xl-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + + .flex-xl-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + + .flex-xl-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + + .flex-xl-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + + .flex-xl-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + + .flex-xl-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + + .flex-xl-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + + .flex-xl-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + + .flex-xl-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + + .flex-xl-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + + .flex-xl-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + + .flex-xl-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + + .justify-content-xl-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + + .justify-content-xl-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + + .justify-content-xl-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + + .justify-content-xl-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + + .justify-content-xl-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + + .align-items-xl-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + + .align-items-xl-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + + .align-items-xl-center { + -ms-flex-align: center !important; + align-items: center !important; + } + + .align-items-xl-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + + .align-items-xl-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + + .align-content-xl-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + + .align-content-xl-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + + .align-content-xl-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + + .align-content-xl-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + + .align-content-xl-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + + .align-content-xl-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + + .align-self-xl-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + + .align-self-xl-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + + .align-self-xl-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + + .align-self-xl-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + + .align-self-xl-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + + .align-self-xl-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +.float-left { + float: left !important; +} + +.float-right { + float: right !important; +} + +.float-none { + float: none !important; +} + +@media (min-width: 576px) { + .float-sm-left { + float: left !important; + } + + .float-sm-right { + float: right !important; + } + + .float-sm-none { + float: none !important; + } +} + +@media (min-width: 768px) { + .float-md-left { + float: left !important; + } + + .float-md-right { + float: right !important; + } + + .float-md-none { + float: none !important; + } +} + +@media (min-width: 992px) { + .float-lg-left { + float: left !important; + } + + .float-lg-right { + float: right !important; + } + + .float-lg-none { + float: none !important; + } +} + +@media (min-width: 1200px) { + .float-xl-left { + float: left !important; + } + + .float-xl-right { + float: right !important; + } + + .float-xl-none { + float: none !important; + } +} + +.overflow-auto { + overflow: auto !important; +} + +.overflow-hidden { + overflow: hidden !important; +} + +.position-static { + position: static !important; +} + +.position-relative { + position: relative !important; +} + +.position-absolute { + position: absolute !important; +} + +.position-fixed { + position: fixed !important; +} + +.position-sticky { + position: -webkit-sticky !important; + position: sticky !important; +} + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; +} + +@supports ((position: -webkit-sticky) or (position: sticky)) { + .sticky-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + overflow: visible; + clip: auto; + white-space: normal; +} + +.shadow-sm { + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; +} + +.shadow { + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; +} + +.shadow-lg { + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; +} + +.shadow-none { + box-shadow: none !important; +} + +.w-25 { + width: 25% !important; +} + +.w-50 { + width: 50% !important; +} + +.w-75 { + width: 75% !important; +} + +.w-100 { + width: 100% !important; +} + +.w-auto { + width: auto !important; +} + +.h-25 { + height: 25% !important; +} + +.h-50 { + height: 50% !important; +} + +.h-75 { + height: 75% !important; +} + +.h-100 { + height: 100% !important; +} + +.h-auto { + height: auto !important; +} + +.mw-100 { + max-width: 100% !important; +} + +.mh-100 { + max-height: 100% !important; +} + +.min-vw-100 { + min-width: 100vw !important; +} + +.min-vh-100 { + min-height: 100vh !important; +} + +.vw-100 { + width: 100vw !important; +} + +.vh-100 { + height: 100vh !important; +} + +.stretched-link::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + pointer-events: auto; + content: ""; + background-color: rgba(0, 0, 0, 0); +} + +.m-0 { + margin: 0 !important; +} + +.mt-0, +.my-0 { + margin-top: 0 !important; +} + +.mr-0, +.mx-0 { + margin-right: 0 !important; +} + +.mb-0, +.my-0 { + margin-bottom: 0 !important; +} + +.ml-0, +.mx-0 { + margin-left: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.mt-1, +.my-1 { + margin-top: 0.25rem !important; +} + +.mr-1, +.mx-1 { + margin-right: 0.25rem !important; +} + +.mb-1, +.my-1 { + margin-bottom: 0.25rem !important; +} + +.ml-1, +.mx-1 { + margin-left: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.mt-2, +.my-2 { + margin-top: 0.5rem !important; +} + +.mr-2, +.mx-2 { + margin-right: 0.5rem !important; +} + +.mb-2, +.my-2 { + margin-bottom: 0.5rem !important; +} + +.ml-2, +.mx-2 { + margin-left: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.mt-3, +.my-3 { + margin-top: 1rem !important; +} + +.mr-3, +.mx-3 { + margin-right: 1rem !important; +} + +.mb-3, +.my-3 { + margin-bottom: 1rem !important; +} + +.ml-3, +.mx-3 { + margin-left: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.mt-4, +.my-4 { + margin-top: 1.5rem !important; +} + +.mr-4, +.mx-4 { + margin-right: 1.5rem !important; +} + +.mb-4, +.my-4 { + margin-bottom: 1.5rem !important; +} + +.ml-4, +.mx-4 { + margin-left: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.mt-5, +.my-5 { + margin-top: 3rem !important; +} + +.mr-5, +.mx-5 { + margin-right: 3rem !important; +} + +.mb-5, +.my-5 { + margin-bottom: 3rem !important; +} + +.ml-5, +.mx-5 { + margin-left: 3rem !important; +} + +.p-0 { + padding: 0 !important; +} + +.pt-0, +.py-0 { + padding-top: 0 !important; +} + +.pr-0, +.px-0 { + padding-right: 0 !important; +} + +.pb-0, +.py-0 { + padding-bottom: 0 !important; +} + +.pl-0, +.px-0 { + padding-left: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.pt-1, +.py-1 { + padding-top: 0.25rem !important; +} + +.pr-1, +.px-1 { + padding-right: 0.25rem !important; +} + +.pb-1, +.py-1 { + padding-bottom: 0.25rem !important; +} + +.pl-1, +.px-1 { + padding-left: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.pt-2, +.py-2 { + padding-top: 0.5rem !important; +} + +.pr-2, +.px-2 { + padding-right: 0.5rem !important; +} + +.pb-2, +.py-2 { + padding-bottom: 0.5rem !important; +} + +.pl-2, +.px-2 { + padding-left: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.pt-3, +.py-3 { + padding-top: 1rem !important; +} + +.pr-3, +.px-3 { + padding-right: 1rem !important; +} + +.pb-3, +.py-3 { + padding-bottom: 1rem !important; +} + +.pl-3, +.px-3 { + padding-left: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.pt-4, +.py-4 { + padding-top: 1.5rem !important; +} + +.pr-4, +.px-4 { + padding-right: 1.5rem !important; +} + +.pb-4, +.py-4 { + padding-bottom: 1.5rem !important; +} + +.pl-4, +.px-4 { + padding-left: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.pt-5, +.py-5 { + padding-top: 3rem !important; +} + +.pr-5, +.px-5 { + padding-right: 3rem !important; +} + +.pb-5, +.py-5 { + padding-bottom: 3rem !important; +} + +.pl-5, +.px-5 { + padding-left: 3rem !important; +} + +.m-n1 { + margin: -0.25rem !important; +} + +.mt-n1, +.my-n1 { + margin-top: -0.25rem !important; +} + +.mr-n1, +.mx-n1 { + margin-right: -0.25rem !important; +} + +.mb-n1, +.my-n1 { + margin-bottom: -0.25rem !important; +} + +.ml-n1, +.mx-n1 { + margin-left: -0.25rem !important; +} + +.m-n2 { + margin: -0.5rem !important; +} + +.mt-n2, +.my-n2 { + margin-top: -0.5rem !important; +} + +.mr-n2, +.mx-n2 { + margin-right: -0.5rem !important; +} + +.mb-n2, +.my-n2 { + margin-bottom: -0.5rem !important; +} + +.ml-n2, +.mx-n2 { + margin-left: -0.5rem !important; +} + +.m-n3 { + margin: -1rem !important; +} + +.mt-n3, +.my-n3 { + margin-top: -1rem !important; +} + +.mr-n3, +.mx-n3 { + margin-right: -1rem !important; +} + +.mb-n3, +.my-n3 { + margin-bottom: -1rem !important; +} + +.ml-n3, +.mx-n3 { + margin-left: -1rem !important; +} + +.m-n4 { + margin: -1.5rem !important; +} + +.mt-n4, +.my-n4 { + margin-top: -1.5rem !important; +} + +.mr-n4, +.mx-n4 { + margin-right: -1.5rem !important; +} + +.mb-n4, +.my-n4 { + margin-bottom: -1.5rem !important; +} + +.ml-n4, +.mx-n4 { + margin-left: -1.5rem !important; +} + +.m-n5 { + margin: -3rem !important; +} + +.mt-n5, +.my-n5 { + margin-top: -3rem !important; +} + +.mr-n5, +.mx-n5 { + margin-right: -3rem !important; +} + +.mb-n5, +.my-n5 { + margin-bottom: -3rem !important; +} + +.ml-n5, +.mx-n5 { + margin-left: -3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mt-auto, +.my-auto { + margin-top: auto !important; +} + +.mr-auto, +.mx-auto { + margin-right: auto !important; +} + +.mb-auto, +.my-auto { + margin-bottom: auto !important; +} + +.ml-auto, +.mx-auto { + margin-left: auto !important; +} + +@media (min-width: 576px) { + .m-sm-0 { + margin: 0 !important; + } + + .mt-sm-0, + .my-sm-0 { + margin-top: 0 !important; + } + + .mr-sm-0, + .mx-sm-0 { + margin-right: 0 !important; + } + + .mb-sm-0, + .my-sm-0 { + margin-bottom: 0 !important; + } + + .ml-sm-0, + .mx-sm-0 { + margin-left: 0 !important; + } + + .m-sm-1 { + margin: 0.25rem !important; + } + + .mt-sm-1, + .my-sm-1 { + margin-top: 0.25rem !important; + } + + .mr-sm-1, + .mx-sm-1 { + margin-right: 0.25rem !important; + } + + .mb-sm-1, + .my-sm-1 { + margin-bottom: 0.25rem !important; + } + + .ml-sm-1, + .mx-sm-1 { + margin-left: 0.25rem !important; + } + + .m-sm-2 { + margin: 0.5rem !important; + } + + .mt-sm-2, + .my-sm-2 { + margin-top: 0.5rem !important; + } + + .mr-sm-2, + .mx-sm-2 { + margin-right: 0.5rem !important; + } + + .mb-sm-2, + .my-sm-2 { + margin-bottom: 0.5rem !important; + } + + .ml-sm-2, + .mx-sm-2 { + margin-left: 0.5rem !important; + } + + .m-sm-3 { + margin: 1rem !important; + } + + .mt-sm-3, + .my-sm-3 { + margin-top: 1rem !important; + } + + .mr-sm-3, + .mx-sm-3 { + margin-right: 1rem !important; + } + + .mb-sm-3, + .my-sm-3 { + margin-bottom: 1rem !important; + } + + .ml-sm-3, + .mx-sm-3 { + margin-left: 1rem !important; + } + + .m-sm-4 { + margin: 1.5rem !important; + } + + .mt-sm-4, + .my-sm-4 { + margin-top: 1.5rem !important; + } + + .mr-sm-4, + .mx-sm-4 { + margin-right: 1.5rem !important; + } + + .mb-sm-4, + .my-sm-4 { + margin-bottom: 1.5rem !important; + } + + .ml-sm-4, + .mx-sm-4 { + margin-left: 1.5rem !important; + } + + .m-sm-5 { + margin: 3rem !important; + } + + .mt-sm-5, + .my-sm-5 { + margin-top: 3rem !important; + } + + .mr-sm-5, + .mx-sm-5 { + margin-right: 3rem !important; + } + + .mb-sm-5, + .my-sm-5 { + margin-bottom: 3rem !important; + } + + .ml-sm-5, + .mx-sm-5 { + margin-left: 3rem !important; + } + + .p-sm-0 { + padding: 0 !important; + } + + .pt-sm-0, + .py-sm-0 { + padding-top: 0 !important; + } + + .pr-sm-0, + .px-sm-0 { + padding-right: 0 !important; + } + + .pb-sm-0, + .py-sm-0 { + padding-bottom: 0 !important; + } + + .pl-sm-0, + .px-sm-0 { + padding-left: 0 !important; + } + + .p-sm-1 { + padding: 0.25rem !important; + } + + .pt-sm-1, + .py-sm-1 { + padding-top: 0.25rem !important; + } + + .pr-sm-1, + .px-sm-1 { + padding-right: 0.25rem !important; + } + + .pb-sm-1, + .py-sm-1 { + padding-bottom: 0.25rem !important; + } + + .pl-sm-1, + .px-sm-1 { + padding-left: 0.25rem !important; + } + + .p-sm-2 { + padding: 0.5rem !important; + } + + .pt-sm-2, + .py-sm-2 { + padding-top: 0.5rem !important; + } + + .pr-sm-2, + .px-sm-2 { + padding-right: 0.5rem !important; + } + + .pb-sm-2, + .py-sm-2 { + padding-bottom: 0.5rem !important; + } + + .pl-sm-2, + .px-sm-2 { + padding-left: 0.5rem !important; + } + + .p-sm-3 { + padding: 1rem !important; + } + + .pt-sm-3, + .py-sm-3 { + padding-top: 1rem !important; + } + + .pr-sm-3, + .px-sm-3 { + padding-right: 1rem !important; + } + + .pb-sm-3, + .py-sm-3 { + padding-bottom: 1rem !important; + } + + .pl-sm-3, + .px-sm-3 { + padding-left: 1rem !important; + } + + .p-sm-4 { + padding: 1.5rem !important; + } + + .pt-sm-4, + .py-sm-4 { + padding-top: 1.5rem !important; + } + + .pr-sm-4, + .px-sm-4 { + padding-right: 1.5rem !important; + } + + .pb-sm-4, + .py-sm-4 { + padding-bottom: 1.5rem !important; + } + + .pl-sm-4, + .px-sm-4 { + padding-left: 1.5rem !important; + } + + .p-sm-5 { + padding: 3rem !important; + } + + .pt-sm-5, + .py-sm-5 { + padding-top: 3rem !important; + } + + .pr-sm-5, + .px-sm-5 { + padding-right: 3rem !important; + } + + .pb-sm-5, + .py-sm-5 { + padding-bottom: 3rem !important; + } + + .pl-sm-5, + .px-sm-5 { + padding-left: 3rem !important; + } + + .m-sm-n1 { + margin: -0.25rem !important; + } + + .mt-sm-n1, + .my-sm-n1 { + margin-top: -0.25rem !important; + } + + .mr-sm-n1, + .mx-sm-n1 { + margin-right: -0.25rem !important; + } + + .mb-sm-n1, + .my-sm-n1 { + margin-bottom: -0.25rem !important; + } + + .ml-sm-n1, + .mx-sm-n1 { + margin-left: -0.25rem !important; + } + + .m-sm-n2 { + margin: -0.5rem !important; + } + + .mt-sm-n2, + .my-sm-n2 { + margin-top: -0.5rem !important; + } + + .mr-sm-n2, + .mx-sm-n2 { + margin-right: -0.5rem !important; + } + + .mb-sm-n2, + .my-sm-n2 { + margin-bottom: -0.5rem !important; + } + + .ml-sm-n2, + .mx-sm-n2 { + margin-left: -0.5rem !important; + } + + .m-sm-n3 { + margin: -1rem !important; + } + + .mt-sm-n3, + .my-sm-n3 { + margin-top: -1rem !important; + } + + .mr-sm-n3, + .mx-sm-n3 { + margin-right: -1rem !important; + } + + .mb-sm-n3, + .my-sm-n3 { + margin-bottom: -1rem !important; + } + + .ml-sm-n3, + .mx-sm-n3 { + margin-left: -1rem !important; + } + + .m-sm-n4 { + margin: -1.5rem !important; + } + + .mt-sm-n4, + .my-sm-n4 { + margin-top: -1.5rem !important; + } + + .mr-sm-n4, + .mx-sm-n4 { + margin-right: -1.5rem !important; + } + + .mb-sm-n4, + .my-sm-n4 { + margin-bottom: -1.5rem !important; + } + + .ml-sm-n4, + .mx-sm-n4 { + margin-left: -1.5rem !important; + } + + .m-sm-n5 { + margin: -3rem !important; + } + + .mt-sm-n5, + .my-sm-n5 { + margin-top: -3rem !important; + } + + .mr-sm-n5, + .mx-sm-n5 { + margin-right: -3rem !important; + } + + .mb-sm-n5, + .my-sm-n5 { + margin-bottom: -3rem !important; + } + + .ml-sm-n5, + .mx-sm-n5 { + margin-left: -3rem !important; + } + + .m-sm-auto { + margin: auto !important; + } + + .mt-sm-auto, + .my-sm-auto { + margin-top: auto !important; + } + + .mr-sm-auto, + .mx-sm-auto { + margin-right: auto !important; + } + + .mb-sm-auto, + .my-sm-auto { + margin-bottom: auto !important; + } + + .ml-sm-auto, + .mx-sm-auto { + margin-left: auto !important; + } +} + +@media (min-width: 768px) { + .m-md-0 { + margin: 0 !important; + } + + .mt-md-0, + .my-md-0 { + margin-top: 0 !important; + } + + .mr-md-0, + .mx-md-0 { + margin-right: 0 !important; + } + + .mb-md-0, + .my-md-0 { + margin-bottom: 0 !important; + } + + .ml-md-0, + .mx-md-0 { + margin-left: 0 !important; + } + + .m-md-1 { + margin: 0.25rem !important; + } + + .mt-md-1, + .my-md-1 { + margin-top: 0.25rem !important; + } + + .mr-md-1, + .mx-md-1 { + margin-right: 0.25rem !important; + } + + .mb-md-1, + .my-md-1 { + margin-bottom: 0.25rem !important; + } + + .ml-md-1, + .mx-md-1 { + margin-left: 0.25rem !important; + } + + .m-md-2 { + margin: 0.5rem !important; + } + + .mt-md-2, + .my-md-2 { + margin-top: 0.5rem !important; + } + + .mr-md-2, + .mx-md-2 { + margin-right: 0.5rem !important; + } + + .mb-md-2, + .my-md-2 { + margin-bottom: 0.5rem !important; + } + + .ml-md-2, + .mx-md-2 { + margin-left: 0.5rem !important; + } + + .m-md-3 { + margin: 1rem !important; + } + + .mt-md-3, + .my-md-3 { + margin-top: 1rem !important; + } + + .mr-md-3, + .mx-md-3 { + margin-right: 1rem !important; + } + + .mb-md-3, + .my-md-3 { + margin-bottom: 1rem !important; + } + + .ml-md-3, + .mx-md-3 { + margin-left: 1rem !important; + } + + .m-md-4 { + margin: 1.5rem !important; + } + + .mt-md-4, + .my-md-4 { + margin-top: 1.5rem !important; + } + + .mr-md-4, + .mx-md-4 { + margin-right: 1.5rem !important; + } + + .mb-md-4, + .my-md-4 { + margin-bottom: 1.5rem !important; + } + + .ml-md-4, + .mx-md-4 { + margin-left: 1.5rem !important; + } + + .m-md-5 { + margin: 3rem !important; + } + + .mt-md-5, + .my-md-5 { + margin-top: 3rem !important; + } + + .mr-md-5, + .mx-md-5 { + margin-right: 3rem !important; + } + + .mb-md-5, + .my-md-5 { + margin-bottom: 3rem !important; + } + + .ml-md-5, + .mx-md-5 { + margin-left: 3rem !important; + } + + .p-md-0 { + padding: 0 !important; + } + + .pt-md-0, + .py-md-0 { + padding-top: 0 !important; + } + + .pr-md-0, + .px-md-0 { + padding-right: 0 !important; + } + + .pb-md-0, + .py-md-0 { + padding-bottom: 0 !important; + } + + .pl-md-0, + .px-md-0 { + padding-left: 0 !important; + } + + .p-md-1 { + padding: 0.25rem !important; + } + + .pt-md-1, + .py-md-1 { + padding-top: 0.25rem !important; + } + + .pr-md-1, + .px-md-1 { + padding-right: 0.25rem !important; + } + + .pb-md-1, + .py-md-1 { + padding-bottom: 0.25rem !important; + } + + .pl-md-1, + .px-md-1 { + padding-left: 0.25rem !important; + } + + .p-md-2 { + padding: 0.5rem !important; + } + + .pt-md-2, + .py-md-2 { + padding-top: 0.5rem !important; + } + + .pr-md-2, + .px-md-2 { + padding-right: 0.5rem !important; + } + + .pb-md-2, + .py-md-2 { + padding-bottom: 0.5rem !important; + } + + .pl-md-2, + .px-md-2 { + padding-left: 0.5rem !important; + } + + .p-md-3 { + padding: 1rem !important; + } + + .pt-md-3, + .py-md-3 { + padding-top: 1rem !important; + } + + .pr-md-3, + .px-md-3 { + padding-right: 1rem !important; + } + + .pb-md-3, + .py-md-3 { + padding-bottom: 1rem !important; + } + + .pl-md-3, + .px-md-3 { + padding-left: 1rem !important; + } + + .p-md-4 { + padding: 1.5rem !important; + } + + .pt-md-4, + .py-md-4 { + padding-top: 1.5rem !important; + } + + .pr-md-4, + .px-md-4 { + padding-right: 1.5rem !important; + } + + .pb-md-4, + .py-md-4 { + padding-bottom: 1.5rem !important; + } + + .pl-md-4, + .px-md-4 { + padding-left: 1.5rem !important; + } + + .p-md-5 { + padding: 3rem !important; + } + + .pt-md-5, + .py-md-5 { + padding-top: 3rem !important; + } + + .pr-md-5, + .px-md-5 { + padding-right: 3rem !important; + } + + .pb-md-5, + .py-md-5 { + padding-bottom: 3rem !important; + } + + .pl-md-5, + .px-md-5 { + padding-left: 3rem !important; + } + + .m-md-n1 { + margin: -0.25rem !important; + } + + .mt-md-n1, + .my-md-n1 { + margin-top: -0.25rem !important; + } + + .mr-md-n1, + .mx-md-n1 { + margin-right: -0.25rem !important; + } + + .mb-md-n1, + .my-md-n1 { + margin-bottom: -0.25rem !important; + } + + .ml-md-n1, + .mx-md-n1 { + margin-left: -0.25rem !important; + } + + .m-md-n2 { + margin: -0.5rem !important; + } + + .mt-md-n2, + .my-md-n2 { + margin-top: -0.5rem !important; + } + + .mr-md-n2, + .mx-md-n2 { + margin-right: -0.5rem !important; + } + + .mb-md-n2, + .my-md-n2 { + margin-bottom: -0.5rem !important; + } + + .ml-md-n2, + .mx-md-n2 { + margin-left: -0.5rem !important; + } + + .m-md-n3 { + margin: -1rem !important; + } + + .mt-md-n3, + .my-md-n3 { + margin-top: -1rem !important; + } + + .mr-md-n3, + .mx-md-n3 { + margin-right: -1rem !important; + } + + .mb-md-n3, + .my-md-n3 { + margin-bottom: -1rem !important; + } + + .ml-md-n3, + .mx-md-n3 { + margin-left: -1rem !important; + } + + .m-md-n4 { + margin: -1.5rem !important; + } + + .mt-md-n4, + .my-md-n4 { + margin-top: -1.5rem !important; + } + + .mr-md-n4, + .mx-md-n4 { + margin-right: -1.5rem !important; + } + + .mb-md-n4, + .my-md-n4 { + margin-bottom: -1.5rem !important; + } + + .ml-md-n4, + .mx-md-n4 { + margin-left: -1.5rem !important; + } + + .m-md-n5 { + margin: -3rem !important; + } + + .mt-md-n5, + .my-md-n5 { + margin-top: -3rem !important; + } + + .mr-md-n5, + .mx-md-n5 { + margin-right: -3rem !important; + } + + .mb-md-n5, + .my-md-n5 { + margin-bottom: -3rem !important; + } + + .ml-md-n5, + .mx-md-n5 { + margin-left: -3rem !important; + } + + .m-md-auto { + margin: auto !important; + } + + .mt-md-auto, + .my-md-auto { + margin-top: auto !important; + } + + .mr-md-auto, + .mx-md-auto { + margin-right: auto !important; + } + + .mb-md-auto, + .my-md-auto { + margin-bottom: auto !important; + } + + .ml-md-auto, + .mx-md-auto { + margin-left: auto !important; + } +} + +@media (min-width: 992px) { + .m-lg-0 { + margin: 0 !important; + } + + .mt-lg-0, + .my-lg-0 { + margin-top: 0 !important; + } + + .mr-lg-0, + .mx-lg-0 { + margin-right: 0 !important; + } + + .mb-lg-0, + .my-lg-0 { + margin-bottom: 0 !important; + } + + .ml-lg-0, + .mx-lg-0 { + margin-left: 0 !important; + } + + .m-lg-1 { + margin: 0.25rem !important; + } + + .mt-lg-1, + .my-lg-1 { + margin-top: 0.25rem !important; + } + + .mr-lg-1, + .mx-lg-1 { + margin-right: 0.25rem !important; + } + + .mb-lg-1, + .my-lg-1 { + margin-bottom: 0.25rem !important; + } + + .ml-lg-1, + .mx-lg-1 { + margin-left: 0.25rem !important; + } + + .m-lg-2 { + margin: 0.5rem !important; + } + + .mt-lg-2, + .my-lg-2 { + margin-top: 0.5rem !important; + } + + .mr-lg-2, + .mx-lg-2 { + margin-right: 0.5rem !important; + } + + .mb-lg-2, + .my-lg-2 { + margin-bottom: 0.5rem !important; + } + + .ml-lg-2, + .mx-lg-2 { + margin-left: 0.5rem !important; + } + + .m-lg-3 { + margin: 1rem !important; + } + + .mt-lg-3, + .my-lg-3 { + margin-top: 1rem !important; + } + + .mr-lg-3, + .mx-lg-3 { + margin-right: 1rem !important; + } + + .mb-lg-3, + .my-lg-3 { + margin-bottom: 1rem !important; + } + + .ml-lg-3, + .mx-lg-3 { + margin-left: 1rem !important; + } + + .m-lg-4 { + margin: 1.5rem !important; + } + + .mt-lg-4, + .my-lg-4 { + margin-top: 1.5rem !important; + } + + .mr-lg-4, + .mx-lg-4 { + margin-right: 1.5rem !important; + } + + .mb-lg-4, + .my-lg-4 { + margin-bottom: 1.5rem !important; + } + + .ml-lg-4, + .mx-lg-4 { + margin-left: 1.5rem !important; + } + + .m-lg-5 { + margin: 3rem !important; + } + + .mt-lg-5, + .my-lg-5 { + margin-top: 3rem !important; + } + + .mr-lg-5, + .mx-lg-5 { + margin-right: 3rem !important; + } + + .mb-lg-5, + .my-lg-5 { + margin-bottom: 3rem !important; + } + + .ml-lg-5, + .mx-lg-5 { + margin-left: 3rem !important; + } + + .p-lg-0 { + padding: 0 !important; + } + + .pt-lg-0, + .py-lg-0 { + padding-top: 0 !important; + } + + .pr-lg-0, + .px-lg-0 { + padding-right: 0 !important; + } + + .pb-lg-0, + .py-lg-0 { + padding-bottom: 0 !important; + } + + .pl-lg-0, + .px-lg-0 { + padding-left: 0 !important; + } + + .p-lg-1 { + padding: 0.25rem !important; + } + + .pt-lg-1, + .py-lg-1 { + padding-top: 0.25rem !important; + } + + .pr-lg-1, + .px-lg-1 { + padding-right: 0.25rem !important; + } + + .pb-lg-1, + .py-lg-1 { + padding-bottom: 0.25rem !important; + } + + .pl-lg-1, + .px-lg-1 { + padding-left: 0.25rem !important; + } + + .p-lg-2 { + padding: 0.5rem !important; + } + + .pt-lg-2, + .py-lg-2 { + padding-top: 0.5rem !important; + } + + .pr-lg-2, + .px-lg-2 { + padding-right: 0.5rem !important; + } + + .pb-lg-2, + .py-lg-2 { + padding-bottom: 0.5rem !important; + } + + .pl-lg-2, + .px-lg-2 { + padding-left: 0.5rem !important; + } + + .p-lg-3 { + padding: 1rem !important; + } + + .pt-lg-3, + .py-lg-3 { + padding-top: 1rem !important; + } + + .pr-lg-3, + .px-lg-3 { + padding-right: 1rem !important; + } + + .pb-lg-3, + .py-lg-3 { + padding-bottom: 1rem !important; + } + + .pl-lg-3, + .px-lg-3 { + padding-left: 1rem !important; + } + + .p-lg-4 { + padding: 1.5rem !important; + } + + .pt-lg-4, + .py-lg-4 { + padding-top: 1.5rem !important; + } + + .pr-lg-4, + .px-lg-4 { + padding-right: 1.5rem !important; + } + + .pb-lg-4, + .py-lg-4 { + padding-bottom: 1.5rem !important; + } + + .pl-lg-4, + .px-lg-4 { + padding-left: 1.5rem !important; + } + + .p-lg-5 { + padding: 3rem !important; + } + + .pt-lg-5, + .py-lg-5 { + padding-top: 3rem !important; + } + + .pr-lg-5, + .px-lg-5 { + padding-right: 3rem !important; + } + + .pb-lg-5, + .py-lg-5 { + padding-bottom: 3rem !important; + } + + .pl-lg-5, + .px-lg-5 { + padding-left: 3rem !important; + } + + .m-lg-n1 { + margin: -0.25rem !important; + } + + .mt-lg-n1, + .my-lg-n1 { + margin-top: -0.25rem !important; + } + + .mr-lg-n1, + .mx-lg-n1 { + margin-right: -0.25rem !important; + } + + .mb-lg-n1, + .my-lg-n1 { + margin-bottom: -0.25rem !important; + } + + .ml-lg-n1, + .mx-lg-n1 { + margin-left: -0.25rem !important; + } + + .m-lg-n2 { + margin: -0.5rem !important; + } + + .mt-lg-n2, + .my-lg-n2 { + margin-top: -0.5rem !important; + } + + .mr-lg-n2, + .mx-lg-n2 { + margin-right: -0.5rem !important; + } + + .mb-lg-n2, + .my-lg-n2 { + margin-bottom: -0.5rem !important; + } + + .ml-lg-n2, + .mx-lg-n2 { + margin-left: -0.5rem !important; + } + + .m-lg-n3 { + margin: -1rem !important; + } + + .mt-lg-n3, + .my-lg-n3 { + margin-top: -1rem !important; + } + + .mr-lg-n3, + .mx-lg-n3 { + margin-right: -1rem !important; + } + + .mb-lg-n3, + .my-lg-n3 { + margin-bottom: -1rem !important; + } + + .ml-lg-n3, + .mx-lg-n3 { + margin-left: -1rem !important; + } + + .m-lg-n4 { + margin: -1.5rem !important; + } + + .mt-lg-n4, + .my-lg-n4 { + margin-top: -1.5rem !important; + } + + .mr-lg-n4, + .mx-lg-n4 { + margin-right: -1.5rem !important; + } + + .mb-lg-n4, + .my-lg-n4 { + margin-bottom: -1.5rem !important; + } + + .ml-lg-n4, + .mx-lg-n4 { + margin-left: -1.5rem !important; + } + + .m-lg-n5 { + margin: -3rem !important; + } + + .mt-lg-n5, + .my-lg-n5 { + margin-top: -3rem !important; + } + + .mr-lg-n5, + .mx-lg-n5 { + margin-right: -3rem !important; + } + + .mb-lg-n5, + .my-lg-n5 { + margin-bottom: -3rem !important; + } + + .ml-lg-n5, + .mx-lg-n5 { + margin-left: -3rem !important; + } + + .m-lg-auto { + margin: auto !important; + } + + .mt-lg-auto, + .my-lg-auto { + margin-top: auto !important; + } + + .mr-lg-auto, + .mx-lg-auto { + margin-right: auto !important; + } + + .mb-lg-auto, + .my-lg-auto { + margin-bottom: auto !important; + } + + .ml-lg-auto, + .mx-lg-auto { + margin-left: auto !important; + } +} + +@media (min-width: 1200px) { + .m-xl-0 { + margin: 0 !important; + } + + .mt-xl-0, + .my-xl-0 { + margin-top: 0 !important; + } + + .mr-xl-0, + .mx-xl-0 { + margin-right: 0 !important; + } + + .mb-xl-0, + .my-xl-0 { + margin-bottom: 0 !important; + } + + .ml-xl-0, + .mx-xl-0 { + margin-left: 0 !important; + } + + .m-xl-1 { + margin: 0.25rem !important; + } + + .mt-xl-1, + .my-xl-1 { + margin-top: 0.25rem !important; + } + + .mr-xl-1, + .mx-xl-1 { + margin-right: 0.25rem !important; + } + + .mb-xl-1, + .my-xl-1 { + margin-bottom: 0.25rem !important; + } + + .ml-xl-1, + .mx-xl-1 { + margin-left: 0.25rem !important; + } + + .m-xl-2 { + margin: 0.5rem !important; + } + + .mt-xl-2, + .my-xl-2 { + margin-top: 0.5rem !important; + } + + .mr-xl-2, + .mx-xl-2 { + margin-right: 0.5rem !important; + } + + .mb-xl-2, + .my-xl-2 { + margin-bottom: 0.5rem !important; + } + + .ml-xl-2, + .mx-xl-2 { + margin-left: 0.5rem !important; + } + + .m-xl-3 { + margin: 1rem !important; + } + + .mt-xl-3, + .my-xl-3 { + margin-top: 1rem !important; + } + + .mr-xl-3, + .mx-xl-3 { + margin-right: 1rem !important; + } + + .mb-xl-3, + .my-xl-3 { + margin-bottom: 1rem !important; + } + + .ml-xl-3, + .mx-xl-3 { + margin-left: 1rem !important; + } + + .m-xl-4 { + margin: 1.5rem !important; + } + + .mt-xl-4, + .my-xl-4 { + margin-top: 1.5rem !important; + } + + .mr-xl-4, + .mx-xl-4 { + margin-right: 1.5rem !important; + } + + .mb-xl-4, + .my-xl-4 { + margin-bottom: 1.5rem !important; + } + + .ml-xl-4, + .mx-xl-4 { + margin-left: 1.5rem !important; + } + + .m-xl-5 { + margin: 3rem !important; + } + + .mt-xl-5, + .my-xl-5 { + margin-top: 3rem !important; + } + + .mr-xl-5, + .mx-xl-5 { + margin-right: 3rem !important; + } + + .mb-xl-5, + .my-xl-5 { + margin-bottom: 3rem !important; + } + + .ml-xl-5, + .mx-xl-5 { + margin-left: 3rem !important; + } + + .p-xl-0 { + padding: 0 !important; + } + + .pt-xl-0, + .py-xl-0 { + padding-top: 0 !important; + } + + .pr-xl-0, + .px-xl-0 { + padding-right: 0 !important; + } + + .pb-xl-0, + .py-xl-0 { + padding-bottom: 0 !important; + } + + .pl-xl-0, + .px-xl-0 { + padding-left: 0 !important; + } + + .p-xl-1 { + padding: 0.25rem !important; + } + + .pt-xl-1, + .py-xl-1 { + padding-top: 0.25rem !important; + } + + .pr-xl-1, + .px-xl-1 { + padding-right: 0.25rem !important; + } + + .pb-xl-1, + .py-xl-1 { + padding-bottom: 0.25rem !important; + } + + .pl-xl-1, + .px-xl-1 { + padding-left: 0.25rem !important; + } + + .p-xl-2 { + padding: 0.5rem !important; + } + + .pt-xl-2, + .py-xl-2 { + padding-top: 0.5rem !important; + } + + .pr-xl-2, + .px-xl-2 { + padding-right: 0.5rem !important; + } + + .pb-xl-2, + .py-xl-2 { + padding-bottom: 0.5rem !important; + } + + .pl-xl-2, + .px-xl-2 { + padding-left: 0.5rem !important; + } + + .p-xl-3 { + padding: 1rem !important; + } + + .pt-xl-3, + .py-xl-3 { + padding-top: 1rem !important; + } + + .pr-xl-3, + .px-xl-3 { + padding-right: 1rem !important; + } + + .pb-xl-3, + .py-xl-3 { + padding-bottom: 1rem !important; + } + + .pl-xl-3, + .px-xl-3 { + padding-left: 1rem !important; + } + + .p-xl-4 { + padding: 1.5rem !important; + } + + .pt-xl-4, + .py-xl-4 { + padding-top: 1.5rem !important; + } + + .pr-xl-4, + .px-xl-4 { + padding-right: 1.5rem !important; + } + + .pb-xl-4, + .py-xl-4 { + padding-bottom: 1.5rem !important; + } + + .pl-xl-4, + .px-xl-4 { + padding-left: 1.5rem !important; + } + + .p-xl-5 { + padding: 3rem !important; + } + + .pt-xl-5, + .py-xl-5 { + padding-top: 3rem !important; + } + + .pr-xl-5, + .px-xl-5 { + padding-right: 3rem !important; + } + + .pb-xl-5, + .py-xl-5 { + padding-bottom: 3rem !important; + } + + .pl-xl-5, + .px-xl-5 { + padding-left: 3rem !important; + } + + .m-xl-n1 { + margin: -0.25rem !important; + } + + .mt-xl-n1, + .my-xl-n1 { + margin-top: -0.25rem !important; + } + + .mr-xl-n1, + .mx-xl-n1 { + margin-right: -0.25rem !important; + } + + .mb-xl-n1, + .my-xl-n1 { + margin-bottom: -0.25rem !important; + } + + .ml-xl-n1, + .mx-xl-n1 { + margin-left: -0.25rem !important; + } + + .m-xl-n2 { + margin: -0.5rem !important; + } + + .mt-xl-n2, + .my-xl-n2 { + margin-top: -0.5rem !important; + } + + .mr-xl-n2, + .mx-xl-n2 { + margin-right: -0.5rem !important; + } + + .mb-xl-n2, + .my-xl-n2 { + margin-bottom: -0.5rem !important; + } + + .ml-xl-n2, + .mx-xl-n2 { + margin-left: -0.5rem !important; + } + + .m-xl-n3 { + margin: -1rem !important; + } + + .mt-xl-n3, + .my-xl-n3 { + margin-top: -1rem !important; + } + + .mr-xl-n3, + .mx-xl-n3 { + margin-right: -1rem !important; + } + + .mb-xl-n3, + .my-xl-n3 { + margin-bottom: -1rem !important; + } + + .ml-xl-n3, + .mx-xl-n3 { + margin-left: -1rem !important; + } + + .m-xl-n4 { + margin: -1.5rem !important; + } + + .mt-xl-n4, + .my-xl-n4 { + margin-top: -1.5rem !important; + } + + .mr-xl-n4, + .mx-xl-n4 { + margin-right: -1.5rem !important; + } + + .mb-xl-n4, + .my-xl-n4 { + margin-bottom: -1.5rem !important; + } + + .ml-xl-n4, + .mx-xl-n4 { + margin-left: -1.5rem !important; + } + + .m-xl-n5 { + margin: -3rem !important; + } + + .mt-xl-n5, + .my-xl-n5 { + margin-top: -3rem !important; + } + + .mr-xl-n5, + .mx-xl-n5 { + margin-right: -3rem !important; + } + + .mb-xl-n5, + .my-xl-n5 { + margin-bottom: -3rem !important; + } + + .ml-xl-n5, + .mx-xl-n5 { + margin-left: -3rem !important; + } + + .m-xl-auto { + margin: auto !important; + } + + .mt-xl-auto, + .my-xl-auto { + margin-top: auto !important; + } + + .mr-xl-auto, + .mx-xl-auto { + margin-right: auto !important; + } + + .mb-xl-auto, + .my-xl-auto { + margin-bottom: auto !important; + } + + .ml-xl-auto, + .mx-xl-auto { + margin-left: auto !important; + } +} + +.text-monospace { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !important; +} + +.text-justify { + text-align: justify !important; +} + +.text-wrap { + white-space: normal !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.text-left { + text-align: left !important; +} + +.text-right { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +@media (min-width: 576px) { + .text-sm-left { + text-align: left !important; + } + + .text-sm-right { + text-align: right !important; + } + + .text-sm-center { + text-align: center !important; + } +} + +@media (min-width: 768px) { + .text-md-left { + text-align: left !important; + } + + .text-md-right { + text-align: right !important; + } + + .text-md-center { + text-align: center !important; + } +} + +@media (min-width: 992px) { + .text-lg-left { + text-align: left !important; + } + + .text-lg-right { + text-align: right !important; + } + + .text-lg-center { + text-align: center !important; + } +} + +@media (min-width: 1200px) { + .text-xl-left { + text-align: left !important; + } + + .text-xl-right { + text-align: right !important; + } + + .text-xl-center { + text-align: center !important; + } +} + +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +.font-weight-light { + font-weight: 300 !important; +} + +.font-weight-lighter { + font-weight: lighter !important; +} + +.font-weight-normal { + font-weight: 400 !important; +} + +.font-weight-bold { + font-weight: 700 !important; +} + +.font-weight-bolder { + font-weight: bolder !important; +} + +.font-italic { + font-style: italic !important; +} + +.text-white { + color: #fff !important; +} + +.text-primary { + color: #007bff !important; +} + +a.text-primary:hover, +a.text-primary:focus { + color: #0056b3 !important; +} + +.text-secondary { + color: #6c757d !important; +} + +a.text-secondary:hover, +a.text-secondary:focus { + color: #494f54 !important; +} + +.text-success { + color: #28a745 !important; +} + +a.text-success:hover, +a.text-success:focus { + color: #19692c !important; +} + +.text-info { + color: #17a2b8 !important; +} + +a.text-info:hover, +a.text-info:focus { + color: #0f6674 !important; +} + +.text-warning { + color: #ffc107 !important; +} + +a.text-warning:hover, +a.text-warning:focus { + color: #ba8b00 !important; +} + +.text-danger { + color: #dc3545 !important; +} + +a.text-danger:hover, +a.text-danger:focus { + color: #a71d2a !important; +} + +.text-light { + color: #f8f9fa !important; +} + +a.text-light:hover, +a.text-light:focus { + color: #cbd3da !important; +} + +.text-dark { + color: #343a40 !important; +} + +a.text-dark:hover, +a.text-dark:focus { + color: #121416 !important; +} + +.text-body { + color: #212529 !important; +} + +.text-muted { + color: #6c757d !important; +} + +.text-black-50 { + color: rgba(0, 0, 0, 0.5) !important; +} + +.text-white-50 { + color: rgba(255, 255, 255, 0.5) !important; +} + +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.text-decoration-none { + text-decoration: none !important; +} + +.text-break { + word-break: break-word !important; + overflow-wrap: break-word !important; +} + +.text-reset { + color: inherit !important; +} + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} + +@media print { + + *, + *::before, + *::after { + text-shadow: none !important; + box-shadow: none !important; + } + + a:not(.btn) { + text-decoration: underline; + } + + abbr[title]::after { + content: " (" attr(title) ")"; + } + + pre { + white-space: pre-wrap !important; + } + + pre, + blockquote { + border: 1px solid #adb5bd; + page-break-inside: avoid; + } + + thead { + display: table-header-group; + } + + tr, + img { + page-break-inside: avoid; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } + + @page { + size: a3; + } + + body { + min-width: 992px !important; + } + + .container { + min-width: 992px !important; + } + + .navbar { + display: none; + } + + .badge { + border: 1px solid #000; + } + + .table { + border-collapse: collapse !important; + } + + .table td, + .table th { + background-color: #fff !important; + } + + .table-bordered th, + .table-bordered td { + border: 1px solid #dee2e6 !important; + } + + .table-dark { + color: inherit; + } + + .table-dark th, + .table-dark td, + .table-dark thead th, + .table-dark tbody+tbody { + border-color: #dee2e6; + } + + .table .thead-dark th { + color: inherit; + border-color: #dee2e6; + } +} + +/*# sourceMappingURL=bootstrap.css.map */ \ No newline at end of file diff --git a/public/static/css/button.css b/public/static/css/button.css new file mode 100644 index 0000000..b4067e5 --- /dev/null +++ b/public/static/css/button.css @@ -0,0 +1,38 @@ +.arrow{ + border: 9px solid transparent; + border-bottom-color: rgb(0, 167, 134); + width: 0px; + height: 0px; + top:0px +} +.stick{ + width: 8px; + height: 14px; + border-radius: 1px; + background-color: rgb(0, 167, 134); + top:15px; +} +#back_top div{ + position: absolute; + margin: auto; + right: 0px; + left: 0px; +} +#back_top{ + /* border: 1px solid rgb(0, 167, 134); */ + background-color: rgb(220, 220, 220); + height: 38px; + width: 38px; + border-radius: 3px; + display: block; + cursor: pointer; + position: fixed; + right: 50px; + bottom: 100px; + display: none; +} +#back_top:hover{ + border: 1px solid rgb(220, 220, 220); + transition: 0.5s; + background-color: white; +} \ No newline at end of file diff --git a/public/static/css/companyIntro.css b/public/static/css/companyIntro.css new file mode 100644 index 0000000..03afd3d --- /dev/null +++ b/public/static/css/companyIntro.css @@ -0,0 +1,327 @@ +/* 公司简介 */ +body { + margin: 0; + padding: 0; +} + +.topPic { + width: 100%; +} + +.barGs:hover { + /* border-bottom: #fff 3px solid; */ + padding-bottom: 15px; + /* border-right: none; */ +} + +.barTop { + display: flex; + width: 90%; + height: auto; + background-color: #00a587; + padding-left: 5%; + padding-top: 20px; + position: relative; + top: -75px; + margin-left: 10%; + +} + +.barTop2 { + position: absolute; + left: -10px; + width: 100%; + +} + +.barName { + width: 30%; + height: 100%; + line-height: 2; + margin-left: 30px; +} + +.barHeadline { + font-size: 40px; + font-weight: bold; + color: #fff; + line-height: 1.6; + font-family: "Microsoft YaHei", 微软雅黑; +} + +.barHeadline2 { + font-size: 30px; + color: #fff; + padding-bottom: 20px; +} + +.barSize { + width: 200px; + height: 30px; + position: absolute; + display: flex; + right: 0; + margin-top: 20px; +} + +.barSize img { + width: 20px; + height: 20px; +} + +.barMap { + font-size: 14px; + color: #fff; +} + +.bar { + margin-top: 50px; + display: flex; + /* width: 600px; */ + height: 30px; + position: absolute; + right: 0; + top: 30px; +} + +.barGs { + line-height: 40px; + /* display: flex; + justify-content: center; + text-align: center; */ + margin: 0 20px; + height: 40px; + color: #fff; + font-size: 15px; + /* border-right: #e2e2e2 2px solid; */ +} + +.body { + margin: 20px auto 100px auto; + width: 90%; + max-width: 2000px; + display: flex; + flex-direction: column; + align-items: center; +} + +.bodyTop { + font-size: 40px; + display: flex; + align-items: center; + justify-content: center; + /* border-bottom: 1px solid #ccc; */ + padding: 20px 0; + +} + +.you { + justify-content: center; + align-items: start; +} + +.boxBody { + margin-left: 3.3%; + width: 45%; +} + +.bodyName-1 { + color: #00a587; + font-size: 27px; + font-weight: bold; + width: 100%; + /*height: 50px;*/ + margin-bottom: 20px; +} + +.bodyName-2 { + color: #00a587; + font-weight: bold; + font-size: 22px; + width: 100%; + margin: 35px 0; +} + +.bodyName-3 { + margin-top: 30px; + width: 100%; + line-height: 3; + font-size: 17px; + display: flex; + white-space: pre-wrap; + /*padding-bottom: 50px;*/ + font-family: "Microsoft YaHei", 微软雅黑; +} + +.boxPic { + width: 45%; + height: 500px; + margin: 10px 10px 10px 60px; +} + +.boxPic img { + width: 100%; + height: 80%; + object-fit: fill; + +} + +.boxPic-1 { + width: 45%; + height: 300px; + margin-left: 3.3%; +} + +.bodyPic-1 { + width: 45%; + height: 350px; + margin: 10px 0px 0px 90px; +} + +.bodyName-4 { + margin-top: 20px; + color: #000; + font-size: 30px; + font-weight: bold; + height: 50px; + margin-bottom: 25px; +} + +.xian { + background-color: #00a587; + width: 100px; + height: 2px; +} + +.bodyPic-2 { + height: 350px; + margin: 20px 90px 0px 0px; +} + +.barTop-xiao { + width: 100%; + background-color: #00a587; + padding: 20px 30px; +} + +.barName-Mini { + color: #fff; + font-size: 700; + font-size: 30px; + border-bottom: #ccc 1px solid; + padding-left: 30px; +} + +.bar-Mini { + display: flex; + margin: 20px 0px; +} + +.barGs-Mini { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 70px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.barGs-sm { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 90px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.body-Mini { + width: 100%; +} + +.bodyTop-Mini { + font-size: 30px; + height: 50px; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + margin-top: 20px; +} + +.bodyName-1-Mini { + color: #00a587; + font-size: 28px; + font-weight: bold; + width: 100%; + padding-bottom: 20px; +} + +.bodyName-2-Mini { + color: #00a587; + font-weight: bold; + font-size: 18px; + width: 100%; + /* padding-bottom: 40px; */ +} + +.bodyName-3-Mini { + margin: 30px 0; + width: 100%; + font-size: 16px; + line-height: 28px; +} + +.bodyPic-1-Mini { + width: 90%; + margin: 10px 0; +} + +.bodyName-4-Mini { + padding: 50px 0 30px 0; + color: #000; + font-size: 22px; + font-weight: bold; + width: 90%; +} + +.body-Mini img { + height: 100%; + max-width: 100%; + margin: 30px 0; +} + +.comp a { + text-decoration: none !important; +} + +.boxPic-Mini { + width: 100%; +} + +.boxPic-Mini img { + width: 100%; + height: 100%; +} + +.boxBody-Mini { + width: 100%; + margin-top: 30px; +} + +.borderBottom { + width: 0; + transition: all 0.3s; + height: 3px; + background-color: #fff; + margin: auto; +} + +.barGs:hover .borderBottom { + width: 60px; + margin: auto; +} \ No newline at end of file diff --git a/public/static/css/developmentHistory.css b/public/static/css/developmentHistory.css new file mode 100644 index 0000000..9e989f7 --- /dev/null +++ b/public/static/css/developmentHistory.css @@ -0,0 +1,338 @@ +/* 发展历程 */ +html, +body { + width: 100%; + margin: 0; + padding: 0; +} + +.topPic { + width: 100%; +} + +.barGs:hover { + /* border-bottom: #fff 3px solid; */ + padding-bottom: 15px; + /* border-right: none; */ +} + +.bodyBox, +.bodyBox2 { + cursor: pointer; +} + +.barTop { + display: flex; + width: 90%; + height: auto; + background-color: #00a587; + padding-left: 5%; + padding-top: 20px; + position: relative; + top: -75px; + margin-left: 10%; + +} + +.barTop2 { + position: absolute; + left: -10px; + width: 100%; + +} + +.barName { + width: 30%; + height: 100%; + line-height: 2; + margin-left: 30px; +} + +.barHeadline { + font-size: 40px; + font-weight: bold; + color: #fff; + line-height: 1.6; +} + +.barHeadline2 { + font-size: 30px; + color: #fff; + padding-bottom: 20px; +} + +.barSize { + width: 200px; + height: 30px; + position: absolute; + display: flex; + right: 0; + margin-top: 20px; +} + +.barSize img { + width: 20px; + height: 20px; +} + +@media (max-width: 767px) { + + .bodyBox, + .bodyBox2 { + width: 80% !important; + margin: 10px auto !important; + padding: 10px 0 !important; + display: flex !important; + } +} + + +.barMap { + font-size: 14px; + color: #fff; +} + +.bar { + margin-top: 50px; + display: flex; + /* width: 600px; */ + height: 30px; + position: absolute; + right: 0; + top: 30px; +} + +.barGs { + line-height: 40px; + /* display: flex; + justify-content: center; + text-align: center; */ + margin: 0 20px; + height: 40px; + color: #fff; + font-size: 15px; + /* border-right: #e2e2e2 2px solid; */ +} + +.body { + margin: 20px auto; + width: 100% !important; +} + +.bodyTop { + font-size: 40px; + display: flex; + align-items: center; + justify-content: center; + padding: 20px 0px; +} + +.bodyTop-subtitle { + width: 100%; + line-height: 2; + font-size: 16px; + color: #333; + flex-wrap: wrap; + padding: 20px 50px; + margin: 0 auto; + text-align: center; +} + +.bodyBox { + width: 70%; + margin: 10px auto; + padding: 10px 0; + display: flex; +} + +.bodyBox2 { + width: 70%; + padding: 10px 0; + margin: 0 auto; + display: -webkit-box; + background-color: #edeaea; +} + +.bodyBox:hover { + box-shadow: 0px 10px 5px #ccc; +} + +.bodyBox2:hover { + box-shadow: 0px 10px 5px #ccc; +} + +.bodyBox-year { + width: 50%; +} + +.year { + font-size: 25px; + float: right; + margin-right: 20px; +} + +.certer-line { + width: 20%; + padding-top: 20px; +} + +.yuan { + width: 20px; + height: 20px; + border-radius: 50%; + border: #00a587 5px solid; + margin: 5px auto; +} + +.xian { + width: 2px; + height: 100px; + background-color: #ccc; + margin-left: 9px; + margin-top: 10px; +} + +.bodyThing { + width: 40%; + margin-left: 20px; +} + +.thing1 { + color: #00a587; + font-size: 20px; + display: flex; + flex-wrap: wrap; +} + +.thing2 { + color: #333; + font-size: 16px; + font-weight: 300; + display: flex; + flex-wrap: wrap; +} + +.bodyThing-2 { + width: 50%; +} + +.thing3 { + color: #00a587; + font-size: 20px; + width: 97%; + text-align: right; + +} + +.thing4 { + width: 97%; + color: #333; + font-size: 16px; + font-weight: 300; + text-align: right; + +} + +.bodyBox-year-2 { + width: 40%; +} + +.year2 { + font-size: 24px; + float: left; + margin-left: 20px; +} + +.barTop-xiao { + width: 100%; + background-color: #00a587; + box-sizing: border-box; + padding: 20px 30px; +} + +.barName-Mini { + color: #fff; + font-size: 700; + font-size: 30px; + border-bottom: #ccc 1px solid; + padding-left: 30px; +} + +.bar-Mini { + display: flex; + margin: 20px 0px; +} + +.barGs-Mini { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 70px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.barGs-sm { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 90px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.body-Mini { + width: 100%; +} + +.bodyTop-Mini { + font-size: 30px; + height: 50px; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + margin-top: 20px; +} + +.bodyTop-subtitle-Mini { + width: 95%; + margin: 10px 2.5%; + line-height: 1.3; + font-size: 14px; + color: #333; + flex-wrap: wrap; + margin: 0 auto; + text-align: center; +} + +.bodyBox-year-Mini { + width: 30%; +} + +.bodyThing-Mini { + width: 60%; + margin-left: 20px; + +} + +#box { + width: 100%; +} + +.borderBottom { + width: 0; + transition: all 0.3s; + height: 3px; + background-color: #fff; + margin: auto; +} + +.barGs:hover .borderBottom { + width: 60px; + margin: auto; +} \ No newline at end of file diff --git a/public/static/css/enterpriseCulture.css b/public/static/css/enterpriseCulture.css new file mode 100644 index 0000000..a6e6466 --- /dev/null +++ b/public/static/css/enterpriseCulture.css @@ -0,0 +1,183 @@ +/* 企业文化 */ +body { + margin: 0; + padding: 0; +} + +.topPic { + width: 100%; + /* margin: 0 50px; */ + text-align: center; +} + +.barGs:hover { + /* border-bottom: #fff 3px solid; */ + padding-bottom: 15px; + /* border-right: none; */ +} + +.barTop { + display: flex; + width: 90%; + height: auto; + background-color: #00a587; + padding-left: 5%; + padding-top: 20px; + position: relative; + top: -75px; + margin-left: 10%; + +} + +.barTop2 { + position: absolute; + left: -10px; + width: 100%; + +} + +.barName { + width: 30%; + height: 100%; + line-height: 2; + margin-left: 30px; +} + +.barHeadline { + font-size: 40px; + font-weight: bold; + color: #fff; + line-height: 1.6; +} + +.barHeadline2 { + font-size: 30px; + color: #fff; + padding-bottom: 20px; +} + +.barSize { + width: 200px; + height: 30px; + position: absolute; + display: flex; + right: 0; + margin-top: 20px; +} + +.barSize img { + width: 20px; + height: 20px; +} + +.barMap { + font-size: 14px; + color: #fff; +} + +.bar { + margin-top: 50px; + display: flex; + /* width: 600px; */ + height: 30px; + position: absolute; + right: 0; + top: 30px; +} + +.barGs { + line-height: 40px; + /* display: flex; + justify-content: center; + text-align: center; */ + margin: 0 20px; + height: 40px; + color: #fff; + font-size: 15px; + /* border-right: #e2e2e2 2px solid; */ +} + +.bodyHead { + display: flex; + text-align: center; + justify-content: center; + font-size: 40px; + /* border-bottom: 1px solid #ccc; */ + padding: 20px; +} + +.bodyPic { + align-items: center; + width: 80%; + max-width: 100%; + margin: 20px 10%; +} + +.body { + width: 90%; + margin: 20px 5%; +} + +.barTop-xiao { + width: 100%; + background-color: #00a587; + padding: 20px 30px; +} + +.barName-Mini { + color: #fff; + font-size: 700; + font-size: 30px; + border-bottom: #ccc 1px solid; + padding-left: 30px; +} + +.bar-Mini { + display: flex; + margin: 20px 0px; +} + +.barGs-Mini { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 70px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.barGs-sm { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 90px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.bodyTop-Mini { + font-size: 30px; + height: 50px; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + margin-top: 20px; +} + +.borderBottom { + width: 0; + transition: all 0.3s; + height: 3px; + background-color: #fff; + margin: auto; +} + +.barGs:hover .borderBottom { + width: 60px; + margin: auto; +} \ No newline at end of file diff --git a/public/static/css/footer.css b/public/static/css/footer.css new file mode 100644 index 0000000..c0fd20c --- /dev/null +++ b/public/static/css/footer.css @@ -0,0 +1,10 @@ +.footer_box { + display: flex; + justify-content: center; + background-color: rgb(12, 50, 16); + color: blueviolet; +} + +.ICPNumber { + color: #7a7a7a; +} \ No newline at end of file diff --git a/public/static/css/headNavFoot.css b/public/static/css/headNavFoot.css new file mode 100644 index 0000000..08628e5 --- /dev/null +++ b/public/static/css/headNavFoot.css @@ -0,0 +1,1058 @@ +/*public*/ +a { + text-decoration: none !important; +} + +.f1 { + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 1; + font-size: 15px; +} + +.f2 { + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + font-size: 13px; +} + +.f3 { + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 3; + font-size: 13px; +} + +.headerBox a { + text-decoration: none !important; +} + +.f7 { + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 7; + font-size: 13px; +} + +.f5 { + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 5; + font-size: 13px; +} + +.dNone { + display: none !important; +} + +.df_jc_ac { + display: flex; + justify-content: center; + align-items: center; +} + +.df_jw_ac { + display: flex; + justify-content: space-between; + align-items: center; +} + +.df_jc_ac_fc { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.dBlock { + display: block !important; +} + +.index { + background: #f3f3f3; +} + +/*移动端*/ +@media (min-width: 576px) { + .container { + max-width: 540px; + } + + /*.phoneReactive {*/ + /* height: 315px !important;*/ + /*}*/ + + .posterReactive { + height: 344px !important; + } + + .showReactive { + /*height: 744px!important;*/ + } + + .showsBox { + width: 100% !important; + } + + .productItem { + height: 520px !important; + } +} + +@media (min-width: 768px) { + .container { + max-width: 720px; + } + + /*.phoneReactive {*/ + /* height: 420px !important;*/ + /*}*/ + + .posterReactive { + height: 400px !important; + } + + .phoneProductInfoReactive { + height: 420px !important; + } + + /*.showReactive {*/ + /* height: 440px !important;*/ + + /*}*/ + +} + +@media (min-width: 991px) { + .container { + max-width: 960px; + } + + /*.phoneReactive {*/ + /* height: 471px !important;*/ + /*}*/ + + .posterReactive { + height: 472px !important; + } + + .phoneProductInfoReactive { + height: 520px !important; + } + + .showReactive { + height: 650px !important; + } + + .show-items { + height: 337px !important; + } + + .productsBigBox { + max-width: 1028px !important; + } + +} + +@media (min-width: 1200px) { + .container { + max-width: 1140px; + } + + /*.phoneReactive {*/ + /* height: 700px !important;*/ + /*}*/ + + .posterReactive { + height: 515px !important; + } + + .phoneProductInfoReactive { + height: 620px !important; + } + + .showReactive { + height: 715px !important; + + } + + .aboutCertificate { + display: -webkit-box; + overflow: hidden; + position: absolute !important; + bottom: 30px !important; + } + + .show-items { + height: 370px !important; + } + + .productsBigBox { + max-width: 1248px !important; + } + +} + +@media (min-width: 1540px) { + .container { + max-width: 1440px; + } + + /*.phoneReactive {*/ + /* height: 900px !important;*/ + /*}*/ + + .posterReactive { + height: 605px !important; + } + + .phoneProductInfoReactive { + height: 720px !important; + } + + .showReactive { + height: 834px !important; + } + + .show-items { + height: 429px !important; + } + + .productsBigBox { + max-width: 1588px !important; + } +} + +@media (max-width: 1273px) { + .phoneHeadNone { + display: none !important; + overflow: hidden; + } + + .phoneBlock-head { + display: flex !important; + justify-content: right; + justify-content: flex-end; + padding-left: 55%; + margin-right: 4%; + width: 100%; + } + + .phoneMoreBlockImportant { + display: block !important; + ; + } +} + +@media (max-width: 991px) { + .phoneNone { + display: none !important; + } + + .showLine { + border-right: 1px solid rgb(51, 186, 164) !important; + } +} + +@media (max-width: 993px) { + .phoneBlock { + display: block; + } + + .phoneBlockImportant { + display: block !important; + ; + } + + .phoneShowContentBoxFlex { + display: flex !important; + } + + .phone-f-c { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + } + + .phone-w-100 { + width: 100% !important; + } + + .phoneFoot-df_jc_ac_fc { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column !important; + } + + .phoneShowItem { + display: flex; + flex-direction: column; + !important; + justify-content: center; + !important; + align-items: center; + !important; + } +} + +@media (max-width: 588px) { + .phoneSmallNone { + display: none !important; + } + + .phoneSmallBlock { + display: block; + } + + /*.phoneReactive {*/ + /* height: 215px !important;*/ + /*}*/ + + .swiper-button-prev { + display: none !important; + } + + .swiper-button-next { + display: none !important; + } + + .posterReactive { + height: 230px !important; + } + + .phoneProductInfoReactive { + height: 400px !important; + } + + .showsBox { + width: 100% !important; + } + + .showButtonBox .showButton { + width: 85%; + } + + .showLeftButton>img, + .showRightButton>img { + cursor: pointer; + padding: 0; + } + + .showReactive { + /*height: 550px!important;*/ + } + + .showImg { + /*height: 430px!important;*/ + } + + .productItem { + height: 520px !important; + } +} + +/* max-width:570px */ +@media (max-width:575px) { + .showLine { + border-right: 1px solid rgb(250, 250, 250) !important; + } +} + +@media (max-width: 350px) { + .psHead { + width: 185px !important; + } + + .posterReactive { + height: 162px !important; + } + + /*.phoneReactive {*/ + /* height: 142px !important;*/ + /*}*/ + + .pscontainer { + padding: 0 !important; + } + + .pscontainer>.productsBox { + padding: 20px 0 20px 0 !important; + } + + .phoneProductInfoReactive { + height: 350px !important; + } + + .productItem { + height: 520px !important; + } +} + +/*修改*/ +.phoneBlock-head { + padding-left: 150px; +} +.phoneReactive{ + width: 100%!important; + height: 49vw!important; +} + +/*pc端*/ + +/*menu*/ +/* .productMenusItem{ + color: black; +} */ +.phoneHideBox { + z-index: 9999; + backdrop-filter: blur(2px); + background: rgba(0, 10, 10, 0.5); + color: white; + height: 100vh; + width: 100%; + overflow-y: auto; + position: fixed; +} + +.phoneHideBox::-webkit-scrollbar-track { + background: #999; + border-radius: 0; +} + +.phoneHideBox::-webkit-scrollbar-thumb { + background: #f7f7f7; + border-radius: 0; +} + +.phoneHideBox::selection { + background: #b3d4fc; + text-shadow: none; +} + +/*nav*/ +.swiper-slide img { + position: relative; + left: auto; + top: auto; + /* transform: translate(0) scale(1.02); */ + width: 100%; + max-width: none; + transition: all 1.8s cubic-bezier(0.250, 0.460, 0.450, 0.940); +} + +.swiper-slide-active img, +.swiper-slide-duplicate-active img { + transition: 1s linear; + transform: translate(0) scale(1) !important; + z-index: 99; +} + +.navHeader { + display: flex; + flex-direction: column; +} + +.navHeader>a { + padding: 30px; + cursor: pointer; + border-bottom: 1px solid #e2e3e5; + font-weight: 600; + transition: 0.6s; + color: white !important; +} + +.navHeader>a:hover { + background: #e2e3e5; + color: #4e555b; +} + +.fMenu { + padding: 30px; + cursor: pointer; + border-bottom: 1px solid #e2e3e5; + font-weight: 600; + transition: 0.6s; +} + +.fMenu:hover { + background: #e2e3e5; + color: #4e555b; +} + +.sMenu { + font-weight: 600; + padding: 30px 30px 30px 45px; + cursor: pointer; + transition: 0.6s; + color: white !important; +} + +.sMenuBox { + display: flex; + flex-direction: column; +} + +.sMenu:hover { + background: #e2e3e5; + color: #4e555b; +} + +/*head*/ +.headerBox { + background: #11bea0; + position: fixed; + margin-left: 0; + margin-right: 0; + width: 100%; + margin-bottom: 0; + z-index: 1001; + padding: 3px; +} + +.headList { + margin-left: 40%; + margin-right: 0; + display: flex; + justify-content: space-between; + align-items: center; + padding-left: 20px; + transition: 0.4s; +} + +.headList>.f1 { + font-weight: 600; + margin: 0 20px 0 10px; + cursor: pointer; + color: white; + font-size: 16px; + transition: 0.4s; + height: 65px; + line-height: 65px; + width: 70px; + text-align: center; +} + +.headList>.f1:after { + content: ' '; + position: relative; + z-index: 2; + display: block; + margin: -2px 0 0 0; + height: 2px; +} + +.headList>.f1:hover:after { + height: 2px; + animation: ad_width .2s linear forwards; + background: #ffffff; +} + +@keyframes ad_width { + from { + width: 0 + } + + to { + width: 100% + } +} + + + +.active { + background: #4e555b; + color: white; + font-weight: 500; +} + +.headerIcon { + height: 115px; + position: absolute; + margin: -11px 1.5%; + width: 315px; + padding: 0 !important; + z-index: -15; +} + +.headerIcon>img { + height: 50%; + /* width: 80%; */ + /* position: absolute; */ + /* z-index: -50; */ + margin: 15px 60px; +} + +.headerIcon2 { + height: 84px; + position: absolute; + margin: -11px 1.5%; + width: 263px; + padding: 0 !important; + display: none; +} + +.headerIcon2>img { + height: 50%; + margin: 20px 60px 20px 0; +} + +.phoneBlock>div { + padding: 20px 10px 25px 16px; +} + +.search { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.search>img { + cursor: pointer; + height: 20px; + width: 20px; +} + +.moreButton { + display: none; +} + +.moreButton>img { + cursor: pointer; + height: 20px; + width: 20px; +} + +.index a { + text-decoration: none !important; +} + +.messagePhone { + padding: 6px 10px 0 16px !important; + color: white; +} + +.messagePhone>div:nth-of-type(1) { + font-size: 18px; + !important; +} + +.messagePhone>div:nth-of-type(2) { + font-weight: 600; + font-size: 24px; + !important; + width: 180px; +} + +/*foot*/ +footer { + padding: 0 !important; +} + +.footBgBox { + display: flex; + flex-wrap: wrap; + padding: 0; + position: relative; +} + +.footItem { + padding: 0; + position: relative; + height: 110px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.footItem>img { + position: absolute; + height: 100%; + width: 100%; + object-fit: cover; +} + +.footContent { + color: white; + position: relative; +} + +.footTitle { + font-weight: 700; + font-size: 24px; +} + +.footText { + font-size: 14px; +} + +.footBigBox { + width: 100%; + color: white; + background: #222222; + padding: 30px 5% 30px 5%; +} + +.footBox { + width: 100%; +} + +.footLeftBoxLeft { + display: flex; + justify-content: left; + flex-direction: column; +} + +.footLeftBox { + padding-left: 0; +} + +.footLeftBox>div { + padding-left: 0; +} + +.footLeftTitle { + font-weight: 550; + font-size: 18px; +} + +.footLine { + margin: 20px auto; + width: 100%; + height: 1px; + background: #7a7a7a; +} + +.footLeftContent { + display: flex; + justify-content: left; + flex-direction: column; + color: #7a7a7a; + font-weight: 550; +} + +.footLeftContentItem { + margin: 5px 0; + cursor: pointer; + color: #7a7a7a !important; + +} + +.footRightTitle { + font-weight: 550; + font-size: 18px; +} + +.footRightContent { + display: flex; + justify-content: left; + flex-direction: column; + color: #7a7a7a; + font-weight: 550; +} + +.footRightContent>a { + margin: 5px 0; + cursor: pointer; +} + +.footRightPhone { + display: flex; + justify-content: left; + align-items: center; +} + +.footRightPhoneContent { + margin-left: 10px; +} + +.footRightPhoneContentText { + color: #7a7a7a; + font-size: 8px; +} + +.footRightPhoneContentTitle { + font-weight: 550; + color: white; + font-size: 22px; +} + +.footRightContentItem { + margin: 5px 0; + cursor: pointer; +} + +.footRightBoxRight { + display: flex; + justify-content: space-around; + /*align-items: center;*/ +} + +.footRightBoxImgItem { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + margin: 5px; + width: 125px; + height: 100%; +} + +.footRightBoxImgItem>img { + height: 100%; + width: 100%; +} + +.footRightBoxImgItemText { + font-size: 8px; + color: #7a7a7a; + text-align: center; +} + +.footFootBox { + margin: 20px auto; + width: 100%; +} + +.footFootBox>div { + color: #7a7a7a; + font-size: 15px; + font-weight: 550; + font-family: "Microsoft YaHei", 微软雅黑; +} + +/*nav*/ +.swiper { + width: 100%; + height: 900px; +} + +.swiper-slide>img { + height: 100% !important; + width: 100% !important; + object-fit: fill; +} + +.swiper-pagination>span { + cursor: pointer; +} + +.swiper-button-prev:after { + color: #989899 !important; +} + +.swiper-button-next:after { + color: #989899 !important; +} + +.swiper-pagination-bullet-active { + background: #11bea0 !important; +} + +.MenuActive { + border-bottom: 1px solid #4e555b; + background: #e2e3e5; + color: #4e555b; +} + +.navBigBox { + position: relative; +} + +.navBox { + display: -webkit-box; + overflow: hidden; + position: relative; + right: 0; + transition: 1s; +} + +.navItem { + cursor: pointer; + height: 650px; + width: 100%; + position: relative; + right: 0; + transition: 0.5s; +} + +.navItem>img { + height: 100%; + width: 100%; + object-fit: cover; + position: absolute; + right: 0; +} + +.navSmallItem { + position: absolute; + display: flex; + justify-content: space-evenly; + align-items: center; + bottom: 0; + width: 100%; + margin: 30px auto; +} + +.navIcon { + position: absolute; + display: flex; + justify-content: space-between; + align-items: center; + height: 500px; + top: 0; + left: 0; + width: 100%; +} + +.navIcon>div { + height: 50px; + width: 50px; + cursor: pointer; + margin: 0 40px; +} + +.navIcon img { + height: 100%; + width: 100%; +} + +.navSmallItem>img { + height: 12%; + width: 12%; + object-fit: cover; + opacity: 0.3; +} + +.navSmallItem>.navActive { + opacity: 1; +} + +/*title*/ +.title { + text-align: center; + margin: 70px auto; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.titleTop { + display: flex; + justify-content: center; + align-items: center; +} + +.titleTop>div { + margin: 0 5px 0 5px; +} + +.titleMiddle { + font-size: 28px; + font-weight: 800; + margin: 0 10px 0 10px; +} + +.titleAside { + display: flex; + justify-content: center; + align-items: center; +} + +.titleAside>div { + margin: 0 5px 0 5px; + height: calc(var(--i)*10px); + opacity: calc(var(--i)*0.2); + width: 5px; + background: #24c3a9; +} + +.titleBottom { + font-weight: 600; + font-family: "Microsoft YaHei", 微软雅黑; +} + +.titleBottom>span:nth-of-type(1) { + color: #2faf94; +} + +.titleBottom>span:nth-of-type(2) { + color: #e1e1e1; +} + +/*搜索*/ + +.searchBox:focus { + outline: none; +} + +.searchBigBox { + height: 0; + width: 100%; + position: fixed; + z-index: 99999; + top: 75px; + left: 0; + text-align: center; + transition: 0.8s; + background: #11bea0; + padding-top: 0; +} + +.searchBox { + height: 80%; + width: 80%; + margin: 0 auto; + border: none; + border-radius: 10px 10px 10px 10px; + display: none; + transition: 0.4s; + padding-left: 20px !important; + +} + +.searchDetail { + width: 80%; + display: none; + background: white; + margin: 0 auto; + text-align: left; + border-radius: 0 0 10px 10px; +} + +.searchDetailItem { + padding: 20px; + text-decoration: none !important; + display: inline-block; + width: 100%; + color: #000000; + overflow: hidden; + overflow-y: visible; + overflow-x: visible; +} + +/*score*/ +::-webkit-scrollbar { + width: 10px; + background-color: white; +} + +::-webkit-scrollbar-thumb { + border-radius: 20px; + background: linear-gradient(#ffffff, #7cbe8b, #429b57, #1e7e34); +} \ No newline at end of file diff --git a/public/static/css/header.css b/public/static/css/header.css new file mode 100644 index 0000000..38016cc --- /dev/null +++ b/public/static/css/header.css @@ -0,0 +1,6 @@ +.header_box { + display: flex; + justify-content: center; + background-color: aqua; + color: blueviolet; +} \ No newline at end of file diff --git a/public/static/css/honour.css b/public/static/css/honour.css new file mode 100644 index 0000000..1618769 --- /dev/null +++ b/public/static/css/honour.css @@ -0,0 +1,320 @@ +/* 荣誉资质 */ +body { + margin: 0; + padding: 0; + height: 100%; +} + + + +.barGs:hover { + /* border-bottom: #fff 3px solid; */ + padding-bottom: 15px; + /* border-right: none; */ +} + +.barTop { + display: flex; + width: 87%; + height: auto; + background-color: #00a587; + padding-left: 5%; + padding-top: 20px; + position: relative; + top: -75px; + margin-left: 13%; + +} + +.barTop2 { + position: absolute; + left: -10px; + width: 100%; + +} + +.barName { + width: 30%; + height: 100%; + line-height: 2; + margin-left: 30px; +} + +.barHeadline { + font-size: 40px; + font-weight: bold; + color: #fff; + line-height: 1.6; +} + +.barHeadline2 { + font-size: 30px; + color: #fff; + padding-bottom: 20px; +} + +.barSize { + width: 200px; + height: 30px; + position: absolute; + display: flex; + right: 0; + margin-top: 20px; +} + +.barSize img { + width: 20px; + height: 20px; +} + +.barMap { + font-size: 14px; + color: #fff; +} + +.bar { + margin-top: 50px; + display: flex; + /* width: 600px; */ + height: 30px; + position: absolute; + right: 0; + top: 30px; +} + +.barGs { + line-height: 40px; + /* display: flex; + justify-content: center; + text-align: center; */ + margin: 0 20px; + height: 40px; + color: #fff; + font-size: 15px; + /* border-right: #e2e2e2 2px solid; */ +} + +.body { + margin: 20px auto; + width: 100%; + max-width: 1500px; +} + +.bodyTop { + width: 100%; + font-size: 40px; + display: flex; + align-items: center; + justify-content: center; + border-bottom: 1px solid #ccc; + padding: 20px 0; +} + +.bodyPicBox { + width: 100%; + display: flex; + float: left; + flex-wrap: wrap; + margin: 50px 0; +} + +.bodyBox { + margin: 55px 2.5%; + width: 20%; + transition: all 1s; + cursor: pointer; + height: 200px; + background: #f2f2f2; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + overflow: hidden; +} + +.bodyBox:hover.bodyBox > img { + transform: scale(1.1); +} +.topPic { + width: 70%; + height: 150px; + object-fit: contain; + transition: all 1s; +} +.bodyPic { + width: 20%; + margin: 25px 25px 5%; + height: 70%; +} + +.PicName { + color: #999; + font-size: 16px; + display: flex; + width: 100%; + padding: 10px; + align-items: center; + justify-content: center; + background-color: #f2f2f2; + z-index: 99; +} + +.bodyBox:hover .PicName { + color: #fff; + background-color: #d94444; +} + +.bodyBox:hover .bodyPic { + width: 270px; + height: 220px; + margin: 15px 15px 10px; +} + + +.barTop-xiao { + width: 100%; + background-color: #00a587; + padding: 20px 30px; +} + +.barName-Mini { + color: #fff; + /*font-size: 700;*/ + font-size: 30px; + border-bottom: #ccc 1px solid; + padding-left: 30px; +} + +.bar-Mini { + display: flex; + margin: 20px 0px; +} + +.barGs-Mini { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 70px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.barGs-sm { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 90px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.body-Mini { + width: 100%; + height: 350px; + cursor: pointer; +} +.bodyBox-Mini:hover .PicName-Mini { + color: #fff; + background-color: #d94444; +} + + +.bodyTop-Mini { + font-size: 30px; + height: 50px; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + margin-top: 20px; +} + +.bodyPicBox-Mini { + width: 90%; + margin: 10px 5%; + display: flex; + float: left; + flex-wrap: wrap; + margin-top: 50px; +} + +.bodyPic-Mini { + width: 100%; + height: 150px; + object-fit: contain; + transition: 0.4s; +} + +.bodyBox-Mini { + width: 40%; + margin: 10px 5%; + height: 300px; +} + + +.PicName-Mini { + color: #999; + font-size: 16px; + display: flex; + width: 100%; + height: 60px; + align-items: center; + justify-content: center; + background-color: #f2f2f2; + transition: 0.4s; +} + +.borderBottom { + width: 0; + transition: all 0.3s; + height: 3px; + background-color: #fff; + margin: auto; +} + +.barGs:hover .borderBottom { + width: 60px; + margin: auto; +} + +#Picture_to_view { + display: none; + width: 100%; + height: 1000px; + background-color: #000; + color: #f2f2f2; + position: fixed; + z-index: 1000; + top: 0; + +} + +#hide { + position: absolute; + padding: 10px 20px; + align-items: center; + font-size: xx-large; + font-weight: 700; + top: 20px; + right: 20px; + cursor: pointer; +} + +.HimgBox { + width: 60%; + margin: 5% 20%; + height: 600px; + position: relative; +} + +.HimgBox>img { + position: absolute; + height: 100%; + width: 100%; + object-fit: contain; + +} \ No newline at end of file diff --git a/public/static/css/index.css b/public/static/css/index.css new file mode 100644 index 0000000..3d99924 --- /dev/null +++ b/public/static/css/index.css @@ -0,0 +1,800 @@ +/*index.css*/ +/*nav*/ +.MenuActive { + border-bottom: 1px solid #4e555b; + background: #e2e3e5; + color: #4e555b; +} + +.navBigBox { + position: relative; + +} + +.navBox { + display: -webkit-box; + overflow: hidden; + position: relative; + right: 0; + transition: 1s; + +} + +.navItem { + cursor: pointer; + height: 650px; + width: 100%; + position: relative; + right: 0; + transition: 0.5s; +} + +.navItem>img { + height: 100%; + width: 100%; + object-fit: cover; + position: absolute; + right: 0; +} + +.navSmallItem { + position: absolute; + display: flex; + justify-content: space-evenly; + align-items: center; + bottom: 0; + width: 100%; + margin: 30px auto; + +} + +.navSmallItem>img { + height: 12%; + width: 12%; + object-fit: cover; + opacity: 0.3; +} + +.navSmallItem>.navActive { + opacity: 1; +} + +/*title*/ +.title { + text-align: center; + margin: 70px auto; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.titleTop { + display: flex; + justify-content: center; + align-items: center; +} + +.titleTop>div { + margin: 0 5px 0 5px; +} + +.titleMiddle { + font-size: 28px; + font-weight: 800; + margin: 0 10px 0 10px; +} + +.titleAside { + display: flex; + justify-content: center; + align-items: center; +} + +.titleAside>div { + margin: 0 5px 0 5px; + height: calc(var(--i)*10px); + opacity: calc(var(--i)*0.2); + width: 5px; + background: #24c3a9; +} + +.titleBottom { + font-weight: 600; +} + +.titleBottom>span:nth-of-type(1) { + color: #2faf94; +} + +.titleBottom>span:nth-of-type(2) { + color: #e1e1e1; +} + +/*产品展示*/ +.showButtonBox { + margin: 40px 0 40px 0; + display: flex; + justify-content: left; + align-items: center; +} + +.showButtonBox>* { + display: flex; + justify-content: center; + align-items: center; + background: #ffffff; + padding: 15px; + cursor: pointer; + /*font-weight: 550;*/ + margin: 10px auto; +} + +.showButton>div { + font-size: 15px !important; +} + +.showActive { + background: #33baa4 !important; + color: white !important; +} + +.showButton { + transition: 0.2s; + color: black; +} + +.showButton:hover { + background: #33baa4 !important; + color: white !important; +} + +.showButtonBox img { + margin-right: 10px; + object-fit: cover; +} + +.shows { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + margin: 50px auto; + padding: 0 0 20px 0; + background: #ededed; + overflow: hidden; +} + +.show { + height: 100%; + background: #7abaff; +} + +/*xiugai*/ +.showsBox { + height: 100%; +} + +.show-item-poster { + margin-left: 0 !important; + height: 100%; + width: 60%; + margin-right: 30px; +} + +.show-item-poster img { + height: 100%; + width: 100%; + /*object-fit: scale-down;*/ + object-fit: fill; +} + +.show-itemsBox { + height: 100%; + display: flex; + justify-content: space-evenly; + /*align-items: center;*/ + width: 100%; + padding-left: 4px; +} + +.show-itemsBox a { + display: inline; +} + +.show-items { + padding: 0 12px 24px 12px; + height: 300px; + width: 100%; +} + +.show-item { + height: 100%; + width: 100%; + position: relative; + /*background: #0b2e13;*/ + cursor: pointer; + transition: 0.8s; + overflow: hidden; + border-left: 1px solid #e4e4e4; + border-right: 1px solid #e4e4e4; + border-top: 1px solid #e4e4e4; +} + +.show-item:hover.show-item>img { + height: 90%; +} + +.show-item>img { + position: absolute; + height: 85%; + width: 100%; + object-fit: contain; + top: 0; + right: 0; + transition: 0.8s; +} + +.show-item-content { + position: absolute; + bottom: -43px; + right: 0; + z-index: 999; + background: rgba(48, 182, 158, 0.8); + width: 100%; + padding: 6px 0 12px 0; + backdrop-filter: blur(4px); + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + color: white; + transition: 0.8s; +} + +.show-item:hover .show-item-content { + bottom: 0; +} + +.show-item-detail { + margin-top: 10px; + border: 1px solid white; + border-radius: 5px; + padding: 2px 20px; + transition: 0.4s; +} + +.show-item-detail:hover { + background: white; + color: rgb(48, 182, 158); + border: 1px solid rgb(48, 182, 158); + +} + +.showLine { + border-right: 1px solid rgb(250, 250, 250); +} + +/*xiugai*/ + +/*show2*/ +._showContentBox { + display: none; + height: 100%; + width: 80%; + align-items: center; + flex-direction: column; + position: relative; +} + +._showContentIcon { + position: absolute; + border-left: 30px solid #11bea0; + border-right: 30px solid transparent; + border-top: 30px solid transparent; + transform: rotate(135deg); + margin: 0 auto; + top: 0; +} + +._showContentText { + font-size: 15px; + margin-bottom: 30px; +} + +._showContent { + width: 100%; + background: #11bea0; + color: white; + padding: 10px 10% 0 10%; + position: relative; + overflow: hidden; +} + +._showContentType { + font-size: 25px; +} + +/*about*/ +.aboutsBox { + position: relative; + background: white; + +} + +.aboutsBg { + height: 496px; + position: absolute; + width: 100%; +} + +.aboutsBg>img { + height: 100%; + width: 100%; + object-fit: cover; +} + +.abouts { + position: relative; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.about { + width: 100%; + height: 100%; + background: white; + margin: 270px 0 0 0; + border: 1px solid #d9d9d9; + padding: 30px; + display: flex; + justify-content: space-evenly; + position: relative; + align-items: stretch; +} + +.aboutImg { + width: 100%; + position: relative; +} + +.aboutImg>img { + height: 100%; + width: 100%; + object-fit: cover; +} + +.aboutContent { + height: 100%; + width: 100%; + padding-left: 30px; +} + +.aboutTitle { + color: #11bea0; + font-weight: 550; + font-size: 24px !important; +} + +.aboutSmallTitle { + font-weight: 550; + font-size: 16px !important; +} + +.aboutContentText { + margin: 20px auto; + color: #9b9b9b; + font-size: 14px; +} + +.aboutCertificate { + display: -webkit-box; + overflow: hidden; + position: relative; +} + +.aboutCertificate>div { + position: relative; + right: 0; + padding-left: 10px; +} + +.aboutCertificate>div>img { + height: 150px; + width: 100%; + /*object-fit: cover;*/ + object-fit: contain; +} + +/*about2*/ +.aboutsBox2 { + display: none; + position: relative; + background: white; +} + +._aboutContent { + height: 100%; + width: 100%; +} + +._aboutsBg { + height: 285px; + position: absolute; + width: 100%; +} + +._aboutsBg>img { + height: 100%; + width: 100%; + object-fit: cover; +} + +.aboutHeadBox { + padding: 30px; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + background: white; +} + +.aboutHeadTitle { + color: #11bea0; + font-size: 28px; + font-weight: 550; +} + +.aboutHeadMiddle { + color: #11bea0; + font-size: 28px; +} + +.aboutHeadBottom { + color: #d7d7d7; + +} + +._about { + width: 90%; + height: 100%; + background: white; + margin: 100px 0 0 0; + border: 1px solid #d9d9d9; + padding: 30px; + display: flex; + justify-content: space-evenly; + align-items: center; +} + +/*new*/ +.newsBox { + background: white; + padding-bottom: 70px; +} + +.newsBox>.title { + margin: 0 auto; + padding: 70px 0; +} + +.news { + display: flex; + justify-content: center; + align-items: center; +} + +.news>div { + padding: 0; + height: 600px; +} + +.newLeft { + + display: flex; + justify-content: left; + position: relative; + background: #f8f8f8; +} + +.newBg { + height: 200px; + background: #11bea0; + width: 100%; + position: absolute; +} + +.newLeftContent { + position: relative; + padding: 0 30px; +} + +.newLeftContent>div { + margin: 30px 0; +} + +.newLeftContentHead { + color: white; +} + +.newLeftContentHead>.newLeftContentHeadTitle:nth-of-type(1) { + font-size: 24px !important; + margin-bottom: 10px; +} + +.newLeftContentHeadText { + font-size: 12px; +} + +.newLeftContent>div { + margin-bottom: 30px; +} + +.newLeftContentImg>img { + height: 100%; + width: 100%; + object-fit: cover; +} + +.newLeftContentText>div { + color: #909090; + font-size: 18px; +} + +.newLeftContentTime { + display: flex; + /*justify-content: space-between;*/ + align-items: center; + width: 100%; + position: absolute; + bottom: 0; +} + +.newLeftContentTime>div:nth-of-type(1) { + color: #a8a8a8; + margin-right: 15px; +} + +.newLeftContentTime>div:nth-of-type(2) { + font-size: 14px; + color: #a8a8a8; +} + +.newRight { + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + margin-left: 40px; +} + +.newRight>div { + height: 50%; + width: 100%; + overflow: hidden; + padding: 30px; + background: #f8f8f8; +} + +.newRight>div:nth-of-type(1) { + margin-bottom: 5%; +} + +.new2RightHeadRight { + margin-top: 20px; +} + +.newRightHead { + display: flex; + justify-content: space-between; + align-items: center; +} + +.newRightHeadLeft>div:nth-of-type(1) { + font-size: 28px; +} + +.newRightHeadLeft>div:nth-of-type(2) { + color: #999999; +} + +.newRightHeadRight { + display: flex; +} + +.newButton { + height: 15px; + width: 15px; + background: #dedede; + border-radius: 50%; + margin: 0 5px; + cursor: pointer; + transition: 0.6s cubic-bezier(0.58, -0.58, 0, 2.13); +} + +.newButtonActive { + height: 15px; + width: 30px; + border-radius: 25px; + background: #11bea0; +} + +.newRightTop { + position: relative; + overflow: hidden; +} + +.newRightContentBox { + display: -webkit-box; + overflow: hidden; + position: relative; + transition: 0.4s; +} + +/*.newRightContentBox:hover{*/ +/* background: white;*/ +/*}*/ +.newRightContent { + display: flex; + justify-content: space-between; + align-items: center; + position: relative; + right: 0; + user-select: none; + width: 50%; +} + +.newRightContent>div { + padding-right: 30px; + width: 100%; + height: 100%; +} + +.newRightContentLeft { + cursor: pointer; + position: relative; +} + +.newRightContentLeftTitle { + margin: 15px auto; + color: #2d2d2d; + font-weight: 550; + font-size: 14px; +} + +.newRightContentLeftText { + color: #a8a8a8; +} + +.newRightContentRightTitle { + margin: 15px auto; + color: #2d2d2d; + font-weight: 550; + font-size: 14px; +} + +.newRightContentRightText { + color: #a8a8a8; +} + +.newRightContentLeftTime { + display: flex; + justify-content: space-between; + margin-top: 35px; + bottom: 0; +} + +/*new2*/ +.news2 { + display: none; +} + +.new2Item { + background: #f8f8f8; + padding: 20px; +} + +.new2Content { + display: flex; + justify-content: space-between; + align-items: center; +} + +.new2Content>div:nth-of-type(1) { + padding-right: 30px; +} + +.new2ContentLeftTitle { + margin: 15px auto; + color: #2d2d2d; + font-weight: 550; + font-size: 14px; +} + +.new2ContentLeftText { + color: #a8a8a8; +} + +.new2ContentRightTitle { + margin: 15px auto; + color: #2d2d2d; + font-weight: 550; + font-size: 14px; +} + +.new2ContentRightText { + color: #a8a8a8; +} + +.new2ContentLeftTime { + display: flex; + justify-content: space-between; + margin-top: 20px; +} + +.new2ContentLeftTime { + display: flex; +} +.showsDetailButton{ + width: 150px; + display:flex; + justify-content: center; + align-items: center; + background: #58c4b0; + color: white; + cursor: pointer; + margin: 0 auto; + padding: 5px; + text-decoration: none; + transition: 0.4s; + +} +.showItemHandle{ + display: flex; + width: 100%; + align-items: start; + justify-content: center; + height: 100%; + margin-bottom: 10px; +} +.showsDetailButton:hover{ + background: #ffffff!important; + color: #58c4b0!important; + +} +/*re shit*/ +.showItemBox { + display: none; +} + +.showItemBoxActive { + width: 100%; + height: 100%; + display: block; +} + +.showDetailBox2 { + display: none; +} + +.showDetailBox2Active { + display: flex; + justify-content: space-between; + align-items: center; +} + +.showItem { + display: none !important; +} + +.showItemActive { + display: flex !important; +} + +.showsButtonActive{ + display: flex; + width: 100%; + margin: 0 auto; +} \ No newline at end of file diff --git a/public/static/css/joinAgent.css b/public/static/css/joinAgent.css new file mode 100644 index 0000000..7bbb12f --- /dev/null +++ b/public/static/css/joinAgent.css @@ -0,0 +1,241 @@ +body { + margin: 0; + padding: 0; +} + +.topPic { + width: 100%; +} + +.barGs:hover { + /* border-bottom: #fff 3px solid; */ + padding-bottom: 15px; + /* border-right: none; */ +} + +.barTop { + display: flex; + width: 90%; + height: auto; + background-color: #00a587; + padding-left: 5%; + padding-top: 20px; + position: relative; + top: -75px; + margin-left: 10%; + +} + +.barTop2 { + position: absolute; + left: -10px; + width: 100%; + +} + +.barName { + width: 30%; + height: 100%; + line-height: 2; + margin-left: 30px; +} + +.barHeadline { + font-size: 40px; + font-weight: bold; + color: #fff; + line-height: 1.6; +} + +.barHeadline2 { + font-size: 30px; + color: #fff; + padding-bottom: 20px; +} + +.barSize { + width: 220px; + height: 30px; + position: absolute; + display: flex; + right: 0; + padding-top: 30px; +} + +.barSize img { + width: 20px; + height: 20px; +} + +.barMap { + font-size: 14px; + color: #fff; +} + +.bar { + margin-top: 50px; + display: flex; + /* width: 600px; */ + height: 30px; + position: absolute; + right: 0; + top: 30px; +} + +.barGs { + line-height: 40px; + /* display: flex; + justify-content: center; + text-align: center; */ + margin: 0 20px; + height: 40px; + color: #fff; + font-size: 15px; + /* border-right: #e2e2e2 2px solid; */ +} + +.body { + width: 100%; +} + +.bodyTop { + padding: 30px 0; + font-size: 40px; + display: flex; + align-items: center; + justify-content: center; + /* border-bottom: 1px solid #ccc; */ +} + +.bodyBox { + width: 100%; + height: auto; + margin-bottom: 50px; +} + +.BoxName { + width: 100%; + color: #00a587; + font-size: 30px; + font-weight: 600; + display: flex; + justify-content: center; + align-items: center; + margin: 50px 0; +} + +.bodyPic { + width: 25%; + height: 300px; + object-fit: cover; + margin: 0 10px; +} + +.bodyPic1 { + width: 80%; + margin-left: 10%; + height: auto; + margin-bottom: 30px; +} + +@media (max-width: 767px) { + .PicBox { + align-items: center; + justify-content: center; + display: grid; + flex-wrap: wrap; + width: 100%; + height: auto; + } +} + +@media (max-width: 767px) { + .bodyPic { + width: 80%; + height: 300px; + object-fit: cover; + margin: 0 auto; + padding: 10px 0; + } +} + +.PicBox { + align-items: center; + justify-content: center; + display: flex; + flex-wrap: wrap; + width: 100%; + height: auto; +} + +.PicBox-Mini { + width: 70%; + margin: 20px 15%; +} + +.bodyPic-Mini { + margin: 50px 123.3px; + width: 80%; + height: auto; + +} + +.barTop-xiao { + width: 100%; + background-color: #00a587; + padding: 10px 10%; +} + +.barName-Mini { + width: 90%; + color: #fff; + font-weight: 700; + font-size: 30px; + border-bottom: #ccc 1px solid; + padding-left: 3%; +} + +.bar-Mini { + display: flex; + margin: 20px 0px; +} + +.barGs-Mini { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 90px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.bodyPic-Mini { + width: 80%; + display: flex; + justify-content: center; + align-items: center; +} + +.bodyTop-Mini { + margin-top: 20px; + font-size: 30px; + height: 50px; + display: flex; + /* align-items: center; */ + justify-content: center; +} + +.borderBottom { + width: 0; + transition: all 0.3s; + height: 3px; + background-color: #fff; + margin: auto; +} + +.barGs:hover .borderBottom { + width: 60px; + margin: auto; +} \ No newline at end of file diff --git a/public/static/css/joinPolicy.css b/public/static/css/joinPolicy.css new file mode 100644 index 0000000..e512c86 --- /dev/null +++ b/public/static/css/joinPolicy.css @@ -0,0 +1,256 @@ +招商政策 + +/* join 通用css样式 */ +body { + margin: 0; + padding: 0; +} + +.topPic { + width: 100%; +} + +.barTop { + display: flex; + width: 90%; + height: auto; + background-color: #00a587; + padding-left: 5%; + padding-top: 20px; + position: relative; + top: -75px; + margin-left: 10%; + +} + +.barGs:hover { + /* border-bottom: #fff 3px solid; */ + padding-bottom: 15px; + /* border-right: none; */ +} + +a { + text-decoration: none +} + +.barTop2 { + position: absolute; + left: -10px; + width: 100%; + +} + +.barName { + width: 30%; + height: 100%; + line-height: 2; +} + +.barHeadline { + font-size: 40px; + font-weight: bold; + color: #fff; + line-height: 1.6; +} + +.barHeadline2 { + font-size: 30px; + color: #fff; + padding-bottom: 20px; +} + +.barSize { + width: 220px; + height: 30px; + position: absolute; + display: flex; + right: 0; + padding-top: 30px; +} + +.barSize img { + width: 20px; + height: 20px; +} + +.barMap { + font-size: 14px; + color: #fff; +} + +.bar { + margin-top: 50px; + display: flex; + /* width: 600px; */ + height: 30px; + position: absolute; + right: 0; + top: 30px; +} + +.barGs { + line-height: 40px; + /* display: flex; + justify-content: center; + text-align: center; */ + margin: 0 20px; + height: 40px; + color: #fff; + font-size: 15px; + /* border-right: #e2e2e2 2px solid; */ +} + +.body { + margin: 0px auto; + width: 100%; + margin: 0 auto; + max-width: 1500px; +} + +.bodyTop { + width: 94%; + margin-left: 3%; + padding: 30px 0; + font-size: 40px; + display: flex; + align-items: center; + justify-content: center; + /* border-bottom: 1px solid #ccc; */ +} + +.bodyText { + + width: 94%; + height: auto; + margin-top: 10px; +} + +.bodyTextTop { + color: #00a587; + font-weight: bold; + font-size: 24px; + /*padding-left: 10px;*/ +} + +.thread { + margin-top: 30px; + width: 50px; + height: 2px; + background-color: #00a587; + /*padding-left: 10px;*/ +} + +.bodyTextTop, +.thread { + margin-left: 30px; +} + +.text { + width: 100%; + margin: 20px 0; + display: flex; + flex-direction: row; +} + +.text-Mini { + width: 100%; + margin: 20px 0; + +} + +.text-1 { + line-height: 2; + font-size: 14px; + color: #333; + flex-wrap: wrap; + font-weight: 500; + list-style-type: decimal; + padding-bottom: 20px; +} + +.bodyPic { + width: 100%; + height: 100%; + margin-left: 10%; + padding-top: 10px; +} + +.boxPic { + width: 600px; + height: 400px; + position: relative; + top: -100px; +} + +.barTop-xiao { + width: 100%; + background-color: #00a587; + padding: 20px 30px; +} + +.barName-Mini { + color: #fff; + font-size: 700; + font-size: 30px; + border-bottom: #ccc 1px solid; + padding-left: 30px; +} + +.bar-Mini { + display: flex; + margin: 20px 0px; +} + +.barGs-Mini { + line-height: 20px; + display: flex; + justify-content: center; + text-align: center; + width: 90px; + height: 20px; + color: #fff; + border-right: #e2e2e2 2px solid; +} + +.bodyPic-Mini { + width: 90%; + height: 400px; + margin-left: 9%; + margin-bottom: 30px; + background-size: contain; + object-fit: contain; + +} + +.bodyTop-Mini { + margin-top: 20px; + padding: 30px 0px; + font-size: 30px; + height: 50px; + display: flex; + align-items: center; + justify-content: center; +} + +.text-1-max { + font-size: 16px; + font-weight: 500; + margin-bottom: 20px; + list-style-type: decimal; + line-height: 40px; + + +} + +.borderBottom { + width: 0; + transition: all 0.3s; + height: 3px; + background-color: #fff; + margin: auto; +} + +.barGs:hover .borderBottom { + width: 60px; + margin: auto; +} \ No newline at end of file diff --git a/public/static/css/news.css b/public/static/css/news.css new file mode 100644 index 0000000..c781b85 --- /dev/null +++ b/public/static/css/news.css @@ -0,0 +1,632 @@ +body { + margin: 0; + padding: 0; +} + +/* 临时修改 */ +.news-header-nav { + z-index: 99999; +} + +.news-header-nav-item { + background-color: rgb(255, 255, 255, 0.32); + display: flex; + justify-content: left; + align-items: center; + padding-left: 10%; + font-size: 15px; +} + +.news_border { + padding: 20px; +} + +.news-content-item-title { + background: white; + padding: 20px; +} + +.news-content-item-title>div { + padding-bottom: 10px; +} + +.news-content-item-title>div:nth-of-type(3) { + /*padding: 10px 10px 0px 10px!important;*/ + padding-bottom: 0 !important; +} + +/* */ + +@media (max-width: 767px) { + #_phone { + display: block !important; + } +} + +@media (max-width: 767px) { + .news-header-nav-item { + display: none !important; + } +} + +#_phone { + display: none; + background: rgb(244, 245, 247); +} + +a { + text-decoration: none !important; + color: white; +} + +.news_img { + width: 100%; + height: auto; +} + +.news_img img { + width: 100%; + height: 100%; +} + +#news { + width: 90%; + height: 60px; + align-items: center; + justify-content: center; +} + +.news_box { + width: 90%; + height: 20%; + margin-top: 10px; +} + +.news_box_left { + width: 40%; + height: 100%; + margin-top: 5px; + float: left; +} + +.size1 { + font-size: 40px; + font-weight: 600; +} + +.size2 { + font-size: 30px; +} + +#news span { + color: rgb(187, 186, 186); + font-size: 15px; + line-height: 20px; +} + +.news_box_right { + /* width: 300px; + height: 100%; */ + float: left; + font-size: 18px; +} + +.news_box_right img { + width: 20px; + height: 20px; +} + + + +.news_border1 { + display: flex; + align-items: center; + margin-top: 20px; + flex-direction: row-reverse; +} + +.news_border1 span { + font-size: 14px; +} + +.news_border span { + padding-bottom: 4px; +} + +.news_border span:hover { + border-bottom: 3px solid white; +} + +#news_visible { + width: 100%; + height: 120px; + background-color: rgb(0, 167, 134); +} + +.news_visible_box { + width: 80%; + height: 80%; + position: relative; + top: 10%; + margin: auto; +} + +.news_visible_top { + width: 100%; + height: 50%; + display: flex; + align-items: center; +} + +.news_visible_top span { + color: white; + font-size: 24px; + font-weight: 600; +} + +.news_visible_bottom { + width: 100%; + height: 50%; + display: flex; + align-items: center; +} + +.news_visible_border a { + width: 65px; + font-size: 14px; + float: left; + border-right: 1px solid white; + margin-right: 10px; +} + +#news_list { + width: 100%; + height: auto; + /* display: flex; */ + justify-content: center; +} + +.news_list_content { + width: 80%; + height: 200px; + margin: 20px auto; + /* border-bottom: 1px solid rgb(190, 190, 190); */ + /* background: #7b14db; */ +} + +.news_list_content_img { + width: 30%; + height: 200px; + /* margin: 0 50px; */ + float: left; + /* display: flex; */ + justify-content: center; + align-items: center; + cursor: pointer; + text-align: center; + line-height: 200px; + object-fit: cover; +} + +.news_list_content_img img { + width: 90%; + height: 90%; + object-fit: cover; + margin-right: 30px; +} + +.news_list_content_title { + width: 100%; + height: 25%; +} + +.news_list_content_name { + width: 100%; + height: 25%; +} + +.news_list_content_time { + width: 100%; + height: 25%; + word-break: break-all; + /* line-height: 80px; */ + font-size: 15px; + color: #898989; + /* padding: 40px 0; */ + font-family: "Microsoft YaHei", 微软雅黑; +} + +.news_list_content_outline { + width: 70%; + height: 45px; + word-break: break-all; + font-size: 15px; + color: #898989; + margin: 20px 0; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + font-family: "Microsoft YaHei", 微软雅黑; +} + +#news_list_visible { + width: 100%; + height: auto; + margin-top: 10px; + border-bottom: 10px solid #f5f5f5; +} + +.news_list_content_visible { + width: 90%; + height: 100%; + margin: 0 auto; +} + +.content_visible_box { + width: 100%; + height: 100%; +} + +.news_list_content_visible_img { + width: 20%; + height: 50px; + float: left; + display: flex; + justify-content: center; + align-items: center; +} + +.news_list_content_visible_img img { + /* width: 50px; + height: 50px; */ + width: 80%; + height: 200px; + margin: 0 10%; + float: left; + justify-content: center; + align-items: center; + cursor: pointer; + text-align: center; + line-height: 200px; + object-fit: cover; + " + +} + +.news_list_content_visible_title { + width: 100%; + height: 33%; + float: left; + font-weight: 600; + font-size: 15px; + +} + +.news_list_content_visible_name { + width: 80%; + height: 33%; + float: left; +} + +.news_list_content_visible_time { + width: 100%; + height: 33%; + float: left; + color: #ccc; +} + +#toggle_bar { + width: 100%; + height: 80px; + display: flex; + justify-content: center; + align-items: center; +} + +.toggle_bar_page { + display: flex; + justify-content: center; + align-items: center; +} + +.toggle_bar_page_size { + display: flex; + justify-content: center; + align-items: center; +} + +.toggle_bar_page_size div { + cursor: pointer; + padding: 8px 15px 8px 14px; + border: 1px solid #eeeeee; + height: 42px; + width: 46px; + text-align: center; +} + +.toggle_bar_page button { + border-style: none; + height: 42px; + width: 46px; + border: 1px solid #eeeeee; + margin: 10px; +} + +#toggle_bar_page_button1 { + background-color: rgb(255, 255, 255); +} + +#toggle_bar_page_button2 { + background-color: #fff; +} + +#toggle_bar_page_button1 img { + width: 15px; + height: 18px; +} + +#toggle_bar_page_button2 img { + width: 15px; + height: 18px; +} + +#toggle_bar_page_button1:hover { + color: rgb(240, 18, 18); +} + +#toggle_bar_page_button2:hover { + color: white; +} + +#toggle_bar_visible { + width: 100%; + height: 50px; + margin-bottom: 10px; +} + +.toggle_bar_page_visible { + width: 90%; + height: 100%; + margin: 0 auto; + display: flex; + justify-content: space-around; +} + +.toggle_bar_page_visible button { + border-style: none; + width: 38%; + height: 80%; + float: left; + margin-top: 10px; + margin-bottom: 10px; +} + +#visible_bottom1 { + /* margin-left: 3%; */ + background: #11bea0; + font-size: 18px; + display: flex; + justify-content: space-around; + align-items: center; + color: #fff; +} + +#visible_bottom1 img { + width: 20px; + height: 20px; +} + +#visible_bottom2 { + /* margin-left: 5%; */ + background: #11bea0; + font-size: 18px; + display: flex; + justify-content: space-around; + align-items: center; + color: #fff; +} + +#visible_bottom2 img { + width: 20px; + height: 20px; +} + +.borderBottom { + width: 0; + transition: all 0.3s; + height: 3px; + background-color: rgb(0, 182, 142); + margin: auto; +} + +.barGs:hover .borderBottom { + width: 50px; + margin: auto; + +} + +.barGs123 { + border-bottom: 2px solid #00a587; +} + +.news_list_content_visible_outline { + font-size: 14px; + width: 80%; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.productPage { + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 50px; + margin-top: 20px; +} + +.productPage>.page { + margin: 0 5px 0 5px; + cursor: pointer; + padding: 8px 15px 8px 14px; + border: 1px solid #eeeeee; + height: 42px; + width: 46px; + text-align: center; + font-size: 15px; +} + +.productPage img { + height: 62%; + width: 100%; + object-fit: cover; +} + +.toggle_bar_page_visible a { + width: 20px; + height: 80%; +} + + + +/*page*/ +.page { + transition: 0.4s; +} + +.page:hover { + background: #11bea0; + color: white; +} + +.pageBigBox { + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 50px; + flex-wrap: wrap; +} + +.pageBigBox>div { + margin: 10px 0; +} + +.productPage { + display: flex; + justify-content: center; + align-items: center; +} + +.pageActive { + background: #11bea0; + color: white; +} + +.productPage>.page { + border: 1px solid #eeeeee; + height: 42px; + width: 46px; + text-align: center; + display: flex; + justify-content: center; + align-items: center; +} + +.productPage>div { + margin: 0 5px 0 5px; + cursor: pointer; + padding: 8px 15px 8px 14px; +} + +.pageMoreInput { + display: flex; + justify-content: center; + align-items: center; +} + +.pageMoreInput label { + margin-bottom: 0 !important; +} + +.pageMoreInput input { + width: 40px; + border: 1px solid #a8a8a8; +} + +.pageMore { + margin: 0 !important; + padding: 8px 7px 8px 7px; + +} + +.productPage img { + height: 62%; + width: 100%; + object-fit: cover; +} + +.pageMoreInput { + display: flex; + justify-content: center; + align-items: center; +} + +.pageMoreInput>* { + padding-left: 4px; + padding-right: 4px; + color: #898989; + font-size: 16px; +} + +.productJump { + cursor: pointer; + transition: 0.4s; + background: #00a587; + color: white; + padding: 5px 10px; +} + +.productJump:hover { + color: #00a587; + background: white; +} + +@media (min-width: 1540px) { + .container { + padding-top: 10px !important; + max-width: 100% !important; + margin: 0 !important; + background: rgb(248, 246, 246); + } +} + +.phone { + width: 100%; + height: 100%; +} + +.news_box { + margin: 10px 0; + width: 80%; + height: 500px; + margin: auto; +} + +.f2 {} + +.news_img_box { + width: 100%; + height: 60%; + background: white; +} + +.news_img_box img { + width: 100%; + height: 100%; + padding: 10px; + object-fit: cover; +} \ No newline at end of file diff --git a/public/static/css/news_detail.css b/public/static/css/news_detail.css new file mode 100644 index 0000000..7adb001 --- /dev/null +++ b/public/static/css/news_detail.css @@ -0,0 +1,350 @@ +body { + margin: 0; + padding: 0; +} + +a { + text-decoration: none; + color: white; +} + +a:hover { + text-decoration: none; + color: white; +} + +.news_img { + width: 100%; + height: auto; +} + +.news_img img { + width: 100%; + height: 100%; +} + +#news { + width: 87%; + height: 160px; + background-color: rgb(0, 167, 134); + position: relative; + top: -90px; + left: 13%; + display: flex; + align-items: center; + justify-content: center; +} + +.news_box { + width: 90%; + height: 90%; +} + +.news_box_left { + width: 25%; + height: 100%; + float: left; +} + +.size1 { + font-size: 40px; + font-weight: 600; +} + +.size2 { + font-size: 30px; +} + +.news span { + color: white; +} + +.news_box_right { + width: 75%; + height: 100%; + float: left; + font-size: 18px; +} + +.news_box_right img { + width: 20px; + height: 20px; +} + +.news_border { + text-align: right; + width: 90px; + margin-left: 30px; + font-size: 14px; + margin-top: 20px; + float: right; +} + +.news_border1 { + display: flex; + align-items: center; + margin-top: 30px; + flex-direction: row-reverse; +} + +.news_border1 span { + font-size: 14px; +} + +.news_border :hover { + border-bottom: 3px solid white; +} + +#news_visible { + width: 100%; + height: 120px; + background-color: rgb(0, 167, 134); + +} + +.news_visible_box { + width: 80%; + height: 80%; + position: relative; + top: 10%; + margin: auto; +} + +.news_visible_top { + width: 100%; + height: 50%; + display: flex; + align-items: center; +} + +.news_visible_top span { + color: white; + font-size: 24px; + font-weight: 600; +} + +.news_visible_bottom { + width: 100%; + height: 50%; + display: flex; + align-items: center; +} + +.news_visible_border a { + width: 65px; + font-size: 14px; + float: left; + margin-right: 10px; +} + +#content { + width: 90%; + height: auto; + margin: 0 auto; + border-bottom: 1px solid rgb(192, 192, 192); +} + +.content_title { + display: flex; + justify-content: center; + /* border-bottom: 1px solid rgb(192, 192, 192); */ + font-weight: 800; + font-size: 20px; +} + +.content_information { + display: flex; + justify-content: center; +} + +.content_link { + display: flex; + justify-content: space-between; + margin-top: 10px +} + +.content_link a { + color: black; +} + +#content_information_visible span { + width: 100%; + margin: 0 auto; +} + +#content_visible { + width: 90%; + height: auto; + margin: 0 auto; +} + +.content_title_visible { + display: flex; + justify-content: center; + font-weight: 800; + font-size: 20px; +} + +.content_information_visible { + display: flex; + justify-content: center; + border-bottom: 1px solid rgb(192, 192, 192); +} + +.content_link_visible p { + margin-top: 20px; +} + +.content_link_visible a { + color: black; + cursor: pointer; +} + +.news_content { + /* width: 100%; + height: auto; + border-bottom: 1px solid rgb(192, 192, 192); + overflow: hidden; */ +} + +.news_content img { + width: 60%; + object-fit: contain; +} + +.information { + width: 100%; + height: 30px; + background-color: rgb(0, 167, 134); + display: flex; + align-items: center; + margin-top: 15px; +} + +.information span { + margin-left: 10px; + color: white; +} + +.content { + width: 100%; + display: flex; + justify-content: space-around; +} + +.keywords { + width: 100%; + height: 30px; + display: flex; + align-items: center; + margin-top: 10px; +} + +a { + cursor: pointer; +} + +.pc { + display: flex; + justify-content: space-around; +} + +#news_list { + width: 28%; + height: 250px; + display: flex; + justify-content: center; +} + +#news_list a { + background-color: transparent !important; + color: #007bff; +} + +.news_list_content { + width: 100%; + height: 80%; + margin: 10px auto; + box-shadow: darkgrey 5px 5px 8px -6px; +} + +.mobile:hover { + margin-top: 20px; + box-shadow: rgb(233 165 165) 9px 9px 18px -6px; +} + +.news_list_content_img { + width: 100%; + height: 50%; + text-align: center; + overflow: hidden; +} + +.news_list_content_img img { + width: 100%; + height: 100%; + object-fit: cover; +} + +#news_list_visible { + width: 25%; + height: 200px; +} + +.news_list_content_title { + + overflow: hidden; + text-overflow: ellipsis; + margin-top: 15px !important; + font-weight: 600; + color: #181818; + padding-left: 15px; + + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; +} + +@media (max-width: 748px) { + .content { + width: 100%; + display: flex; + justify-content: space-around; + flex-direction: column !important; + } + + #news_list_visible { + width: 100%; + height: 300px; + } + + .news_list_content_title { + + overflow: hidden; + text-overflow: ellipsis; + margin-top: 15px !important; + font-weight: 600; + color: #181818; + padding-left: 10px; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; + } + + .de { + padding-left: 10px; + } + +} + +.text_box { + width: 100%; + height: 100%; +} + + +.news_title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} \ No newline at end of file diff --git a/public/static/css/poster.css b/public/static/css/poster.css new file mode 100644 index 0000000..b19534d --- /dev/null +++ b/public/static/css/poster.css @@ -0,0 +1,32 @@ +.posterBigBox{ + overflow: hidden; +} +.posterBox{ + height: 700px; + width: 100%; + position: relative; + transform: translateY(0); +} +.poster{ + position: absolute; + height: 100%; + width: 100%; + background-image: url('/glh_web/api/public/uploads/bannerImg/20220718/0a9df91715a8c1a152b4ce52f40c30d1.jpg'); + /*background-repeat: no-repeat;*/ + /*background-attachment: fixed;*/ + /*transition: 0.4s;*/ + /*background-size: 100% 100%;*/ + /*-webkit-background-size: cover;*/ + /*background-size: 100% auto;*/ + /*-moz-background-size: 100% 100%;*/ + /*-webkit-background-size: 100% 100%;*/ + /*-o-background-size: 100% 100%;*/ + /*filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/glh_web/api/public/uploads/bannerImg/20220718/0a9df91715a8c1a152b4ce52f40c30d1.jpg",sizingMethod='scale');*/ + /*background-position:center center;*/ + background: no-repeat center/cover; + top: 0; + bottom: 0; + left: 0; + right: 0; + filter: blur(0); +} diff --git a/public/static/css/product.css b/public/static/css/product.css new file mode 100644 index 0000000..7743d5a --- /dev/null +++ b/public/static/css/product.css @@ -0,0 +1,351 @@ +/*product.css*/ +/*product*/ +.product a { + text-decoration: none !important; +} + +.productsBigBox { + margin: 60px auto; + display: flex; + justify-content: center; +} + +/* .productsBigBox>div { + padding: 20px; +} */ + +.productMenusBox { + display: flex; + flex-direction: column; +} + +/* .productMenusBox>div{ + border: 1px solid #5555; +} */ +.productMenusHead { + background: #11bea0; + font-size: 20px; + font-weight: 550; + color: white; + text-align: left; + position: relative; + overflow: hidden; + +} + +.productMenusHeadContent { + position: relative; + height: 80px; + text-align: center; + font-size: 25px; + line-height: 80px; +} + +.upLeft { + width: 0; + height: 0; + position: absolute; + border-top: solid 15px transparent; + border-right: solid 15px #ffffff; + border-bottom: solid 15px transparent; + left: -3px; + transform: rotate(45deg); + top: -10px; +} + +.upLeft2 { + width: 0; + height: 0; + position: absolute; + border-top: solid 10px transparent; + border-right: solid 10px #11bea0; + border-bottom: solid 10px transparent; + left: -1px; + transform: rotate(45deg); + top: -6px; +} + +.upLeft3 { + width: 0; + height: 0; + position: absolute; + border-top: solid 18px transparent; + border-right: solid 18px #ffffff; + border-bottom: solid 18px transparent; + right: -3px; + transform: rotate(-135deg); + bottom: -13px; +} + +.upLeft4 { + width: 0; + height: 0; + position: absolute; + border-top: solid 8px transparent; + border-right: solid 8px #11bea0; + border-bottom: solid 8px transparent; + right: -1px; + transform: rotate(-135deg); + bottom: -6px; +} + +.upLeft5 { + width: 40px; + height: 3px; + position: absolute; + background: #11bea0; + right: -12px; + transform: rotate(-225deg); + bottom: 10px; +} + +.productMenusBody>a { + padding: 10px 10px; + border-bottom: 1px solid rgb(234, 234, 234); + font-family: "Microsoft YaHei", 微软雅黑; +} + +.productMenusBody { + width: 100%; + /* border-bottom: 1px solid #5555; */ + border: 1px solid rgb(234, 234, 234); + /* background: #f2fbfa; */ +} + +.productMenusBody:last-child { + border-top: none; +} + +.productMenusBody>a:last-child { + border-bottom: none; +} + +.productMenusBodyTitle { + font-size: 20px; + color: rgb(121, 121, 121); + font-weight: 550; + height: 40px; + line-height: 20px; + border-bottom: 1px solid rgb(234, 234, 234); + padding: 10px; +} + +.productMenusItem { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + transition: 0.6s; + /* border-bottom: 1px solid #aaaaaa; */ + color: #898989; +} + +.productMenusItem:hover { + background: #11bea0; + color: white; + margin-left: 0; + padding: 10px 15px 10px 20px; +} + +.productMenusItemActive { + background: #11bea0 !important; + color: rgb(250, 246, 246) !important; + margin-left: -0px !important; + padding: 10px 20px 10px 20px !important; +} + +.productMenuLine { + border-bottom: 1px solid #ecf2f2; +} + +.productsTitle { + font-size: 28px; +} + +.productsTitleDetail { + color: #bbbbbb; + font-size: 18px !important; +} + +.productsBody { + display: flex; + justify-content: left; + align-items: center; + flex-wrap: wrap; + width: 100%; +} + +.productItem { + height: 350px; + padding: 10px; +} + +.products { + height: 100%; + position: relative; + overflow: hidden; + cursor: pointer; + border: 1px solid #f5f5f5; + transition: 0.6s; +} + +.products>.productImg { + /*position: absolute;*/ + height: 80%; + width: 100%; + /*padding: 10px;*/ + object-fit: contain; +} + +.productsBox { + width: 100%; + padding-top: 10px; +} + +.productMenusBox { + width: 30%; + /*padding: 20px 50px 0 1px;*/ + padding: 20px 20px 0 20px; + margin: 0 auto; +} + +.productContent { + position: absolute; + bottom: 0; + /*height: 23%;*/ + z-index: 9; + width: 100%; + background: white; + padding-bottom: 20px; +} + +.productContent>div, +.productContent>span { + margin: 5px 0 11px 20px; +} + +.productButton { + border: 1px solid #eeeeee; + color: #4fcaaf; + background: white; + transition: 0.6s; + padding: 5px; +} + +.productType { + color: #cccccc; +} + +.products:hover { + transform: translate(0, -10px); + box-shadow: 4px 4px 4px #f5f5f5; +} + +.productButton:hover { + background: #4fcaaf; + color: white; +} + +.productSMenu { + cursor: pointer; + /* color: #898989; */ +} + +/*page*/ +.page { + transition: 0.4s; +} + +.page:hover { + background: #11bea0; + color: white; +} + +.pageBigBox { + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 50px; + flex-wrap: wrap; +} + +.pageBigBox>div { + margin: 10px 0; +} + +.productPage { + display: flex; + justify-content: center; + align-items: center; +} + +.pageActive { + background: #11bea0; + color: white; +} + +.productPage>.page { + border: 1px solid #eeeeee; + height: 42px; + width: 46px; + text-align: center; +} + +.productPage>div { + margin: 0 5px 0 5px; + cursor: pointer; + padding: 8px 15px 8px 14px; +} + +.pageMoreInput { + display: flex; + justify-content: center; + align-items: center; +} + +.pageMoreInput label { + margin-bottom: 0 !important; +} + +.pageMoreInput input { + width: 40px; + border: 1px solid #a8a8a8; +} + +.pageMore { + margin: 0 !important; + padding: 8px 7px 8px 7px; + +} + +.productPage img { + height: 62%; + width: 100%; + object-fit: cover; +} + +.pageMoreInput { + display: flex; + justify-content: center; + align-items: center; +} + +.pageMoreInput>* { + padding-left: 4px; + padding-right: 4px; + color: #898989; + font-size: 16px; +} + +.productJump { + cursor: pointer; + transition: 0.4s; + background: #00a587; + color: white; + padding: 5px 10px; +} + +.productJump:hover { + color: #00a587; + background: white; +} \ No newline at end of file diff --git a/public/static/css/productInfo.css b/public/static/css/productInfo.css new file mode 100644 index 0000000..54ba8a0 --- /dev/null +++ b/public/static/css/productInfo.css @@ -0,0 +1,180 @@ +/*productInfo.css*/ +/*productInfoTitle*/ +/*title*/ +.ProductInfosTitle { + position: relative; + padding: 10px 15px; +} + + +.ProductInfosTitle>* { + display: inline-block; + font-size: 24px; +} + +.ProductInfosTitle>span { + width: 6px; + height: 12px; + position: absolute; + left: 0; + top: calc(50% - 4px); + z-index: -1; + transition: all .8s; + background: #0cbf97; +} + +section:hover .ProductInfosTitle>span { + width: 100%; +} + +/*title-end*/ +.f12 { + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 12; + font-size: 13px; +} + +.aboutContentText { + text-indent: 2em; +} + +.productInfo { + padding-bottom: 20px; + background: white; +} + +.productInfoT { + padding-left: 50px !important; + position: relative; +} + +.productInfosBox>div { + margin-top: 50px; +} + +.productInfosHeader { + display: flex; + width: 100%; + justify-content: space-between; + align-items: center; + padding: 0 !important; +} + +.productsInfos { + display: flex; + justify-content: space-between; +} + +.productInfoImgBox { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + height: 500px; + border: 1px solid #e6e6e6; + width: 100%; +} + +.productInfoImgBox>img { + height: 100%; + width: 100%; + object-fit: contain; + cursor: crosshair; +} + +.productInfoMd { + font-size: 15px; + color: #717171; +} + +.productsInfos { + margin-bottom: 50px; + margin-left: 0 !important; + margin-right: 0 !important; + position: relative; +} + +.productDetail { + position: absolute; + left: 0; + top: 0; + height: 100%; + width: 100%; + background: white; + z-index: 999; + display: -webkit-box; + overflow: hidden; + display: none; +} + +.productDetail>img { + position: relative; + left: 0; + top: 0; + height: 100%; + width: 100%; + object-fit: contain; + transform: scale(2); +} + +.productInfoTitle { + font-size: 28px; + font-weight: 600; + margin-bottom: 40px; + margin-top: 20px; +} + +.productInfoLine { + height: 2px; + width: 100%; + background: #eeeeee; +} + +.productInfoContent { + margin-top: 20px; + font-size: 15px !important; + margin-bottom: 100px; + line-height: 2; +} + +.productInfoBuy>a { + display: inline-block; + background: #00a587; + color: #ffffff; + padding: 10px 50px 10px 50px; + cursor: pointer; + margin-top: 15px; + transition: 0.4s; +} + +.productInfoBuy>a:hover { + background: #ffffff; + color: #00a587; +} + +.productInfoDetailRtx { + margin: 40px 0; +} + +.productInfoDetailRtx img { + width: 100%; +} + +.productInfoPage { + width: 100%; + padding: 20px 0; + display: flex; + justify-content: space-between; + align-items: center; +} + +.productInfoPage>div { + cursor: pointer; +} + +.productInfoPage>div:hover { + color: #00a587; +} \ No newline at end of file diff --git a/public/static/css/swiper-bundle.css b/public/static/css/swiper-bundle.css new file mode 100644 index 0000000..a995259 --- /dev/null +++ b/public/static/css/swiper-bundle.css @@ -0,0 +1,647 @@ +/** + * Swiper 8.3.0 + * Most modern mobile touch slider and framework with hardware accelerated transitions + * https://swiperjs.com + * + * Copyright 2014-2022 Vladimir Kharlampidi + * + * Released under the MIT License + * + * Released on: July 6, 2022 + */ + +@font-face { + font-family: 'swiper-icons'; + src: url('data:application/font-woff;charset=utf-8;base64, d09GRgABAAAAAAZgABAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAGRAAAABoAAAAci6qHkUdERUYAAAWgAAAAIwAAACQAYABXR1BPUwAABhQAAAAuAAAANuAY7+xHU1VCAAAFxAAAAFAAAABm2fPczU9TLzIAAAHcAAAASgAAAGBP9V5RY21hcAAAAkQAAACIAAABYt6F0cBjdnQgAAACzAAAAAQAAAAEABEBRGdhc3AAAAWYAAAACAAAAAj//wADZ2x5ZgAAAywAAADMAAAD2MHtryVoZWFkAAABbAAAADAAAAA2E2+eoWhoZWEAAAGcAAAAHwAAACQC9gDzaG10eAAAAigAAAAZAAAArgJkABFsb2NhAAAC0AAAAFoAAABaFQAUGG1heHAAAAG8AAAAHwAAACAAcABAbmFtZQAAA/gAAAE5AAACXvFdBwlwb3N0AAAFNAAAAGIAAACE5s74hXjaY2BkYGAAYpf5Hu/j+W2+MnAzMYDAzaX6QjD6/4//Bxj5GA8AuRwMYGkAPywL13jaY2BkYGA88P8Agx4j+/8fQDYfA1AEBWgDAIB2BOoAeNpjYGRgYNBh4GdgYgABEMnIABJzYNADCQAACWgAsQB42mNgYfzCOIGBlYGB0YcxjYGBwR1Kf2WQZGhhYGBiYGVmgAFGBiQQkOaawtDAoMBQxXjg/wEGPcYDDA4wNUA2CCgwsAAAO4EL6gAAeNpj2M0gyAACqxgGNWBkZ2D4/wMA+xkDdgAAAHjaY2BgYGaAYBkGRgYQiAHyGMF8FgYHIM3DwMHABGQrMOgyWDLEM1T9/w8UBfEMgLzE////P/5//f/V/xv+r4eaAAeMbAxwIUYmIMHEgKYAYjUcsDAwsLKxc3BycfPw8jEQA/gZBASFhEVExcQlJKWkZWTl5BUUlZRVVNXUNTQZBgMAAMR+E+gAEQFEAAAAKgAqACoANAA+AEgAUgBcAGYAcAB6AIQAjgCYAKIArAC2AMAAygDUAN4A6ADyAPwBBgEQARoBJAEuATgBQgFMAVYBYAFqAXQBfgGIAZIBnAGmAbIBzgHsAAB42u2NMQ6CUAyGW568x9AneYYgm4MJbhKFaExIOAVX8ApewSt4Bic4AfeAid3VOBixDxfPYEza5O+Xfi04YADggiUIULCuEJK8VhO4bSvpdnktHI5QCYtdi2sl8ZnXaHlqUrNKzdKcT8cjlq+rwZSvIVczNiezsfnP/uznmfPFBNODM2K7MTQ45YEAZqGP81AmGGcF3iPqOop0r1SPTaTbVkfUe4HXj97wYE+yNwWYxwWu4v1ugWHgo3S1XdZEVqWM7ET0cfnLGxWfkgR42o2PvWrDMBSFj/IHLaF0zKjRgdiVMwScNRAoWUoH78Y2icB/yIY09An6AH2Bdu/UB+yxopYshQiEvnvu0dURgDt8QeC8PDw7Fpji3fEA4z/PEJ6YOB5hKh4dj3EvXhxPqH/SKUY3rJ7srZ4FZnh1PMAtPhwP6fl2PMJMPDgeQ4rY8YT6Gzao0eAEA409DuggmTnFnOcSCiEiLMgxCiTI6Cq5DZUd3Qmp10vO0LaLTd2cjN4fOumlc7lUYbSQcZFkutRG7g6JKZKy0RmdLY680CDnEJ+UMkpFFe1RN7nxdVpXrC4aTtnaurOnYercZg2YVmLN/d/gczfEimrE/fs/bOuq29Zmn8tloORaXgZgGa78yO9/cnXm2BpaGvq25Dv9S4E9+5SIc9PqupJKhYFSSl47+Qcr1mYNAAAAeNptw0cKwkAAAMDZJA8Q7OUJvkLsPfZ6zFVERPy8qHh2YER+3i/BP83vIBLLySsoKimrqKqpa2hp6+jq6RsYGhmbmJqZSy0sraxtbO3sHRydnEMU4uR6yx7JJXveP7WrDycAAAAAAAH//wACeNpjYGRgYOABYhkgZgJCZgZNBkYGLQZtIJsFLMYAAAw3ALgAeNolizEKgDAQBCchRbC2sFER0YD6qVQiBCv/H9ezGI6Z5XBAw8CBK/m5iQQVauVbXLnOrMZv2oLdKFa8Pjuru2hJzGabmOSLzNMzvutpB3N42mNgZGBg4GKQYzBhYMxJLMlj4GBgAYow/P/PAJJhLM6sSoWKfWCAAwDAjgbRAAB42mNgYGBkAIIbCZo5IPrmUn0hGA0AO8EFTQAA'); + font-weight: 400; + font-style: normal; +} +:root { + --swiper-theme-color: #007aff; +} +.swiper { + margin-left: auto; + margin-right: auto; + position: relative; + overflow: hidden; + list-style: none; + padding: 0; + /* Fix of Webkit flickering */ + z-index: 1; +} +.swiper-vertical > .swiper-wrapper { + flex-direction: column; +} +.swiper-wrapper { + position: relative; + width: 100%; + height: 100%; + z-index: 1; + display: flex; + transition-property: transform; + box-sizing: content-box; +} +.swiper-android .swiper-slide, +.swiper-wrapper { + transform: translate3d(0px, 0, 0); +} +.swiper-pointer-events { + touch-action: pan-y; +} +.swiper-pointer-events.swiper-vertical { + touch-action: pan-x; +} +.swiper-slide { + flex-shrink: 0; + width: 100%; + height: 100%; + position: relative; + transition-property: transform; +} +.swiper-slide-invisible-blank { + visibility: hidden; +} +/* Auto Height */ +.swiper-autoheight, +.swiper-autoheight .swiper-slide { + height: auto; +} +.swiper-autoheight .swiper-wrapper { + align-items: flex-start; + transition-property: transform, height; +} +.swiper-backface-hidden .swiper-slide { + transform: translateZ(0); + -webkit-backface-visibility: hidden; + backface-visibility: hidden; +} +/* 3D Effects */ +.swiper-3d, +.swiper-3d.swiper-css-mode .swiper-wrapper { + perspective: 1200px; +} +.swiper-3d .swiper-wrapper, +.swiper-3d .swiper-slide, +.swiper-3d .swiper-slide-shadow, +.swiper-3d .swiper-slide-shadow-left, +.swiper-3d .swiper-slide-shadow-right, +.swiper-3d .swiper-slide-shadow-top, +.swiper-3d .swiper-slide-shadow-bottom, +.swiper-3d .swiper-cube-shadow { + transform-style: preserve-3d; +} +.swiper-3d .swiper-slide-shadow, +.swiper-3d .swiper-slide-shadow-left, +.swiper-3d .swiper-slide-shadow-right, +.swiper-3d .swiper-slide-shadow-top, +.swiper-3d .swiper-slide-shadow-bottom { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 10; +} +.swiper-3d .swiper-slide-shadow { + background: rgba(0, 0, 0, 0.15); +} +.swiper-3d .swiper-slide-shadow-left { + background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0)); +} +.swiper-3d .swiper-slide-shadow-right { + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0)); +} +.swiper-3d .swiper-slide-shadow-top { + background-image: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0)); +} +.swiper-3d .swiper-slide-shadow-bottom { + background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0)); +} +/* CSS Mode */ +.swiper-css-mode > .swiper-wrapper { + overflow: auto; + scrollbar-width: none; + /* For Firefox */ + -ms-overflow-style: none; + /* For Internet Explorer and Edge */ +} +.swiper-css-mode > .swiper-wrapper::-webkit-scrollbar { + display: none; +} +.swiper-css-mode > .swiper-wrapper > .swiper-slide { + scroll-snap-align: start start; +} +.swiper-horizontal.swiper-css-mode > .swiper-wrapper { + scroll-snap-type: x mandatory; +} +.swiper-vertical.swiper-css-mode > .swiper-wrapper { + scroll-snap-type: y mandatory; +} +.swiper-centered > .swiper-wrapper::before { + content: ''; + flex-shrink: 0; + order: 9999; +} +.swiper-centered.swiper-horizontal > .swiper-wrapper > .swiper-slide:first-child { + margin-inline-start: var(--swiper-centered-offset-before); +} +.swiper-centered.swiper-horizontal > .swiper-wrapper::before { + height: 100%; + min-height: 1px; + width: var(--swiper-centered-offset-after); +} +.swiper-centered.swiper-vertical > .swiper-wrapper > .swiper-slide:first-child { + margin-block-start: var(--swiper-centered-offset-before); +} +.swiper-centered.swiper-vertical > .swiper-wrapper::before { + width: 100%; + min-width: 1px; + height: var(--swiper-centered-offset-after); +} +.swiper-centered > .swiper-wrapper > .swiper-slide { + scroll-snap-align: center center; +} +.swiper-virtual .swiper-slide { + -webkit-backface-visibility: hidden; + transform: translateZ(0); +} +.swiper-virtual.swiper-css-mode .swiper-wrapper::after { + content: ''; + position: absolute; + left: 0; + top: 0; + pointer-events: none; +} +.swiper-virtual.swiper-css-mode.swiper-horizontal .swiper-wrapper::after { + height: 1px; + width: var(--swiper-virtual-size); +} +.swiper-virtual.swiper-css-mode.swiper-vertical .swiper-wrapper::after { + width: 1px; + height: var(--swiper-virtual-size); +} +:root { + --swiper-navigation-size: 44px; + /* + --swiper-navigation-color: var(--swiper-theme-color); + */ +} +.swiper-button-prev, +.swiper-button-next { + position: absolute; + top: 50%; + width: calc(var(--swiper-navigation-size) / 44 * 27); + height: var(--swiper-navigation-size); + margin-top: calc(0px - (var(--swiper-navigation-size) / 2)); + z-index: 10; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + color: var(--swiper-navigation-color, var(--swiper-theme-color)); +} +.swiper-button-prev.swiper-button-disabled, +.swiper-button-next.swiper-button-disabled { + opacity: 0.35; + cursor: auto; + pointer-events: none; +} +.swiper-button-prev.swiper-button-hidden, +.swiper-button-next.swiper-button-hidden { + opacity: 0; + cursor: auto; + pointer-events: none; +} +.swiper-navigation-disabled .swiper-button-prev, +.swiper-navigation-disabled .swiper-button-next { + display: none !important; +} +.swiper-button-prev:after, +.swiper-button-next:after { + font-family: swiper-icons; + font-size: var(--swiper-navigation-size); + text-transform: none !important; + letter-spacing: 0; + font-variant: initial; + line-height: 1; +} +.swiper-button-prev, +.swiper-rtl .swiper-button-next { + left: 10px; + right: auto; +} +.swiper-button-prev:after, +.swiper-rtl .swiper-button-next:after { + content: 'prev'; +} +.swiper-button-next, +.swiper-rtl .swiper-button-prev { + right: 10px; + left: auto; +} +.swiper-button-next:after, +.swiper-rtl .swiper-button-prev:after { + content: 'next'; +} +.swiper-button-lock { + display: none; +} +:root { + /* + --swiper-pagination-color: var(--swiper-theme-color); + --swiper-pagination-bullet-size: 8px; + --swiper-pagination-bullet-width: 8px; + --swiper-pagination-bullet-height: 8px; + --swiper-pagination-bullet-inactive-color: #000; + --swiper-pagination-bullet-inactive-opacity: 0.2; + --swiper-pagination-bullet-opacity: 1; + --swiper-pagination-bullet-horizontal-gap: 4px; + --swiper-pagination-bullet-vertical-gap: 6px; + */ +} +.swiper-pagination { + position: absolute; + text-align: center; + transition: 300ms opacity; + transform: translate3d(0, 0, 0); + z-index: 10; +} +.swiper-pagination.swiper-pagination-hidden { + opacity: 0; +} +.swiper-pagination-disabled > .swiper-pagination, +.swiper-pagination.swiper-pagination-disabled { + display: none !important; +} +/* Common Styles */ +.swiper-pagination-fraction, +.swiper-pagination-custom, +.swiper-horizontal > .swiper-pagination-bullets, +.swiper-pagination-bullets.swiper-pagination-horizontal { + bottom: 10px; + left: 0; + width: 100%; +} +/* Bullets */ +.swiper-pagination-bullets-dynamic { + overflow: hidden; + font-size: 0; +} +.swiper-pagination-bullets-dynamic .swiper-pagination-bullet { + transform: scale(0.33); + position: relative; +} +.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active { + transform: scale(1); +} +.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-main { + transform: scale(1); +} +.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-prev { + transform: scale(0.66); +} +.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-prev-prev { + transform: scale(0.33); +} +.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-next { + transform: scale(0.66); +} +.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-next-next { + transform: scale(0.33); +} +.swiper-pagination-bullet { + width: var(--swiper-pagination-bullet-width, var(--swiper-pagination-bullet-size, 8px)); + height: var(--swiper-pagination-bullet-height, var(--swiper-pagination-bullet-size, 8px)); + display: inline-block; + border-radius: 50%; + background: var(--swiper-pagination-bullet-inactive-color, #000); + opacity: var(--swiper-pagination-bullet-inactive-opacity, 0.2); +} +button.swiper-pagination-bullet { + border: none; + margin: 0; + padding: 0; + box-shadow: none; + -webkit-appearance: none; + appearance: none; +} +.swiper-pagination-clickable .swiper-pagination-bullet { + cursor: pointer; +} +.swiper-pagination-bullet:only-child { + display: none !important; +} +.swiper-pagination-bullet-active { + opacity: var(--swiper-pagination-bullet-opacity, 1); + background: var(--swiper-pagination-color, var(--swiper-theme-color)); +} +.swiper-vertical > .swiper-pagination-bullets, +.swiper-pagination-vertical.swiper-pagination-bullets { + right: 10px; + top: 50%; + transform: translate3d(0px, -50%, 0); +} +.swiper-vertical > .swiper-pagination-bullets .swiper-pagination-bullet, +.swiper-pagination-vertical.swiper-pagination-bullets .swiper-pagination-bullet { + margin: var(--swiper-pagination-bullet-vertical-gap, 6px) 0; + display: block; +} +.swiper-vertical > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic, +.swiper-pagination-vertical.swiper-pagination-bullets.swiper-pagination-bullets-dynamic { + top: 50%; + transform: translateY(-50%); + width: 8px; +} +.swiper-vertical > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet, +.swiper-pagination-vertical.swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet { + display: inline-block; + transition: 200ms transform, 200ms top; +} +.swiper-horizontal > .swiper-pagination-bullets .swiper-pagination-bullet, +.swiper-pagination-horizontal.swiper-pagination-bullets .swiper-pagination-bullet { + margin: 0 var(--swiper-pagination-bullet-horizontal-gap, 4px); +} +.swiper-horizontal > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic, +.swiper-pagination-horizontal.swiper-pagination-bullets.swiper-pagination-bullets-dynamic { + left: 50%; + transform: translateX(-50%); + white-space: nowrap; +} +.swiper-horizontal > .swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet, +.swiper-pagination-horizontal.swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet { + transition: 200ms transform, 200ms left; +} +.swiper-horizontal.swiper-rtl > .swiper-pagination-bullets-dynamic .swiper-pagination-bullet { + transition: 200ms transform, 200ms right; +} +/* Progress */ +.swiper-pagination-progressbar { + background: rgba(0, 0, 0, 0.25); + position: absolute; +} +.swiper-pagination-progressbar .swiper-pagination-progressbar-fill { + background: var(--swiper-pagination-color, var(--swiper-theme-color)); + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + transform: scale(0); + transform-origin: left top; +} +.swiper-rtl .swiper-pagination-progressbar .swiper-pagination-progressbar-fill { + transform-origin: right top; +} +.swiper-horizontal > .swiper-pagination-progressbar, +.swiper-pagination-progressbar.swiper-pagination-horizontal, +.swiper-vertical > .swiper-pagination-progressbar.swiper-pagination-progressbar-opposite, +.swiper-pagination-progressbar.swiper-pagination-vertical.swiper-pagination-progressbar-opposite { + width: 100%; + height: 4px; + left: 0; + top: 0; +} +.swiper-vertical > .swiper-pagination-progressbar, +.swiper-pagination-progressbar.swiper-pagination-vertical, +.swiper-horizontal > .swiper-pagination-progressbar.swiper-pagination-progressbar-opposite, +.swiper-pagination-progressbar.swiper-pagination-horizontal.swiper-pagination-progressbar-opposite { + width: 4px; + height: 100%; + left: 0; + top: 0; +} +.swiper-pagination-lock { + display: none; +} +/* Scrollbar */ +.swiper-scrollbar { + border-radius: 10px; + position: relative; + -ms-touch-action: none; + background: rgba(0, 0, 0, 0.1); +} +.swiper-scrollbar-disabled > .swiper-scrollbar, +.swiper-scrollbar.swiper-scrollbar-disabled { + display: none !important; +} +.swiper-horizontal > .swiper-scrollbar, +.swiper-scrollbar.swiper-scrollbar-horizontal { + position: absolute; + left: 1%; + bottom: 3px; + z-index: 50; + height: 5px; + width: 98%; +} +.swiper-vertical > .swiper-scrollbar, +.swiper-scrollbar.swiper-scrollbar-vertical { + position: absolute; + right: 3px; + top: 1%; + z-index: 50; + width: 5px; + height: 98%; +} +.swiper-scrollbar-drag { + height: 100%; + width: 100%; + position: relative; + background: rgba(0, 0, 0, 0.5); + border-radius: 10px; + left: 0; + top: 0; +} +.swiper-scrollbar-cursor-drag { + cursor: move; +} +.swiper-scrollbar-lock { + display: none; +} +.swiper-zoom-container { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + text-align: center; +} +.swiper-zoom-container > img, +.swiper-zoom-container > svg, +.swiper-zoom-container > canvas { + max-width: 100%; + max-height: 100%; + object-fit: contain; +} +.swiper-slide-zoomed { + cursor: move; +} +/* Preloader */ +:root { + /* + --swiper-preloader-color: var(--swiper-theme-color); + */ +} +.swiper-lazy-preloader { + width: 42px; + height: 42px; + position: absolute; + left: 50%; + top: 50%; + margin-left: -21px; + margin-top: -21px; + z-index: 10; + transform-origin: 50%; + box-sizing: border-box; + border: 4px solid var(--swiper-preloader-color, var(--swiper-theme-color)); + border-radius: 50%; + border-top-color: transparent; +} +.swiper:not(.swiper-watch-progress) .swiper-lazy-preloader, +.swiper-watch-progress .swiper-slide-visible .swiper-lazy-preloader { + animation: swiper-preloader-spin 1s infinite linear; +} +.swiper-lazy-preloader-white { + --swiper-preloader-color: #fff; +} +.swiper-lazy-preloader-black { + --swiper-preloader-color: #000; +} +@keyframes swiper-preloader-spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +/* a11y */ +.swiper .swiper-notification { + position: absolute; + left: 0; + top: 0; + pointer-events: none; + opacity: 0; + z-index: -1000; +} +.swiper-free-mode > .swiper-wrapper { + transition-timing-function: ease-out; + margin: 0 auto; +} +.swiper-grid > .swiper-wrapper { + flex-wrap: wrap; +} +.swiper-grid-column > .swiper-wrapper { + flex-wrap: wrap; + flex-direction: column; +} +.swiper-fade.swiper-free-mode .swiper-slide { + transition-timing-function: ease-out; +} +.swiper-fade .swiper-slide { + pointer-events: none; + transition-property: opacity; +} +.swiper-fade .swiper-slide .swiper-slide { + pointer-events: none; +} +.swiper-fade .swiper-slide-active, +.swiper-fade .swiper-slide-active .swiper-slide-active { + pointer-events: auto; +} +.swiper-cube { + overflow: visible; +} +.swiper-cube .swiper-slide { + pointer-events: none; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + z-index: 1; + visibility: hidden; + transform-origin: 0 0; + width: 100%; + height: 100%; +} +.swiper-cube .swiper-slide .swiper-slide { + pointer-events: none; +} +.swiper-cube.swiper-rtl .swiper-slide { + transform-origin: 100% 0; +} +.swiper-cube .swiper-slide-active, +.swiper-cube .swiper-slide-active .swiper-slide-active { + pointer-events: auto; +} +.swiper-cube .swiper-slide-active, +.swiper-cube .swiper-slide-next, +.swiper-cube .swiper-slide-prev, +.swiper-cube .swiper-slide-next + .swiper-slide { + pointer-events: auto; + visibility: visible; +} +.swiper-cube .swiper-slide-shadow-top, +.swiper-cube .swiper-slide-shadow-bottom, +.swiper-cube .swiper-slide-shadow-left, +.swiper-cube .swiper-slide-shadow-right { + z-index: 0; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; +} +.swiper-cube .swiper-cube-shadow { + position: absolute; + left: 0; + bottom: 0px; + width: 100%; + height: 100%; + opacity: 0.6; + z-index: 0; +} +.swiper-cube .swiper-cube-shadow:before { + content: ''; + background: #000; + position: absolute; + left: 0; + top: 0; + bottom: 0; + right: 0; + filter: blur(50px); +} +.swiper-flip { + overflow: visible; +} +.swiper-flip .swiper-slide { + pointer-events: none; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + z-index: 1; +} +.swiper-flip .swiper-slide .swiper-slide { + pointer-events: none; +} +.swiper-flip .swiper-slide-active, +.swiper-flip .swiper-slide-active .swiper-slide-active { + pointer-events: auto; +} +.swiper-flip .swiper-slide-shadow-top, +.swiper-flip .swiper-slide-shadow-bottom, +.swiper-flip .swiper-slide-shadow-left, +.swiper-flip .swiper-slide-shadow-right { + z-index: 0; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; +} +.swiper-creative .swiper-slide { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + overflow: hidden; + transition-property: transform, opacity, height; +} +.swiper-cards { + overflow: visible; +} +.swiper-cards .swiper-slide { + transform-origin: center bottom; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + overflow: hidden; +} diff --git a/public/static/js/button.js b/public/static/js/button.js new file mode 100644 index 0000000..c57296c --- /dev/null +++ b/public/static/js/button.js @@ -0,0 +1,25 @@ +$(function(){ + + $(window).scroll(function(){ //只要窗口滚动,就触发下面代码 + + var scrollt = document.documentElement.scrollTop + document.body.scrollTop; //获取滚动后的高度 + + if( scrollt >200 ){ //判断滚动后高度超过200px,就显示 + + $("#back_top").fadeIn(400); //淡入 + + }else{ + + $("#back_top").stop().fadeOut(400); //如果返回或者没有超过,就淡出.必须加上stop()停止之前动画,否则会出现闪动 + + } + + }); + + $("#back_top").click(function(){ //当点击标签的时候,使用animate在200毫秒的时间内,滚到顶部 + + $("html,body").animate({scrollTop:"0px"},200); + + }); + +}); \ No newline at end of file diff --git a/public/static/js/contact.js b/public/static/js/contact.js new file mode 100644 index 0000000..53598bc --- /dev/null +++ b/public/static/js/contact.js @@ -0,0 +1,69 @@ +//高德地图 +var map = new AMap.Map("container", { + zoom: 30, + center: [113.241678, 22.69780] + // center:[113.241538,22.698132] +}); +var marker = new AMap.Marker({ + position: new AMap.LngLat(113.241678, 22.69780), + title: "高路华" +}); +map.add(marker) + + + + +function ajaxPost(type, addMsgApi, captchaApi) { + let message_content; + let message_name; + let message_phone; + let message_mail; + let message_address; + let captcha; + + if (type == 'pc') { + message_content = $('textarea[name="message_content"]').val(); + message_name = $('input[name="message_name"]').val(); + message_phone = $('input[name="message_phone"]').val(); + message_mail = $('input[name="message_mail"]').val(); + message_address = $('input[name="message_address"]').val(); + captcha = $('input[name="captcha"]').val(); + } else { + message_content = $('textarea[name="message_content_app"]').val(); + message_name = $('input[name="message_name_app"]').val(); + message_phone = $('input[name="message_phone_app"]').val(); + message_mail = $('input[name="message_mail_app"]').val(); + message_address = $('input[name="message_address_app"]').val(); + captcha = $('input[name="captcha_app"]').val(); + } + + + console.log('表单数据'); + $.ajax({ + url: addMsgApi, + type: "POST", + data: { + message_content: message_content, + message_name: message_name, + message_phone: message_phone, + message_mail: message_mail, + message_address: message_address, + captcha: captcha, + }, + success: function (data) { + if (data.code == 0) { + alert(data.msg); + } else { + alert(data.msg); + } + //留言后刷新验证码 + if (type == 'pc') { + $('#msg_code').attr("src", captchaApi + '?' + Math.random()) + } else { + $('#msg_code_app').attr("src", captchaApi + '?' + Math.random()) + } + } + + }) +} + diff --git a/public/static/js/hyw/bootstrap/css/bootstrap.css b/public/static/js/hyw/bootstrap/css/bootstrap.css new file mode 100644 index 0000000..8eac957 --- /dev/null +++ b/public/static/js/hyw/bootstrap/css/bootstrap.css @@ -0,0 +1,10224 @@ +/*! + * Bootstrap v4.4.1 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +:root { + --blue: #007bff; + --indigo: #6610f2; + --purple: #6f42c1; + --pink: #e83e8c; + --red: #dc3545; + --orange: #fd7e14; + --yellow: #ffc107; + --green: #28a745; + --teal: #20c997; + --cyan: #17a2b8; + --white: #fff; + --gray: #6c757d; + --gray-dark: #343a40; + --primary: #007bff; + --secondary: #6c757d; + --success: #28a745; + --info: #17a2b8; + --warning: #ffc107; + --danger: #dc3545; + --light: #f8f9fa; + --dark: #343a40; + --breakpoint-xs: 0; + --breakpoint-sm: 576px; + --breakpoint-md: 768px; + --breakpoint-lg: 992px; + --breakpoint-xl: 1200px; + --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + font-family: sans-serif; + line-height: 1.15; + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { + display: block; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: left; + background-color: #fff; +} + +[tabindex="-1"]:focus:not(:focus-visible) { + outline: 0 !important; +} + +hr { + box-sizing: content-box; + height: 0; + overflow: visible; +} + +h1, h2, h3, h4, h5, h6 { + margin-top: 0; + margin-bottom: 0.5rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title], +abbr[data-original-title] { + text-decoration: underline; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + cursor: help; + border-bottom: 0; + -webkit-text-decoration-skip-ink: none; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: 700; +} + +dd { + margin-bottom: .5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small { + font-size: 80%; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -.25em; +} + +sup { + top: -.5em; +} + +a { + color: #007bff; + text-decoration: none; + background-color: transparent; +} + +a:hover { + color: #0056b3; + text-decoration: underline; +} + +a:not([href]) { + color: inherit; + text-decoration: none; +} + +a:not([href]):hover { + color: inherit; + text-decoration: none; +} + +pre, +code, +kbd, +samp { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + font-size: 1em; +} + +pre { + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; +} + +figure { + margin: 0 0 1rem; +} + +img { + vertical-align: middle; + border-style: none; +} + +svg { + overflow: hidden; + vertical-align: middle; +} + +table { + border-collapse: collapse; +} + +caption { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + color: #6c757d; + text-align: left; + caption-side: bottom; +} + +th { + text-align: inherit; +} + +label { + display: inline-block; + margin-bottom: 0.5rem; +} + +button { + border-radius: 0; +} + +button:focus { + outline: 1px dotted; + outline: 5px auto -webkit-focus-ring-color; +} + +input, +button, +select, +optgroup, +textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +input { + overflow: visible; +} + +button, +select { + text-transform: none; +} + +select { + word-wrap: normal; +} + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +button:not(:disabled), +[type="button"]:not(:disabled), +[type="reset"]:not(:disabled), +[type="submit"]:not(:disabled) { + cursor: pointer; +} + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + padding: 0; + border-style: none; +} + +input[type="radio"], +input[type="checkbox"] { + box-sizing: border-box; + padding: 0; +} + +input[type="date"], +input[type="time"], +input[type="datetime-local"], +input[type="month"] { + -webkit-appearance: listbox; +} + +textarea { + overflow: auto; + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + max-width: 100%; + padding: 0; + margin-bottom: .5rem; + font-size: 1.5rem; + line-height: inherit; + color: inherit; + white-space: normal; +} + +progress { + vertical-align: baseline; +} + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +[type="search"] { + outline-offset: -2px; + -webkit-appearance: none; +} + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-file-upload-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +summary { + display: list-item; + cursor: pointer; +} + +template { + display: none; +} + +[hidden] { + display: none !important; +} + +h1, h2, h3, h4, h5, h6, +.h1, .h2, .h3, .h4, .h5, .h6 { + margin-bottom: 0.5rem; + font-weight: 500; + line-height: 1.2; +} + +h1, .h1 { + font-size: 2.5rem; +} + +h2, .h2 { + font-size: 2rem; +} + +h3, .h3 { + font-size: 1.75rem; +} + +h4, .h4 { + font-size: 1.5rem; +} + +h5, .h5 { + font-size: 1.25rem; +} + +h6, .h6 { + font-size: 1rem; +} + +.lead { + font-size: 1.25rem; + font-weight: 300; +} + +.display-1 { + font-size: 6rem; + font-weight: 300; + line-height: 1.2; +} + +.display-2 { + font-size: 5.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-3 { + font-size: 4.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-4 { + font-size: 3.5rem; + font-weight: 300; + line-height: 1.2; +} + +hr { + margin-top: 1rem; + margin-bottom: 1rem; + border: 0; + border-top: 1px solid rgba(0, 0, 0, 0.1); +} + +small, +.small { + font-size: 80%; + font-weight: 400; +} + +mark, +.mark { + padding: 0.2em; + background-color: #fcf8e3; +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline-item { + display: inline-block; +} + +.list-inline-item:not(:last-child) { + margin-right: 0.5rem; +} + +.initialism { + font-size: 90%; + text-transform: uppercase; +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.25rem; +} + +.blockquote-footer { + display: block; + font-size: 80%; + color: #6c757d; +} + +.blockquote-footer::before { + content: "\2014\00A0"; +} + +.img-fluid { + max-width: 100%; + height: auto; +} + +.img-thumbnail { + padding: 0.25rem; + background-color: #fff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + max-width: 100%; + height: auto; +} + +.figure { + display: inline-block; +} + +.figure-img { + margin-bottom: 0.5rem; + line-height: 1; +} + +.figure-caption { + font-size: 90%; + color: #6c757d; +} + +code { + font-size: 87.5%; + color: #e83e8c; + word-wrap: break-word; +} + +a > code { + color: inherit; +} + +kbd { + padding: 0.2rem 0.4rem; + font-size: 87.5%; + color: #fff; + background-color: #212529; + border-radius: 0.2rem; +} + +kbd kbd { + padding: 0; + font-size: 100%; + font-weight: 700; +} + +pre { + display: block; + font-size: 87.5%; + color: #212529; +} + +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +.container { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container { + max-width: 540px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 720px; + } +} + +@media (min-width: 992px) { + .container { + max-width: 960px; + } +} + +@media (min-width: 1200px) { + .container { + max-width: 1140px; + } +} + +.container-fluid, .container-sm, .container-md, .container-lg, .container-xl { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container, .container-sm { + max-width: 540px; + } +} + +@media (min-width: 768px) { + .container, .container-sm, .container-md { + max-width: 720px; + } +} + +@media (min-width: 992px) { + .container, .container-sm, .container-md, .container-lg { + max-width: 960px; + } +} + +@media (min-width: 1200px) { + .container, .container-sm, .container-md, .container-lg, .container-xl { + max-width: 1140px; + } +} + +.row { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -15px; + margin-left: -15px; +} + +.no-gutters { + margin-right: 0; + margin-left: 0; +} + +.no-gutters > .col, +.no-gutters > [class*="col-"] { + padding-right: 0; + padding-left: 0; +} + +.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col, +.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm, +.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md, +.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg, +.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl, +.col-xl-auto { + position: relative; + width: 100%; + padding-right: 15px; + padding-left: 15px; +} + +.col { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; +} + +.row-cols-1 > * { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; +} + +.row-cols-2 > * { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; +} + +.row-cols-3 > * { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; +} + +.row-cols-4 > * { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; +} + +.row-cols-5 > * { + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; +} + +.row-cols-6 > * { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; +} + +.col-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; +} + +.col-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; +} + +.col-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; +} + +.col-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; +} + +.col-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; +} + +.col-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; +} + +.col-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; +} + +.col-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; +} + +.col-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; +} + +.col-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; +} + +.col-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; +} + +.col-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; +} + +.col-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; +} + +.order-first { + -ms-flex-order: -1; + order: -1; +} + +.order-last { + -ms-flex-order: 13; + order: 13; +} + +.order-0 { + -ms-flex-order: 0; + order: 0; +} + +.order-1 { + -ms-flex-order: 1; + order: 1; +} + +.order-2 { + -ms-flex-order: 2; + order: 2; +} + +.order-3 { + -ms-flex-order: 3; + order: 3; +} + +.order-4 { + -ms-flex-order: 4; + order: 4; +} + +.order-5 { + -ms-flex-order: 5; + order: 5; +} + +.order-6 { + -ms-flex-order: 6; + order: 6; +} + +.order-7 { + -ms-flex-order: 7; + order: 7; +} + +.order-8 { + -ms-flex-order: 8; + order: 8; +} + +.order-9 { + -ms-flex-order: 9; + order: 9; +} + +.order-10 { + -ms-flex-order: 10; + order: 10; +} + +.order-11 { + -ms-flex-order: 11; + order: 11; +} + +.order-12 { + -ms-flex-order: 12; + order: 12; +} + +.offset-1 { + margin-left: 8.333333%; +} + +.offset-2 { + margin-left: 16.666667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.333333%; +} + +.offset-5 { + margin-left: 41.666667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.333333%; +} + +.offset-8 { + margin-left: 66.666667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.333333%; +} + +.offset-11 { + margin-left: 91.666667%; +} + +@media (min-width: 576px) { + .col-sm { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .row-cols-sm-1 > * { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .row-cols-sm-2 > * { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .row-cols-sm-3 > * { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .row-cols-sm-4 > * { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .row-cols-sm-5 > * { + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; + } + .row-cols-sm-6 > * { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-sm-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-sm-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + .col-sm-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-sm-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-sm-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .col-sm-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + .col-sm-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-sm-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + .col-sm-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + .col-sm-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-sm-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + .col-sm-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + .col-sm-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-sm-first { + -ms-flex-order: -1; + order: -1; + } + .order-sm-last { + -ms-flex-order: 13; + order: 13; + } + .order-sm-0 { + -ms-flex-order: 0; + order: 0; + } + .order-sm-1 { + -ms-flex-order: 1; + order: 1; + } + .order-sm-2 { + -ms-flex-order: 2; + order: 2; + } + .order-sm-3 { + -ms-flex-order: 3; + order: 3; + } + .order-sm-4 { + -ms-flex-order: 4; + order: 4; + } + .order-sm-5 { + -ms-flex-order: 5; + order: 5; + } + .order-sm-6 { + -ms-flex-order: 6; + order: 6; + } + .order-sm-7 { + -ms-flex-order: 7; + order: 7; + } + .order-sm-8 { + -ms-flex-order: 8; + order: 8; + } + .order-sm-9 { + -ms-flex-order: 9; + order: 9; + } + .order-sm-10 { + -ms-flex-order: 10; + order: 10; + } + .order-sm-11 { + -ms-flex-order: 11; + order: 11; + } + .order-sm-12 { + -ms-flex-order: 12; + order: 12; + } + .offset-sm-0 { + margin-left: 0; + } + .offset-sm-1 { + margin-left: 8.333333%; + } + .offset-sm-2 { + margin-left: 16.666667%; + } + .offset-sm-3 { + margin-left: 25%; + } + .offset-sm-4 { + margin-left: 33.333333%; + } + .offset-sm-5 { + margin-left: 41.666667%; + } + .offset-sm-6 { + margin-left: 50%; + } + .offset-sm-7 { + margin-left: 58.333333%; + } + .offset-sm-8 { + margin-left: 66.666667%; + } + .offset-sm-9 { + margin-left: 75%; + } + .offset-sm-10 { + margin-left: 83.333333%; + } + .offset-sm-11 { + margin-left: 91.666667%; + } +} + +@media (min-width: 768px) { + .col-md { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .row-cols-md-1 > * { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .row-cols-md-2 > * { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .row-cols-md-3 > * { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .row-cols-md-4 > * { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .row-cols-md-5 > * { + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; + } + .row-cols-md-6 > * { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-md-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-md-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + .col-md-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-md-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-md-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .col-md-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + .col-md-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-md-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + .col-md-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + .col-md-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-md-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + .col-md-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + .col-md-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-md-first { + -ms-flex-order: -1; + order: -1; + } + .order-md-last { + -ms-flex-order: 13; + order: 13; + } + .order-md-0 { + -ms-flex-order: 0; + order: 0; + } + .order-md-1 { + -ms-flex-order: 1; + order: 1; + } + .order-md-2 { + -ms-flex-order: 2; + order: 2; + } + .order-md-3 { + -ms-flex-order: 3; + order: 3; + } + .order-md-4 { + -ms-flex-order: 4; + order: 4; + } + .order-md-5 { + -ms-flex-order: 5; + order: 5; + } + .order-md-6 { + -ms-flex-order: 6; + order: 6; + } + .order-md-7 { + -ms-flex-order: 7; + order: 7; + } + .order-md-8 { + -ms-flex-order: 8; + order: 8; + } + .order-md-9 { + -ms-flex-order: 9; + order: 9; + } + .order-md-10 { + -ms-flex-order: 10; + order: 10; + } + .order-md-11 { + -ms-flex-order: 11; + order: 11; + } + .order-md-12 { + -ms-flex-order: 12; + order: 12; + } + .offset-md-0 { + margin-left: 0; + } + .offset-md-1 { + margin-left: 8.333333%; + } + .offset-md-2 { + margin-left: 16.666667%; + } + .offset-md-3 { + margin-left: 25%; + } + .offset-md-4 { + margin-left: 33.333333%; + } + .offset-md-5 { + margin-left: 41.666667%; + } + .offset-md-6 { + margin-left: 50%; + } + .offset-md-7 { + margin-left: 58.333333%; + } + .offset-md-8 { + margin-left: 66.666667%; + } + .offset-md-9 { + margin-left: 75%; + } + .offset-md-10 { + margin-left: 83.333333%; + } + .offset-md-11 { + margin-left: 91.666667%; + } +} + +@media (min-width: 992px) { + .col-lg { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .row-cols-lg-1 > * { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .row-cols-lg-2 > * { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .row-cols-lg-3 > * { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .row-cols-lg-4 > * { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .row-cols-lg-5 > * { + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; + } + .row-cols-lg-6 > * { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-lg-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-lg-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + .col-lg-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-lg-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-lg-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .col-lg-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + .col-lg-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-lg-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + .col-lg-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + .col-lg-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-lg-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + .col-lg-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + .col-lg-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-lg-first { + -ms-flex-order: -1; + order: -1; + } + .order-lg-last { + -ms-flex-order: 13; + order: 13; + } + .order-lg-0 { + -ms-flex-order: 0; + order: 0; + } + .order-lg-1 { + -ms-flex-order: 1; + order: 1; + } + .order-lg-2 { + -ms-flex-order: 2; + order: 2; + } + .order-lg-3 { + -ms-flex-order: 3; + order: 3; + } + .order-lg-4 { + -ms-flex-order: 4; + order: 4; + } + .order-lg-5 { + -ms-flex-order: 5; + order: 5; + } + .order-lg-6 { + -ms-flex-order: 6; + order: 6; + } + .order-lg-7 { + -ms-flex-order: 7; + order: 7; + } + .order-lg-8 { + -ms-flex-order: 8; + order: 8; + } + .order-lg-9 { + -ms-flex-order: 9; + order: 9; + } + .order-lg-10 { + -ms-flex-order: 10; + order: 10; + } + .order-lg-11 { + -ms-flex-order: 11; + order: 11; + } + .order-lg-12 { + -ms-flex-order: 12; + order: 12; + } + .offset-lg-0 { + margin-left: 0; + } + .offset-lg-1 { + margin-left: 8.333333%; + } + .offset-lg-2 { + margin-left: 16.666667%; + } + .offset-lg-3 { + margin-left: 25%; + } + .offset-lg-4 { + margin-left: 33.333333%; + } + .offset-lg-5 { + margin-left: 41.666667%; + } + .offset-lg-6 { + margin-left: 50%; + } + .offset-lg-7 { + margin-left: 58.333333%; + } + .offset-lg-8 { + margin-left: 66.666667%; + } + .offset-lg-9 { + margin-left: 75%; + } + .offset-lg-10 { + margin-left: 83.333333%; + } + .offset-lg-11 { + margin-left: 91.666667%; + } +} + +@media (min-width: 1200px) { + .col-xl { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + max-width: 100%; + } + .row-cols-xl-1 > * { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .row-cols-xl-2 > * { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .row-cols-xl-3 > * { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .row-cols-xl-4 > * { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .row-cols-xl-5 > * { + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; + } + .row-cols-xl-6 > * { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-xl-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; + } + .col-xl-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; + } + .col-xl-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-xl-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-xl-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } + .col-xl-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; + } + .col-xl-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } + .col-xl-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; + } + .col-xl-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; + } + .col-xl-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } + .col-xl-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; + } + .col-xl-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; + } + .col-xl-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; + } + .order-xl-first { + -ms-flex-order: -1; + order: -1; + } + .order-xl-last { + -ms-flex-order: 13; + order: 13; + } + .order-xl-0 { + -ms-flex-order: 0; + order: 0; + } + .order-xl-1 { + -ms-flex-order: 1; + order: 1; + } + .order-xl-2 { + -ms-flex-order: 2; + order: 2; + } + .order-xl-3 { + -ms-flex-order: 3; + order: 3; + } + .order-xl-4 { + -ms-flex-order: 4; + order: 4; + } + .order-xl-5 { + -ms-flex-order: 5; + order: 5; + } + .order-xl-6 { + -ms-flex-order: 6; + order: 6; + } + .order-xl-7 { + -ms-flex-order: 7; + order: 7; + } + .order-xl-8 { + -ms-flex-order: 8; + order: 8; + } + .order-xl-9 { + -ms-flex-order: 9; + order: 9; + } + .order-xl-10 { + -ms-flex-order: 10; + order: 10; + } + .order-xl-11 { + -ms-flex-order: 11; + order: 11; + } + .order-xl-12 { + -ms-flex-order: 12; + order: 12; + } + .offset-xl-0 { + margin-left: 0; + } + .offset-xl-1 { + margin-left: 8.333333%; + } + .offset-xl-2 { + margin-left: 16.666667%; + } + .offset-xl-3 { + margin-left: 25%; + } + .offset-xl-4 { + margin-left: 33.333333%; + } + .offset-xl-5 { + margin-left: 41.666667%; + } + .offset-xl-6 { + margin-left: 50%; + } + .offset-xl-7 { + margin-left: 58.333333%; + } + .offset-xl-8 { + margin-left: 66.666667%; + } + .offset-xl-9 { + margin-left: 75%; + } + .offset-xl-10 { + margin-left: 83.333333%; + } + .offset-xl-11 { + margin-left: 91.666667%; + } +} + +.table { + width: 100%; + margin-bottom: 1rem; + color: #212529; +} + +.table th, +.table td { + padding: 0.75rem; + vertical-align: top; + border-top: 1px solid #dee2e6; +} + +.table thead th { + vertical-align: bottom; + border-bottom: 2px solid #dee2e6; +} + +.table tbody + tbody { + border-top: 2px solid #dee2e6; +} + +.table-sm th, +.table-sm td { + padding: 0.3rem; +} + +.table-bordered { + border: 1px solid #dee2e6; +} + +.table-bordered th, +.table-bordered td { + border: 1px solid #dee2e6; +} + +.table-bordered thead th, +.table-bordered thead td { + border-bottom-width: 2px; +} + +.table-borderless th, +.table-borderless td, +.table-borderless thead th, +.table-borderless tbody + tbody { + border: 0; +} + +.table-striped tbody tr:nth-of-type(odd) { + background-color: rgba(0, 0, 0, 0.05); +} + +.table-hover tbody tr:hover { + color: #212529; + background-color: rgba(0, 0, 0, 0.075); +} + +.table-primary, +.table-primary > th, +.table-primary > td { + background-color: #b8daff; +} + +.table-primary th, +.table-primary td, +.table-primary thead th, +.table-primary tbody + tbody { + border-color: #7abaff; +} + +.table-hover .table-primary:hover { + background-color: #9fcdff; +} + +.table-hover .table-primary:hover > td, +.table-hover .table-primary:hover > th { + background-color: #9fcdff; +} + +.table-secondary, +.table-secondary > th, +.table-secondary > td { + background-color: #d6d8db; +} + +.table-secondary th, +.table-secondary td, +.table-secondary thead th, +.table-secondary tbody + tbody { + border-color: #b3b7bb; +} + +.table-hover .table-secondary:hover { + background-color: #c8cbcf; +} + +.table-hover .table-secondary:hover > td, +.table-hover .table-secondary:hover > th { + background-color: #c8cbcf; +} + +.table-success, +.table-success > th, +.table-success > td { + background-color: #c3e6cb; +} + +.table-success th, +.table-success td, +.table-success thead th, +.table-success tbody + tbody { + border-color: #8fd19e; +} + +.table-hover .table-success:hover { + background-color: #b1dfbb; +} + +.table-hover .table-success:hover > td, +.table-hover .table-success:hover > th { + background-color: #b1dfbb; +} + +.table-info, +.table-info > th, +.table-info > td { + background-color: #bee5eb; +} + +.table-info th, +.table-info td, +.table-info thead th, +.table-info tbody + tbody { + border-color: #86cfda; +} + +.table-hover .table-info:hover { + background-color: #abdde5; +} + +.table-hover .table-info:hover > td, +.table-hover .table-info:hover > th { + background-color: #abdde5; +} + +.table-warning, +.table-warning > th, +.table-warning > td { + background-color: #ffeeba; +} + +.table-warning th, +.table-warning td, +.table-warning thead th, +.table-warning tbody + tbody { + border-color: #ffdf7e; +} + +.table-hover .table-warning:hover { + background-color: #ffe8a1; +} + +.table-hover .table-warning:hover > td, +.table-hover .table-warning:hover > th { + background-color: #ffe8a1; +} + +.table-danger, +.table-danger > th, +.table-danger > td { + background-color: #f5c6cb; +} + +.table-danger th, +.table-danger td, +.table-danger thead th, +.table-danger tbody + tbody { + border-color: #ed969e; +} + +.table-hover .table-danger:hover { + background-color: #f1b0b7; +} + +.table-hover .table-danger:hover > td, +.table-hover .table-danger:hover > th { + background-color: #f1b0b7; +} + +.table-light, +.table-light > th, +.table-light > td { + background-color: #fdfdfe; +} + +.table-light th, +.table-light td, +.table-light thead th, +.table-light tbody + tbody { + border-color: #fbfcfc; +} + +.table-hover .table-light:hover { + background-color: #ececf6; +} + +.table-hover .table-light:hover > td, +.table-hover .table-light:hover > th { + background-color: #ececf6; +} + +.table-dark, +.table-dark > th, +.table-dark > td { + background-color: #c6c8ca; +} + +.table-dark th, +.table-dark td, +.table-dark thead th, +.table-dark tbody + tbody { + border-color: #95999c; +} + +.table-hover .table-dark:hover { + background-color: #b9bbbe; +} + +.table-hover .table-dark:hover > td, +.table-hover .table-dark:hover > th { + background-color: #b9bbbe; +} + +.table-active, +.table-active > th, +.table-active > td { + background-color: rgba(0, 0, 0, 0.075); +} + +.table-hover .table-active:hover { + background-color: rgba(0, 0, 0, 0.075); +} + +.table-hover .table-active:hover > td, +.table-hover .table-active:hover > th { + background-color: rgba(0, 0, 0, 0.075); +} + +.table .thead-dark th { + color: #fff; + background-color: #343a40; + border-color: #454d55; +} + +.table .thead-light th { + color: #495057; + background-color: #e9ecef; + border-color: #dee2e6; +} + +.table-dark { + color: #fff; + background-color: #343a40; +} + +.table-dark th, +.table-dark td, +.table-dark thead th { + border-color: #454d55; +} + +.table-dark.table-bordered { + border: 0; +} + +.table-dark.table-striped tbody tr:nth-of-type(odd) { + background-color: rgba(255, 255, 255, 0.05); +} + +.table-dark.table-hover tbody tr:hover { + color: #fff; + background-color: rgba(255, 255, 255, 0.075); +} + +@media (max-width: 575.98px) { + .table-responsive-sm { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + .table-responsive-sm > .table-bordered { + border: 0; + } +} + +@media (max-width: 767.98px) { + .table-responsive-md { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + .table-responsive-md > .table-bordered { + border: 0; + } +} + +@media (max-width: 991.98px) { + .table-responsive-lg { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + .table-responsive-lg > .table-bordered { + border: 0; + } +} + +@media (max-width: 1199.98px) { + .table-responsive-xl { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + .table-responsive-xl > .table-bordered { + border: 0; + } +} + +.table-responsive { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +.table-responsive > .table-bordered { + border: 0; +} + +.form-control { + display: block; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ced4da; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-control { + transition: none; + } +} + +.form-control::-ms-expand { + background-color: transparent; + border: 0; +} + +.form-control:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 #495057; +} + +.form-control:focus { + color: #495057; + background-color: #fff; + border-color: #80bdff; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.form-control::-webkit-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::-moz-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control:-ms-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::-ms-input-placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control::placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control:disabled, .form-control[readonly] { + background-color: #e9ecef; + opacity: 1; +} + +select.form-control:focus::-ms-value { + color: #495057; + background-color: #fff; +} + +.form-control-file, +.form-control-range { + display: block; + width: 100%; +} + +.col-form-label { + padding-top: calc(0.375rem + 1px); + padding-bottom: calc(0.375rem + 1px); + margin-bottom: 0; + font-size: inherit; + line-height: 1.5; +} + +.col-form-label-lg { + padding-top: calc(0.5rem + 1px); + padding-bottom: calc(0.5rem + 1px); + font-size: 1.25rem; + line-height: 1.5; +} + +.col-form-label-sm { + padding-top: calc(0.25rem + 1px); + padding-bottom: calc(0.25rem + 1px); + font-size: 0.875rem; + line-height: 1.5; +} + +.form-control-plaintext { + display: block; + width: 100%; + padding: 0.375rem 0; + margin-bottom: 0; + font-size: 1rem; + line-height: 1.5; + color: #212529; + background-color: transparent; + border: solid transparent; + border-width: 1px 0; +} + +.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { + padding-right: 0; + padding-left: 0; +} + +.form-control-sm { + height: calc(1.5em + 0.5rem + 2px); + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.form-control-lg { + height: calc(1.5em + 1rem + 2px); + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +select.form-control[size], select.form-control[multiple] { + height: auto; +} + +textarea.form-control { + height: auto; +} + +.form-group { + margin-bottom: 1rem; +} + +.form-text { + display: block; + margin-top: 0.25rem; +} + +.form-row { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -5px; + margin-left: -5px; +} + +.form-row > .col, +.form-row > [class*="col-"] { + padding-right: 5px; + padding-left: 5px; +} + +.form-check { + position: relative; + display: block; + padding-left: 1.25rem; +} + +.form-check-input { + position: absolute; + margin-top: 0.3rem; + margin-left: -1.25rem; +} + +.form-check-input[disabled] ~ .form-check-label, +.form-check-input:disabled ~ .form-check-label { + color: #6c757d; +} + +.form-check-label { + margin-bottom: 0; +} + +.form-check-inline { + display: -ms-inline-flexbox; + display: inline-flex; + -ms-flex-align: center; + align-items: center; + padding-left: 0; + margin-right: 0.75rem; +} + +.form-check-inline .form-check-input { + position: static; + margin-top: 0; + margin-right: 0.3125rem; + margin-left: 0; +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #28a745; +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #fff; + background-color: rgba(40, 167, 69, 0.9); + border-radius: 0.25rem; +} + +.was-validated :valid ~ .valid-feedback, +.was-validated :valid ~ .valid-tooltip, +.is-valid ~ .valid-feedback, +.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-control:valid, .form-control.is-valid { + border-color: #28a745; + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .form-control:valid:focus, .form-control.is-valid:focus { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated textarea.form-control:valid, textarea.form-control.is-valid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.was-validated .custom-select:valid, .custom-select.is-valid { + border-color: #28a745; + padding-right: calc(0.75em + 2.3125rem); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .custom-select:valid:focus, .custom-select.is-valid:focus { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { + color: #28a745; +} + +.was-validated .form-check-input:valid ~ .valid-feedback, +.was-validated .form-check-input:valid ~ .valid-tooltip, .form-check-input.is-valid ~ .valid-feedback, +.form-check-input.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .custom-control-input:valid ~ .custom-control-label, .custom-control-input.is-valid ~ .custom-control-label { + color: #28a745; +} + +.was-validated .custom-control-input:valid ~ .custom-control-label::before, .custom-control-input.is-valid ~ .custom-control-label::before { + border-color: #28a745; +} + +.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, .custom-control-input.is-valid:checked ~ .custom-control-label::before { + border-color: #34ce57; + background-color: #34ce57; +} + +.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, .custom-control-input.is-valid:focus ~ .custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .custom-control-input:valid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-valid:focus:not(:checked) ~ .custom-control-label::before { + border-color: #28a745; +} + +.was-validated .custom-file-input:valid ~ .custom-file-label, .custom-file-input.is-valid ~ .custom-file-label { + border-color: #28a745; +} + +.was-validated .custom-file-input:valid:focus ~ .custom-file-label, .custom-file-input.is-valid:focus ~ .custom-file-label { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.invalid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #dc3545; +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #fff; + background-color: rgba(220, 53, 69, 0.9); + border-radius: 0.25rem; +} + +.was-validated :invalid ~ .invalid-feedback, +.was-validated :invalid ~ .invalid-tooltip, +.is-invalid ~ .invalid-feedback, +.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-control:invalid, .form-control.is-invalid { + border-color: #dc3545; + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.was-validated .custom-select:invalid, .custom-select.is-invalid { + border-color: #dc3545; + padding-right: calc(0.75em + 2.3125rem); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .custom-select:invalid:focus, .custom-select.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { + color: #dc3545; +} + +.was-validated .form-check-input:invalid ~ .invalid-feedback, +.was-validated .form-check-input:invalid ~ .invalid-tooltip, .form-check-input.is-invalid ~ .invalid-feedback, +.form-check-input.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .custom-control-input:invalid ~ .custom-control-label, .custom-control-input.is-invalid ~ .custom-control-label { + color: #dc3545; +} + +.was-validated .custom-control-input:invalid ~ .custom-control-label::before, .custom-control-input.is-invalid ~ .custom-control-label::before { + border-color: #dc3545; +} + +.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, .custom-control-input.is-invalid:checked ~ .custom-control-label::before { + border-color: #e4606d; + background-color: #e4606d; +} + +.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, .custom-control-input.is-invalid:focus ~ .custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .custom-control-input:invalid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-invalid:focus:not(:checked) ~ .custom-control-label::before { + border-color: #dc3545; +} + +.was-validated .custom-file-input:invalid ~ .custom-file-label, .custom-file-input.is-invalid ~ .custom-file-label { + border-color: #dc3545; +} + +.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, .custom-file-input.is-invalid:focus ~ .custom-file-label { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.form-inline { + display: -ms-flexbox; + display: flex; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -ms-flex-align: center; + align-items: center; +} + +.form-inline .form-check { + width: 100%; +} + +@media (min-width: 576px) { + .form-inline label { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + margin-bottom: 0; + } + .form-inline .form-group { + display: -ms-flexbox; + display: flex; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -ms-flex-align: center; + align-items: center; + margin-bottom: 0; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-plaintext { + display: inline-block; + } + .form-inline .input-group, + .form-inline .custom-select { + width: auto; + } + .form-inline .form-check { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + width: auto; + padding-left: 0; + } + .form-inline .form-check-input { + position: relative; + -ms-flex-negative: 0; + flex-shrink: 0; + margin-top: 0; + margin-right: 0.25rem; + margin-left: 0; + } + .form-inline .custom-control { + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + } + .form-inline .custom-control-label { + margin-bottom: 0; + } +} + +.btn { + display: inline-block; + font-weight: 400; + color: #212529; + text-align: center; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: transparent; + border: 1px solid transparent; + padding: 0.375rem 0.75rem; + font-size: 1rem; + line-height: 1.5; + border-radius: 0.25rem; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .btn { + transition: none; + } +} + +.btn:hover { + color: #212529; + text-decoration: none; +} + +.btn:focus, .btn.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.btn.disabled, .btn:disabled { + opacity: 0.65; +} + +a.btn.disabled, +fieldset:disabled a.btn { + pointer-events: none; +} + +.btn-primary { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-primary:hover { + color: #fff; + background-color: #0069d9; + border-color: #0062cc; +} + +.btn-primary:focus, .btn-primary.focus { + color: #fff; + background-color: #0069d9; + border-color: #0062cc; + box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); +} + +.btn-primary.disabled, .btn-primary:disabled { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active, +.show > .btn-primary.dropdown-toggle { + color: #fff; + background-color: #0062cc; + border-color: #005cbf; +} + +.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus, +.show > .btn-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5); +} + +.btn-secondary { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-secondary:hover { + color: #fff; + background-color: #5a6268; + border-color: #545b62; +} + +.btn-secondary:focus, .btn-secondary.focus { + color: #fff; + background-color: #5a6268; + border-color: #545b62; + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-secondary.disabled, .btn-secondary:disabled { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active, +.show > .btn-secondary.dropdown-toggle { + color: #fff; + background-color: #545b62; + border-color: #4e555b; +} + +.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus, +.show > .btn-secondary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-success { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-success:hover { + color: #fff; + background-color: #218838; + border-color: #1e7e34; +} + +.btn-success:focus, .btn-success.focus { + color: #fff; + background-color: #218838; + border-color: #1e7e34; + box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); +} + +.btn-success.disabled, .btn-success:disabled { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active, +.show > .btn-success.dropdown-toggle { + color: #fff; + background-color: #1e7e34; + border-color: #1c7430; +} + +.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus, +.show > .btn-success.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5); +} + +.btn-info { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-info:hover { + color: #fff; + background-color: #138496; + border-color: #117a8b; +} + +.btn-info:focus, .btn-info.focus { + color: #fff; + background-color: #138496; + border-color: #117a8b; + box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); +} + +.btn-info.disabled, .btn-info:disabled { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active, +.show > .btn-info.dropdown-toggle { + color: #fff; + background-color: #117a8b; + border-color: #10707f; +} + +.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus, +.show > .btn-info.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5); +} + +.btn-warning { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-warning:hover { + color: #212529; + background-color: #e0a800; + border-color: #d39e00; +} + +.btn-warning:focus, .btn-warning.focus { + color: #212529; + background-color: #e0a800; + border-color: #d39e00; + box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); +} + +.btn-warning.disabled, .btn-warning:disabled { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active, +.show > .btn-warning.dropdown-toggle { + color: #212529; + background-color: #d39e00; + border-color: #c69500; +} + +.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus, +.show > .btn-warning.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); +} + +.btn-danger { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-danger:hover { + color: #fff; + background-color: #c82333; + border-color: #bd2130; +} + +.btn-danger:focus, .btn-danger.focus { + color: #fff; + background-color: #c82333; + border-color: #bd2130; + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-danger.disabled, .btn-danger:disabled { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active, +.show > .btn-danger.dropdown-toggle { + color: #fff; + background-color: #bd2130; + border-color: #b21f2d; +} + +.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus, +.show > .btn-danger.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-light { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-light:hover { + color: #212529; + background-color: #e2e6ea; + border-color: #dae0e5; +} + +.btn-light:focus, .btn-light.focus { + color: #212529; + background-color: #e2e6ea; + border-color: #dae0e5; + box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); +} + +.btn-light.disabled, .btn-light:disabled { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active, +.show > .btn-light.dropdown-toggle { + color: #212529; + background-color: #dae0e5; + border-color: #d3d9df; +} + +.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus, +.show > .btn-light.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5); +} + +.btn-dark { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-dark:hover { + color: #fff; + background-color: #23272b; + border-color: #1d2124; +} + +.btn-dark:focus, .btn-dark.focus { + color: #fff; + background-color: #23272b; + border-color: #1d2124; + box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); +} + +.btn-dark.disabled, .btn-dark:disabled { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active, +.show > .btn-dark.dropdown-toggle { + color: #fff; + background-color: #1d2124; + border-color: #171a1d; +} + +.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus, +.show > .btn-dark.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5); +} + +.btn-outline-primary { + color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:hover { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:focus, .btn-outline-primary.focus { + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.btn-outline-primary.disabled, .btn-outline-primary:disabled { + color: #007bff; + background-color: transparent; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active, +.show > .btn-outline-primary.dropdown-toggle { + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.btn-outline-secondary { + color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:hover { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:focus, .btn-outline-secondary.focus { + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-outline-secondary.disabled, .btn-outline-secondary:disabled { + color: #6c757d; + background-color: transparent; +} + +.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active, +.show > .btn-outline-secondary.dropdown-toggle { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-secondary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-outline-success { + color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:hover { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:focus, .btn-outline-success.focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-outline-success.disabled, .btn-outline-success:disabled { + color: #28a745; + background-color: transparent; +} + +.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active, +.show > .btn-outline-success.dropdown-toggle { + color: #fff; + background-color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-success.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-outline-info { + color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:hover { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:focus, .btn-outline-info.focus { + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-outline-info.disabled, .btn-outline-info:disabled { + color: #17a2b8; + background-color: transparent; +} + +.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active, +.show > .btn-outline-info.dropdown-toggle { + color: #fff; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-info.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-outline-warning { + color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:hover { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:focus, .btn-outline-warning.focus { + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-outline-warning.disabled, .btn-outline-warning:disabled { + color: #ffc107; + background-color: transparent; +} + +.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active, +.show > .btn-outline-warning.dropdown-toggle { + color: #212529; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-warning.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-outline-danger { + color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:hover { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:focus, .btn-outline-danger.focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-outline-danger.disabled, .btn-outline-danger:disabled { + color: #dc3545; + background-color: transparent; +} + +.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active, +.show > .btn-outline-danger.dropdown-toggle { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-danger.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-outline-light { + color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:hover { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:focus, .btn-outline-light.focus { + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-outline-light.disabled, .btn-outline-light:disabled { + color: #f8f9fa; + background-color: transparent; +} + +.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active, +.show > .btn-outline-light.dropdown-toggle { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-light.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-outline-dark { + color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:hover { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:focus, .btn-outline-dark.focus { + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.btn-outline-dark.disabled, .btn-outline-dark:disabled { + color: #343a40; + background-color: transparent; +} + +.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active, +.show > .btn-outline-dark.dropdown-toggle { + color: #fff; + background-color: #343a40; + border-color: #343a40; +} + +.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus, +.show > .btn-outline-dark.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.btn-link { + font-weight: 400; + color: #007bff; + text-decoration: none; +} + +.btn-link:hover { + color: #0056b3; + text-decoration: underline; +} + +.btn-link:focus, .btn-link.focus { + text-decoration: underline; + box-shadow: none; +} + +.btn-link:disabled, .btn-link.disabled { + color: #6c757d; + pointer-events: none; +} + +.btn-lg, .btn-group-lg > .btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +.btn-sm, .btn-group-sm > .btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.btn-block { + display: block; + width: 100%; +} + +.btn-block + .btn-block { + margin-top: 0.5rem; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.fade { + transition: opacity 0.15s linear; +} + +@media (prefers-reduced-motion: reduce) { + .fade { + transition: none; + } +} + +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + position: relative; + height: 0; + overflow: hidden; + transition: height 0.35s ease; +} + +@media (prefers-reduced-motion: reduce) { + .collapsing { + transition: none; + } +} + +.dropup, +.dropright, +.dropdown, +.dropleft { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; +} + +.dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; +} + +.dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 10rem; + padding: 0.5rem 0; + margin: 0.125rem 0 0; + font-size: 1rem; + color: #212529; + text-align: left; + list-style: none; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0.25rem; +} + +.dropdown-menu-left { + right: auto; + left: 0; +} + +.dropdown-menu-right { + right: 0; + left: auto; +} + +@media (min-width: 576px) { + .dropdown-menu-sm-left { + right: auto; + left: 0; + } + .dropdown-menu-sm-right { + right: 0; + left: auto; + } +} + +@media (min-width: 768px) { + .dropdown-menu-md-left { + right: auto; + left: 0; + } + .dropdown-menu-md-right { + right: 0; + left: auto; + } +} + +@media (min-width: 992px) { + .dropdown-menu-lg-left { + right: auto; + left: 0; + } + .dropdown-menu-lg-right { + right: 0; + left: auto; + } +} + +@media (min-width: 1200px) { + .dropdown-menu-xl-left { + right: auto; + left: 0; + } + .dropdown-menu-xl-right { + right: 0; + left: auto; + } +} + +.dropup .dropdown-menu { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: 0.125rem; +} + +.dropup .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0; + border-right: 0.3em solid transparent; + border-bottom: 0.3em solid; + border-left: 0.3em solid transparent; +} + +.dropup .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropright .dropdown-menu { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: 0.125rem; +} + +.dropright .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0; + border-bottom: 0.3em solid transparent; + border-left: 0.3em solid; +} + +.dropright .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropright .dropdown-toggle::after { + vertical-align: 0; +} + +.dropleft .dropdown-menu { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: 0.125rem; +} + +.dropleft .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; +} + +.dropleft .dropdown-toggle::after { + display: none; +} + +.dropleft .dropdown-toggle::before { + display: inline-block; + margin-right: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0.3em solid; + border-bottom: 0.3em solid transparent; +} + +.dropleft .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropleft .dropdown-toggle::before { + vertical-align: 0; +} + +.dropdown-menu[x-placement^="top"], .dropdown-menu[x-placement^="right"], .dropdown-menu[x-placement^="bottom"], .dropdown-menu[x-placement^="left"] { + right: auto; + bottom: auto; +} + +.dropdown-divider { + height: 0; + margin: 0.5rem 0; + overflow: hidden; + border-top: 1px solid #e9ecef; +} + +.dropdown-item { + display: block; + width: 100%; + padding: 0.25rem 1.5rem; + clear: both; + font-weight: 400; + color: #212529; + text-align: inherit; + white-space: nowrap; + background-color: transparent; + border: 0; +} + +.dropdown-item:hover, .dropdown-item:focus { + color: #16181b; + text-decoration: none; + background-color: #f8f9fa; +} + +.dropdown-item.active, .dropdown-item:active { + color: #fff; + text-decoration: none; + background-color: #007bff; +} + +.dropdown-item.disabled, .dropdown-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-header { + display: block; + padding: 0.5rem 1.5rem; + margin-bottom: 0; + font-size: 0.875rem; + color: #6c757d; + white-space: nowrap; +} + +.dropdown-item-text { + display: block; + padding: 0.25rem 1.5rem; + color: #212529; +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: -ms-inline-flexbox; + display: inline-flex; + vertical-align: middle; +} + +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; +} + +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover { + z-index: 1; +} + +.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active, +.btn-group-vertical > .btn:focus, +.btn-group-vertical > .btn:active, +.btn-group-vertical > .btn.active { + z-index: 1; +} + +.btn-toolbar { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.btn-toolbar .input-group { + width: auto; +} + +.btn-group > .btn:not(:first-child), +.btn-group > .btn-group:not(:first-child) { + margin-left: -1px; +} + +.btn-group > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.btn-group > .btn:not(:first-child), +.btn-group > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.dropdown-toggle-split { + padding-right: 0.5625rem; + padding-left: 0.5625rem; +} + +.dropdown-toggle-split::after, +.dropup .dropdown-toggle-split::after, +.dropright .dropdown-toggle-split::after { + margin-left: 0; +} + +.dropleft .dropdown-toggle-split::before { + margin-right: 0; +} + +.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { + padding-right: 0.375rem; + padding-left: 0.375rem; +} + +.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { + padding-right: 0.75rem; + padding-left: 0.75rem; +} + +.btn-group-vertical { + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-align: start; + align-items: flex-start; + -ms-flex-pack: center; + justify-content: center; +} + +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group { + width: 100%; +} + +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) { + margin-top: -1px; +} + +.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group-vertical > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.btn-group-toggle > .btn, +.btn-group-toggle > .btn-group > .btn { + margin-bottom: 0; +} + +.btn-group-toggle > .btn input[type="radio"], +.btn-group-toggle > .btn input[type="checkbox"], +.btn-group-toggle > .btn-group > .btn input[type="radio"], +.btn-group-toggle > .btn-group > .btn input[type="checkbox"] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} + +.input-group { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: stretch; + align-items: stretch; + width: 100%; +} + +.input-group > .form-control, +.input-group > .form-control-plaintext, +.input-group > .custom-select, +.input-group > .custom-file { + position: relative; + -ms-flex: 1 1 0%; + flex: 1 1 0%; + min-width: 0; + margin-bottom: 0; +} + +.input-group > .form-control + .form-control, +.input-group > .form-control + .custom-select, +.input-group > .form-control + .custom-file, +.input-group > .form-control-plaintext + .form-control, +.input-group > .form-control-plaintext + .custom-select, +.input-group > .form-control-plaintext + .custom-file, +.input-group > .custom-select + .form-control, +.input-group > .custom-select + .custom-select, +.input-group > .custom-select + .custom-file, +.input-group > .custom-file + .form-control, +.input-group > .custom-file + .custom-select, +.input-group > .custom-file + .custom-file { + margin-left: -1px; +} + +.input-group > .form-control:focus, +.input-group > .custom-select:focus, +.input-group > .custom-file .custom-file-input:focus ~ .custom-file-label { + z-index: 3; +} + +.input-group > .custom-file .custom-file-input:focus { + z-index: 4; +} + +.input-group > .form-control:not(:last-child), +.input-group > .custom-select:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > .form-control:not(:first-child), +.input-group > .custom-select:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.input-group > .custom-file { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; +} + +.input-group > .custom-file:not(:last-child) .custom-file-label, +.input-group > .custom-file:not(:last-child) .custom-file-label::after { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > .custom-file:not(:first-child) .custom-file-label { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.input-group-prepend, +.input-group-append { + display: -ms-flexbox; + display: flex; +} + +.input-group-prepend .btn, +.input-group-append .btn { + position: relative; + z-index: 2; +} + +.input-group-prepend .btn:focus, +.input-group-append .btn:focus { + z-index: 3; +} + +.input-group-prepend .btn + .btn, +.input-group-prepend .btn + .input-group-text, +.input-group-prepend .input-group-text + .input-group-text, +.input-group-prepend .input-group-text + .btn, +.input-group-append .btn + .btn, +.input-group-append .btn + .input-group-text, +.input-group-append .input-group-text + .input-group-text, +.input-group-append .input-group-text + .btn { + margin-left: -1px; +} + +.input-group-prepend { + margin-right: -1px; +} + +.input-group-append { + margin-left: -1px; +} + +.input-group-text { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + padding: 0.375rem 0.75rem; + margin-bottom: 0; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + text-align: center; + white-space: nowrap; + background-color: #e9ecef; + border: 1px solid #ced4da; + border-radius: 0.25rem; +} + +.input-group-text input[type="radio"], +.input-group-text input[type="checkbox"] { + margin-top: 0; +} + +.input-group-lg > .form-control:not(textarea), +.input-group-lg > .custom-select { + height: calc(1.5em + 1rem + 2px); +} + +.input-group-lg > .form-control, +.input-group-lg > .custom-select, +.input-group-lg > .input-group-prepend > .input-group-text, +.input-group-lg > .input-group-append > .input-group-text, +.input-group-lg > .input-group-prepend > .btn, +.input-group-lg > .input-group-append > .btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + line-height: 1.5; + border-radius: 0.3rem; +} + +.input-group-sm > .form-control:not(textarea), +.input-group-sm > .custom-select { + height: calc(1.5em + 0.5rem + 2px); +} + +.input-group-sm > .form-control, +.input-group-sm > .custom-select, +.input-group-sm > .input-group-prepend > .input-group-text, +.input-group-sm > .input-group-append > .input-group-text, +.input-group-sm > .input-group-prepend > .btn, +.input-group-sm > .input-group-append > .btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; + border-radius: 0.2rem; +} + +.input-group-lg > .custom-select, +.input-group-sm > .custom-select { + padding-right: 1.75rem; +} + +.input-group > .input-group-prepend > .btn, +.input-group > .input-group-prepend > .input-group-text, +.input-group > .input-group-append:not(:last-child) > .btn, +.input-group > .input-group-append:not(:last-child) > .input-group-text, +.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > .input-group-append > .btn, +.input-group > .input-group-append > .input-group-text, +.input-group > .input-group-prepend:not(:first-child) > .btn, +.input-group > .input-group-prepend:not(:first-child) > .input-group-text, +.input-group > .input-group-prepend:first-child > .btn:not(:first-child), +.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.custom-control { + position: relative; + display: block; + min-height: 1.5rem; + padding-left: 1.5rem; +} + +.custom-control-inline { + display: -ms-inline-flexbox; + display: inline-flex; + margin-right: 1rem; +} + +.custom-control-input { + position: absolute; + left: 0; + z-index: -1; + width: 1rem; + height: 1.25rem; + opacity: 0; +} + +.custom-control-input:checked ~ .custom-control-label::before { + color: #fff; + border-color: #007bff; + background-color: #007bff; +} + +.custom-control-input:focus ~ .custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-control-input:focus:not(:checked) ~ .custom-control-label::before { + border-color: #80bdff; +} + +.custom-control-input:not(:disabled):active ~ .custom-control-label::before { + color: #fff; + background-color: #b3d7ff; + border-color: #b3d7ff; +} + +.custom-control-input[disabled] ~ .custom-control-label, .custom-control-input:disabled ~ .custom-control-label { + color: #6c757d; +} + +.custom-control-input[disabled] ~ .custom-control-label::before, .custom-control-input:disabled ~ .custom-control-label::before { + background-color: #e9ecef; +} + +.custom-control-label { + position: relative; + margin-bottom: 0; + vertical-align: top; +} + +.custom-control-label::before { + position: absolute; + top: 0.25rem; + left: -1.5rem; + display: block; + width: 1rem; + height: 1rem; + pointer-events: none; + content: ""; + background-color: #fff; + border: #adb5bd solid 1px; +} + +.custom-control-label::after { + position: absolute; + top: 0.25rem; + left: -1.5rem; + display: block; + width: 1rem; + height: 1rem; + content: ""; + background: no-repeat 50% / 50% 50%; +} + +.custom-checkbox .custom-control-label::before { + border-radius: 0.25rem; +} + +.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e"); +} + +.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before { + border-color: #007bff; + background-color: #007bff; +} + +.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e"); +} + +.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-radio .custom-control-label::before { + border-radius: 50%; +} + +.custom-radio .custom-control-input:checked ~ .custom-control-label::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); +} + +.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-switch { + padding-left: 2.25rem; +} + +.custom-switch .custom-control-label::before { + left: -2.25rem; + width: 1.75rem; + pointer-events: all; + border-radius: 0.5rem; +} + +.custom-switch .custom-control-label::after { + top: calc(0.25rem + 2px); + left: calc(-2.25rem + 2px); + width: calc(1rem - 4px); + height: calc(1rem - 4px); + background-color: #adb5bd; + border-radius: 0.5rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out; + transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .custom-switch .custom-control-label::after { + transition: none; + } +} + +.custom-switch .custom-control-input:checked ~ .custom-control-label::after { + background-color: #fff; + -webkit-transform: translateX(0.75rem); + transform: translateX(0.75rem); +} + +.custom-switch .custom-control-input:disabled:checked ~ .custom-control-label::before { + background-color: rgba(0, 123, 255, 0.5); +} + +.custom-select { + display: inline-block; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem 1.75rem 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + vertical-align: middle; + background: #fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px; + border: 1px solid #ced4da; + border-radius: 0.25rem; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.custom-select:focus { + border-color: #80bdff; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-select:focus::-ms-value { + color: #495057; + background-color: #fff; +} + +.custom-select[multiple], .custom-select[size]:not([size="1"]) { + height: auto; + padding-right: 0.75rem; + background-image: none; +} + +.custom-select:disabled { + color: #6c757d; + background-color: #e9ecef; +} + +.custom-select::-ms-expand { + display: none; +} + +.custom-select:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 #495057; +} + +.custom-select-sm { + height: calc(1.5em + 0.5rem + 2px); + padding-top: 0.25rem; + padding-bottom: 0.25rem; + padding-left: 0.5rem; + font-size: 0.875rem; +} + +.custom-select-lg { + height: calc(1.5em + 1rem + 2px); + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 1rem; + font-size: 1.25rem; +} + +.custom-file { + position: relative; + display: inline-block; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + margin-bottom: 0; +} + +.custom-file-input { + position: relative; + z-index: 2; + width: 100%; + height: calc(1.5em + 0.75rem + 2px); + margin: 0; + opacity: 0; +} + +.custom-file-input:focus ~ .custom-file-label { + border-color: #80bdff; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-file-input[disabled] ~ .custom-file-label, +.custom-file-input:disabled ~ .custom-file-label { + background-color: #e9ecef; +} + +.custom-file-input:lang(en) ~ .custom-file-label::after { + content: "Browse"; +} + +.custom-file-input ~ .custom-file-label[data-browse]::after { + content: attr(data-browse); +} + +.custom-file-label { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 1; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem 0.75rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + border: 1px solid #ced4da; + border-radius: 0.25rem; +} + +.custom-file-label::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + z-index: 3; + display: block; + height: calc(1.5em + 0.75rem); + padding: 0.375rem 0.75rem; + line-height: 1.5; + color: #495057; + content: "Browse"; + background-color: #e9ecef; + border-left: inherit; + border-radius: 0 0.25rem 0.25rem 0; +} + +.custom-range { + width: 100%; + height: 1.4rem; + padding: 0; + background-color: transparent; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.custom-range:focus { + outline: none; +} + +.custom-range:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range:focus::-ms-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.custom-range::-moz-focus-outer { + border: 0; +} + +.custom-range::-webkit-slider-thumb { + width: 1rem; + height: 1rem; + margin-top: -0.25rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + -webkit-appearance: none; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .custom-range::-webkit-slider-thumb { + -webkit-transition: none; + transition: none; + } +} + +.custom-range::-webkit-slider-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-webkit-slider-runnable-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.custom-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + -moz-appearance: none; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .custom-range::-moz-range-thumb { + -moz-transition: none; + transition: none; + } +} + +.custom-range::-moz-range-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-moz-range-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.custom-range::-ms-thumb { + width: 1rem; + height: 1rem; + margin-top: 0; + margin-right: 0.2rem; + margin-left: 0.2rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + -ms-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .custom-range::-ms-thumb { + -ms-transition: none; + transition: none; + } +} + +.custom-range::-ms-thumb:active { + background-color: #b3d7ff; +} + +.custom-range::-ms-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: transparent; + border-color: transparent; + border-width: 0.5rem; +} + +.custom-range::-ms-fill-lower { + background-color: #dee2e6; + border-radius: 1rem; +} + +.custom-range::-ms-fill-upper { + margin-right: 15px; + background-color: #dee2e6; + border-radius: 1rem; +} + +.custom-range:disabled::-webkit-slider-thumb { + background-color: #adb5bd; +} + +.custom-range:disabled::-webkit-slider-runnable-track { + cursor: default; +} + +.custom-range:disabled::-moz-range-thumb { + background-color: #adb5bd; +} + +.custom-range:disabled::-moz-range-track { + cursor: default; +} + +.custom-range:disabled::-ms-thumb { + background-color: #adb5bd; +} + +.custom-control-label::before, +.custom-file-label, +.custom-select { + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .custom-control-label::before, + .custom-file-label, + .custom-select { + transition: none; + } +} + +.nav { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: 0.5rem 1rem; +} + +.nav-link:hover, .nav-link:focus { + text-decoration: none; +} + +.nav-link.disabled { + color: #6c757d; + pointer-events: none; + cursor: default; +} + +.nav-tabs { + border-bottom: 1px solid #dee2e6; +} + +.nav-tabs .nav-item { + margin-bottom: -1px; +} + +.nav-tabs .nav-link { + border: 1px solid transparent; + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { + border-color: #e9ecef #e9ecef #dee2e6; +} + +.nav-tabs .nav-link.disabled { + color: #6c757d; + background-color: transparent; + border-color: transparent; +} + +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + color: #495057; + background-color: #fff; + border-color: #dee2e6 #dee2e6 #fff; +} + +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav-pills .nav-link { + border-radius: 0.25rem; +} + +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link { + color: #fff; + background-color: #007bff; +} + +.nav-fill .nav-item { + -ms-flex: 1 1 auto; + flex: 1 1 auto; + text-align: center; +} + +.nav-justified .nav-item { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + text-align: center; +} + +.tab-content > .tab-pane { + display: none; +} + +.tab-content > .active { + display: block; +} + +.navbar { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 0.5rem 1rem; +} + +.navbar .container, +.navbar .container-fluid, .navbar .container-sm, .navbar .container-md, .navbar .container-lg, .navbar .container-xl { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.navbar-brand { + display: inline-block; + padding-top: 0.3125rem; + padding-bottom: 0.3125rem; + margin-right: 1rem; + font-size: 1.25rem; + line-height: inherit; + white-space: nowrap; +} + +.navbar-brand:hover, .navbar-brand:focus { + text-decoration: none; +} + +.navbar-nav { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.navbar-nav .nav-link { + padding-right: 0; + padding-left: 0; +} + +.navbar-nav .dropdown-menu { + position: static; + float: none; +} + +.navbar-text { + display: inline-block; + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.navbar-collapse { + -ms-flex-preferred-size: 100%; + flex-basis: 100%; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-align: center; + align-items: center; +} + +.navbar-toggler { + padding: 0.25rem 0.75rem; + font-size: 1.25rem; + line-height: 1; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.navbar-toggler:hover, .navbar-toggler:focus { + text-decoration: none; +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + content: ""; + background: no-repeat center center; + background-size: 100% 100%; +} + +@media (max-width: 575.98px) { + .navbar-expand-sm > .container, + .navbar-expand-sm > .container-fluid, .navbar-expand-sm > .container-sm, .navbar-expand-sm > .container-md, .navbar-expand-sm > .container-lg, .navbar-expand-sm > .container-xl { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 576px) { + .navbar-expand-sm { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-sm .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-sm > .container, + .navbar-expand-sm > .container-fluid, .navbar-expand-sm > .container-sm, .navbar-expand-sm > .container-md, .navbar-expand-sm > .container-lg, .navbar-expand-sm > .container-xl { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-sm .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-sm .navbar-toggler { + display: none; + } +} + +@media (max-width: 767.98px) { + .navbar-expand-md > .container, + .navbar-expand-md > .container-fluid, .navbar-expand-md > .container-sm, .navbar-expand-md > .container-md, .navbar-expand-md > .container-lg, .navbar-expand-md > .container-xl { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 768px) { + .navbar-expand-md { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-md .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-md .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-md > .container, + .navbar-expand-md > .container-fluid, .navbar-expand-md > .container-sm, .navbar-expand-md > .container-md, .navbar-expand-md > .container-lg, .navbar-expand-md > .container-xl { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-md .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-md .navbar-toggler { + display: none; + } +} + +@media (max-width: 991.98px) { + .navbar-expand-lg > .container, + .navbar-expand-lg > .container-fluid, .navbar-expand-lg > .container-sm, .navbar-expand-lg > .container-md, .navbar-expand-lg > .container-lg, .navbar-expand-lg > .container-xl { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 992px) { + .navbar-expand-lg { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-lg .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-lg > .container, + .navbar-expand-lg > .container-fluid, .navbar-expand-lg > .container-sm, .navbar-expand-lg > .container-md, .navbar-expand-lg > .container-lg, .navbar-expand-lg > .container-xl { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-lg .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-lg .navbar-toggler { + display: none; + } +} + +@media (max-width: 1199.98px) { + .navbar-expand-xl > .container, + .navbar-expand-xl > .container-fluid, .navbar-expand-xl > .container-sm, .navbar-expand-xl > .container-md, .navbar-expand-xl > .container-lg, .navbar-expand-xl > .container-xl { + padding-right: 0; + padding-left: 0; + } +} + +@media (min-width: 1200px) { + .navbar-expand-xl { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; + } + .navbar-expand-xl .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; + } + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-xl > .container, + .navbar-expand-xl > .container-fluid, .navbar-expand-xl > .container-sm, .navbar-expand-xl > .container-md, .navbar-expand-xl > .container-lg, .navbar-expand-xl > .container-xl { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .navbar-expand-xl .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; + } + .navbar-expand-xl .navbar-toggler { + display: none; + } +} + +.navbar-expand { + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.navbar-expand > .container, +.navbar-expand > .container-fluid, .navbar-expand > .container-sm, .navbar-expand > .container-md, .navbar-expand > .container-lg, .navbar-expand > .container-xl { + padding-right: 0; + padding-left: 0; +} + +.navbar-expand .navbar-nav { + -ms-flex-direction: row; + flex-direction: row; +} + +.navbar-expand .navbar-nav .dropdown-menu { + position: absolute; +} + +.navbar-expand .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; +} + +.navbar-expand > .container, +.navbar-expand > .container-fluid, .navbar-expand > .container-sm, .navbar-expand > .container-md, .navbar-expand > .container-lg, .navbar-expand > .container-xl { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; +} + +.navbar-expand .navbar-collapse { + display: -ms-flexbox !important; + display: flex !important; + -ms-flex-preferred-size: auto; + flex-basis: auto; +} + +.navbar-expand .navbar-toggler { + display: none; +} + +.navbar-light .navbar-brand { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-nav .nav-link { + color: rgba(0, 0, 0, 0.5); +} + +.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus { + color: rgba(0, 0, 0, 0.7); +} + +.navbar-light .navbar-nav .nav-link.disabled { + color: rgba(0, 0, 0, 0.3); +} + +.navbar-light .navbar-nav .show > .nav-link, +.navbar-light .navbar-nav .active > .nav-link, +.navbar-light .navbar-nav .nav-link.show, +.navbar-light .navbar-nav .nav-link.active { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-toggler { + color: rgba(0, 0, 0, 0.5); + border-color: rgba(0, 0, 0, 0.1); +} + +.navbar-light .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-light .navbar-text { + color: rgba(0, 0, 0, 0.5); +} + +.navbar-light .navbar-text a { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-dark .navbar-brand { + color: #fff; +} + +.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus { + color: #fff; +} + +.navbar-dark .navbar-nav .nav-link { + color: rgba(255, 255, 255, 0.5); +} + +.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { + color: rgba(255, 255, 255, 0.75); +} + +.navbar-dark .navbar-nav .nav-link.disabled { + color: rgba(255, 255, 255, 0.25); +} + +.navbar-dark .navbar-nav .show > .nav-link, +.navbar-dark .navbar-nav .active > .nav-link, +.navbar-dark .navbar-nav .nav-link.show, +.navbar-dark .navbar-nav .nav-link.active { + color: #fff; +} + +.navbar-dark .navbar-toggler { + color: rgba(255, 255, 255, 0.5); + border-color: rgba(255, 255, 255, 0.1); +} + +.navbar-dark .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-dark .navbar-text { + color: rgba(255, 255, 255, 0.5); +} + +.navbar-dark .navbar-text a { + color: #fff; +} + +.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus { + color: #fff; +} + +.card { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + min-width: 0; + word-wrap: break-word; + background-color: #fff; + background-clip: border-box; + border: 1px solid rgba(0, 0, 0, 0.125); + border-radius: 0.25rem; +} + +.card > hr { + margin-right: 0; + margin-left: 0; +} + +.card > .list-group:first-child .list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card > .list-group:last-child .list-group-item:last-child { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.card-body { + -ms-flex: 1 1 auto; + flex: 1 1 auto; + min-height: 1px; + padding: 1.25rem; +} + +.card-title { + margin-bottom: 0.75rem; +} + +.card-subtitle { + margin-top: -0.375rem; + margin-bottom: 0; +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link:hover { + text-decoration: none; +} + +.card-link + .card-link { + margin-left: 1.25rem; +} + +.card-header { + padding: 0.75rem 1.25rem; + margin-bottom: 0; + background-color: rgba(0, 0, 0, 0.03); + border-bottom: 1px solid rgba(0, 0, 0, 0.125); +} + +.card-header:first-child { + border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0; +} + +.card-header + .list-group .list-group-item:first-child { + border-top: 0; +} + +.card-footer { + padding: 0.75rem 1.25rem; + background-color: rgba(0, 0, 0, 0.03); + border-top: 1px solid rgba(0, 0, 0, 0.125); +} + +.card-footer:last-child { + border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px); +} + +.card-header-tabs { + margin-right: -0.625rem; + margin-bottom: -0.75rem; + margin-left: -0.625rem; + border-bottom: 0; +} + +.card-header-pills { + margin-right: -0.625rem; + margin-left: -0.625rem; +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: 1.25rem; +} + +.card-img, +.card-img-top, +.card-img-bottom { + -ms-flex-negative: 0; + flex-shrink: 0; + width: 100%; +} + +.card-img, +.card-img-top { + border-top-left-radius: calc(0.25rem - 1px); + border-top-right-radius: calc(0.25rem - 1px); +} + +.card-img, +.card-img-bottom { + border-bottom-right-radius: calc(0.25rem - 1px); + border-bottom-left-radius: calc(0.25rem - 1px); +} + +.card-deck .card { + margin-bottom: 15px; +} + +@media (min-width: 576px) { + .card-deck { + display: -ms-flexbox; + display: flex; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + margin-right: -15px; + margin-left: -15px; + } + .card-deck .card { + -ms-flex: 1 0 0%; + flex: 1 0 0%; + margin-right: 15px; + margin-bottom: 0; + margin-left: 15px; + } +} + +.card-group > .card { + margin-bottom: 15px; +} + +@media (min-width: 576px) { + .card-group { + display: -ms-flexbox; + display: flex; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + } + .card-group > .card { + -ms-flex: 1 0 0%; + flex: 1 0 0%; + margin-bottom: 0; + } + .card-group > .card + .card { + margin-left: 0; + border-left: 0; + } + .card-group > .card:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-top, + .card-group > .card:not(:last-child) .card-header { + border-top-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-bottom, + .card-group > .card:not(:last-child) .card-footer { + border-bottom-right-radius: 0; + } + .card-group > .card:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-top, + .card-group > .card:not(:first-child) .card-header { + border-top-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-bottom, + .card-group > .card:not(:first-child) .card-footer { + border-bottom-left-radius: 0; + } +} + +.card-columns .card { + margin-bottom: 0.75rem; +} + +@media (min-width: 576px) { + .card-columns { + -webkit-column-count: 3; + -moz-column-count: 3; + column-count: 3; + -webkit-column-gap: 1.25rem; + -moz-column-gap: 1.25rem; + column-gap: 1.25rem; + orphans: 1; + widows: 1; + } + .card-columns .card { + display: inline-block; + width: 100%; + } +} + +.accordion > .card { + overflow: hidden; +} + +.accordion > .card:not(:last-of-type) { + border-bottom: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.accordion > .card:not(:first-of-type) { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.accordion > .card > .card-header { + border-radius: 0; + margin-bottom: -1px; +} + +.breadcrumb { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + padding: 0.75rem 1rem; + margin-bottom: 1rem; + list-style: none; + background-color: #e9ecef; + border-radius: 0.25rem; +} + +.breadcrumb-item + .breadcrumb-item { + padding-left: 0.5rem; +} + +.breadcrumb-item + .breadcrumb-item::before { + display: inline-block; + padding-right: 0.5rem; + color: #6c757d; + content: "/"; +} + +.breadcrumb-item + .breadcrumb-item:hover::before { + text-decoration: underline; +} + +.breadcrumb-item + .breadcrumb-item:hover::before { + text-decoration: none; +} + +.breadcrumb-item.active { + color: #6c757d; +} + +.pagination { + display: -ms-flexbox; + display: flex; + padding-left: 0; + list-style: none; + border-radius: 0.25rem; +} + +.page-link { + position: relative; + display: block; + padding: 0.5rem 0.75rem; + margin-left: -1px; + line-height: 1.25; + color: #007bff; + background-color: #fff; + border: 1px solid #dee2e6; +} + +.page-link:hover { + z-index: 2; + color: #0056b3; + text-decoration: none; + background-color: #e9ecef; + border-color: #dee2e6; +} + +.page-link:focus { + z-index: 3; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.page-item:first-child .page-link { + margin-left: 0; + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.page-item:last-child .page-link { + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +.page-item.active .page-link { + z-index: 3; + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.page-item.disabled .page-link { + color: #6c757d; + pointer-events: none; + cursor: auto; + background-color: #fff; + border-color: #dee2e6; +} + +.pagination-lg .page-link { + padding: 0.75rem 1.5rem; + font-size: 1.25rem; + line-height: 1.5; +} + +.pagination-lg .page-item:first-child .page-link { + border-top-left-radius: 0.3rem; + border-bottom-left-radius: 0.3rem; +} + +.pagination-lg .page-item:last-child .page-link { + border-top-right-radius: 0.3rem; + border-bottom-right-radius: 0.3rem; +} + +.pagination-sm .page-link { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + line-height: 1.5; +} + +.pagination-sm .page-item:first-child .page-link { + border-top-left-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; +} + +.pagination-sm .page-item:last-child .page-link { + border-top-right-radius: 0.2rem; + border-bottom-right-radius: 0.2rem; +} + +.badge { + display: inline-block; + padding: 0.25em 0.4em; + font-size: 75%; + font-weight: 700; + line-height: 1; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: 0.25rem; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .badge { + transition: none; + } +} + +a.badge:hover, a.badge:focus { + text-decoration: none; +} + +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +.badge-pill { + padding-right: 0.6em; + padding-left: 0.6em; + border-radius: 10rem; +} + +.badge-primary { + color: #fff; + background-color: #007bff; +} + +a.badge-primary:hover, a.badge-primary:focus { + color: #fff; + background-color: #0062cc; +} + +a.badge-primary:focus, a.badge-primary.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5); +} + +.badge-secondary { + color: #fff; + background-color: #6c757d; +} + +a.badge-secondary:hover, a.badge-secondary:focus { + color: #fff; + background-color: #545b62; +} + +a.badge-secondary:focus, a.badge-secondary.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.badge-success { + color: #fff; + background-color: #28a745; +} + +a.badge-success:hover, a.badge-success:focus { + color: #fff; + background-color: #1e7e34; +} + +a.badge-success:focus, a.badge-success.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.badge-info { + color: #fff; + background-color: #17a2b8; +} + +a.badge-info:hover, a.badge-info:focus { + color: #fff; + background-color: #117a8b; +} + +a.badge-info:focus, a.badge-info.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.badge-warning { + color: #212529; + background-color: #ffc107; +} + +a.badge-warning:hover, a.badge-warning:focus { + color: #212529; + background-color: #d39e00; +} + +a.badge-warning:focus, a.badge-warning.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.badge-danger { + color: #fff; + background-color: #dc3545; +} + +a.badge-danger:hover, a.badge-danger:focus { + color: #fff; + background-color: #bd2130; +} + +a.badge-danger:focus, a.badge-danger.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.badge-light { + color: #212529; + background-color: #f8f9fa; +} + +a.badge-light:hover, a.badge-light:focus { + color: #212529; + background-color: #dae0e5; +} + +a.badge-light:focus, a.badge-light.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.badge-dark { + color: #fff; + background-color: #343a40; +} + +a.badge-dark:hover, a.badge-dark:focus { + color: #fff; + background-color: #1d2124; +} + +a.badge-dark:focus, a.badge-dark.focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5); +} + +.jumbotron { + padding: 2rem 1rem; + margin-bottom: 2rem; + background-color: #e9ecef; + border-radius: 0.3rem; +} + +@media (min-width: 576px) { + .jumbotron { + padding: 4rem 2rem; + } +} + +.jumbotron-fluid { + padding-right: 0; + padding-left: 0; + border-radius: 0; +} + +.alert { + position: relative; + padding: 0.75rem 1.25rem; + margin-bottom: 1rem; + border: 1px solid transparent; + border-radius: 0.25rem; +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: 700; +} + +.alert-dismissible { + padding-right: 4rem; +} + +.alert-dismissible .close { + position: absolute; + top: 0; + right: 0; + padding: 0.75rem 1.25rem; + color: inherit; +} + +.alert-primary { + color: #004085; + background-color: #cce5ff; + border-color: #b8daff; +} + +.alert-primary hr { + border-top-color: #9fcdff; +} + +.alert-primary .alert-link { + color: #002752; +} + +.alert-secondary { + color: #383d41; + background-color: #e2e3e5; + border-color: #d6d8db; +} + +.alert-secondary hr { + border-top-color: #c8cbcf; +} + +.alert-secondary .alert-link { + color: #202326; +} + +.alert-success { + color: #155724; + background-color: #d4edda; + border-color: #c3e6cb; +} + +.alert-success hr { + border-top-color: #b1dfbb; +} + +.alert-success .alert-link { + color: #0b2e13; +} + +.alert-info { + color: #0c5460; + background-color: #d1ecf1; + border-color: #bee5eb; +} + +.alert-info hr { + border-top-color: #abdde5; +} + +.alert-info .alert-link { + color: #062c33; +} + +.alert-warning { + color: #856404; + background-color: #fff3cd; + border-color: #ffeeba; +} + +.alert-warning hr { + border-top-color: #ffe8a1; +} + +.alert-warning .alert-link { + color: #533f03; +} + +.alert-danger { + color: #721c24; + background-color: #f8d7da; + border-color: #f5c6cb; +} + +.alert-danger hr { + border-top-color: #f1b0b7; +} + +.alert-danger .alert-link { + color: #491217; +} + +.alert-light { + color: #818182; + background-color: #fefefe; + border-color: #fdfdfe; +} + +.alert-light hr { + border-top-color: #ececf6; +} + +.alert-light .alert-link { + color: #686868; +} + +.alert-dark { + color: #1b1e21; + background-color: #d6d8d9; + border-color: #c6c8ca; +} + +.alert-dark hr { + border-top-color: #b9bbbe; +} + +.alert-dark .alert-link { + color: #040505; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 1rem 0; + } + to { + background-position: 0 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 1rem 0; + } + to { + background-position: 0 0; + } +} + +.progress { + display: -ms-flexbox; + display: flex; + height: 1rem; + overflow: hidden; + font-size: 0.75rem; + background-color: #e9ecef; + border-radius: 0.25rem; +} + +.progress-bar { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-pack: center; + justify-content: center; + overflow: hidden; + color: #fff; + text-align: center; + white-space: nowrap; + background-color: #007bff; + transition: width 0.6s ease; +} + +@media (prefers-reduced-motion: reduce) { + .progress-bar { + transition: none; + } +} + +.progress-bar-striped { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 1rem 1rem; +} + +.progress-bar-animated { + -webkit-animation: progress-bar-stripes 1s linear infinite; + animation: progress-bar-stripes 1s linear infinite; +} + +@media (prefers-reduced-motion: reduce) { + .progress-bar-animated { + -webkit-animation: none; + animation: none; + } +} + +.media { + display: -ms-flexbox; + display: flex; + -ms-flex-align: start; + align-items: flex-start; +} + +.media-body { + -ms-flex: 1; + flex: 1; +} + +.list-group { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; +} + +.list-group-item-action { + width: 100%; + color: #495057; + text-align: inherit; +} + +.list-group-item-action:hover, .list-group-item-action:focus { + z-index: 1; + color: #495057; + text-decoration: none; + background-color: #f8f9fa; +} + +.list-group-item-action:active { + color: #212529; + background-color: #e9ecef; +} + +.list-group-item { + position: relative; + display: block; + padding: 0.75rem 1.25rem; + background-color: #fff; + border: 1px solid rgba(0, 0, 0, 0.125); +} + +.list-group-item:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.list-group-item:last-child { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.list-group-item.disabled, .list-group-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: #fff; +} + +.list-group-item.active { + z-index: 2; + color: #fff; + background-color: #007bff; + border-color: #007bff; +} + +.list-group-item + .list-group-item { + border-top-width: 0; +} + +.list-group-item + .list-group-item.active { + margin-top: -1px; + border-top-width: 1px; +} + +.list-group-horizontal { + -ms-flex-direction: row; + flex-direction: row; +} + +.list-group-horizontal .list-group-item:first-child { + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; +} + +.list-group-horizontal .list-group-item:last-child { + border-top-right-radius: 0.25rem; + border-bottom-left-radius: 0; +} + +.list-group-horizontal .list-group-item.active { + margin-top: 0; +} + +.list-group-horizontal .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; +} + +.list-group-horizontal .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; +} + +@media (min-width: 576px) { + .list-group-horizontal-sm { + -ms-flex-direction: row; + flex-direction: row; + } + .list-group-horizontal-sm .list-group-item:first-child { + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + .list-group-horizontal-sm .list-group-item:last-child { + border-top-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-sm .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-sm .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-sm .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 768px) { + .list-group-horizontal-md { + -ms-flex-direction: row; + flex-direction: row; + } + .list-group-horizontal-md .list-group-item:first-child { + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + .list-group-horizontal-md .list-group-item:last-child { + border-top-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-md .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-md .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-md .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 992px) { + .list-group-horizontal-lg { + -ms-flex-direction: row; + flex-direction: row; + } + .list-group-horizontal-lg .list-group-item:first-child { + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + .list-group-horizontal-lg .list-group-item:last-child { + border-top-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-lg .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-lg .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-lg .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 1200px) { + .list-group-horizontal-xl { + -ms-flex-direction: row; + flex-direction: row; + } + .list-group-horizontal-xl .list-group-item:first-child { + border-bottom-left-radius: 0.25rem; + border-top-right-radius: 0; + } + .list-group-horizontal-xl .list-group-item:last-child { + border-top-right-radius: 0.25rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-xl .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xl .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-xl .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +.list-group-flush .list-group-item { + border-right-width: 0; + border-left-width: 0; + border-radius: 0; +} + +.list-group-flush .list-group-item:first-child { + border-top-width: 0; +} + +.list-group-flush:last-child .list-group-item:last-child { + border-bottom-width: 0; +} + +.list-group-item-primary { + color: #004085; + background-color: #b8daff; +} + +.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus { + color: #004085; + background-color: #9fcdff; +} + +.list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #004085; + border-color: #004085; +} + +.list-group-item-secondary { + color: #383d41; + background-color: #d6d8db; +} + +.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus { + color: #383d41; + background-color: #c8cbcf; +} + +.list-group-item-secondary.list-group-item-action.active { + color: #fff; + background-color: #383d41; + border-color: #383d41; +} + +.list-group-item-success { + color: #155724; + background-color: #c3e6cb; +} + +.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus { + color: #155724; + background-color: #b1dfbb; +} + +.list-group-item-success.list-group-item-action.active { + color: #fff; + background-color: #155724; + border-color: #155724; +} + +.list-group-item-info { + color: #0c5460; + background-color: #bee5eb; +} + +.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus { + color: #0c5460; + background-color: #abdde5; +} + +.list-group-item-info.list-group-item-action.active { + color: #fff; + background-color: #0c5460; + border-color: #0c5460; +} + +.list-group-item-warning { + color: #856404; + background-color: #ffeeba; +} + +.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus { + color: #856404; + background-color: #ffe8a1; +} + +.list-group-item-warning.list-group-item-action.active { + color: #fff; + background-color: #856404; + border-color: #856404; +} + +.list-group-item-danger { + color: #721c24; + background-color: #f5c6cb; +} + +.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus { + color: #721c24; + background-color: #f1b0b7; +} + +.list-group-item-danger.list-group-item-action.active { + color: #fff; + background-color: #721c24; + border-color: #721c24; +} + +.list-group-item-light { + color: #818182; + background-color: #fdfdfe; +} + +.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus { + color: #818182; + background-color: #ececf6; +} + +.list-group-item-light.list-group-item-action.active { + color: #fff; + background-color: #818182; + border-color: #818182; +} + +.list-group-item-dark { + color: #1b1e21; + background-color: #c6c8ca; +} + +.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus { + color: #1b1e21; + background-color: #b9bbbe; +} + +.list-group-item-dark.list-group-item-action.active { + color: #fff; + background-color: #1b1e21; + border-color: #1b1e21; +} + +.close { + float: right; + font-size: 1.5rem; + font-weight: 700; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + opacity: .5; +} + +.close:hover { + color: #000; + text-decoration: none; +} + +.close:not(:disabled):not(.disabled):hover, .close:not(:disabled):not(.disabled):focus { + opacity: .75; +} + +button.close { + padding: 0; + background-color: transparent; + border: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +a.close.disabled { + pointer-events: none; +} + +.toast { + max-width: 350px; + overflow: hidden; + font-size: 0.875rem; + background-color: rgba(255, 255, 255, 0.85); + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); + opacity: 0; + border-radius: 0.25rem; +} + +.toast:not(:last-child) { + margin-bottom: 0.75rem; +} + +.toast.showing { + opacity: 1; +} + +.toast.show { + display: block; + opacity: 1; +} + +.toast.hide { + display: none; +} + +.toast-header { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + padding: 0.25rem 0.75rem; + color: #6c757d; + background-color: rgba(255, 255, 255, 0.85); + background-clip: padding-box; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); +} + +.toast-body { + padding: 0.75rem; +} + +.modal-open { + overflow: hidden; +} + +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} + +.modal { + position: fixed; + top: 0; + left: 0; + z-index: 1050; + display: none; + width: 100%; + height: 100%; + overflow: hidden; + outline: 0; +} + +.modal-dialog { + position: relative; + width: auto; + margin: 0.5rem; + pointer-events: none; +} + +.modal.fade .modal-dialog { + transition: -webkit-transform 0.3s ease-out; + transition: transform 0.3s ease-out; + transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out; + -webkit-transform: translate(0, -50px); + transform: translate(0, -50px); +} + +@media (prefers-reduced-motion: reduce) { + .modal.fade .modal-dialog { + transition: none; + } +} + +.modal.show .modal-dialog { + -webkit-transform: none; + transform: none; +} + +.modal.modal-static .modal-dialog { + -webkit-transform: scale(1.02); + transform: scale(1.02); +} + +.modal-dialog-scrollable { + display: -ms-flexbox; + display: flex; + max-height: calc(100% - 1rem); +} + +.modal-dialog-scrollable .modal-content { + max-height: calc(100vh - 1rem); + overflow: hidden; +} + +.modal-dialog-scrollable .modal-header, +.modal-dialog-scrollable .modal-footer { + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.modal-dialog-scrollable .modal-body { + overflow-y: auto; +} + +.modal-dialog-centered { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + min-height: calc(100% - 1rem); +} + +.modal-dialog-centered::before { + display: block; + height: calc(100vh - 1rem); + content: ""; +} + +.modal-dialog-centered.modal-dialog-scrollable { + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-pack: center; + justify-content: center; + height: 100%; +} + +.modal-dialog-centered.modal-dialog-scrollable .modal-content { + max-height: none; +} + +.modal-dialog-centered.modal-dialog-scrollable::before { + content: none; +} + +.modal-content { + position: relative; + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; + pointer-events: auto; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 0.3rem; + outline: 0; +} + +.modal-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop.show { + opacity: 0.5; +} + +.modal-header { + display: -ms-flexbox; + display: flex; + -ms-flex-align: start; + align-items: flex-start; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 1rem 1rem; + border-bottom: 1px solid #dee2e6; + border-top-left-radius: calc(0.3rem - 1px); + border-top-right-radius: calc(0.3rem - 1px); +} + +.modal-header .close { + padding: 1rem 1rem; + margin: -1rem -1rem -1rem auto; +} + +.modal-title { + margin-bottom: 0; + line-height: 1.5; +} + +.modal-body { + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + padding: 1rem; +} + +.modal-footer { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: end; + justify-content: flex-end; + padding: 0.75rem; + border-top: 1px solid #dee2e6; + border-bottom-right-radius: calc(0.3rem - 1px); + border-bottom-left-radius: calc(0.3rem - 1px); +} + +.modal-footer > * { + margin: 0.25rem; +} + +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} + +@media (min-width: 576px) { + .modal-dialog { + max-width: 500px; + margin: 1.75rem auto; + } + .modal-dialog-scrollable { + max-height: calc(100% - 3.5rem); + } + .modal-dialog-scrollable .modal-content { + max-height: calc(100vh - 3.5rem); + } + .modal-dialog-centered { + min-height: calc(100% - 3.5rem); + } + .modal-dialog-centered::before { + height: calc(100vh - 3.5rem); + } + .modal-sm { + max-width: 300px; + } +} + +@media (min-width: 992px) { + .modal-lg, + .modal-xl { + max-width: 800px; + } +} + +@media (min-width: 1200px) { + .modal-xl { + max-width: 1140px; + } +} + +.tooltip { + position: absolute; + z-index: 1070; + display: block; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: 0.875rem; + word-wrap: break-word; + opacity: 0; +} + +.tooltip.show { + opacity: 0.9; +} + +.tooltip .arrow { + position: absolute; + display: block; + width: 0.8rem; + height: 0.4rem; +} + +.tooltip .arrow::before { + position: absolute; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-tooltip-top, .bs-tooltip-auto[x-placement^="top"] { + padding: 0.4rem 0; +} + +.bs-tooltip-top .arrow, .bs-tooltip-auto[x-placement^="top"] .arrow { + bottom: 0; +} + +.bs-tooltip-top .arrow::before, .bs-tooltip-auto[x-placement^="top"] .arrow::before { + top: 0; + border-width: 0.4rem 0.4rem 0; + border-top-color: #000; +} + +.bs-tooltip-right, .bs-tooltip-auto[x-placement^="right"] { + padding: 0 0.4rem; +} + +.bs-tooltip-right .arrow, .bs-tooltip-auto[x-placement^="right"] .arrow { + left: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-right .arrow::before, .bs-tooltip-auto[x-placement^="right"] .arrow::before { + right: 0; + border-width: 0.4rem 0.4rem 0.4rem 0; + border-right-color: #000; +} + +.bs-tooltip-bottom, .bs-tooltip-auto[x-placement^="bottom"] { + padding: 0.4rem 0; +} + +.bs-tooltip-bottom .arrow, .bs-tooltip-auto[x-placement^="bottom"] .arrow { + top: 0; +} + +.bs-tooltip-bottom .arrow::before, .bs-tooltip-auto[x-placement^="bottom"] .arrow::before { + bottom: 0; + border-width: 0 0.4rem 0.4rem; + border-bottom-color: #000; +} + +.bs-tooltip-left, .bs-tooltip-auto[x-placement^="left"] { + padding: 0 0.4rem; +} + +.bs-tooltip-left .arrow, .bs-tooltip-auto[x-placement^="left"] .arrow { + right: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-left .arrow::before, .bs-tooltip-auto[x-placement^="left"] .arrow::before { + left: 0; + border-width: 0.4rem 0 0.4rem 0.4rem; + border-left-color: #000; +} + +.tooltip-inner { + max-width: 200px; + padding: 0.25rem 0.5rem; + color: #fff; + text-align: center; + background-color: #000; + border-radius: 0.25rem; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: block; + max-width: 276px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: 0.875rem; + word-wrap: break-word; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 0.3rem; +} + +.popover .arrow { + position: absolute; + display: block; + width: 1rem; + height: 0.5rem; + margin: 0 0.3rem; +} + +.popover .arrow::before, .popover .arrow::after { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-popover-top, .bs-popover-auto[x-placement^="top"] { + margin-bottom: 0.5rem; +} + +.bs-popover-top > .arrow, .bs-popover-auto[x-placement^="top"] > .arrow { + bottom: calc(-0.5rem - 1px); +} + +.bs-popover-top > .arrow::before, .bs-popover-auto[x-placement^="top"] > .arrow::before { + bottom: 0; + border-width: 0.5rem 0.5rem 0; + border-top-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-top > .arrow::after, .bs-popover-auto[x-placement^="top"] > .arrow::after { + bottom: 1px; + border-width: 0.5rem 0.5rem 0; + border-top-color: #fff; +} + +.bs-popover-right, .bs-popover-auto[x-placement^="right"] { + margin-left: 0.5rem; +} + +.bs-popover-right > .arrow, .bs-popover-auto[x-placement^="right"] > .arrow { + left: calc(-0.5rem - 1px); + width: 0.5rem; + height: 1rem; + margin: 0.3rem 0; +} + +.bs-popover-right > .arrow::before, .bs-popover-auto[x-placement^="right"] > .arrow::before { + left: 0; + border-width: 0.5rem 0.5rem 0.5rem 0; + border-right-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-right > .arrow::after, .bs-popover-auto[x-placement^="right"] > .arrow::after { + left: 1px; + border-width: 0.5rem 0.5rem 0.5rem 0; + border-right-color: #fff; +} + +.bs-popover-bottom, .bs-popover-auto[x-placement^="bottom"] { + margin-top: 0.5rem; +} + +.bs-popover-bottom > .arrow, .bs-popover-auto[x-placement^="bottom"] > .arrow { + top: calc(-0.5rem - 1px); +} + +.bs-popover-bottom > .arrow::before, .bs-popover-auto[x-placement^="bottom"] > .arrow::before { + top: 0; + border-width: 0 0.5rem 0.5rem 0.5rem; + border-bottom-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-bottom > .arrow::after, .bs-popover-auto[x-placement^="bottom"] > .arrow::after { + top: 1px; + border-width: 0 0.5rem 0.5rem 0.5rem; + border-bottom-color: #fff; +} + +.bs-popover-bottom .popover-header::before, .bs-popover-auto[x-placement^="bottom"] .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: 1rem; + margin-left: -0.5rem; + content: ""; + border-bottom: 1px solid #f7f7f7; +} + +.bs-popover-left, .bs-popover-auto[x-placement^="left"] { + margin-right: 0.5rem; +} + +.bs-popover-left > .arrow, .bs-popover-auto[x-placement^="left"] > .arrow { + right: calc(-0.5rem - 1px); + width: 0.5rem; + height: 1rem; + margin: 0.3rem 0; +} + +.bs-popover-left > .arrow::before, .bs-popover-auto[x-placement^="left"] > .arrow::before { + right: 0; + border-width: 0.5rem 0 0.5rem 0.5rem; + border-left-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-left > .arrow::after, .bs-popover-auto[x-placement^="left"] > .arrow::after { + right: 1px; + border-width: 0.5rem 0 0.5rem 0.5rem; + border-left-color: #fff; +} + +.popover-header { + padding: 0.5rem 0.75rem; + margin-bottom: 0; + font-size: 1rem; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-top-left-radius: calc(0.3rem - 1px); + border-top-right-radius: calc(0.3rem - 1px); +} + +.popover-header:empty { + display: none; +} + +.popover-body { + padding: 0.5rem 0.75rem; + color: #212529; +} + +.carousel { + position: relative; +} + +.carousel.pointer-event { + -ms-touch-action: pan-y; + touch-action: pan-y; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner::after { + display: block; + clear: both; + content: ""; +} + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transition: -webkit-transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .carousel-item { + transition: none; + } +} + +.carousel-item.active, +.carousel-item-next, +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-left), +.active.carousel-item-right { + -webkit-transform: translateX(100%); + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-right), +.active.carousel-item-left { + -webkit-transform: translateX(-100%); + transform: translateX(-100%); +} + +.carousel-fade .carousel-item { + opacity: 0; + transition-property: opacity; + -webkit-transform: none; + transform: none; +} + +.carousel-fade .carousel-item.active, +.carousel-fade .carousel-item-next.carousel-item-left, +.carousel-fade .carousel-item-prev.carousel-item-right { + z-index: 1; + opacity: 1; +} + +.carousel-fade .active.carousel-item-left, +.carousel-fade .active.carousel-item-right { + z-index: 0; + opacity: 0; + transition: opacity 0s 0.6s; +} + +@media (prefers-reduced-motion: reduce) { + .carousel-fade .active.carousel-item-left, + .carousel-fade .active.carousel-item-right { + transition: none; + } +} + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + width: 15%; + color: #fff; + text-align: center; + opacity: 0.5; + transition: opacity 0.15s ease; +} + +@media (prefers-reduced-motion: reduce) { + .carousel-control-prev, + .carousel-control-next { + transition: none; + } +} + +.carousel-control-prev:hover, .carousel-control-prev:focus, +.carousel-control-next:hover, +.carousel-control-next:focus { + color: #fff; + text-decoration: none; + outline: 0; + opacity: 0.9; +} + +.carousel-control-prev { + left: 0; +} + +.carousel-control-next { + right: 0; +} + +.carousel-control-prev-icon, +.carousel-control-next-icon { + display: inline-block; + width: 20px; + height: 20px; + background: no-repeat 50% / 100% 100%; +} + +.carousel-control-prev-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e"); +} + +.carousel-control-next-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e"); +} + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 15; + display: -ms-flexbox; + display: flex; + -ms-flex-pack: center; + justify-content: center; + padding-left: 0; + margin-right: 15%; + margin-left: 15%; + list-style: none; +} + +.carousel-indicators li { + box-sizing: content-box; + -ms-flex: 0 1 auto; + flex: 0 1 auto; + width: 30px; + height: 3px; + margin-right: 3px; + margin-left: 3px; + text-indent: -999px; + cursor: pointer; + background-color: #fff; + background-clip: padding-box; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + opacity: .5; + transition: opacity 0.6s ease; +} + +@media (prefers-reduced-motion: reduce) { + .carousel-indicators li { + transition: none; + } +} + +.carousel-indicators .active { + opacity: 1; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #fff; + text-align: center; +} + +@-webkit-keyframes spinner-border { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes spinner-border { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +.spinner-border { + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: text-bottom; + border: 0.25em solid currentColor; + border-right-color: transparent; + border-radius: 50%; + -webkit-animation: spinner-border .75s linear infinite; + animation: spinner-border .75s linear infinite; +} + +.spinner-border-sm { + width: 1rem; + height: 1rem; + border-width: 0.2em; +} + +@-webkit-keyframes spinner-grow { + 0% { + -webkit-transform: scale(0); + transform: scale(0); + } + 50% { + opacity: 1; + } +} + +@keyframes spinner-grow { + 0% { + -webkit-transform: scale(0); + transform: scale(0); + } + 50% { + opacity: 1; + } +} + +.spinner-grow { + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: text-bottom; + background-color: currentColor; + border-radius: 50%; + opacity: 0; + -webkit-animation: spinner-grow .75s linear infinite; + animation: spinner-grow .75s linear infinite; +} + +.spinner-grow-sm { + width: 1rem; + height: 1rem; +} + +.align-baseline { + vertical-align: baseline !important; +} + +.align-top { + vertical-align: top !important; +} + +.align-middle { + vertical-align: middle !important; +} + +.align-bottom { + vertical-align: bottom !important; +} + +.align-text-bottom { + vertical-align: text-bottom !important; +} + +.align-text-top { + vertical-align: text-top !important; +} + +.bg-primary { + background-color: #007bff !important; +} + +a.bg-primary:hover, a.bg-primary:focus, +button.bg-primary:hover, +button.bg-primary:focus { + background-color: #0062cc !important; +} + +.bg-secondary { + background-color: #6c757d !important; +} + +a.bg-secondary:hover, a.bg-secondary:focus, +button.bg-secondary:hover, +button.bg-secondary:focus { + background-color: #545b62 !important; +} + +.bg-success { + background-color: #28a745 !important; +} + +a.bg-success:hover, a.bg-success:focus, +button.bg-success:hover, +button.bg-success:focus { + background-color: #1e7e34 !important; +} + +.bg-info { + background-color: #17a2b8 !important; +} + +a.bg-info:hover, a.bg-info:focus, +button.bg-info:hover, +button.bg-info:focus { + background-color: #117a8b !important; +} + +.bg-warning { + background-color: #ffc107 !important; +} + +a.bg-warning:hover, a.bg-warning:focus, +button.bg-warning:hover, +button.bg-warning:focus { + background-color: #d39e00 !important; +} + +.bg-danger { + background-color: #dc3545 !important; +} + +a.bg-danger:hover, a.bg-danger:focus, +button.bg-danger:hover, +button.bg-danger:focus { + background-color: #bd2130 !important; +} + +.bg-light { + background-color: #f8f9fa !important; +} + +a.bg-light:hover, a.bg-light:focus, +button.bg-light:hover, +button.bg-light:focus { + background-color: #dae0e5 !important; +} + +.bg-dark { + background-color: #343a40 !important; +} + +a.bg-dark:hover, a.bg-dark:focus, +button.bg-dark:hover, +button.bg-dark:focus { + background-color: #1d2124 !important; +} + +.bg-white { + background-color: #fff !important; +} + +.bg-transparent { + background-color: transparent !important; +} + +.border { + border: 1px solid #dee2e6 !important; +} + +.border-top { + border-top: 1px solid #dee2e6 !important; +} + +.border-right { + border-right: 1px solid #dee2e6 !important; +} + +.border-bottom { + border-bottom: 1px solid #dee2e6 !important; +} + +.border-left { + border-left: 1px solid #dee2e6 !important; +} + +.border-0 { + border: 0 !important; +} + +.border-top-0 { + border-top: 0 !important; +} + +.border-right-0 { + border-right: 0 !important; +} + +.border-bottom-0 { + border-bottom: 0 !important; +} + +.border-left-0 { + border-left: 0 !important; +} + +.border-primary { + border-color: #007bff !important; +} + +.border-secondary { + border-color: #6c757d !important; +} + +.border-success { + border-color: #28a745 !important; +} + +.border-info { + border-color: #17a2b8 !important; +} + +.border-warning { + border-color: #ffc107 !important; +} + +.border-danger { + border-color: #dc3545 !important; +} + +.border-light { + border-color: #f8f9fa !important; +} + +.border-dark { + border-color: #343a40 !important; +} + +.border-white { + border-color: #fff !important; +} + +.rounded-sm { + border-radius: 0.2rem !important; +} + +.rounded { + border-radius: 0.25rem !important; +} + +.rounded-top { + border-top-left-radius: 0.25rem !important; + border-top-right-radius: 0.25rem !important; +} + +.rounded-right { + border-top-right-radius: 0.25rem !important; + border-bottom-right-radius: 0.25rem !important; +} + +.rounded-bottom { + border-bottom-right-radius: 0.25rem !important; + border-bottom-left-radius: 0.25rem !important; +} + +.rounded-left { + border-top-left-radius: 0.25rem !important; + border-bottom-left-radius: 0.25rem !important; +} + +.rounded-lg { + border-radius: 0.3rem !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: 50rem !important; +} + +.rounded-0 { + border-radius: 0 !important; +} + +.clearfix::after { + display: block; + clear: both; + content: ""; +} + +.d-none { + display: none !important; +} + +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: -ms-flexbox !important; + display: flex !important; +} + +.d-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; +} + +@media (min-width: 576px) { + .d-sm-none { + display: none !important; + } + .d-sm-inline { + display: inline !important; + } + .d-sm-inline-block { + display: inline-block !important; + } + .d-sm-block { + display: block !important; + } + .d-sm-table { + display: table !important; + } + .d-sm-table-row { + display: table-row !important; + } + .d-sm-table-cell { + display: table-cell !important; + } + .d-sm-flex { + display: -ms-flexbox !important; + display: flex !important; + } + .d-sm-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 768px) { + .d-md-none { + display: none !important; + } + .d-md-inline { + display: inline !important; + } + .d-md-inline-block { + display: inline-block !important; + } + .d-md-block { + display: block !important; + } + .d-md-table { + display: table !important; + } + .d-md-table-row { + display: table-row !important; + } + .d-md-table-cell { + display: table-cell !important; + } + .d-md-flex { + display: -ms-flexbox !important; + display: flex !important; + } + .d-md-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 992px) { + .d-lg-none { + display: none !important; + } + .d-lg-inline { + display: inline !important; + } + .d-lg-inline-block { + display: inline-block !important; + } + .d-lg-block { + display: block !important; + } + .d-lg-table { + display: table !important; + } + .d-lg-table-row { + display: table-row !important; + } + .d-lg-table-cell { + display: table-cell !important; + } + .d-lg-flex { + display: -ms-flexbox !important; + display: flex !important; + } + .d-lg-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media (min-width: 1200px) { + .d-xl-none { + display: none !important; + } + .d-xl-inline { + display: inline !important; + } + .d-xl-inline-block { + display: inline-block !important; + } + .d-xl-block { + display: block !important; + } + .d-xl-table { + display: table !important; + } + .d-xl-table-row { + display: table-row !important; + } + .d-xl-table-cell { + display: table-cell !important; + } + .d-xl-flex { + display: -ms-flexbox !important; + display: flex !important; + } + .d-xl-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +@media print { + .d-print-none { + display: none !important; + } + .d-print-inline { + display: inline !important; + } + .d-print-inline-block { + display: inline-block !important; + } + .d-print-block { + display: block !important; + } + .d-print-table { + display: table !important; + } + .d-print-table-row { + display: table-row !important; + } + .d-print-table-cell { + display: table-cell !important; + } + .d-print-flex { + display: -ms-flexbox !important; + display: flex !important; + } + .d-print-inline-flex { + display: -ms-inline-flexbox !important; + display: inline-flex !important; + } +} + +.embed-responsive { + position: relative; + display: block; + width: 100%; + padding: 0; + overflow: hidden; +} + +.embed-responsive::before { + display: block; + content: ""; +} + +.embed-responsive .embed-responsive-item, +.embed-responsive iframe, +.embed-responsive embed, +.embed-responsive object, +.embed-responsive video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; +} + +.embed-responsive-21by9::before { + padding-top: 42.857143%; +} + +.embed-responsive-16by9::before { + padding-top: 56.25%; +} + +.embed-responsive-4by3::before { + padding-top: 75%; +} + +.embed-responsive-1by1::before { + padding-top: 100%; +} + +.flex-row { + -ms-flex-direction: row !important; + flex-direction: row !important; +} + +.flex-column { + -ms-flex-direction: column !important; + flex-direction: column !important; +} + +.flex-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; +} + +.flex-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; +} + +.flex-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; +} + +.flex-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; +} + +.flex-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; +} + +.flex-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; +} + +.flex-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; +} + +.justify-content-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; +} + +.justify-content-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; +} + +.justify-content-center { + -ms-flex-pack: center !important; + justify-content: center !important; +} + +.justify-content-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; +} + +.justify-content-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; +} + +.align-items-start { + -ms-flex-align: start !important; + align-items: flex-start !important; +} + +.align-items-end { + -ms-flex-align: end !important; + align-items: flex-end !important; +} + +.align-items-center { + -ms-flex-align: center !important; + align-items: center !important; +} + +.align-items-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; +} + +.align-items-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; +} + +.align-content-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; +} + +.align-content-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; +} + +.align-content-center { + -ms-flex-line-pack: center !important; + align-content: center !important; +} + +.align-content-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; +} + +.align-content-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; +} + +.align-content-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; +} + +.align-self-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; +} + +.align-self-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; +} + +.align-self-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; +} + +.align-self-center { + -ms-flex-item-align: center !important; + align-self: center !important; +} + +.align-self-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; +} + +.align-self-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; +} + +@media (min-width: 576px) { + .flex-sm-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-sm-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-sm-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-sm-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-sm-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-sm-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-sm-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-sm-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-sm-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-sm-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-sm-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-sm-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-sm-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-sm-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-sm-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-sm-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-sm-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-sm-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-sm-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-sm-center { + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-sm-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-sm-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-sm-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-sm-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-sm-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-sm-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-sm-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-sm-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-sm-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-sm-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-sm-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-sm-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-sm-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-sm-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 768px) { + .flex-md-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-md-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-md-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-md-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-md-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-md-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-md-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-md-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-md-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-md-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-md-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-md-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-md-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-md-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-md-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-md-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-md-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-md-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-md-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-md-center { + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-md-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-md-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-md-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-md-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-md-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-md-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-md-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-md-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-md-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-md-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-md-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-md-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-md-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-md-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 992px) { + .flex-lg-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-lg-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-lg-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-lg-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-lg-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-lg-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-lg-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-lg-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-lg-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-lg-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-lg-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-lg-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-lg-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-lg-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-lg-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-lg-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-lg-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-lg-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-lg-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-lg-center { + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-lg-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-lg-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-lg-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-lg-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-lg-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-lg-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-lg-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-lg-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-lg-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-lg-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-lg-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-lg-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-lg-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-lg-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +@media (min-width: 1200px) { + .flex-xl-row { + -ms-flex-direction: row !important; + flex-direction: row !important; + } + .flex-xl-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .flex-xl-row-reverse { + -ms-flex-direction: row-reverse !important; + flex-direction: row-reverse !important; + } + .flex-xl-column-reverse { + -ms-flex-direction: column-reverse !important; + flex-direction: column-reverse !important; + } + .flex-xl-wrap { + -ms-flex-wrap: wrap !important; + flex-wrap: wrap !important; + } + .flex-xl-nowrap { + -ms-flex-wrap: nowrap !important; + flex-wrap: nowrap !important; + } + .flex-xl-wrap-reverse { + -ms-flex-wrap: wrap-reverse !important; + flex-wrap: wrap-reverse !important; + } + .flex-xl-fill { + -ms-flex: 1 1 auto !important; + flex: 1 1 auto !important; + } + .flex-xl-grow-0 { + -ms-flex-positive: 0 !important; + flex-grow: 0 !important; + } + .flex-xl-grow-1 { + -ms-flex-positive: 1 !important; + flex-grow: 1 !important; + } + .flex-xl-shrink-0 { + -ms-flex-negative: 0 !important; + flex-shrink: 0 !important; + } + .flex-xl-shrink-1 { + -ms-flex-negative: 1 !important; + flex-shrink: 1 !important; + } + .justify-content-xl-start { + -ms-flex-pack: start !important; + justify-content: flex-start !important; + } + .justify-content-xl-end { + -ms-flex-pack: end !important; + justify-content: flex-end !important; + } + .justify-content-xl-center { + -ms-flex-pack: center !important; + justify-content: center !important; + } + .justify-content-xl-between { + -ms-flex-pack: justify !important; + justify-content: space-between !important; + } + .justify-content-xl-around { + -ms-flex-pack: distribute !important; + justify-content: space-around !important; + } + .align-items-xl-start { + -ms-flex-align: start !important; + align-items: flex-start !important; + } + .align-items-xl-end { + -ms-flex-align: end !important; + align-items: flex-end !important; + } + .align-items-xl-center { + -ms-flex-align: center !important; + align-items: center !important; + } + .align-items-xl-baseline { + -ms-flex-align: baseline !important; + align-items: baseline !important; + } + .align-items-xl-stretch { + -ms-flex-align: stretch !important; + align-items: stretch !important; + } + .align-content-xl-start { + -ms-flex-line-pack: start !important; + align-content: flex-start !important; + } + .align-content-xl-end { + -ms-flex-line-pack: end !important; + align-content: flex-end !important; + } + .align-content-xl-center { + -ms-flex-line-pack: center !important; + align-content: center !important; + } + .align-content-xl-between { + -ms-flex-line-pack: justify !important; + align-content: space-between !important; + } + .align-content-xl-around { + -ms-flex-line-pack: distribute !important; + align-content: space-around !important; + } + .align-content-xl-stretch { + -ms-flex-line-pack: stretch !important; + align-content: stretch !important; + } + .align-self-xl-auto { + -ms-flex-item-align: auto !important; + align-self: auto !important; + } + .align-self-xl-start { + -ms-flex-item-align: start !important; + align-self: flex-start !important; + } + .align-self-xl-end { + -ms-flex-item-align: end !important; + align-self: flex-end !important; + } + .align-self-xl-center { + -ms-flex-item-align: center !important; + align-self: center !important; + } + .align-self-xl-baseline { + -ms-flex-item-align: baseline !important; + align-self: baseline !important; + } + .align-self-xl-stretch { + -ms-flex-item-align: stretch !important; + align-self: stretch !important; + } +} + +.float-left { + float: left !important; +} + +.float-right { + float: right !important; +} + +.float-none { + float: none !important; +} + +@media (min-width: 576px) { + .float-sm-left { + float: left !important; + } + .float-sm-right { + float: right !important; + } + .float-sm-none { + float: none !important; + } +} + +@media (min-width: 768px) { + .float-md-left { + float: left !important; + } + .float-md-right { + float: right !important; + } + .float-md-none { + float: none !important; + } +} + +@media (min-width: 992px) { + .float-lg-left { + float: left !important; + } + .float-lg-right { + float: right !important; + } + .float-lg-none { + float: none !important; + } +} + +@media (min-width: 1200px) { + .float-xl-left { + float: left !important; + } + .float-xl-right { + float: right !important; + } + .float-xl-none { + float: none !important; + } +} + +.overflow-auto { + overflow: auto !important; +} + +.overflow-hidden { + overflow: hidden !important; +} + +.position-static { + position: static !important; +} + +.position-relative { + position: relative !important; +} + +.position-absolute { + position: absolute !important; +} + +.position-fixed { + position: fixed !important; +} + +.position-sticky { + position: -webkit-sticky !important; + position: sticky !important; +} + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; +} + +@supports ((position: -webkit-sticky) or (position: sticky)) { + .sticky-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +.sr-only-focusable:active, .sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + overflow: visible; + clip: auto; + white-space: normal; +} + +.shadow-sm { + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; +} + +.shadow { + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; +} + +.shadow-lg { + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; +} + +.shadow-none { + box-shadow: none !important; +} + +.w-25 { + width: 25% !important; +} + +.w-50 { + width: 50% !important; +} + +.w-75 { + width: 75% !important; +} + +.w-100 { + width: 100% !important; +} + +.w-auto { + width: auto !important; +} + +.h-25 { + height: 25% !important; +} + +.h-50 { + height: 50% !important; +} + +.h-75 { + height: 75% !important; +} + +.h-100 { + height: 100% !important; +} + +.h-auto { + height: auto !important; +} + +.mw-100 { + max-width: 100% !important; +} + +.mh-100 { + max-height: 100% !important; +} + +.min-vw-100 { + min-width: 100vw !important; +} + +.min-vh-100 { + min-height: 100vh !important; +} + +.vw-100 { + width: 100vw !important; +} + +.vh-100 { + height: 100vh !important; +} + +.stretched-link::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + pointer-events: auto; + content: ""; + background-color: rgba(0, 0, 0, 0); +} + +.m-0 { + margin: 0 !important; +} + +.mt-0, +.my-0 { + margin-top: 0 !important; +} + +.mr-0, +.mx-0 { + margin-right: 0 !important; +} + +.mb-0, +.my-0 { + margin-bottom: 0 !important; +} + +.ml-0, +.mx-0 { + margin-left: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.mt-1, +.my-1 { + margin-top: 0.25rem !important; +} + +.mr-1, +.mx-1 { + margin-right: 0.25rem !important; +} + +.mb-1, +.my-1 { + margin-bottom: 0.25rem !important; +} + +.ml-1, +.mx-1 { + margin-left: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.mt-2, +.my-2 { + margin-top: 0.5rem !important; +} + +.mr-2, +.mx-2 { + margin-right: 0.5rem !important; +} + +.mb-2, +.my-2 { + margin-bottom: 0.5rem !important; +} + +.ml-2, +.mx-2 { + margin-left: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.mt-3, +.my-3 { + margin-top: 1rem !important; +} + +.mr-3, +.mx-3 { + margin-right: 1rem !important; +} + +.mb-3, +.my-3 { + margin-bottom: 1rem !important; +} + +.ml-3, +.mx-3 { + margin-left: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.mt-4, +.my-4 { + margin-top: 1.5rem !important; +} + +.mr-4, +.mx-4 { + margin-right: 1.5rem !important; +} + +.mb-4, +.my-4 { + margin-bottom: 1.5rem !important; +} + +.ml-4, +.mx-4 { + margin-left: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.mt-5, +.my-5 { + margin-top: 3rem !important; +} + +.mr-5, +.mx-5 { + margin-right: 3rem !important; +} + +.mb-5, +.my-5 { + margin-bottom: 3rem !important; +} + +.ml-5, +.mx-5 { + margin-left: 3rem !important; +} + +.p-0 { + padding: 0 !important; +} + +.pt-0, +.py-0 { + padding-top: 0 !important; +} + +.pr-0, +.px-0 { + padding-right: 0 !important; +} + +.pb-0, +.py-0 { + padding-bottom: 0 !important; +} + +.pl-0, +.px-0 { + padding-left: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.pt-1, +.py-1 { + padding-top: 0.25rem !important; +} + +.pr-1, +.px-1 { + padding-right: 0.25rem !important; +} + +.pb-1, +.py-1 { + padding-bottom: 0.25rem !important; +} + +.pl-1, +.px-1 { + padding-left: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.pt-2, +.py-2 { + padding-top: 0.5rem !important; +} + +.pr-2, +.px-2 { + padding-right: 0.5rem !important; +} + +.pb-2, +.py-2 { + padding-bottom: 0.5rem !important; +} + +.pl-2, +.px-2 { + padding-left: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.pt-3, +.py-3 { + padding-top: 1rem !important; +} + +.pr-3, +.px-3 { + padding-right: 1rem !important; +} + +.pb-3, +.py-3 { + padding-bottom: 1rem !important; +} + +.pl-3, +.px-3 { + padding-left: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.pt-4, +.py-4 { + padding-top: 1.5rem !important; +} + +.pr-4, +.px-4 { + padding-right: 1.5rem !important; +} + +.pb-4, +.py-4 { + padding-bottom: 1.5rem !important; +} + +.pl-4, +.px-4 { + padding-left: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.pt-5, +.py-5 { + padding-top: 3rem !important; +} + +.pr-5, +.px-5 { + padding-right: 3rem !important; +} + +.pb-5, +.py-5 { + padding-bottom: 3rem !important; +} + +.pl-5, +.px-5 { + padding-left: 3rem !important; +} + +.m-n1 { + margin: -0.25rem !important; +} + +.mt-n1, +.my-n1 { + margin-top: -0.25rem !important; +} + +.mr-n1, +.mx-n1 { + margin-right: -0.25rem !important; +} + +.mb-n1, +.my-n1 { + margin-bottom: -0.25rem !important; +} + +.ml-n1, +.mx-n1 { + margin-left: -0.25rem !important; +} + +.m-n2 { + margin: -0.5rem !important; +} + +.mt-n2, +.my-n2 { + margin-top: -0.5rem !important; +} + +.mr-n2, +.mx-n2 { + margin-right: -0.5rem !important; +} + +.mb-n2, +.my-n2 { + margin-bottom: -0.5rem !important; +} + +.ml-n2, +.mx-n2 { + margin-left: -0.5rem !important; +} + +.m-n3 { + margin: -1rem !important; +} + +.mt-n3, +.my-n3 { + margin-top: -1rem !important; +} + +.mr-n3, +.mx-n3 { + margin-right: -1rem !important; +} + +.mb-n3, +.my-n3 { + margin-bottom: -1rem !important; +} + +.ml-n3, +.mx-n3 { + margin-left: -1rem !important; +} + +.m-n4 { + margin: -1.5rem !important; +} + +.mt-n4, +.my-n4 { + margin-top: -1.5rem !important; +} + +.mr-n4, +.mx-n4 { + margin-right: -1.5rem !important; +} + +.mb-n4, +.my-n4 { + margin-bottom: -1.5rem !important; +} + +.ml-n4, +.mx-n4 { + margin-left: -1.5rem !important; +} + +.m-n5 { + margin: -3rem !important; +} + +.mt-n5, +.my-n5 { + margin-top: -3rem !important; +} + +.mr-n5, +.mx-n5 { + margin-right: -3rem !important; +} + +.mb-n5, +.my-n5 { + margin-bottom: -3rem !important; +} + +.ml-n5, +.mx-n5 { + margin-left: -3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mt-auto, +.my-auto { + margin-top: auto !important; +} + +.mr-auto, +.mx-auto { + margin-right: auto !important; +} + +.mb-auto, +.my-auto { + margin-bottom: auto !important; +} + +.ml-auto, +.mx-auto { + margin-left: auto !important; +} + +@media (min-width: 576px) { + .m-sm-0 { + margin: 0 !important; + } + .mt-sm-0, + .my-sm-0 { + margin-top: 0 !important; + } + .mr-sm-0, + .mx-sm-0 { + margin-right: 0 !important; + } + .mb-sm-0, + .my-sm-0 { + margin-bottom: 0 !important; + } + .ml-sm-0, + .mx-sm-0 { + margin-left: 0 !important; + } + .m-sm-1 { + margin: 0.25rem !important; + } + .mt-sm-1, + .my-sm-1 { + margin-top: 0.25rem !important; + } + .mr-sm-1, + .mx-sm-1 { + margin-right: 0.25rem !important; + } + .mb-sm-1, + .my-sm-1 { + margin-bottom: 0.25rem !important; + } + .ml-sm-1, + .mx-sm-1 { + margin-left: 0.25rem !important; + } + .m-sm-2 { + margin: 0.5rem !important; + } + .mt-sm-2, + .my-sm-2 { + margin-top: 0.5rem !important; + } + .mr-sm-2, + .mx-sm-2 { + margin-right: 0.5rem !important; + } + .mb-sm-2, + .my-sm-2 { + margin-bottom: 0.5rem !important; + } + .ml-sm-2, + .mx-sm-2 { + margin-left: 0.5rem !important; + } + .m-sm-3 { + margin: 1rem !important; + } + .mt-sm-3, + .my-sm-3 { + margin-top: 1rem !important; + } + .mr-sm-3, + .mx-sm-3 { + margin-right: 1rem !important; + } + .mb-sm-3, + .my-sm-3 { + margin-bottom: 1rem !important; + } + .ml-sm-3, + .mx-sm-3 { + margin-left: 1rem !important; + } + .m-sm-4 { + margin: 1.5rem !important; + } + .mt-sm-4, + .my-sm-4 { + margin-top: 1.5rem !important; + } + .mr-sm-4, + .mx-sm-4 { + margin-right: 1.5rem !important; + } + .mb-sm-4, + .my-sm-4 { + margin-bottom: 1.5rem !important; + } + .ml-sm-4, + .mx-sm-4 { + margin-left: 1.5rem !important; + } + .m-sm-5 { + margin: 3rem !important; + } + .mt-sm-5, + .my-sm-5 { + margin-top: 3rem !important; + } + .mr-sm-5, + .mx-sm-5 { + margin-right: 3rem !important; + } + .mb-sm-5, + .my-sm-5 { + margin-bottom: 3rem !important; + } + .ml-sm-5, + .mx-sm-5 { + margin-left: 3rem !important; + } + .p-sm-0 { + padding: 0 !important; + } + .pt-sm-0, + .py-sm-0 { + padding-top: 0 !important; + } + .pr-sm-0, + .px-sm-0 { + padding-right: 0 !important; + } + .pb-sm-0, + .py-sm-0 { + padding-bottom: 0 !important; + } + .pl-sm-0, + .px-sm-0 { + padding-left: 0 !important; + } + .p-sm-1 { + padding: 0.25rem !important; + } + .pt-sm-1, + .py-sm-1 { + padding-top: 0.25rem !important; + } + .pr-sm-1, + .px-sm-1 { + padding-right: 0.25rem !important; + } + .pb-sm-1, + .py-sm-1 { + padding-bottom: 0.25rem !important; + } + .pl-sm-1, + .px-sm-1 { + padding-left: 0.25rem !important; + } + .p-sm-2 { + padding: 0.5rem !important; + } + .pt-sm-2, + .py-sm-2 { + padding-top: 0.5rem !important; + } + .pr-sm-2, + .px-sm-2 { + padding-right: 0.5rem !important; + } + .pb-sm-2, + .py-sm-2 { + padding-bottom: 0.5rem !important; + } + .pl-sm-2, + .px-sm-2 { + padding-left: 0.5rem !important; + } + .p-sm-3 { + padding: 1rem !important; + } + .pt-sm-3, + .py-sm-3 { + padding-top: 1rem !important; + } + .pr-sm-3, + .px-sm-3 { + padding-right: 1rem !important; + } + .pb-sm-3, + .py-sm-3 { + padding-bottom: 1rem !important; + } + .pl-sm-3, + .px-sm-3 { + padding-left: 1rem !important; + } + .p-sm-4 { + padding: 1.5rem !important; + } + .pt-sm-4, + .py-sm-4 { + padding-top: 1.5rem !important; + } + .pr-sm-4, + .px-sm-4 { + padding-right: 1.5rem !important; + } + .pb-sm-4, + .py-sm-4 { + padding-bottom: 1.5rem !important; + } + .pl-sm-4, + .px-sm-4 { + padding-left: 1.5rem !important; + } + .p-sm-5 { + padding: 3rem !important; + } + .pt-sm-5, + .py-sm-5 { + padding-top: 3rem !important; + } + .pr-sm-5, + .px-sm-5 { + padding-right: 3rem !important; + } + .pb-sm-5, + .py-sm-5 { + padding-bottom: 3rem !important; + } + .pl-sm-5, + .px-sm-5 { + padding-left: 3rem !important; + } + .m-sm-n1 { + margin: -0.25rem !important; + } + .mt-sm-n1, + .my-sm-n1 { + margin-top: -0.25rem !important; + } + .mr-sm-n1, + .mx-sm-n1 { + margin-right: -0.25rem !important; + } + .mb-sm-n1, + .my-sm-n1 { + margin-bottom: -0.25rem !important; + } + .ml-sm-n1, + .mx-sm-n1 { + margin-left: -0.25rem !important; + } + .m-sm-n2 { + margin: -0.5rem !important; + } + .mt-sm-n2, + .my-sm-n2 { + margin-top: -0.5rem !important; + } + .mr-sm-n2, + .mx-sm-n2 { + margin-right: -0.5rem !important; + } + .mb-sm-n2, + .my-sm-n2 { + margin-bottom: -0.5rem !important; + } + .ml-sm-n2, + .mx-sm-n2 { + margin-left: -0.5rem !important; + } + .m-sm-n3 { + margin: -1rem !important; + } + .mt-sm-n3, + .my-sm-n3 { + margin-top: -1rem !important; + } + .mr-sm-n3, + .mx-sm-n3 { + margin-right: -1rem !important; + } + .mb-sm-n3, + .my-sm-n3 { + margin-bottom: -1rem !important; + } + .ml-sm-n3, + .mx-sm-n3 { + margin-left: -1rem !important; + } + .m-sm-n4 { + margin: -1.5rem !important; + } + .mt-sm-n4, + .my-sm-n4 { + margin-top: -1.5rem !important; + } + .mr-sm-n4, + .mx-sm-n4 { + margin-right: -1.5rem !important; + } + .mb-sm-n4, + .my-sm-n4 { + margin-bottom: -1.5rem !important; + } + .ml-sm-n4, + .mx-sm-n4 { + margin-left: -1.5rem !important; + } + .m-sm-n5 { + margin: -3rem !important; + } + .mt-sm-n5, + .my-sm-n5 { + margin-top: -3rem !important; + } + .mr-sm-n5, + .mx-sm-n5 { + margin-right: -3rem !important; + } + .mb-sm-n5, + .my-sm-n5 { + margin-bottom: -3rem !important; + } + .ml-sm-n5, + .mx-sm-n5 { + margin-left: -3rem !important; + } + .m-sm-auto { + margin: auto !important; + } + .mt-sm-auto, + .my-sm-auto { + margin-top: auto !important; + } + .mr-sm-auto, + .mx-sm-auto { + margin-right: auto !important; + } + .mb-sm-auto, + .my-sm-auto { + margin-bottom: auto !important; + } + .ml-sm-auto, + .mx-sm-auto { + margin-left: auto !important; + } +} + +@media (min-width: 768px) { + .m-md-0 { + margin: 0 !important; + } + .mt-md-0, + .my-md-0 { + margin-top: 0 !important; + } + .mr-md-0, + .mx-md-0 { + margin-right: 0 !important; + } + .mb-md-0, + .my-md-0 { + margin-bottom: 0 !important; + } + .ml-md-0, + .mx-md-0 { + margin-left: 0 !important; + } + .m-md-1 { + margin: 0.25rem !important; + } + .mt-md-1, + .my-md-1 { + margin-top: 0.25rem !important; + } + .mr-md-1, + .mx-md-1 { + margin-right: 0.25rem !important; + } + .mb-md-1, + .my-md-1 { + margin-bottom: 0.25rem !important; + } + .ml-md-1, + .mx-md-1 { + margin-left: 0.25rem !important; + } + .m-md-2 { + margin: 0.5rem !important; + } + .mt-md-2, + .my-md-2 { + margin-top: 0.5rem !important; + } + .mr-md-2, + .mx-md-2 { + margin-right: 0.5rem !important; + } + .mb-md-2, + .my-md-2 { + margin-bottom: 0.5rem !important; + } + .ml-md-2, + .mx-md-2 { + margin-left: 0.5rem !important; + } + .m-md-3 { + margin: 1rem !important; + } + .mt-md-3, + .my-md-3 { + margin-top: 1rem !important; + } + .mr-md-3, + .mx-md-3 { + margin-right: 1rem !important; + } + .mb-md-3, + .my-md-3 { + margin-bottom: 1rem !important; + } + .ml-md-3, + .mx-md-3 { + margin-left: 1rem !important; + } + .m-md-4 { + margin: 1.5rem !important; + } + .mt-md-4, + .my-md-4 { + margin-top: 1.5rem !important; + } + .mr-md-4, + .mx-md-4 { + margin-right: 1.5rem !important; + } + .mb-md-4, + .my-md-4 { + margin-bottom: 1.5rem !important; + } + .ml-md-4, + .mx-md-4 { + margin-left: 1.5rem !important; + } + .m-md-5 { + margin: 3rem !important; + } + .mt-md-5, + .my-md-5 { + margin-top: 3rem !important; + } + .mr-md-5, + .mx-md-5 { + margin-right: 3rem !important; + } + .mb-md-5, + .my-md-5 { + margin-bottom: 3rem !important; + } + .ml-md-5, + .mx-md-5 { + margin-left: 3rem !important; + } + .p-md-0 { + padding: 0 !important; + } + .pt-md-0, + .py-md-0 { + padding-top: 0 !important; + } + .pr-md-0, + .px-md-0 { + padding-right: 0 !important; + } + .pb-md-0, + .py-md-0 { + padding-bottom: 0 !important; + } + .pl-md-0, + .px-md-0 { + padding-left: 0 !important; + } + .p-md-1 { + padding: 0.25rem !important; + } + .pt-md-1, + .py-md-1 { + padding-top: 0.25rem !important; + } + .pr-md-1, + .px-md-1 { + padding-right: 0.25rem !important; + } + .pb-md-1, + .py-md-1 { + padding-bottom: 0.25rem !important; + } + .pl-md-1, + .px-md-1 { + padding-left: 0.25rem !important; + } + .p-md-2 { + padding: 0.5rem !important; + } + .pt-md-2, + .py-md-2 { + padding-top: 0.5rem !important; + } + .pr-md-2, + .px-md-2 { + padding-right: 0.5rem !important; + } + .pb-md-2, + .py-md-2 { + padding-bottom: 0.5rem !important; + } + .pl-md-2, + .px-md-2 { + padding-left: 0.5rem !important; + } + .p-md-3 { + padding: 1rem !important; + } + .pt-md-3, + .py-md-3 { + padding-top: 1rem !important; + } + .pr-md-3, + .px-md-3 { + padding-right: 1rem !important; + } + .pb-md-3, + .py-md-3 { + padding-bottom: 1rem !important; + } + .pl-md-3, + .px-md-3 { + padding-left: 1rem !important; + } + .p-md-4 { + padding: 1.5rem !important; + } + .pt-md-4, + .py-md-4 { + padding-top: 1.5rem !important; + } + .pr-md-4, + .px-md-4 { + padding-right: 1.5rem !important; + } + .pb-md-4, + .py-md-4 { + padding-bottom: 1.5rem !important; + } + .pl-md-4, + .px-md-4 { + padding-left: 1.5rem !important; + } + .p-md-5 { + padding: 3rem !important; + } + .pt-md-5, + .py-md-5 { + padding-top: 3rem !important; + } + .pr-md-5, + .px-md-5 { + padding-right: 3rem !important; + } + .pb-md-5, + .py-md-5 { + padding-bottom: 3rem !important; + } + .pl-md-5, + .px-md-5 { + padding-left: 3rem !important; + } + .m-md-n1 { + margin: -0.25rem !important; + } + .mt-md-n1, + .my-md-n1 { + margin-top: -0.25rem !important; + } + .mr-md-n1, + .mx-md-n1 { + margin-right: -0.25rem !important; + } + .mb-md-n1, + .my-md-n1 { + margin-bottom: -0.25rem !important; + } + .ml-md-n1, + .mx-md-n1 { + margin-left: -0.25rem !important; + } + .m-md-n2 { + margin: -0.5rem !important; + } + .mt-md-n2, + .my-md-n2 { + margin-top: -0.5rem !important; + } + .mr-md-n2, + .mx-md-n2 { + margin-right: -0.5rem !important; + } + .mb-md-n2, + .my-md-n2 { + margin-bottom: -0.5rem !important; + } + .ml-md-n2, + .mx-md-n2 { + margin-left: -0.5rem !important; + } + .m-md-n3 { + margin: -1rem !important; + } + .mt-md-n3, + .my-md-n3 { + margin-top: -1rem !important; + } + .mr-md-n3, + .mx-md-n3 { + margin-right: -1rem !important; + } + .mb-md-n3, + .my-md-n3 { + margin-bottom: -1rem !important; + } + .ml-md-n3, + .mx-md-n3 { + margin-left: -1rem !important; + } + .m-md-n4 { + margin: -1.5rem !important; + } + .mt-md-n4, + .my-md-n4 { + margin-top: -1.5rem !important; + } + .mr-md-n4, + .mx-md-n4 { + margin-right: -1.5rem !important; + } + .mb-md-n4, + .my-md-n4 { + margin-bottom: -1.5rem !important; + } + .ml-md-n4, + .mx-md-n4 { + margin-left: -1.5rem !important; + } + .m-md-n5 { + margin: -3rem !important; + } + .mt-md-n5, + .my-md-n5 { + margin-top: -3rem !important; + } + .mr-md-n5, + .mx-md-n5 { + margin-right: -3rem !important; + } + .mb-md-n5, + .my-md-n5 { + margin-bottom: -3rem !important; + } + .ml-md-n5, + .mx-md-n5 { + margin-left: -3rem !important; + } + .m-md-auto { + margin: auto !important; + } + .mt-md-auto, + .my-md-auto { + margin-top: auto !important; + } + .mr-md-auto, + .mx-md-auto { + margin-right: auto !important; + } + .mb-md-auto, + .my-md-auto { + margin-bottom: auto !important; + } + .ml-md-auto, + .mx-md-auto { + margin-left: auto !important; + } +} + +@media (min-width: 992px) { + .m-lg-0 { + margin: 0 !important; + } + .mt-lg-0, + .my-lg-0 { + margin-top: 0 !important; + } + .mr-lg-0, + .mx-lg-0 { + margin-right: 0 !important; + } + .mb-lg-0, + .my-lg-0 { + margin-bottom: 0 !important; + } + .ml-lg-0, + .mx-lg-0 { + margin-left: 0 !important; + } + .m-lg-1 { + margin: 0.25rem !important; + } + .mt-lg-1, + .my-lg-1 { + margin-top: 0.25rem !important; + } + .mr-lg-1, + .mx-lg-1 { + margin-right: 0.25rem !important; + } + .mb-lg-1, + .my-lg-1 { + margin-bottom: 0.25rem !important; + } + .ml-lg-1, + .mx-lg-1 { + margin-left: 0.25rem !important; + } + .m-lg-2 { + margin: 0.5rem !important; + } + .mt-lg-2, + .my-lg-2 { + margin-top: 0.5rem !important; + } + .mr-lg-2, + .mx-lg-2 { + margin-right: 0.5rem !important; + } + .mb-lg-2, + .my-lg-2 { + margin-bottom: 0.5rem !important; + } + .ml-lg-2, + .mx-lg-2 { + margin-left: 0.5rem !important; + } + .m-lg-3 { + margin: 1rem !important; + } + .mt-lg-3, + .my-lg-3 { + margin-top: 1rem !important; + } + .mr-lg-3, + .mx-lg-3 { + margin-right: 1rem !important; + } + .mb-lg-3, + .my-lg-3 { + margin-bottom: 1rem !important; + } + .ml-lg-3, + .mx-lg-3 { + margin-left: 1rem !important; + } + .m-lg-4 { + margin: 1.5rem !important; + } + .mt-lg-4, + .my-lg-4 { + margin-top: 1.5rem !important; + } + .mr-lg-4, + .mx-lg-4 { + margin-right: 1.5rem !important; + } + .mb-lg-4, + .my-lg-4 { + margin-bottom: 1.5rem !important; + } + .ml-lg-4, + .mx-lg-4 { + margin-left: 1.5rem !important; + } + .m-lg-5 { + margin: 3rem !important; + } + .mt-lg-5, + .my-lg-5 { + margin-top: 3rem !important; + } + .mr-lg-5, + .mx-lg-5 { + margin-right: 3rem !important; + } + .mb-lg-5, + .my-lg-5 { + margin-bottom: 3rem !important; + } + .ml-lg-5, + .mx-lg-5 { + margin-left: 3rem !important; + } + .p-lg-0 { + padding: 0 !important; + } + .pt-lg-0, + .py-lg-0 { + padding-top: 0 !important; + } + .pr-lg-0, + .px-lg-0 { + padding-right: 0 !important; + } + .pb-lg-0, + .py-lg-0 { + padding-bottom: 0 !important; + } + .pl-lg-0, + .px-lg-0 { + padding-left: 0 !important; + } + .p-lg-1 { + padding: 0.25rem !important; + } + .pt-lg-1, + .py-lg-1 { + padding-top: 0.25rem !important; + } + .pr-lg-1, + .px-lg-1 { + padding-right: 0.25rem !important; + } + .pb-lg-1, + .py-lg-1 { + padding-bottom: 0.25rem !important; + } + .pl-lg-1, + .px-lg-1 { + padding-left: 0.25rem !important; + } + .p-lg-2 { + padding: 0.5rem !important; + } + .pt-lg-2, + .py-lg-2 { + padding-top: 0.5rem !important; + } + .pr-lg-2, + .px-lg-2 { + padding-right: 0.5rem !important; + } + .pb-lg-2, + .py-lg-2 { + padding-bottom: 0.5rem !important; + } + .pl-lg-2, + .px-lg-2 { + padding-left: 0.5rem !important; + } + .p-lg-3 { + padding: 1rem !important; + } + .pt-lg-3, + .py-lg-3 { + padding-top: 1rem !important; + } + .pr-lg-3, + .px-lg-3 { + padding-right: 1rem !important; + } + .pb-lg-3, + .py-lg-3 { + padding-bottom: 1rem !important; + } + .pl-lg-3, + .px-lg-3 { + padding-left: 1rem !important; + } + .p-lg-4 { + padding: 1.5rem !important; + } + .pt-lg-4, + .py-lg-4 { + padding-top: 1.5rem !important; + } + .pr-lg-4, + .px-lg-4 { + padding-right: 1.5rem !important; + } + .pb-lg-4, + .py-lg-4 { + padding-bottom: 1.5rem !important; + } + .pl-lg-4, + .px-lg-4 { + padding-left: 1.5rem !important; + } + .p-lg-5 { + padding: 3rem !important; + } + .pt-lg-5, + .py-lg-5 { + padding-top: 3rem !important; + } + .pr-lg-5, + .px-lg-5 { + padding-right: 3rem !important; + } + .pb-lg-5, + .py-lg-5 { + padding-bottom: 3rem !important; + } + .pl-lg-5, + .px-lg-5 { + padding-left: 3rem !important; + } + .m-lg-n1 { + margin: -0.25rem !important; + } + .mt-lg-n1, + .my-lg-n1 { + margin-top: -0.25rem !important; + } + .mr-lg-n1, + .mx-lg-n1 { + margin-right: -0.25rem !important; + } + .mb-lg-n1, + .my-lg-n1 { + margin-bottom: -0.25rem !important; + } + .ml-lg-n1, + .mx-lg-n1 { + margin-left: -0.25rem !important; + } + .m-lg-n2 { + margin: -0.5rem !important; + } + .mt-lg-n2, + .my-lg-n2 { + margin-top: -0.5rem !important; + } + .mr-lg-n2, + .mx-lg-n2 { + margin-right: -0.5rem !important; + } + .mb-lg-n2, + .my-lg-n2 { + margin-bottom: -0.5rem !important; + } + .ml-lg-n2, + .mx-lg-n2 { + margin-left: -0.5rem !important; + } + .m-lg-n3 { + margin: -1rem !important; + } + .mt-lg-n3, + .my-lg-n3 { + margin-top: -1rem !important; + } + .mr-lg-n3, + .mx-lg-n3 { + margin-right: -1rem !important; + } + .mb-lg-n3, + .my-lg-n3 { + margin-bottom: -1rem !important; + } + .ml-lg-n3, + .mx-lg-n3 { + margin-left: -1rem !important; + } + .m-lg-n4 { + margin: -1.5rem !important; + } + .mt-lg-n4, + .my-lg-n4 { + margin-top: -1.5rem !important; + } + .mr-lg-n4, + .mx-lg-n4 { + margin-right: -1.5rem !important; + } + .mb-lg-n4, + .my-lg-n4 { + margin-bottom: -1.5rem !important; + } + .ml-lg-n4, + .mx-lg-n4 { + margin-left: -1.5rem !important; + } + .m-lg-n5 { + margin: -3rem !important; + } + .mt-lg-n5, + .my-lg-n5 { + margin-top: -3rem !important; + } + .mr-lg-n5, + .mx-lg-n5 { + margin-right: -3rem !important; + } + .mb-lg-n5, + .my-lg-n5 { + margin-bottom: -3rem !important; + } + .ml-lg-n5, + .mx-lg-n5 { + margin-left: -3rem !important; + } + .m-lg-auto { + margin: auto !important; + } + .mt-lg-auto, + .my-lg-auto { + margin-top: auto !important; + } + .mr-lg-auto, + .mx-lg-auto { + margin-right: auto !important; + } + .mb-lg-auto, + .my-lg-auto { + margin-bottom: auto !important; + } + .ml-lg-auto, + .mx-lg-auto { + margin-left: auto !important; + } +} + +@media (min-width: 1200px) { + .m-xl-0 { + margin: 0 !important; + } + .mt-xl-0, + .my-xl-0 { + margin-top: 0 !important; + } + .mr-xl-0, + .mx-xl-0 { + margin-right: 0 !important; + } + .mb-xl-0, + .my-xl-0 { + margin-bottom: 0 !important; + } + .ml-xl-0, + .mx-xl-0 { + margin-left: 0 !important; + } + .m-xl-1 { + margin: 0.25rem !important; + } + .mt-xl-1, + .my-xl-1 { + margin-top: 0.25rem !important; + } + .mr-xl-1, + .mx-xl-1 { + margin-right: 0.25rem !important; + } + .mb-xl-1, + .my-xl-1 { + margin-bottom: 0.25rem !important; + } + .ml-xl-1, + .mx-xl-1 { + margin-left: 0.25rem !important; + } + .m-xl-2 { + margin: 0.5rem !important; + } + .mt-xl-2, + .my-xl-2 { + margin-top: 0.5rem !important; + } + .mr-xl-2, + .mx-xl-2 { + margin-right: 0.5rem !important; + } + .mb-xl-2, + .my-xl-2 { + margin-bottom: 0.5rem !important; + } + .ml-xl-2, + .mx-xl-2 { + margin-left: 0.5rem !important; + } + .m-xl-3 { + margin: 1rem !important; + } + .mt-xl-3, + .my-xl-3 { + margin-top: 1rem !important; + } + .mr-xl-3, + .mx-xl-3 { + margin-right: 1rem !important; + } + .mb-xl-3, + .my-xl-3 { + margin-bottom: 1rem !important; + } + .ml-xl-3, + .mx-xl-3 { + margin-left: 1rem !important; + } + .m-xl-4 { + margin: 1.5rem !important; + } + .mt-xl-4, + .my-xl-4 { + margin-top: 1.5rem !important; + } + .mr-xl-4, + .mx-xl-4 { + margin-right: 1.5rem !important; + } + .mb-xl-4, + .my-xl-4 { + margin-bottom: 1.5rem !important; + } + .ml-xl-4, + .mx-xl-4 { + margin-left: 1.5rem !important; + } + .m-xl-5 { + margin: 3rem !important; + } + .mt-xl-5, + .my-xl-5 { + margin-top: 3rem !important; + } + .mr-xl-5, + .mx-xl-5 { + margin-right: 3rem !important; + } + .mb-xl-5, + .my-xl-5 { + margin-bottom: 3rem !important; + } + .ml-xl-5, + .mx-xl-5 { + margin-left: 3rem !important; + } + .p-xl-0 { + padding: 0 !important; + } + .pt-xl-0, + .py-xl-0 { + padding-top: 0 !important; + } + .pr-xl-0, + .px-xl-0 { + padding-right: 0 !important; + } + .pb-xl-0, + .py-xl-0 { + padding-bottom: 0 !important; + } + .pl-xl-0, + .px-xl-0 { + padding-left: 0 !important; + } + .p-xl-1 { + padding: 0.25rem !important; + } + .pt-xl-1, + .py-xl-1 { + padding-top: 0.25rem !important; + } + .pr-xl-1, + .px-xl-1 { + padding-right: 0.25rem !important; + } + .pb-xl-1, + .py-xl-1 { + padding-bottom: 0.25rem !important; + } + .pl-xl-1, + .px-xl-1 { + padding-left: 0.25rem !important; + } + .p-xl-2 { + padding: 0.5rem !important; + } + .pt-xl-2, + .py-xl-2 { + padding-top: 0.5rem !important; + } + .pr-xl-2, + .px-xl-2 { + padding-right: 0.5rem !important; + } + .pb-xl-2, + .py-xl-2 { + padding-bottom: 0.5rem !important; + } + .pl-xl-2, + .px-xl-2 { + padding-left: 0.5rem !important; + } + .p-xl-3 { + padding: 1rem !important; + } + .pt-xl-3, + .py-xl-3 { + padding-top: 1rem !important; + } + .pr-xl-3, + .px-xl-3 { + padding-right: 1rem !important; + } + .pb-xl-3, + .py-xl-3 { + padding-bottom: 1rem !important; + } + .pl-xl-3, + .px-xl-3 { + padding-left: 1rem !important; + } + .p-xl-4 { + padding: 1.5rem !important; + } + .pt-xl-4, + .py-xl-4 { + padding-top: 1.5rem !important; + } + .pr-xl-4, + .px-xl-4 { + padding-right: 1.5rem !important; + } + .pb-xl-4, + .py-xl-4 { + padding-bottom: 1.5rem !important; + } + .pl-xl-4, + .px-xl-4 { + padding-left: 1.5rem !important; + } + .p-xl-5 { + padding: 3rem !important; + } + .pt-xl-5, + .py-xl-5 { + padding-top: 3rem !important; + } + .pr-xl-5, + .px-xl-5 { + padding-right: 3rem !important; + } + .pb-xl-5, + .py-xl-5 { + padding-bottom: 3rem !important; + } + .pl-xl-5, + .px-xl-5 { + padding-left: 3rem !important; + } + .m-xl-n1 { + margin: -0.25rem !important; + } + .mt-xl-n1, + .my-xl-n1 { + margin-top: -0.25rem !important; + } + .mr-xl-n1, + .mx-xl-n1 { + margin-right: -0.25rem !important; + } + .mb-xl-n1, + .my-xl-n1 { + margin-bottom: -0.25rem !important; + } + .ml-xl-n1, + .mx-xl-n1 { + margin-left: -0.25rem !important; + } + .m-xl-n2 { + margin: -0.5rem !important; + } + .mt-xl-n2, + .my-xl-n2 { + margin-top: -0.5rem !important; + } + .mr-xl-n2, + .mx-xl-n2 { + margin-right: -0.5rem !important; + } + .mb-xl-n2, + .my-xl-n2 { + margin-bottom: -0.5rem !important; + } + .ml-xl-n2, + .mx-xl-n2 { + margin-left: -0.5rem !important; + } + .m-xl-n3 { + margin: -1rem !important; + } + .mt-xl-n3, + .my-xl-n3 { + margin-top: -1rem !important; + } + .mr-xl-n3, + .mx-xl-n3 { + margin-right: -1rem !important; + } + .mb-xl-n3, + .my-xl-n3 { + margin-bottom: -1rem !important; + } + .ml-xl-n3, + .mx-xl-n3 { + margin-left: -1rem !important; + } + .m-xl-n4 { + margin: -1.5rem !important; + } + .mt-xl-n4, + .my-xl-n4 { + margin-top: -1.5rem !important; + } + .mr-xl-n4, + .mx-xl-n4 { + margin-right: -1.5rem !important; + } + .mb-xl-n4, + .my-xl-n4 { + margin-bottom: -1.5rem !important; + } + .ml-xl-n4, + .mx-xl-n4 { + margin-left: -1.5rem !important; + } + .m-xl-n5 { + margin: -3rem !important; + } + .mt-xl-n5, + .my-xl-n5 { + margin-top: -3rem !important; + } + .mr-xl-n5, + .mx-xl-n5 { + margin-right: -3rem !important; + } + .mb-xl-n5, + .my-xl-n5 { + margin-bottom: -3rem !important; + } + .ml-xl-n5, + .mx-xl-n5 { + margin-left: -3rem !important; + } + .m-xl-auto { + margin: auto !important; + } + .mt-xl-auto, + .my-xl-auto { + margin-top: auto !important; + } + .mr-xl-auto, + .mx-xl-auto { + margin-right: auto !important; + } + .mb-xl-auto, + .my-xl-auto { + margin-bottom: auto !important; + } + .ml-xl-auto, + .mx-xl-auto { + margin-left: auto !important; + } +} + +.text-monospace { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !important; +} + +.text-justify { + text-align: justify !important; +} + +.text-wrap { + white-space: normal !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.text-left { + text-align: left !important; +} + +.text-right { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +@media (min-width: 576px) { + .text-sm-left { + text-align: left !important; + } + .text-sm-right { + text-align: right !important; + } + .text-sm-center { + text-align: center !important; + } +} + +@media (min-width: 768px) { + .text-md-left { + text-align: left !important; + } + .text-md-right { + text-align: right !important; + } + .text-md-center { + text-align: center !important; + } +} + +@media (min-width: 992px) { + .text-lg-left { + text-align: left !important; + } + .text-lg-right { + text-align: right !important; + } + .text-lg-center { + text-align: center !important; + } +} + +@media (min-width: 1200px) { + .text-xl-left { + text-align: left !important; + } + .text-xl-right { + text-align: right !important; + } + .text-xl-center { + text-align: center !important; + } +} + +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +.font-weight-light { + font-weight: 300 !important; +} + +.font-weight-lighter { + font-weight: lighter !important; +} + +.font-weight-normal { + font-weight: 400 !important; +} + +.font-weight-bold { + font-weight: 700 !important; +} + +.font-weight-bolder { + font-weight: bolder !important; +} + +.font-italic { + font-style: italic !important; +} + +.text-white { + color: #fff !important; +} + +.text-primary { + color: #007bff !important; +} + +a.text-primary:hover, a.text-primary:focus { + color: #0056b3 !important; +} + +.text-secondary { + color: #6c757d !important; +} + +a.text-secondary:hover, a.text-secondary:focus { + color: #494f54 !important; +} + +.text-success { + color: #28a745 !important; +} + +a.text-success:hover, a.text-success:focus { + color: #19692c !important; +} + +.text-info { + color: #17a2b8 !important; +} + +a.text-info:hover, a.text-info:focus { + color: #0f6674 !important; +} + +.text-warning { + color: #ffc107 !important; +} + +a.text-warning:hover, a.text-warning:focus { + color: #ba8b00 !important; +} + +.text-danger { + color: #dc3545 !important; +} + +a.text-danger:hover, a.text-danger:focus { + color: #a71d2a !important; +} + +.text-light { + color: #f8f9fa !important; +} + +a.text-light:hover, a.text-light:focus { + color: #cbd3da !important; +} + +.text-dark { + color: #343a40 !important; +} + +a.text-dark:hover, a.text-dark:focus { + color: #121416 !important; +} + +.text-body { + color: #212529 !important; +} + +.text-muted { + color: #6c757d !important; +} + +.text-black-50 { + color: rgba(0, 0, 0, 0.5) !important; +} + +.text-white-50 { + color: rgba(255, 255, 255, 0.5) !important; +} + +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.text-decoration-none { + text-decoration: none !important; +} + +.text-break { + word-break: break-word !important; + overflow-wrap: break-word !important; +} + +.text-reset { + color: inherit !important; +} + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} + +@media print { + *, + *::before, + *::after { + text-shadow: none !important; + box-shadow: none !important; + } + a:not(.btn) { + text-decoration: underline; + } + abbr[title]::after { + content: " (" attr(title) ")"; + } + pre { + white-space: pre-wrap !important; + } + pre, + blockquote { + border: 1px solid #adb5bd; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + @page { + size: a3; + } + body { + min-width: 992px !important; + } + .container { + min-width: 992px !important; + } + .navbar { + display: none; + } + .badge { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table td, + .table th { + background-color: #fff !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #dee2e6 !important; + } + .table-dark { + color: inherit; + } + .table-dark th, + .table-dark td, + .table-dark thead th, + .table-dark tbody + tbody { + border-color: #dee2e6; + } + .table .thead-dark th { + color: inherit; + border-color: #dee2e6; + } +} +/*# sourceMappingURL=bootstrap.css.map */ \ No newline at end of file diff --git a/public/static/js/hyw/bootstrap/js/bootstrap.js b/public/static/js/hyw/bootstrap/js/bootstrap.js new file mode 100644 index 0000000..f1e68d3 --- /dev/null +++ b/public/static/js/hyw/bootstrap/js/bootstrap.js @@ -0,0 +1,4521 @@ +/*! + * Bootstrap v4.4.1 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery'), require('popper.js')) : + typeof define === 'function' && define.amd ? define(['exports', 'jquery', 'popper.js'], factory) : + (global = global || self, factory(global.bootstrap = {}, global.jQuery, global.Popper)); +}(this, (function (exports, $, Popper) { 'use strict'; + + $ = $ && $.hasOwnProperty('default') ? $['default'] : $; + Popper = Popper && Popper.hasOwnProperty('default') ? Popper['default'] : Popper; + + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; + } + + function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; + } + + function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + if (enumerableOnly) symbols = symbols.filter(function (sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + }); + keys.push.apply(keys, symbols); + } + + return keys; + } + + function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + + if (i % 2) { + ownKeys(Object(source), true).forEach(function (key) { + _defineProperty(target, key, source[key]); + }); + } else if (Object.getOwnPropertyDescriptors) { + Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); + } else { + ownKeys(Object(source)).forEach(function (key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + } + + return target; + } + + function _inheritsLoose(subClass, superClass) { + subClass.prototype = Object.create(superClass.prototype); + subClass.prototype.constructor = subClass; + subClass.__proto__ = superClass; + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.4.1): util.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Private TransitionEnd Helpers + * ------------------------------------------------------------------------ + */ + + var TRANSITION_END = 'transitionend'; + var MAX_UID = 1000000; + var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp) + + function toType(obj) { + return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase(); + } + + function getSpecialTransitionEndEvent() { + return { + bindType: TRANSITION_END, + delegateType: TRANSITION_END, + handle: function handle(event) { + if ($(event.target).is(this)) { + return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params + } + + return undefined; // eslint-disable-line no-undefined + } + }; + } + + function transitionEndEmulator(duration) { + var _this = this; + + var called = false; + $(this).one(Util.TRANSITION_END, function () { + called = true; + }); + setTimeout(function () { + if (!called) { + Util.triggerTransitionEnd(_this); + } + }, duration); + return this; + } + + function setTransitionEndSupport() { + $.fn.emulateTransitionEnd = transitionEndEmulator; + $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent(); + } + /** + * -------------------------------------------------------------------------- + * Public Util Api + * -------------------------------------------------------------------------- + */ + + + var Util = { + TRANSITION_END: 'bsTransitionEnd', + getUID: function getUID(prefix) { + do { + // eslint-disable-next-line no-bitwise + prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here + } while (document.getElementById(prefix)); + + return prefix; + }, + getSelectorFromElement: function getSelectorFromElement(element) { + var selector = element.getAttribute('data-target'); + + if (!selector || selector === '#') { + var hrefAttr = element.getAttribute('href'); + selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : ''; + } + + try { + return document.querySelector(selector) ? selector : null; + } catch (err) { + return null; + } + }, + getTransitionDurationFromElement: function getTransitionDurationFromElement(element) { + if (!element) { + return 0; + } // Get transition-duration of the element + + + var transitionDuration = $(element).css('transition-duration'); + var transitionDelay = $(element).css('transition-delay'); + var floatTransitionDuration = parseFloat(transitionDuration); + var floatTransitionDelay = parseFloat(transitionDelay); // Return 0 if element or transition duration is not found + + if (!floatTransitionDuration && !floatTransitionDelay) { + return 0; + } // If multiple durations are defined, take the first + + + transitionDuration = transitionDuration.split(',')[0]; + transitionDelay = transitionDelay.split(',')[0]; + return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; + }, + reflow: function reflow(element) { + return element.offsetHeight; + }, + triggerTransitionEnd: function triggerTransitionEnd(element) { + $(element).trigger(TRANSITION_END); + }, + // TODO: Remove in v5 + supportsTransitionEnd: function supportsTransitionEnd() { + return Boolean(TRANSITION_END); + }, + isElement: function isElement(obj) { + return (obj[0] || obj).nodeType; + }, + typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) { + for (var property in configTypes) { + if (Object.prototype.hasOwnProperty.call(configTypes, property)) { + var expectedTypes = configTypes[property]; + var value = config[property]; + var valueType = value && Util.isElement(value) ? 'element' : toType(value); + + if (!new RegExp(expectedTypes).test(valueType)) { + throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\".")); + } + } + } + }, + findShadowRoot: function findShadowRoot(element) { + if (!document.documentElement.attachShadow) { + return null; + } // Can find the shadow root otherwise it'll return the document + + + if (typeof element.getRootNode === 'function') { + var root = element.getRootNode(); + return root instanceof ShadowRoot ? root : null; + } + + if (element instanceof ShadowRoot) { + return element; + } // when we don't find a shadow root + + + if (!element.parentNode) { + return null; + } + + return Util.findShadowRoot(element.parentNode); + }, + jQueryDetection: function jQueryDetection() { + if (typeof $ === 'undefined') { + throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.'); + } + + var version = $.fn.jquery.split(' ')[0].split('.'); + var minMajor = 1; + var ltMajor = 2; + var minMinor = 9; + var minPatch = 1; + var maxMajor = 4; + + if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) { + throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0'); + } + } + }; + Util.jQueryDetection(); + setTransitionEndSupport(); + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME = 'alert'; + var VERSION = '4.4.1'; + var DATA_KEY = 'bs.alert'; + var EVENT_KEY = "." + DATA_KEY; + var DATA_API_KEY = '.data-api'; + var JQUERY_NO_CONFLICT = $.fn[NAME]; + var Selector = { + DISMISS: '[data-dismiss="alert"]' + }; + var Event = { + CLOSE: "close" + EVENT_KEY, + CLOSED: "closed" + EVENT_KEY, + CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY + }; + var ClassName = { + ALERT: 'alert', + FADE: 'fade', + SHOW: 'show' + }; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + var Alert = + /*#__PURE__*/ + function () { + function Alert(element) { + this._element = element; + } // Getters + + + var _proto = Alert.prototype; + + // Public + _proto.close = function close(element) { + var rootElement = this._element; + + if (element) { + rootElement = this._getRootElement(element); + } + + var customEvent = this._triggerCloseEvent(rootElement); + + if (customEvent.isDefaultPrevented()) { + return; + } + + this._removeElement(rootElement); + }; + + _proto.dispose = function dispose() { + $.removeData(this._element, DATA_KEY); + this._element = null; + } // Private + ; + + _proto._getRootElement = function _getRootElement(element) { + var selector = Util.getSelectorFromElement(element); + var parent = false; + + if (selector) { + parent = document.querySelector(selector); + } + + if (!parent) { + parent = $(element).closest("." + ClassName.ALERT)[0]; + } + + return parent; + }; + + _proto._triggerCloseEvent = function _triggerCloseEvent(element) { + var closeEvent = $.Event(Event.CLOSE); + $(element).trigger(closeEvent); + return closeEvent; + }; + + _proto._removeElement = function _removeElement(element) { + var _this = this; + + $(element).removeClass(ClassName.SHOW); + + if (!$(element).hasClass(ClassName.FADE)) { + this._destroyElement(element); + + return; + } + + var transitionDuration = Util.getTransitionDurationFromElement(element); + $(element).one(Util.TRANSITION_END, function (event) { + return _this._destroyElement(element, event); + }).emulateTransitionEnd(transitionDuration); + }; + + _proto._destroyElement = function _destroyElement(element) { + $(element).detach().trigger(Event.CLOSED).remove(); + } // Static + ; + + Alert._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var $element = $(this); + var data = $element.data(DATA_KEY); + + if (!data) { + data = new Alert(this); + $element.data(DATA_KEY, data); + } + + if (config === 'close') { + data[config](this); + } + }); + }; + + Alert._handleDismiss = function _handleDismiss(alertInstance) { + return function (event) { + if (event) { + event.preventDefault(); + } + + alertInstance.close(this); + }; + }; + + _createClass(Alert, null, [{ + key: "VERSION", + get: function get() { + return VERSION; + } + }]); + + return Alert; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert())); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME] = Alert._jQueryInterface; + $.fn[NAME].Constructor = Alert; + + $.fn[NAME].noConflict = function () { + $.fn[NAME] = JQUERY_NO_CONFLICT; + return Alert._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$1 = 'button'; + var VERSION$1 = '4.4.1'; + var DATA_KEY$1 = 'bs.button'; + var EVENT_KEY$1 = "." + DATA_KEY$1; + var DATA_API_KEY$1 = '.data-api'; + var JQUERY_NO_CONFLICT$1 = $.fn[NAME$1]; + var ClassName$1 = { + ACTIVE: 'active', + BUTTON: 'btn', + FOCUS: 'focus' + }; + var Selector$1 = { + DATA_TOGGLE_CARROT: '[data-toggle^="button"]', + DATA_TOGGLES: '[data-toggle="buttons"]', + DATA_TOGGLE: '[data-toggle="button"]', + DATA_TOGGLES_BUTTONS: '[data-toggle="buttons"] .btn', + INPUT: 'input:not([type="hidden"])', + ACTIVE: '.active', + BUTTON: '.btn' + }; + var Event$1 = { + CLICK_DATA_API: "click" + EVENT_KEY$1 + DATA_API_KEY$1, + FOCUS_BLUR_DATA_API: "focus" + EVENT_KEY$1 + DATA_API_KEY$1 + " " + ("blur" + EVENT_KEY$1 + DATA_API_KEY$1), + LOAD_DATA_API: "load" + EVENT_KEY$1 + DATA_API_KEY$1 + }; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + var Button = + /*#__PURE__*/ + function () { + function Button(element) { + this._element = element; + } // Getters + + + var _proto = Button.prototype; + + // Public + _proto.toggle = function toggle() { + var triggerChangeEvent = true; + var addAriaPressed = true; + var rootElement = $(this._element).closest(Selector$1.DATA_TOGGLES)[0]; + + if (rootElement) { + var input = this._element.querySelector(Selector$1.INPUT); + + if (input) { + if (input.type === 'radio') { + if (input.checked && this._element.classList.contains(ClassName$1.ACTIVE)) { + triggerChangeEvent = false; + } else { + var activeElement = rootElement.querySelector(Selector$1.ACTIVE); + + if (activeElement) { + $(activeElement).removeClass(ClassName$1.ACTIVE); + } + } + } else if (input.type === 'checkbox') { + if (this._element.tagName === 'LABEL' && input.checked === this._element.classList.contains(ClassName$1.ACTIVE)) { + triggerChangeEvent = false; + } + } else { + // if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input + triggerChangeEvent = false; + } + + if (triggerChangeEvent) { + input.checked = !this._element.classList.contains(ClassName$1.ACTIVE); + $(input).trigger('change'); + } + + input.focus(); + addAriaPressed = false; + } + } + + if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) { + if (addAriaPressed) { + this._element.setAttribute('aria-pressed', !this._element.classList.contains(ClassName$1.ACTIVE)); + } + + if (triggerChangeEvent) { + $(this._element).toggleClass(ClassName$1.ACTIVE); + } + } + }; + + _proto.dispose = function dispose() { + $.removeData(this._element, DATA_KEY$1); + this._element = null; + } // Static + ; + + Button._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY$1); + + if (!data) { + data = new Button(this); + $(this).data(DATA_KEY$1, data); + } + + if (config === 'toggle') { + data[config](); + } + }); + }; + + _createClass(Button, null, [{ + key: "VERSION", + get: function get() { + return VERSION$1; + } + }]); + + return Button; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event$1.CLICK_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) { + var button = event.target; + + if (!$(button).hasClass(ClassName$1.BUTTON)) { + button = $(button).closest(Selector$1.BUTTON)[0]; + } + + if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) { + event.preventDefault(); // work around Firefox bug #1540995 + } else { + var inputBtn = button.querySelector(Selector$1.INPUT); + + if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) { + event.preventDefault(); // work around Firefox bug #1540995 + + return; + } + + Button._jQueryInterface.call($(button), 'toggle'); + } + }).on(Event$1.FOCUS_BLUR_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) { + var button = $(event.target).closest(Selector$1.BUTTON)[0]; + $(button).toggleClass(ClassName$1.FOCUS, /^focus(in)?$/.test(event.type)); + }); + $(window).on(Event$1.LOAD_DATA_API, function () { + // ensure correct active class is set to match the controls' actual values/states + // find all checkboxes/readio buttons inside data-toggle groups + var buttons = [].slice.call(document.querySelectorAll(Selector$1.DATA_TOGGLES_BUTTONS)); + + for (var i = 0, len = buttons.length; i < len; i++) { + var button = buttons[i]; + var input = button.querySelector(Selector$1.INPUT); + + if (input.checked || input.hasAttribute('checked')) { + button.classList.add(ClassName$1.ACTIVE); + } else { + button.classList.remove(ClassName$1.ACTIVE); + } + } // find all button toggles + + + buttons = [].slice.call(document.querySelectorAll(Selector$1.DATA_TOGGLE)); + + for (var _i = 0, _len = buttons.length; _i < _len; _i++) { + var _button = buttons[_i]; + + if (_button.getAttribute('aria-pressed') === 'true') { + _button.classList.add(ClassName$1.ACTIVE); + } else { + _button.classList.remove(ClassName$1.ACTIVE); + } + } + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME$1] = Button._jQueryInterface; + $.fn[NAME$1].Constructor = Button; + + $.fn[NAME$1].noConflict = function () { + $.fn[NAME$1] = JQUERY_NO_CONFLICT$1; + return Button._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$2 = 'carousel'; + var VERSION$2 = '4.4.1'; + var DATA_KEY$2 = 'bs.carousel'; + var EVENT_KEY$2 = "." + DATA_KEY$2; + var DATA_API_KEY$2 = '.data-api'; + var JQUERY_NO_CONFLICT$2 = $.fn[NAME$2]; + var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key + + var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key + + var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch + + var SWIPE_THRESHOLD = 40; + var Default = { + interval: 5000, + keyboard: true, + slide: false, + pause: 'hover', + wrap: true, + touch: true + }; + var DefaultType = { + interval: '(number|boolean)', + keyboard: 'boolean', + slide: '(boolean|string)', + pause: '(string|boolean)', + wrap: 'boolean', + touch: 'boolean' + }; + var Direction = { + NEXT: 'next', + PREV: 'prev', + LEFT: 'left', + RIGHT: 'right' + }; + var Event$2 = { + SLIDE: "slide" + EVENT_KEY$2, + SLID: "slid" + EVENT_KEY$2, + KEYDOWN: "keydown" + EVENT_KEY$2, + MOUSEENTER: "mouseenter" + EVENT_KEY$2, + MOUSELEAVE: "mouseleave" + EVENT_KEY$2, + TOUCHSTART: "touchstart" + EVENT_KEY$2, + TOUCHMOVE: "touchmove" + EVENT_KEY$2, + TOUCHEND: "touchend" + EVENT_KEY$2, + POINTERDOWN: "pointerdown" + EVENT_KEY$2, + POINTERUP: "pointerup" + EVENT_KEY$2, + DRAG_START: "dragstart" + EVENT_KEY$2, + LOAD_DATA_API: "load" + EVENT_KEY$2 + DATA_API_KEY$2, + CLICK_DATA_API: "click" + EVENT_KEY$2 + DATA_API_KEY$2 + }; + var ClassName$2 = { + CAROUSEL: 'carousel', + ACTIVE: 'active', + SLIDE: 'slide', + RIGHT: 'carousel-item-right', + LEFT: 'carousel-item-left', + NEXT: 'carousel-item-next', + PREV: 'carousel-item-prev', + ITEM: 'carousel-item', + POINTER_EVENT: 'pointer-event' + }; + var Selector$2 = { + ACTIVE: '.active', + ACTIVE_ITEM: '.active.carousel-item', + ITEM: '.carousel-item', + ITEM_IMG: '.carousel-item img', + NEXT_PREV: '.carousel-item-next, .carousel-item-prev', + INDICATORS: '.carousel-indicators', + DATA_SLIDE: '[data-slide], [data-slide-to]', + DATA_RIDE: '[data-ride="carousel"]' + }; + var PointerType = { + TOUCH: 'touch', + PEN: 'pen' + }; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + var Carousel = + /*#__PURE__*/ + function () { + function Carousel(element, config) { + this._items = null; + this._interval = null; + this._activeElement = null; + this._isPaused = false; + this._isSliding = false; + this.touchTimeout = null; + this.touchStartX = 0; + this.touchDeltaX = 0; + this._config = this._getConfig(config); + this._element = element; + this._indicatorsElement = this._element.querySelector(Selector$2.INDICATORS); + this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0; + this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent); + + this._addEventListeners(); + } // Getters + + + var _proto = Carousel.prototype; + + // Public + _proto.next = function next() { + if (!this._isSliding) { + this._slide(Direction.NEXT); + } + }; + + _proto.nextWhenVisible = function nextWhenVisible() { + // Don't call next when the page isn't visible + // or the carousel or its parent isn't visible + if (!document.hidden && $(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden') { + this.next(); + } + }; + + _proto.prev = function prev() { + if (!this._isSliding) { + this._slide(Direction.PREV); + } + }; + + _proto.pause = function pause(event) { + if (!event) { + this._isPaused = true; + } + + if (this._element.querySelector(Selector$2.NEXT_PREV)) { + Util.triggerTransitionEnd(this._element); + this.cycle(true); + } + + clearInterval(this._interval); + this._interval = null; + }; + + _proto.cycle = function cycle(event) { + if (!event) { + this._isPaused = false; + } + + if (this._interval) { + clearInterval(this._interval); + this._interval = null; + } + + if (this._config.interval && !this._isPaused) { + this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval); + } + }; + + _proto.to = function to(index) { + var _this = this; + + this._activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM); + + var activeIndex = this._getItemIndex(this._activeElement); + + if (index > this._items.length - 1 || index < 0) { + return; + } + + if (this._isSliding) { + $(this._element).one(Event$2.SLID, function () { + return _this.to(index); + }); + return; + } + + if (activeIndex === index) { + this.pause(); + this.cycle(); + return; + } + + var direction = index > activeIndex ? Direction.NEXT : Direction.PREV; + + this._slide(direction, this._items[index]); + }; + + _proto.dispose = function dispose() { + $(this._element).off(EVENT_KEY$2); + $.removeData(this._element, DATA_KEY$2); + this._items = null; + this._config = null; + this._element = null; + this._interval = null; + this._isPaused = null; + this._isSliding = null; + this._activeElement = null; + this._indicatorsElement = null; + } // Private + ; + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread2({}, Default, {}, config); + Util.typeCheckConfig(NAME$2, config, DefaultType); + return config; + }; + + _proto._handleSwipe = function _handleSwipe() { + var absDeltax = Math.abs(this.touchDeltaX); + + if (absDeltax <= SWIPE_THRESHOLD) { + return; + } + + var direction = absDeltax / this.touchDeltaX; + this.touchDeltaX = 0; // swipe left + + if (direction > 0) { + this.prev(); + } // swipe right + + + if (direction < 0) { + this.next(); + } + }; + + _proto._addEventListeners = function _addEventListeners() { + var _this2 = this; + + if (this._config.keyboard) { + $(this._element).on(Event$2.KEYDOWN, function (event) { + return _this2._keydown(event); + }); + } + + if (this._config.pause === 'hover') { + $(this._element).on(Event$2.MOUSEENTER, function (event) { + return _this2.pause(event); + }).on(Event$2.MOUSELEAVE, function (event) { + return _this2.cycle(event); + }); + } + + if (this._config.touch) { + this._addTouchEventListeners(); + } + }; + + _proto._addTouchEventListeners = function _addTouchEventListeners() { + var _this3 = this; + + if (!this._touchSupported) { + return; + } + + var start = function start(event) { + if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { + _this3.touchStartX = event.originalEvent.clientX; + } else if (!_this3._pointerEvent) { + _this3.touchStartX = event.originalEvent.touches[0].clientX; + } + }; + + var move = function move(event) { + // ensure swiping with one touch and not pinching + if (event.originalEvent.touches && event.originalEvent.touches.length > 1) { + _this3.touchDeltaX = 0; + } else { + _this3.touchDeltaX = event.originalEvent.touches[0].clientX - _this3.touchStartX; + } + }; + + var end = function end(event) { + if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { + _this3.touchDeltaX = event.originalEvent.clientX - _this3.touchStartX; + } + + _this3._handleSwipe(); + + if (_this3._config.pause === 'hover') { + // If it's a touch-enabled device, mouseenter/leave are fired as + // part of the mouse compatibility events on first tap - the carousel + // would stop cycling until user tapped out of it; + // here, we listen for touchend, explicitly pause the carousel + // (as if it's the second time we tap on it, mouseenter compat event + // is NOT fired) and after a timeout (to allow for mouse compatibility + // events to fire) we explicitly restart cycling + _this3.pause(); + + if (_this3.touchTimeout) { + clearTimeout(_this3.touchTimeout); + } + + _this3.touchTimeout = setTimeout(function (event) { + return _this3.cycle(event); + }, TOUCHEVENT_COMPAT_WAIT + _this3._config.interval); + } + }; + + $(this._element.querySelectorAll(Selector$2.ITEM_IMG)).on(Event$2.DRAG_START, function (e) { + return e.preventDefault(); + }); + + if (this._pointerEvent) { + $(this._element).on(Event$2.POINTERDOWN, function (event) { + return start(event); + }); + $(this._element).on(Event$2.POINTERUP, function (event) { + return end(event); + }); + + this._element.classList.add(ClassName$2.POINTER_EVENT); + } else { + $(this._element).on(Event$2.TOUCHSTART, function (event) { + return start(event); + }); + $(this._element).on(Event$2.TOUCHMOVE, function (event) { + return move(event); + }); + $(this._element).on(Event$2.TOUCHEND, function (event) { + return end(event); + }); + } + }; + + _proto._keydown = function _keydown(event) { + if (/input|textarea/i.test(event.target.tagName)) { + return; + } + + switch (event.which) { + case ARROW_LEFT_KEYCODE: + event.preventDefault(); + this.prev(); + break; + + case ARROW_RIGHT_KEYCODE: + event.preventDefault(); + this.next(); + break; + } + }; + + _proto._getItemIndex = function _getItemIndex(element) { + this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(Selector$2.ITEM)) : []; + return this._items.indexOf(element); + }; + + _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) { + var isNextDirection = direction === Direction.NEXT; + var isPrevDirection = direction === Direction.PREV; + + var activeIndex = this._getItemIndex(activeElement); + + var lastItemIndex = this._items.length - 1; + var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex; + + if (isGoingToWrap && !this._config.wrap) { + return activeElement; + } + + var delta = direction === Direction.PREV ? -1 : 1; + var itemIndex = (activeIndex + delta) % this._items.length; + return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex]; + }; + + _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) { + var targetIndex = this._getItemIndex(relatedTarget); + + var fromIndex = this._getItemIndex(this._element.querySelector(Selector$2.ACTIVE_ITEM)); + + var slideEvent = $.Event(Event$2.SLIDE, { + relatedTarget: relatedTarget, + direction: eventDirectionName, + from: fromIndex, + to: targetIndex + }); + $(this._element).trigger(slideEvent); + return slideEvent; + }; + + _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) { + if (this._indicatorsElement) { + var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector$2.ACTIVE)); + $(indicators).removeClass(ClassName$2.ACTIVE); + + var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)]; + + if (nextIndicator) { + $(nextIndicator).addClass(ClassName$2.ACTIVE); + } + } + }; + + _proto._slide = function _slide(direction, element) { + var _this4 = this; + + var activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM); + + var activeElementIndex = this._getItemIndex(activeElement); + + var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement); + + var nextElementIndex = this._getItemIndex(nextElement); + + var isCycling = Boolean(this._interval); + var directionalClassName; + var orderClassName; + var eventDirectionName; + + if (direction === Direction.NEXT) { + directionalClassName = ClassName$2.LEFT; + orderClassName = ClassName$2.NEXT; + eventDirectionName = Direction.LEFT; + } else { + directionalClassName = ClassName$2.RIGHT; + orderClassName = ClassName$2.PREV; + eventDirectionName = Direction.RIGHT; + } + + if (nextElement && $(nextElement).hasClass(ClassName$2.ACTIVE)) { + this._isSliding = false; + return; + } + + var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName); + + if (slideEvent.isDefaultPrevented()) { + return; + } + + if (!activeElement || !nextElement) { + // Some weirdness is happening, so we bail + return; + } + + this._isSliding = true; + + if (isCycling) { + this.pause(); + } + + this._setActiveIndicatorElement(nextElement); + + var slidEvent = $.Event(Event$2.SLID, { + relatedTarget: nextElement, + direction: eventDirectionName, + from: activeElementIndex, + to: nextElementIndex + }); + + if ($(this._element).hasClass(ClassName$2.SLIDE)) { + $(nextElement).addClass(orderClassName); + Util.reflow(nextElement); + $(activeElement).addClass(directionalClassName); + $(nextElement).addClass(directionalClassName); + var nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10); + + if (nextElementInterval) { + this._config.defaultInterval = this._config.defaultInterval || this._config.interval; + this._config.interval = nextElementInterval; + } else { + this._config.interval = this._config.defaultInterval || this._config.interval; + } + + var transitionDuration = Util.getTransitionDurationFromElement(activeElement); + $(activeElement).one(Util.TRANSITION_END, function () { + $(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName$2.ACTIVE); + $(activeElement).removeClass(ClassName$2.ACTIVE + " " + orderClassName + " " + directionalClassName); + _this4._isSliding = false; + setTimeout(function () { + return $(_this4._element).trigger(slidEvent); + }, 0); + }).emulateTransitionEnd(transitionDuration); + } else { + $(activeElement).removeClass(ClassName$2.ACTIVE); + $(nextElement).addClass(ClassName$2.ACTIVE); + this._isSliding = false; + $(this._element).trigger(slidEvent); + } + + if (isCycling) { + this.cycle(); + } + } // Static + ; + + Carousel._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY$2); + + var _config = _objectSpread2({}, Default, {}, $(this).data()); + + if (typeof config === 'object') { + _config = _objectSpread2({}, _config, {}, config); + } + + var action = typeof config === 'string' ? config : _config.slide; + + if (!data) { + data = new Carousel(this, _config); + $(this).data(DATA_KEY$2, data); + } + + if (typeof config === 'number') { + data.to(config); + } else if (typeof action === 'string') { + if (typeof data[action] === 'undefined') { + throw new TypeError("No method named \"" + action + "\""); + } + + data[action](); + } else if (_config.interval && _config.ride) { + data.pause(); + data.cycle(); + } + }); + }; + + Carousel._dataApiClickHandler = function _dataApiClickHandler(event) { + var selector = Util.getSelectorFromElement(this); + + if (!selector) { + return; + } + + var target = $(selector)[0]; + + if (!target || !$(target).hasClass(ClassName$2.CAROUSEL)) { + return; + } + + var config = _objectSpread2({}, $(target).data(), {}, $(this).data()); + + var slideIndex = this.getAttribute('data-slide-to'); + + if (slideIndex) { + config.interval = false; + } + + Carousel._jQueryInterface.call($(target), config); + + if (slideIndex) { + $(target).data(DATA_KEY$2).to(slideIndex); + } + + event.preventDefault(); + }; + + _createClass(Carousel, null, [{ + key: "VERSION", + get: function get() { + return VERSION$2; + } + }, { + key: "Default", + get: function get() { + return Default; + } + }]); + + return Carousel; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event$2.CLICK_DATA_API, Selector$2.DATA_SLIDE, Carousel._dataApiClickHandler); + $(window).on(Event$2.LOAD_DATA_API, function () { + var carousels = [].slice.call(document.querySelectorAll(Selector$2.DATA_RIDE)); + + for (var i = 0, len = carousels.length; i < len; i++) { + var $carousel = $(carousels[i]); + + Carousel._jQueryInterface.call($carousel, $carousel.data()); + } + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME$2] = Carousel._jQueryInterface; + $.fn[NAME$2].Constructor = Carousel; + + $.fn[NAME$2].noConflict = function () { + $.fn[NAME$2] = JQUERY_NO_CONFLICT$2; + return Carousel._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$3 = 'collapse'; + var VERSION$3 = '4.4.1'; + var DATA_KEY$3 = 'bs.collapse'; + var EVENT_KEY$3 = "." + DATA_KEY$3; + var DATA_API_KEY$3 = '.data-api'; + var JQUERY_NO_CONFLICT$3 = $.fn[NAME$3]; + var Default$1 = { + toggle: true, + parent: '' + }; + var DefaultType$1 = { + toggle: 'boolean', + parent: '(string|element)' + }; + var Event$3 = { + SHOW: "show" + EVENT_KEY$3, + SHOWN: "shown" + EVENT_KEY$3, + HIDE: "hide" + EVENT_KEY$3, + HIDDEN: "hidden" + EVENT_KEY$3, + CLICK_DATA_API: "click" + EVENT_KEY$3 + DATA_API_KEY$3 + }; + var ClassName$3 = { + SHOW: 'show', + COLLAPSE: 'collapse', + COLLAPSING: 'collapsing', + COLLAPSED: 'collapsed' + }; + var Dimension = { + WIDTH: 'width', + HEIGHT: 'height' + }; + var Selector$3 = { + ACTIVES: '.show, .collapsing', + DATA_TOGGLE: '[data-toggle="collapse"]' + }; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + var Collapse = + /*#__PURE__*/ + function () { + function Collapse(element, config) { + this._isTransitioning = false; + this._element = element; + this._config = this._getConfig(config); + this._triggerArray = [].slice.call(document.querySelectorAll("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]"))); + var toggleList = [].slice.call(document.querySelectorAll(Selector$3.DATA_TOGGLE)); + + for (var i = 0, len = toggleList.length; i < len; i++) { + var elem = toggleList[i]; + var selector = Util.getSelectorFromElement(elem); + var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) { + return foundElem === element; + }); + + if (selector !== null && filterElement.length > 0) { + this._selector = selector; + + this._triggerArray.push(elem); + } + } + + this._parent = this._config.parent ? this._getParent() : null; + + if (!this._config.parent) { + this._addAriaAndCollapsedClass(this._element, this._triggerArray); + } + + if (this._config.toggle) { + this.toggle(); + } + } // Getters + + + var _proto = Collapse.prototype; + + // Public + _proto.toggle = function toggle() { + if ($(this._element).hasClass(ClassName$3.SHOW)) { + this.hide(); + } else { + this.show(); + } + }; + + _proto.show = function show() { + var _this = this; + + if (this._isTransitioning || $(this._element).hasClass(ClassName$3.SHOW)) { + return; + } + + var actives; + var activesData; + + if (this._parent) { + actives = [].slice.call(this._parent.querySelectorAll(Selector$3.ACTIVES)).filter(function (elem) { + if (typeof _this._config.parent === 'string') { + return elem.getAttribute('data-parent') === _this._config.parent; + } + + return elem.classList.contains(ClassName$3.COLLAPSE); + }); + + if (actives.length === 0) { + actives = null; + } + } + + if (actives) { + activesData = $(actives).not(this._selector).data(DATA_KEY$3); + + if (activesData && activesData._isTransitioning) { + return; + } + } + + var startEvent = $.Event(Event$3.SHOW); + $(this._element).trigger(startEvent); + + if (startEvent.isDefaultPrevented()) { + return; + } + + if (actives) { + Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide'); + + if (!activesData) { + $(actives).data(DATA_KEY$3, null); + } + } + + var dimension = this._getDimension(); + + $(this._element).removeClass(ClassName$3.COLLAPSE).addClass(ClassName$3.COLLAPSING); + this._element.style[dimension] = 0; + + if (this._triggerArray.length) { + $(this._triggerArray).removeClass(ClassName$3.COLLAPSED).attr('aria-expanded', true); + } + + this.setTransitioning(true); + + var complete = function complete() { + $(_this._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).addClass(ClassName$3.SHOW); + _this._element.style[dimension] = ''; + + _this.setTransitioning(false); + + $(_this._element).trigger(Event$3.SHOWN); + }; + + var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); + var scrollSize = "scroll" + capitalizedDimension; + var transitionDuration = Util.getTransitionDurationFromElement(this._element); + $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); + this._element.style[dimension] = this._element[scrollSize] + "px"; + }; + + _proto.hide = function hide() { + var _this2 = this; + + if (this._isTransitioning || !$(this._element).hasClass(ClassName$3.SHOW)) { + return; + } + + var startEvent = $.Event(Event$3.HIDE); + $(this._element).trigger(startEvent); + + if (startEvent.isDefaultPrevented()) { + return; + } + + var dimension = this._getDimension(); + + this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px"; + Util.reflow(this._element); + $(this._element).addClass(ClassName$3.COLLAPSING).removeClass(ClassName$3.COLLAPSE).removeClass(ClassName$3.SHOW); + var triggerArrayLength = this._triggerArray.length; + + if (triggerArrayLength > 0) { + for (var i = 0; i < triggerArrayLength; i++) { + var trigger = this._triggerArray[i]; + var selector = Util.getSelectorFromElement(trigger); + + if (selector !== null) { + var $elem = $([].slice.call(document.querySelectorAll(selector))); + + if (!$elem.hasClass(ClassName$3.SHOW)) { + $(trigger).addClass(ClassName$3.COLLAPSED).attr('aria-expanded', false); + } + } + } + } + + this.setTransitioning(true); + + var complete = function complete() { + _this2.setTransitioning(false); + + $(_this2._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).trigger(Event$3.HIDDEN); + }; + + this._element.style[dimension] = ''; + var transitionDuration = Util.getTransitionDurationFromElement(this._element); + $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); + }; + + _proto.setTransitioning = function setTransitioning(isTransitioning) { + this._isTransitioning = isTransitioning; + }; + + _proto.dispose = function dispose() { + $.removeData(this._element, DATA_KEY$3); + this._config = null; + this._parent = null; + this._element = null; + this._triggerArray = null; + this._isTransitioning = null; + } // Private + ; + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread2({}, Default$1, {}, config); + config.toggle = Boolean(config.toggle); // Coerce string values + + Util.typeCheckConfig(NAME$3, config, DefaultType$1); + return config; + }; + + _proto._getDimension = function _getDimension() { + var hasWidth = $(this._element).hasClass(Dimension.WIDTH); + return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT; + }; + + _proto._getParent = function _getParent() { + var _this3 = this; + + var parent; + + if (Util.isElement(this._config.parent)) { + parent = this._config.parent; // It's a jQuery object + + if (typeof this._config.parent.jquery !== 'undefined') { + parent = this._config.parent[0]; + } + } else { + parent = document.querySelector(this._config.parent); + } + + var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]"; + var children = [].slice.call(parent.querySelectorAll(selector)); + $(children).each(function (i, element) { + _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]); + }); + return parent; + }; + + _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) { + var isOpen = $(element).hasClass(ClassName$3.SHOW); + + if (triggerArray.length) { + $(triggerArray).toggleClass(ClassName$3.COLLAPSED, !isOpen).attr('aria-expanded', isOpen); + } + } // Static + ; + + Collapse._getTargetFromElement = function _getTargetFromElement(element) { + var selector = Util.getSelectorFromElement(element); + return selector ? document.querySelector(selector) : null; + }; + + Collapse._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DATA_KEY$3); + + var _config = _objectSpread2({}, Default$1, {}, $this.data(), {}, typeof config === 'object' && config ? config : {}); + + if (!data && _config.toggle && /show|hide/.test(config)) { + _config.toggle = false; + } + + if (!data) { + data = new Collapse(this, _config); + $this.data(DATA_KEY$3, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + _createClass(Collapse, null, [{ + key: "VERSION", + get: function get() { + return VERSION$3; + } + }, { + key: "Default", + get: function get() { + return Default$1; + } + }]); + + return Collapse; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event$3.CLICK_DATA_API, Selector$3.DATA_TOGGLE, function (event) { + // preventDefault only for elements (which change the URL) not inside the collapsible element + if (event.currentTarget.tagName === 'A') { + event.preventDefault(); + } + + var $trigger = $(this); + var selector = Util.getSelectorFromElement(this); + var selectors = [].slice.call(document.querySelectorAll(selector)); + $(selectors).each(function () { + var $target = $(this); + var data = $target.data(DATA_KEY$3); + var config = data ? 'toggle' : $trigger.data(); + + Collapse._jQueryInterface.call($target, config); + }); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME$3] = Collapse._jQueryInterface; + $.fn[NAME$3].Constructor = Collapse; + + $.fn[NAME$3].noConflict = function () { + $.fn[NAME$3] = JQUERY_NO_CONFLICT$3; + return Collapse._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$4 = 'dropdown'; + var VERSION$4 = '4.4.1'; + var DATA_KEY$4 = 'bs.dropdown'; + var EVENT_KEY$4 = "." + DATA_KEY$4; + var DATA_API_KEY$4 = '.data-api'; + var JQUERY_NO_CONFLICT$4 = $.fn[NAME$4]; + var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key + + var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key + + var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key + + var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key + + var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key + + var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse) + + var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE); + var Event$4 = { + HIDE: "hide" + EVENT_KEY$4, + HIDDEN: "hidden" + EVENT_KEY$4, + SHOW: "show" + EVENT_KEY$4, + SHOWN: "shown" + EVENT_KEY$4, + CLICK: "click" + EVENT_KEY$4, + CLICK_DATA_API: "click" + EVENT_KEY$4 + DATA_API_KEY$4, + KEYDOWN_DATA_API: "keydown" + EVENT_KEY$4 + DATA_API_KEY$4, + KEYUP_DATA_API: "keyup" + EVENT_KEY$4 + DATA_API_KEY$4 + }; + var ClassName$4 = { + DISABLED: 'disabled', + SHOW: 'show', + DROPUP: 'dropup', + DROPRIGHT: 'dropright', + DROPLEFT: 'dropleft', + MENURIGHT: 'dropdown-menu-right', + MENULEFT: 'dropdown-menu-left', + POSITION_STATIC: 'position-static' + }; + var Selector$4 = { + DATA_TOGGLE: '[data-toggle="dropdown"]', + FORM_CHILD: '.dropdown form', + MENU: '.dropdown-menu', + NAVBAR_NAV: '.navbar-nav', + VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' + }; + var AttachmentMap = { + TOP: 'top-start', + TOPEND: 'top-end', + BOTTOM: 'bottom-start', + BOTTOMEND: 'bottom-end', + RIGHT: 'right-start', + RIGHTEND: 'right-end', + LEFT: 'left-start', + LEFTEND: 'left-end' + }; + var Default$2 = { + offset: 0, + flip: true, + boundary: 'scrollParent', + reference: 'toggle', + display: 'dynamic', + popperConfig: null + }; + var DefaultType$2 = { + offset: '(number|string|function)', + flip: 'boolean', + boundary: '(string|element)', + reference: '(string|element)', + display: 'string', + popperConfig: '(null|object)' + }; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + var Dropdown = + /*#__PURE__*/ + function () { + function Dropdown(element, config) { + this._element = element; + this._popper = null; + this._config = this._getConfig(config); + this._menu = this._getMenuElement(); + this._inNavbar = this._detectNavbar(); + + this._addEventListeners(); + } // Getters + + + var _proto = Dropdown.prototype; + + // Public + _proto.toggle = function toggle() { + if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED)) { + return; + } + + var isActive = $(this._menu).hasClass(ClassName$4.SHOW); + + Dropdown._clearMenus(); + + if (isActive) { + return; + } + + this.show(true); + }; + + _proto.show = function show(usePopper) { + if (usePopper === void 0) { + usePopper = false; + } + + if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || $(this._menu).hasClass(ClassName$4.SHOW)) { + return; + } + + var relatedTarget = { + relatedTarget: this._element + }; + var showEvent = $.Event(Event$4.SHOW, relatedTarget); + + var parent = Dropdown._getParentFromElement(this._element); + + $(parent).trigger(showEvent); + + if (showEvent.isDefaultPrevented()) { + return; + } // Disable totally Popper.js for Dropdown in Navbar + + + if (!this._inNavbar && usePopper) { + /** + * Check for Popper dependency + * Popper - https://popper.js.org + */ + if (typeof Popper === 'undefined') { + throw new TypeError('Bootstrap\'s dropdowns require Popper.js (https://popper.js.org/)'); + } + + var referenceElement = this._element; + + if (this._config.reference === 'parent') { + referenceElement = parent; + } else if (Util.isElement(this._config.reference)) { + referenceElement = this._config.reference; // Check if it's jQuery element + + if (typeof this._config.reference.jquery !== 'undefined') { + referenceElement = this._config.reference[0]; + } + } // If boundary is not `scrollParent`, then set position to `static` + // to allow the menu to "escape" the scroll parent's boundaries + // https://github.com/twbs/bootstrap/issues/24251 + + + if (this._config.boundary !== 'scrollParent') { + $(parent).addClass(ClassName$4.POSITION_STATIC); + } + + this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig()); + } // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + + + if ('ontouchstart' in document.documentElement && $(parent).closest(Selector$4.NAVBAR_NAV).length === 0) { + $(document.body).children().on('mouseover', null, $.noop); + } + + this._element.focus(); + + this._element.setAttribute('aria-expanded', true); + + $(this._menu).toggleClass(ClassName$4.SHOW); + $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget)); + }; + + _proto.hide = function hide() { + if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || !$(this._menu).hasClass(ClassName$4.SHOW)) { + return; + } + + var relatedTarget = { + relatedTarget: this._element + }; + var hideEvent = $.Event(Event$4.HIDE, relatedTarget); + + var parent = Dropdown._getParentFromElement(this._element); + + $(parent).trigger(hideEvent); + + if (hideEvent.isDefaultPrevented()) { + return; + } + + if (this._popper) { + this._popper.destroy(); + } + + $(this._menu).toggleClass(ClassName$4.SHOW); + $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget)); + }; + + _proto.dispose = function dispose() { + $.removeData(this._element, DATA_KEY$4); + $(this._element).off(EVENT_KEY$4); + this._element = null; + this._menu = null; + + if (this._popper !== null) { + this._popper.destroy(); + + this._popper = null; + } + }; + + _proto.update = function update() { + this._inNavbar = this._detectNavbar(); + + if (this._popper !== null) { + this._popper.scheduleUpdate(); + } + } // Private + ; + + _proto._addEventListeners = function _addEventListeners() { + var _this = this; + + $(this._element).on(Event$4.CLICK, function (event) { + event.preventDefault(); + event.stopPropagation(); + + _this.toggle(); + }); + }; + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread2({}, this.constructor.Default, {}, $(this._element).data(), {}, config); + Util.typeCheckConfig(NAME$4, config, this.constructor.DefaultType); + return config; + }; + + _proto._getMenuElement = function _getMenuElement() { + if (!this._menu) { + var parent = Dropdown._getParentFromElement(this._element); + + if (parent) { + this._menu = parent.querySelector(Selector$4.MENU); + } + } + + return this._menu; + }; + + _proto._getPlacement = function _getPlacement() { + var $parentDropdown = $(this._element.parentNode); + var placement = AttachmentMap.BOTTOM; // Handle dropup + + if ($parentDropdown.hasClass(ClassName$4.DROPUP)) { + placement = AttachmentMap.TOP; + + if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) { + placement = AttachmentMap.TOPEND; + } + } else if ($parentDropdown.hasClass(ClassName$4.DROPRIGHT)) { + placement = AttachmentMap.RIGHT; + } else if ($parentDropdown.hasClass(ClassName$4.DROPLEFT)) { + placement = AttachmentMap.LEFT; + } else if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) { + placement = AttachmentMap.BOTTOMEND; + } + + return placement; + }; + + _proto._detectNavbar = function _detectNavbar() { + return $(this._element).closest('.navbar').length > 0; + }; + + _proto._getOffset = function _getOffset() { + var _this2 = this; + + var offset = {}; + + if (typeof this._config.offset === 'function') { + offset.fn = function (data) { + data.offsets = _objectSpread2({}, data.offsets, {}, _this2._config.offset(data.offsets, _this2._element) || {}); + return data; + }; + } else { + offset.offset = this._config.offset; + } + + return offset; + }; + + _proto._getPopperConfig = function _getPopperConfig() { + var popperConfig = { + placement: this._getPlacement(), + modifiers: { + offset: this._getOffset(), + flip: { + enabled: this._config.flip + }, + preventOverflow: { + boundariesElement: this._config.boundary + } + } + }; // Disable Popper.js if we have a static display + + if (this._config.display === 'static') { + popperConfig.modifiers.applyStyle = { + enabled: false + }; + } + + return _objectSpread2({}, popperConfig, {}, this._config.popperConfig); + } // Static + ; + + Dropdown._jQueryInterface = function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY$4); + + var _config = typeof config === 'object' ? config : null; + + if (!data) { + data = new Dropdown(this, _config); + $(this).data(DATA_KEY$4, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](); + } + }); + }; + + Dropdown._clearMenus = function _clearMenus(event) { + if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) { + return; + } + + var toggles = [].slice.call(document.querySelectorAll(Selector$4.DATA_TOGGLE)); + + for (var i = 0, len = toggles.length; i < len; i++) { + var parent = Dropdown._getParentFromElement(toggles[i]); + + var context = $(toggles[i]).data(DATA_KEY$4); + var relatedTarget = { + relatedTarget: toggles[i] + }; + + if (event && event.type === 'click') { + relatedTarget.clickEvent = event; + } + + if (!context) { + continue; + } + + var dropdownMenu = context._menu; + + if (!$(parent).hasClass(ClassName$4.SHOW)) { + continue; + } + + if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) { + continue; + } + + var hideEvent = $.Event(Event$4.HIDE, relatedTarget); + $(parent).trigger(hideEvent); + + if (hideEvent.isDefaultPrevented()) { + continue; + } // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + + + if ('ontouchstart' in document.documentElement) { + $(document.body).children().off('mouseover', null, $.noop); + } + + toggles[i].setAttribute('aria-expanded', 'false'); + + if (context._popper) { + context._popper.destroy(); + } + + $(dropdownMenu).removeClass(ClassName$4.SHOW); + $(parent).removeClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget)); + } + }; + + Dropdown._getParentFromElement = function _getParentFromElement(element) { + var parent; + var selector = Util.getSelectorFromElement(element); + + if (selector) { + parent = document.querySelector(selector); + } + + return parent || element.parentNode; + } // eslint-disable-next-line complexity + ; + + Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) { + // If not input/textarea: + // - And not a key in REGEXP_KEYDOWN => not a dropdown command + // If input/textarea: + // - If space key => not a dropdown command + // - If key is other than escape + // - If key is not up or down => not a dropdown command + // - If trigger inside the menu => not a dropdown command + if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $(event.target).closest(Selector$4.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + + if (this.disabled || $(this).hasClass(ClassName$4.DISABLED)) { + return; + } + + var parent = Dropdown._getParentFromElement(this); + + var isActive = $(parent).hasClass(ClassName$4.SHOW); + + if (!isActive && event.which === ESCAPE_KEYCODE) { + return; + } + + if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) { + if (event.which === ESCAPE_KEYCODE) { + var toggle = parent.querySelector(Selector$4.DATA_TOGGLE); + $(toggle).trigger('focus'); + } + + $(this).trigger('click'); + return; + } + + var items = [].slice.call(parent.querySelectorAll(Selector$4.VISIBLE_ITEMS)).filter(function (item) { + return $(item).is(':visible'); + }); + + if (items.length === 0) { + return; + } + + var index = items.indexOf(event.target); + + if (event.which === ARROW_UP_KEYCODE && index > 0) { + // Up + index--; + } + + if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { + // Down + index++; + } + + if (index < 0) { + index = 0; + } + + items[index].focus(); + }; + + _createClass(Dropdown, null, [{ + key: "VERSION", + get: function get() { + return VERSION$4; + } + }, { + key: "Default", + get: function get() { + return Default$2; + } + }, { + key: "DefaultType", + get: function get() { + return DefaultType$2; + } + }]); + + return Dropdown; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event$4.KEYDOWN_DATA_API, Selector$4.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event$4.KEYDOWN_DATA_API, Selector$4.MENU, Dropdown._dataApiKeydownHandler).on(Event$4.CLICK_DATA_API + " " + Event$4.KEYUP_DATA_API, Dropdown._clearMenus).on(Event$4.CLICK_DATA_API, Selector$4.DATA_TOGGLE, function (event) { + event.preventDefault(); + event.stopPropagation(); + + Dropdown._jQueryInterface.call($(this), 'toggle'); + }).on(Event$4.CLICK_DATA_API, Selector$4.FORM_CHILD, function (e) { + e.stopPropagation(); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME$4] = Dropdown._jQueryInterface; + $.fn[NAME$4].Constructor = Dropdown; + + $.fn[NAME$4].noConflict = function () { + $.fn[NAME$4] = JQUERY_NO_CONFLICT$4; + return Dropdown._jQueryInterface; + }; + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$5 = 'modal'; + var VERSION$5 = '4.4.1'; + var DATA_KEY$5 = 'bs.modal'; + var EVENT_KEY$5 = "." + DATA_KEY$5; + var DATA_API_KEY$5 = '.data-api'; + var JQUERY_NO_CONFLICT$5 = $.fn[NAME$5]; + var ESCAPE_KEYCODE$1 = 27; // KeyboardEvent.which value for Escape (Esc) key + + var Default$3 = { + backdrop: true, + keyboard: true, + focus: true, + show: true + }; + var DefaultType$3 = { + backdrop: '(boolean|string)', + keyboard: 'boolean', + focus: 'boolean', + show: 'boolean' + }; + var Event$5 = { + HIDE: "hide" + EVENT_KEY$5, + HIDE_PREVENTED: "hidePrevented" + EVENT_KEY$5, + HIDDEN: "hidden" + EVENT_KEY$5, + SHOW: "show" + EVENT_KEY$5, + SHOWN: "shown" + EVENT_KEY$5, + FOCUSIN: "focusin" + EVENT_KEY$5, + RESIZE: "resize" + EVENT_KEY$5, + CLICK_DISMISS: "click.dismiss" + EVENT_KEY$5, + KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY$5, + MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY$5, + MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY$5, + CLICK_DATA_API: "click" + EVENT_KEY$5 + DATA_API_KEY$5 + }; + var ClassName$5 = { + SCROLLABLE: 'modal-dialog-scrollable', + SCROLLBAR_MEASURER: 'modal-scrollbar-measure', + BACKDROP: 'modal-backdrop', + OPEN: 'modal-open', + FADE: 'fade', + SHOW: 'show', + STATIC: 'modal-static' + }; + var Selector$5 = { + DIALOG: '.modal-dialog', + MODAL_BODY: '.modal-body', + DATA_TOGGLE: '[data-toggle="modal"]', + DATA_DISMISS: '[data-dismiss="modal"]', + FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', + STICKY_CONTENT: '.sticky-top' + }; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + var Modal = + /*#__PURE__*/ + function () { + function Modal(element, config) { + this._config = this._getConfig(config); + this._element = element; + this._dialog = element.querySelector(Selector$5.DIALOG); + this._backdrop = null; + this._isShown = false; + this._isBodyOverflowing = false; + this._ignoreBackdropClick = false; + this._isTransitioning = false; + this._scrollbarWidth = 0; + } // Getters + + + var _proto = Modal.prototype; + + // Public + _proto.toggle = function toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + }; + + _proto.show = function show(relatedTarget) { + var _this = this; + + if (this._isShown || this._isTransitioning) { + return; + } + + if ($(this._element).hasClass(ClassName$5.FADE)) { + this._isTransitioning = true; + } + + var showEvent = $.Event(Event$5.SHOW, { + relatedTarget: relatedTarget + }); + $(this._element).trigger(showEvent); + + if (this._isShown || showEvent.isDefaultPrevented()) { + return; + } + + this._isShown = true; + + this._checkScrollbar(); + + this._setScrollbar(); + + this._adjustDialog(); + + this._setEscapeEvent(); + + this._setResizeEvent(); + + $(this._element).on(Event$5.CLICK_DISMISS, Selector$5.DATA_DISMISS, function (event) { + return _this.hide(event); + }); + $(this._dialog).on(Event$5.MOUSEDOWN_DISMISS, function () { + $(_this._element).one(Event$5.MOUSEUP_DISMISS, function (event) { + if ($(event.target).is(_this._element)) { + _this._ignoreBackdropClick = true; + } + }); + }); + + this._showBackdrop(function () { + return _this._showElement(relatedTarget); + }); + }; + + _proto.hide = function hide(event) { + var _this2 = this; + + if (event) { + event.preventDefault(); + } + + if (!this._isShown || this._isTransitioning) { + return; + } + + var hideEvent = $.Event(Event$5.HIDE); + $(this._element).trigger(hideEvent); + + if (!this._isShown || hideEvent.isDefaultPrevented()) { + return; + } + + this._isShown = false; + var transition = $(this._element).hasClass(ClassName$5.FADE); + + if (transition) { + this._isTransitioning = true; + } + + this._setEscapeEvent(); + + this._setResizeEvent(); + + $(document).off(Event$5.FOCUSIN); + $(this._element).removeClass(ClassName$5.SHOW); + $(this._element).off(Event$5.CLICK_DISMISS); + $(this._dialog).off(Event$5.MOUSEDOWN_DISMISS); + + if (transition) { + var transitionDuration = Util.getTransitionDurationFromElement(this._element); + $(this._element).one(Util.TRANSITION_END, function (event) { + return _this2._hideModal(event); + }).emulateTransitionEnd(transitionDuration); + } else { + this._hideModal(); + } + }; + + _proto.dispose = function dispose() { + [window, this._element, this._dialog].forEach(function (htmlElement) { + return $(htmlElement).off(EVENT_KEY$5); + }); + /** + * `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API` + * Do not move `document` in `htmlElements` array + * It will remove `Event.CLICK_DATA_API` event that should remain + */ + + $(document).off(Event$5.FOCUSIN); + $.removeData(this._element, DATA_KEY$5); + this._config = null; + this._element = null; + this._dialog = null; + this._backdrop = null; + this._isShown = null; + this._isBodyOverflowing = null; + this._ignoreBackdropClick = null; + this._isTransitioning = null; + this._scrollbarWidth = null; + }; + + _proto.handleUpdate = function handleUpdate() { + this._adjustDialog(); + } // Private + ; + + _proto._getConfig = function _getConfig(config) { + config = _objectSpread2({}, Default$3, {}, config); + Util.typeCheckConfig(NAME$5, config, DefaultType$3); + return config; + }; + + _proto._triggerBackdropTransition = function _triggerBackdropTransition() { + var _this3 = this; + + if (this._config.backdrop === 'static') { + var hideEventPrevented = $.Event(Event$5.HIDE_PREVENTED); + $(this._element).trigger(hideEventPrevented); + + if (hideEventPrevented.defaultPrevented) { + return; + } + + this._element.classList.add(ClassName$5.STATIC); + + var modalTransitionDuration = Util.getTransitionDurationFromElement(this._element); + $(this._element).one(Util.TRANSITION_END, function () { + _this3._element.classList.remove(ClassName$5.STATIC); + }).emulateTransitionEnd(modalTransitionDuration); + + this._element.focus(); + } else { + this.hide(); + } + }; + + _proto._showElement = function _showElement(relatedTarget) { + var _this4 = this; + + var transition = $(this._element).hasClass(ClassName$5.FADE); + var modalBody = this._dialog ? this._dialog.querySelector(Selector$5.MODAL_BODY) : null; + + if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { + // Don't move modal's DOM position + document.body.appendChild(this._element); + } + + this._element.style.display = 'block'; + + this._element.removeAttribute('aria-hidden'); + + this._element.setAttribute('aria-modal', true); + + if ($(this._dialog).hasClass(ClassName$5.SCROLLABLE) && modalBody) { + modalBody.scrollTop = 0; + } else { + this._element.scrollTop = 0; + } + + if (transition) { + Util.reflow(this._element); + } + + $(this._element).addClass(ClassName$5.SHOW); + + if (this._config.focus) { + this._enforceFocus(); + } + + var shownEvent = $.Event(Event$5.SHOWN, { + relatedTarget: relatedTarget + }); + + var transitionComplete = function transitionComplete() { + if (_this4._config.focus) { + _this4._element.focus(); + } + + _this4._isTransitioning = false; + $(_this4._element).trigger(shownEvent); + }; + + if (transition) { + var transitionDuration = Util.getTransitionDurationFromElement(this._dialog); + $(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration); + } else { + transitionComplete(); + } + }; + + _proto._enforceFocus = function _enforceFocus() { + var _this5 = this; + + $(document).off(Event$5.FOCUSIN) // Guard against infinite focus loop + .on(Event$5.FOCUSIN, function (event) { + if (document !== event.target && _this5._element !== event.target && $(_this5._element).has(event.target).length === 0) { + _this5._element.focus(); + } + }); + }; + + _proto._setEscapeEvent = function _setEscapeEvent() { + var _this6 = this; + + if (this._isShown && this._config.keyboard) { + $(this._element).on(Event$5.KEYDOWN_DISMISS, function (event) { + if (event.which === ESCAPE_KEYCODE$1) { + _this6._triggerBackdropTransition(); + } + }); + } else if (!this._isShown) { + $(this._element).off(Event$5.KEYDOWN_DISMISS); + } + }; + + _proto._setResizeEvent = function _setResizeEvent() { + var _this7 = this; + + if (this._isShown) { + $(window).on(Event$5.RESIZE, function (event) { + return _this7.handleUpdate(event); + }); + } else { + $(window).off(Event$5.RESIZE); + } + }; + + _proto._hideModal = function _hideModal() { + var _this8 = this; + + this._element.style.display = 'none'; + + this._element.setAttribute('aria-hidden', true); + + this._element.removeAttribute('aria-modal'); + + this._isTransitioning = false; + + this._showBackdrop(function () { + $(document.body).removeClass(ClassName$5.OPEN); + + _this8._resetAdjustments(); + + _this8._resetScrollbar(); + + $(_this8._element).trigger(Event$5.HIDDEN); + }); + }; + + _proto._removeBackdrop = function _removeBackdrop() { + if (this._backdrop) { + $(this._backdrop).remove(); + this._backdrop = null; + } + }; + + _proto._showBackdrop = function _showBackdrop(callback) { + var _this9 = this; + + var animate = $(this._element).hasClass(ClassName$5.FADE) ? ClassName$5.FADE : ''; + + if (this._isShown && this._config.backdrop) { + this._backdrop = document.createElement('div'); + this._backdrop.className = ClassName$5.BACKDROP; + + if (animate) { + this._backdrop.classList.add(animate); + } + + $(this._backdrop).appendTo(document.body); + $(this._element).on(Event$5.CLICK_DISMISS, function (event) { + if (_this9._ignoreBackdropClick) { + _this9._ignoreBackdropClick = false; + return; + } + + if (event.target !== event.currentTarget) { + return; + } + + _this9._triggerBackdropTransition(); + }); + + if (animate) { + Util.reflow(this._backdrop); + } + + $(this._backdrop).addClass(ClassName$5.SHOW); + + if (!callback) { + return; + } + + if (!animate) { + callback(); + return; + } + + var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop); + $(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration); + } else if (!this._isShown && this._backdrop) { + $(this._backdrop).removeClass(ClassName$5.SHOW); + + var callbackRemove = function callbackRemove() { + _this9._removeBackdrop(); + + if (callback) { + callback(); + } + }; + + if ($(this._element).hasClass(ClassName$5.FADE)) { + var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop); + + $(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration); + } else { + callbackRemove(); + } + } else if (callback) { + callback(); + } + } // ---------------------------------------------------------------------- + // the following methods are used to handle overflowing modals + // todo (fat): these should probably be refactored out of modal.js + // ---------------------------------------------------------------------- + ; + + _proto._adjustDialog = function _adjustDialog() { + var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; + + if (!this._isBodyOverflowing && isModalOverflowing) { + this._element.style.paddingLeft = this._scrollbarWidth + "px"; + } + + if (this._isBodyOverflowing && !isModalOverflowing) { + this._element.style.paddingRight = this._scrollbarWidth + "px"; + } + }; + + _proto._resetAdjustments = function _resetAdjustments() { + this._element.style.paddingLeft = ''; + this._element.style.paddingRight = ''; + }; + + _proto._checkScrollbar = function _checkScrollbar() { + var rect = document.body.getBoundingClientRect(); + this._isBodyOverflowing = rect.left + rect.right < window.innerWidth; + this._scrollbarWidth = this._getScrollbarWidth(); + }; + + _proto._setScrollbar = function _setScrollbar() { + var _this10 = this; + + if (this._isBodyOverflowing) { + // Note: DOMNode.style.paddingRight returns the actual value or '' if not set + // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set + var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT)); + var stickyContent = [].slice.call(document.querySelectorAll(Selector$5.STICKY_CONTENT)); // Adjust fixed content padding + + $(fixedContent).each(function (index, element) { + var actualPadding = element.style.paddingRight; + var calculatedPadding = $(element).css('padding-right'); + $(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this10._scrollbarWidth + "px"); + }); // Adjust sticky content margin + + $(stickyContent).each(function (index, element) { + var actualMargin = element.style.marginRight; + var calculatedMargin = $(element).css('margin-right'); + $(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this10._scrollbarWidth + "px"); + }); // Adjust body padding + + var actualPadding = document.body.style.paddingRight; + var calculatedPadding = $(document.body).css('padding-right'); + $(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px"); + } + + $(document.body).addClass(ClassName$5.OPEN); + }; + + _proto._resetScrollbar = function _resetScrollbar() { + // Restore fixed content padding + var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT)); + $(fixedContent).each(function (index, element) { + var padding = $(element).data('padding-right'); + $(element).removeData('padding-right'); + element.style.paddingRight = padding ? padding : ''; + }); // Restore sticky content + + var elements = [].slice.call(document.querySelectorAll("" + Selector$5.STICKY_CONTENT)); + $(elements).each(function (index, element) { + var margin = $(element).data('margin-right'); + + if (typeof margin !== 'undefined') { + $(element).css('margin-right', margin).removeData('margin-right'); + } + }); // Restore body padding + + var padding = $(document.body).data('padding-right'); + $(document.body).removeData('padding-right'); + document.body.style.paddingRight = padding ? padding : ''; + }; + + _proto._getScrollbarWidth = function _getScrollbarWidth() { + // thx d.walsh + var scrollDiv = document.createElement('div'); + scrollDiv.className = ClassName$5.SCROLLBAR_MEASURER; + document.body.appendChild(scrollDiv); + var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth; + document.body.removeChild(scrollDiv); + return scrollbarWidth; + } // Static + ; + + Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) { + return this.each(function () { + var data = $(this).data(DATA_KEY$5); + + var _config = _objectSpread2({}, Default$3, {}, $(this).data(), {}, typeof config === 'object' && config ? config : {}); + + if (!data) { + data = new Modal(this, _config); + $(this).data(DATA_KEY$5, data); + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError("No method named \"" + config + "\""); + } + + data[config](relatedTarget); + } else if (_config.show) { + data.show(relatedTarget); + } + }); + }; + + _createClass(Modal, null, [{ + key: "VERSION", + get: function get() { + return VERSION$5; + } + }, { + key: "Default", + get: function get() { + return Default$3; + } + }]); + + return Modal; + }(); + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + $(document).on(Event$5.CLICK_DATA_API, Selector$5.DATA_TOGGLE, function (event) { + var _this11 = this; + + var target; + var selector = Util.getSelectorFromElement(this); + + if (selector) { + target = document.querySelector(selector); + } + + var config = $(target).data(DATA_KEY$5) ? 'toggle' : _objectSpread2({}, $(target).data(), {}, $(this).data()); + + if (this.tagName === 'A' || this.tagName === 'AREA') { + event.preventDefault(); + } + + var $target = $(target).one(Event$5.SHOW, function (showEvent) { + if (showEvent.isDefaultPrevented()) { + // Only register focus restorer if modal will actually get shown + return; + } + + $target.one(Event$5.HIDDEN, function () { + if ($(_this11).is(':visible')) { + _this11.focus(); + } + }); + }); + + Modal._jQueryInterface.call($(target), config, this); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + $.fn[NAME$5] = Modal._jQueryInterface; + $.fn[NAME$5].Constructor = Modal; + + $.fn[NAME$5].noConflict = function () { + $.fn[NAME$5] = JQUERY_NO_CONFLICT$5; + return Modal._jQueryInterface; + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v4.4.1): tools/sanitizer.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + var uriAttrs = ['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']; + var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i; + var DefaultWhitelist = { + // Global attributes allowed on any supplied element below. + '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], + a: ['target', 'href', 'title', 'rel'], + area: [], + b: [], + br: [], + col: [], + code: [], + div: [], + em: [], + hr: [], + h1: [], + h2: [], + h3: [], + h4: [], + h5: [], + h6: [], + i: [], + img: ['src', 'alt', 'title', 'width', 'height'], + li: [], + ol: [], + p: [], + pre: [], + s: [], + small: [], + span: [], + sub: [], + sup: [], + strong: [], + u: [], + ul: [] + }; + /** + * A pattern that recognizes a commonly useful subset of URLs that are safe. + * + * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts + */ + + var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi; + /** + * A pattern that matches safe data URLs. Only matches image, video and audio types. + * + * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts + */ + + var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i; + + function allowedAttribute(attr, allowedAttributeList) { + var attrName = attr.nodeName.toLowerCase(); + + if (allowedAttributeList.indexOf(attrName) !== -1) { + if (uriAttrs.indexOf(attrName) !== -1) { + return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN)); + } + + return true; + } + + var regExp = allowedAttributeList.filter(function (attrRegex) { + return attrRegex instanceof RegExp; + }); // Check if a regular expression validates the attribute. + + for (var i = 0, l = regExp.length; i < l; i++) { + if (attrName.match(regExp[i])) { + return true; + } + } + + return false; + } + + function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) { + if (unsafeHtml.length === 0) { + return unsafeHtml; + } + + if (sanitizeFn && typeof sanitizeFn === 'function') { + return sanitizeFn(unsafeHtml); + } + + var domParser = new window.DOMParser(); + var createdDocument = domParser.parseFromString(unsafeHtml, 'text/html'); + var whitelistKeys = Object.keys(whiteList); + var elements = [].slice.call(createdDocument.body.querySelectorAll('*')); + + var _loop = function _loop(i, len) { + var el = elements[i]; + var elName = el.nodeName.toLowerCase(); + + if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) { + el.parentNode.removeChild(el); + return "continue"; + } + + var attributeList = [].slice.call(el.attributes); + var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []); + attributeList.forEach(function (attr) { + if (!allowedAttribute(attr, whitelistedAttributes)) { + el.removeAttribute(attr.nodeName); + } + }); + }; + + for (var i = 0, len = elements.length; i < len; i++) { + var _ret = _loop(i); + + if (_ret === "continue") continue; + } + + return createdDocument.body.innerHTML; + } + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME$6 = 'tooltip'; + var VERSION$6 = '4.4.1'; + var DATA_KEY$6 = 'bs.tooltip'; + var EVENT_KEY$6 = "." + DATA_KEY$6; + var JQUERY_NO_CONFLICT$6 = $.fn[NAME$6]; + var CLASS_PREFIX = 'bs-tooltip'; + var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g'); + var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']; + var DefaultType$4 = { + animation: 'boolean', + template: 'string', + title: '(string|element|function)', + trigger: 'string', + delay: '(number|object)', + html: 'boolean', + selector: '(string|boolean)', + placement: '(string|function)', + offset: '(number|string|function)', + container: '(string|element|boolean)', + fallbackPlacement: '(string|array)', + boundary: '(string|element)', + sanitize: 'boolean', + sanitizeFn: '(null|function)', + whiteList: 'object', + popperConfig: '(null|object)' + }; + var AttachmentMap$1 = { + AUTO: 'auto', + TOP: 'top', + RIGHT: 'right', + BOTTOM: 'bottom', + LEFT: 'left' + }; + var Default$4 = { + animation: true, + template: '