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 .= '
+
+
\";
+ } 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']}】新增成功!
54$9XXWD1 @VEuo5e5#35_nR?
z*zV>eH!GcQ+6g`lQM4~#Q4jw-H{2QQpIv`n>HnmR>Z~JU^m`9)1_uCOzJKGdT4-x*
zU|?rU_xr-|t0<<$E=Q!&BL Cw{1H3cX}0N%kQZ1*lhazLTNF^4LLS9kl}pC-GVUT_D($Wi!$dnC
z&Ga0&ql)E-l6y?C%}_s$Qs3-Fiz*ZZDT|P1L<`^srs`W=`xfX#a71;x4
zZk0xQI`4%@TM2%~3I$~QQ<6>kf>^grw@7gN-| WwxMNzwLbsH`El~Luf5H%Na{|-|#c9mUAb?s}s$Oxf{XWKd-z
zalzf!EX!rfH7a^kP-n){c1Caoj8t==P3zuoZr^*A6dKhih@WG>!o_pNce9OcutkUP`_L;%8CG--ZBBwnn7|tF{
ztuxg2+~DhQ0~ulE*Q%2T#%NGT)0I*0Fi-|L<4;I7w*lVr%vu0!2e-oT1i(VyH!n
zX2mohfpy!Dau@)F$z3dxEYGzc#nF=jF}M05N4LhD1DO3u
zbOyVTYHrp9xUF!RaD7tZPmLQuUvRqObojXWuQc{k%2GZ5>)0VY69!8Cz17}%pE+Zc*qt(
+hc+CwOenb$8b}1Y|iodPOx1TG_pPO)r3_vGo&5AihIy!hDc=X$7;_?
z-pb*vG
C>=!@h=qj=BXM;N$^I6mGt#DNOlT1wlf5$xWgug68qR|BF(;HJ!>!%4Rl_J_$
zy?M(=_mnae1-eQ#Ptkbdg6p_