From 384e793c7ea0e01aa073faef1f55fe28d07c7f8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=A8=E6=A0=88=E5=B0=8F=E5=AD=A6=E7=94=9F?= <1518079521@qq.com> Date: Fri, 23 May 2025 14:40:12 +0800 Subject: [PATCH] up --- .../app/adminapi/controller/addon/Backup.php | 125 ++++ .../app/adminapi/controller/addon/Upgrade.php | 42 +- .../app/adminapi/controller/diy/Config.php | 6 +- niucloud/app/adminapi/controller/diy/Diy.php | 6 +- .../app/adminapi/controller/diy/DiyForm.php | 12 - .../app/adminapi/controller/member/Member.php | 1 + .../adminapi/controller/niucloud/Module.php | 37 +- .../app/adminapi/controller/pay/PayRefund.php | 7 + .../app/adminapi/controller/sys/Config.php | 52 +- .../app/adminapi/controller/sys/System.php | 15 + .../adminapi/controller/verify/Verifier.php | 36 +- .../app/adminapi/controller/verify/Verify.php | 14 +- niucloud/app/adminapi/route/niucloud.php | 3 + niucloud/app/adminapi/route/pay.php | 1 + niucloud/app/adminapi/route/sys.php | 4 +- niucloud/app/adminapi/route/upgrade.php | 47 +- niucloud/app/adminapi/route/verify.php | 2 + niucloud/app/api/controller/sys/Verify.php | 48 +- niucloud/app/common.php | 77 +- niucloud/app/dict/diy_form/ComponentDict.php | 671 +++++++++--------- niucloud/app/dict/diy_form/TemplateDict.php | 4 +- niucloud/app/dict/menu/admin.php | 465 +++++++----- niucloud/app/dict/schedule/schedule.php | 28 +- niucloud/app/dict/sys/BackupDict.php | 34 + niucloud/app/dict/sys/CloudDict.php | 5 +- niucloud/app/dict/sys/UpgradeDict.php | 40 ++ niucloud/app/install/source/database.sql | 53 +- .../app/job/schedule/AutoClearScheduleLog.php | 47 ++ .../job/upgrade/AutoClearUpgradeRecords.php | 54 ++ .../wxoplatform/GetVersionUploadResult.php | 34 + .../job/wxoplatform/VersionUploadSuccess.php | 34 + niucloud/app/lang/en/validate.php | 13 - niucloud/app/lang/zh-cn/api.php | 9 +- niucloud/app/lang/zh-cn/dict.php | 15 +- niucloud/app/lang/zh-cn/validate.php | 16 - .../app/listener/system/ShowAppListener.php | 21 +- niucloud/app/model/member/Member.php | 10 +- niucloud/app/model/sys/SysBackupRecords.php | 112 +++ niucloud/app/model/sys/SysUpgradeRecords.php | 130 ++++ niucloud/app/model/verify/Verify.php | 23 +- niucloud/app/model/weapp/WeappVersion.php | 2 +- .../service/admin/diy_form/DiyFormService.php | 33 - .../admin/generator/vm/search/select2.vm | 2 +- .../service/admin/member/MemberService.php | 116 +-- .../admin/niucloud/NiucloudService.php | 44 +- .../app/service/admin/sys/ConfigService.php | 18 +- .../app/service/admin/sys/SystemService.php | 43 +- .../admin/upgrade/BackupRecordsService.php | 662 +++++++++++++++++ .../service/admin/upgrade/BackupService.php | 91 +-- .../service/admin/upgrade/RestoreService.php | 40 -- .../admin/upgrade/UpgradeRecordsService.php | 128 ++++ .../service/admin/upgrade/UpgradeService.php | 600 ++++++++++++---- .../service/admin/verify/VerifierService.php | 48 +- .../service/admin/verify/VerifyService.php | 22 +- .../app/service/api/diy/DiyConfigService.php | 3 +- niucloud/app/service/api/diy/DiyService.php | 36 +- niucloud/app/service/api/sys/AreaService.php | 2 +- .../app/service/api/verify/VerifyService.php | 5 +- .../core/addon/CoreAddonCloudService.php | 32 +- .../core/addon/CoreAddonDevelopService.php | 1 + niucloud/app/service/core/addon/WapTrait.php | 1 + .../app/service/core/diy/CoreDiyService.php | 52 +- .../app/service/core/menu/CoreMenuService.php | 11 +- .../core/niucloud/CoreCloudBuildService.php | 166 +++-- .../core/niucloud/CoreModuleService.php | 40 +- .../app/service/core/pay/CorePayService.php | 14 +- .../service/core/pay/CoreRefundService.php | 7 + .../core/pay/CoreTransferSceneService.php | 73 -- .../service/core/pay/CoreTransferService.php | 157 ++-- .../service/core/verify/CoreVerifyService.php | 46 +- .../core/weapp/CoreWeappCloudService.php | 107 ++- .../core/weapp/CoreWeappDeliveryService.php | 10 +- .../service/core/weapp/CoreWeappService.php | 2 +- niucloud/app/upgrade/v152/Upgrade.php | 35 +- niucloud/app/upgrade/v153/upgrade.sql | 48 ++ .../app/validate/member/CashOutConfig.php | 4 +- niucloud/config/version.php | 4 +- niucloud/core/dict/PackageGift.php | 1 - .../core/exception/CloudBuildException.php | 18 + niucloud/core/pay/Wechatpay.php | 1 - niucloud/core/util/DbBackup.php | 656 +++++------------ 81 files changed, 3763 insertions(+), 1971 deletions(-) create mode 100644 niucloud/app/adminapi/controller/addon/Backup.php create mode 100644 niucloud/app/dict/sys/BackupDict.php create mode 100644 niucloud/app/dict/sys/UpgradeDict.php create mode 100644 niucloud/app/job/schedule/AutoClearScheduleLog.php create mode 100644 niucloud/app/job/upgrade/AutoClearUpgradeRecords.php create mode 100644 niucloud/app/job/wxoplatform/GetVersionUploadResult.php create mode 100644 niucloud/app/job/wxoplatform/VersionUploadSuccess.php create mode 100644 niucloud/app/model/sys/SysBackupRecords.php create mode 100644 niucloud/app/model/sys/SysUpgradeRecords.php create mode 100644 niucloud/app/service/admin/upgrade/BackupRecordsService.php create mode 100644 niucloud/app/service/admin/upgrade/UpgradeRecordsService.php create mode 100644 niucloud/app/upgrade/v153/upgrade.sql delete mode 100644 niucloud/core/dict/PackageGift.php create mode 100644 niucloud/core/exception/CloudBuildException.php diff --git a/niucloud/app/adminapi/controller/addon/Backup.php b/niucloud/app/adminapi/controller/addon/Backup.php new file mode 100644 index 000000000..f0b0183af --- /dev/null +++ b/niucloud/app/adminapi/controller/addon/Backup.php @@ -0,0 +1,125 @@ +request->params([ + [ "content", "" ], + ]); + return success(( new BackupRecordsService() )->getPage($data)); + } + + /** + * 修改备注 + * @return Response + */ + public function modifyRemark() + { + $data = $this->request->params([ + [ "id", "" ], + [ 'remark', '' ] + ]); + ( new BackupRecordsService() )->modifyRemark($data); + return success('MODIFY_SUCCESS'); + } + + /** + * 恢复前检测文件是否存在 + * @return Response + */ + public function checkDirExist() + { + $data = $this->request->params([ + [ "id", 0 ], + ]); + return success(( new BackupRecordsService() )->checkDirExist($data[ 'id' ])); + } + + /** + * 检测目录权限 + * @return Response + */ + public function checkPermission() + { + return success(( new BackupRecordsService() )->checkPermission()); + } + + /** + * 恢复备份 + * @return Response + */ + public function restoreBackup() + { + $data = $this->request->params([ + [ 'id', 0 ], + [ 'task', '' ] + ]); + $res = ( new BackupRecordsService() )->restore($data); + return $res; + } + + /** + * 删除升级记录 + * @return Response + */ + public function deleteRecords() + { + $data = $this->request->params([ + [ "ids", [] ], + ]); + ( new BackupRecordsService() )->del($data[ 'ids' ]); + return success('DELETE_SUCCESS'); + } + + /** + * 手动备份 + * @return Response + */ + public function manualBackup() + { + $data = $this->request->params([ + [ 'task', '' ] + ]); + $res = ( new BackupRecordsService() )->manualBackup($data); + return $res; + } + + /** + * 获取正在进行的恢复任务 + * @return Response + */ + public function getRestoreTask() + { + return success(( new BackupRecordsService() )->getRestoreTask()); + } + + /** + * 获取正在进行的备份任务 + * @return Response + */ + public function getBackupTask() + { + return success(( new BackupRecordsService() )->getBackupTask()); + } +} diff --git a/niucloud/app/adminapi/controller/addon/Upgrade.php b/niucloud/app/adminapi/controller/addon/Upgrade.php index cadf62f55..6433c1856 100644 --- a/niucloud/app/adminapi/controller/addon/Upgrade.php +++ b/niucloud/app/adminapi/controller/addon/Upgrade.php @@ -11,6 +11,7 @@ namespace app\adminapi\controller\addon; +use app\service\admin\upgrade\UpgradeRecordsService; use app\service\admin\upgrade\UpgradeService; use core\base\BaseAdminController; use think\Response; @@ -24,7 +25,10 @@ class Upgrade extends BaseAdminController */ public function upgrade($addon = '') { - return success(data:( new UpgradeService() )->upgrade($addon)); + $data = $this->request->params([ + ['is_need_backup', true] + ]); + return success(data: ( new UpgradeService() )->upgrade($addon, $data)); } /** @@ -32,9 +36,9 @@ class Upgrade extends BaseAdminController * @param $app_key * @return Response */ - public function execute($addon = '') + public function execute() { - return success(data:( new UpgradeService() )->execute()); + return success(data: ( new UpgradeService() )->execute()); } /** @@ -44,7 +48,7 @@ class Upgrade extends BaseAdminController */ public function getUpgradeContent($addon = '') { - return success(data:( new UpgradeService() )->getUpgradeContent($addon)); + return success(data: ( new UpgradeService() )->getUpgradeContent($addon)); } /** @@ -53,7 +57,7 @@ class Upgrade extends BaseAdminController */ public function getUpgradeTask() { - return success(data:( new UpgradeService() )->getUpgradeTask()); + return success(data: ( new UpgradeService() )->getUpgradeTask()); } /** @@ -63,7 +67,7 @@ class Upgrade extends BaseAdminController */ public function upgradePreCheck($addon = '') { - return success(data:( new UpgradeService() )->upgradePreCheck($addon)); + return success(data: ( new UpgradeService() )->upgradePreCheck($addon)); } /** @@ -72,6 +76,30 @@ class Upgrade extends BaseAdminController */ public function clearUpgradeTask() { - return success(data:( new UpgradeService() )->clearUpgradeTask()); + return success(data: ( new UpgradeService() )->clearUpgradeTask(0, 1)); + } + + public function operate($operate) { + return success(( new UpgradeService() )->operate($operate)); + } + + /** + * 获取升级记录分页列表 + * @return Response + */ + public function getRecords() + { + $data = $this->request->params([ + [ "name", "" ], + ]); + return success(( new UpgradeRecordsService() )->getPage($data)); + } + + public function delRecords() { + $data = $this->request->params([ + [ 'ids', '' ], + ]); + ( new UpgradeRecordsService() )->del($data['ids']); + return success('DELETE_SUCCESS'); } } diff --git a/niucloud/app/adminapi/controller/diy/Config.php b/niucloud/app/adminapi/controller/diy/Config.php index d01765f26..7ca66bec1 100644 --- a/niucloud/app/adminapi/controller/diy/Config.php +++ b/niucloud/app/adminapi/controller/diy/Config.php @@ -29,7 +29,7 @@ class Config extends BaseAdminController */ public function getBottomList() { - return success((new DiyConfigService())->getBottomList()); + return success(( new DiyConfigService() )->getBottomList()); } /** @@ -41,7 +41,7 @@ class Config extends BaseAdminController $params = $this->request->params([ [ 'key', 'app' ], ]); - return success((new DiyConfigService())->getBottomConfig($params[ 'key' ])); + return success(( new DiyConfigService() )->getBottomConfig($params[ 'key' ])); } /** @@ -54,7 +54,7 @@ class Config extends BaseAdminController [ 'value', [] ], [ 'key', 'app' ] ]); - (new DiyConfigService())->setBottomConfig($data[ 'value' ], $data[ 'key' ]); + ( new DiyConfigService() )->setBottomConfig($data[ 'value' ], $data[ 'key' ]); return success(); } diff --git a/niucloud/app/adminapi/controller/diy/Diy.php b/niucloud/app/adminapi/controller/diy/Diy.php index 22164579f..cefaf5545 100644 --- a/niucloud/app/adminapi/controller/diy/Diy.php +++ b/niucloud/app/adminapi/controller/diy/Diy.php @@ -274,7 +274,7 @@ class Diy extends BaseAdminController */ public function getDiyTheme() { - return success(( new DiyService() )->getDiyTheme()); + return success(( new DiyService() )->getDiyTheme()); } /** @@ -291,7 +291,7 @@ class Diy extends BaseAdminController [ 'new_theme', '' ], ]); ( new DiyService() )->setDiyTheme($data); - return success('ADD_SUCCESS'); + return success('ADD_SUCCESS'); } /** @@ -303,7 +303,7 @@ class Diy extends BaseAdminController $data = $this->request->params([ [ 'addon', '' ], ]); - return success(( new DiyService() )->getDefaultThemeColor($data)); + return success(( new DiyService() )->getDefaultThemeColor($data)); } /** diff --git a/niucloud/app/adminapi/controller/diy/DiyForm.php b/niucloud/app/adminapi/controller/diy/DiyForm.php index 7c4bf1765..19565a394 100644 --- a/niucloud/app/adminapi/controller/diy/DiyForm.php +++ b/niucloud/app/adminapi/controller/diy/DiyForm.php @@ -370,16 +370,4 @@ class DiyForm extends BaseAdminController return success(( new DiyFormRecordsService() )->getFieldStatList($data)); } - /** - * 获取万能表单微信小程序二维码 - * @return Response - */ - public function getQrcode() - { - $data = $this->request->params([ - [ "form_id", '' ], - ]); - return success(( new DiyFormService() )->getQrcode($data[ 'form_id' ])); - } - } diff --git a/niucloud/app/adminapi/controller/member/Member.php b/niucloud/app/adminapi/controller/member/Member.php index 70cba88a2..04fbfd034 100644 --- a/niucloud/app/adminapi/controller/member/Member.php +++ b/niucloud/app/adminapi/controller/member/Member.php @@ -152,6 +152,7 @@ class Member extends BaseAdminController { $data = $this->request->params([ ['keyword', ''], + ['member_ids', []], ]); return success((new MemberService())->getList($data)); } diff --git a/niucloud/app/adminapi/controller/niucloud/Module.php b/niucloud/app/adminapi/controller/niucloud/Module.php index 797e72642..e856cf55e 100644 --- a/niucloud/app/adminapi/controller/niucloud/Module.php +++ b/niucloud/app/adminapi/controller/niucloud/Module.php @@ -20,7 +20,7 @@ class Module extends BaseAdminController { public function authorize() { - return success((new CoreAuthService())->getAuthInfo()); + return success(( new CoreAuthService() )->getAuthInfo()); } /** @@ -29,11 +29,11 @@ class Module extends BaseAdminController public function setAuthorize() { $data = $this->request->params([ - ['auth_code', ''], - ['auth_secret', ''] + [ 'auth_code', '' ], + [ 'auth_secret', '' ] ]); $this->validate($data, 'app\validate\niucloud\Module.set'); - return success("SUCCESS", (new NiucloudService())->setAuthorize($data)); + return success("SUCCESS", ( new NiucloudService() )->setAuthorize($data)); } /** @@ -41,7 +41,7 @@ class Module extends BaseAdminController */ public function getAuthorize() { - return success((new NiucloudService())->getAuthorize()); + return success(( new NiucloudService() )->getAuthorize()); } /** @@ -49,8 +49,9 @@ class Module extends BaseAdminController * @return Response * @throws \GuzzleHttp\Exception\GuzzleException */ - public function getFrameworkLastVersion() { - return success(data:(new NiucloudService())->getFrameworkLastVersion()); + public function getFrameworkLastVersion() + { + return success(data: ( new NiucloudService() )->getFrameworkLastVersion()); } /** @@ -58,15 +59,29 @@ class Module extends BaseAdminController * @return Response * @throws \GuzzleHttp\Exception\GuzzleException */ - public function getFrameworkVersionList() { - return success(data:(new NiucloudService())->getFrameworkVersionList()); + public function getFrameworkVersionList() + { + return success(data: ( new NiucloudService() )->getFrameworkVersionList()); } /** * 申请体验 * @return Response */ - public function applyExperience() { - return success((new NiucloudService())->applyExperience()); + public function applyExperience() + { + return success(( new NiucloudService() )->applyExperience()); + } + + /** + * 获取应用/插件的版本更新记录 + * @return Response + */ + public function getAppVersionList() + { + $data = $this->request->params([ + [ 'app_key', '' ], + ]); + return success(data: ( new NiucloudService() )->getAppVersionList($data[ 'app_key' ])); } } diff --git a/niucloud/app/adminapi/controller/pay/PayRefund.php b/niucloud/app/adminapi/controller/pay/PayRefund.php index 2f96de55c..e7fa2367c 100644 --- a/niucloud/app/adminapi/controller/pay/PayRefund.php +++ b/niucloud/app/adminapi/controller/pay/PayRefund.php @@ -17,6 +17,13 @@ use core\base\BaseAdminController; class PayRefund extends BaseAdminController { + /** + * @return \think\Response + */ + public function getStatus() + { + return success(RefundDict::getStatus()); + } /** * 退款列表 * @return \think\Response diff --git a/niucloud/app/adminapi/controller/sys/Config.php b/niucloud/app/adminapi/controller/sys/Config.php index a373f7e98..639aa9867 100644 --- a/niucloud/app/adminapi/controller/sys/Config.php +++ b/niucloud/app/adminapi/controller/sys/Config.php @@ -23,7 +23,7 @@ class Config extends BaseAdminController */ public function getWebsite() { - return success((new ConfigService())->getWebSite()); + return success(( new ConfigService() )->getWebSite()); } /** @@ -51,14 +51,14 @@ class Config extends BaseAdminController [ "front_end_icon", "" ], [ "icon", "" ] ]); - (new ConfigService())->setWebSite($data); + ( new ConfigService() )->setWebSite($data); $service_data = $this->request->params([ [ "wechat_code", "" ], [ "enterprise_wechat", "" ], [ "tel", "" ], ]); - (new ConfigService())->setService($service_data); + ( new ConfigService() )->setService($service_data); return success(); } @@ -69,7 +69,7 @@ class Config extends BaseAdminController */ public function getCopyright() { - return success((new ConfigService())->getCopyright()); + return success(( new ConfigService() )->getCopyright()); } /**设置版权信息 @@ -78,16 +78,16 @@ class Config extends BaseAdminController public function setCopyright() { $data = $this->request->params([ - ['icp', ''], - ['gov_record', ''], - ['gov_url', ''], - ['market_supervision_url', ''], - ['logo', ''], - ['company_name', ''], - ['copyright_link', ''], - ['copyright_desc', ''], + [ 'icp', '' ], + [ 'gov_record', '' ], + [ 'gov_url', '' ], + [ 'market_supervision_url', '' ], + [ 'logo', '' ], + [ 'company_name', '' ], + [ 'copyright_link', '' ], + [ 'copyright_desc', '' ], ]); - (new ConfigService())->setCopyright($data); + ( new ConfigService() )->setCopyright($data); return success(); } @@ -97,7 +97,7 @@ class Config extends BaseAdminController */ public function getSceneDomain() { - return success((new ConfigService())->getSceneDomain()); + return success(( new ConfigService() )->getSceneDomain()); } /** @@ -106,7 +106,7 @@ class Config extends BaseAdminController */ public function getServiceInfo() { - return success((new ConfigService())->getService()); + return success(( new ConfigService() )->getService()); } /**设置版权信息 @@ -115,11 +115,11 @@ class Config extends BaseAdminController public function setMap() { $data = $this->request->params([ - ['key', ''], + [ 'key', '' ], [ 'is_open', 0 ], // 是否开启定位 [ 'valid_time', 0 ] // 定位有效期/分钟,过期后将重新获取定位信息,0为不过期 ]); - (new ConfigService())->setMap($data); + ( new ConfigService() )->setMap($data); return success(); } @@ -129,7 +129,7 @@ class Config extends BaseAdminController */ public function getMap() { - return success((new ConfigService())->getMap()); + return success(( new ConfigService() )->getMap()); } /** @@ -148,19 +148,21 @@ class Config extends BaseAdminController * 获取开发者key * @return Response */ - public function getDeveloperToken() { - return success(data: (new ConfigService())->getDeveloperToken()); + public function getDeveloperToken() + { + return success(data: ( new ConfigService() )->getDeveloperToken()); } /** * 设置开发者key * @return Response */ - public function setDeveloperToken() { + public function setDeveloperToken() + { $data = $this->request->params([ - ['token', ''], + [ 'token', '' ], ]); - (new ConfigService())->setDeveloperToken($data); + ( new ConfigService() )->setDeveloperToken($data); return success(); } @@ -168,7 +170,9 @@ class Config extends BaseAdminController * 获取install.php配置 * @return Response */ - public function getInstallConfig() { + public function getInstallConfig() + { return success(config('install')); } + } diff --git a/niucloud/app/adminapi/controller/sys/System.php b/niucloud/app/adminapi/controller/sys/System.php index 491917249..98a895964 100644 --- a/niucloud/app/adminapi/controller/sys/System.php +++ b/niucloud/app/adminapi/controller/sys/System.php @@ -91,4 +91,19 @@ class System extends BaseAdminController { return success(['app_debug' => env('app_debug', false)]); } + + /** + * 获取推广二维码 + * @return Response + */ + public function getSpreadQrcode() + { + $params = $this->request->params([ + ['form_id', ''], + ['folder',''], + ['page',''], + ['params',[]] + ]); + return success((new SystemService())->getQrcode($params)); + } } diff --git a/niucloud/app/adminapi/controller/verify/Verifier.php b/niucloud/app/adminapi/controller/verify/Verifier.php index 735da5211..e76e15340 100644 --- a/niucloud/app/adminapi/controller/verify/Verifier.php +++ b/niucloud/app/adminapi/controller/verify/Verifier.php @@ -24,7 +24,7 @@ class Verifier extends BaseAdminController */ public function lists() { - return success(data:(new VerifierService())->getPage()); + return success(data: ( new VerifierService() )->getPage()); } /** @@ -33,7 +33,17 @@ class Verifier extends BaseAdminController */ public function select() { - return success(data:(new VerifierService())->getList()); + return success(data: ( new VerifierService() )->getList()); + } + + /** + * 获取核销员信息 + * @param int $order_id + * @return Response + */ + public function detail($id) + { + return success(data: ( new VerifierService() )->getDetail($id)); } /** @@ -44,10 +54,24 @@ class Verifier extends BaseAdminController public function add() { $data = $this->request->params([ - ['member_id', 0], - ['verify_type', ''], + [ 'member_id', 0 ], + [ 'verify_type', '' ], ]); - return success(data:(new VerifierService())->add($data)); + return success(data: ( new VerifierService() )->add($data)); + } + + /** + * 添加核销员 + * @param int $order_id + * @return Response + */ + public function edit($id) + { + $data = $this->request->params([ + [ 'verify_type', '' ], + ]); + ( new VerifierService() )->edit($id,$data); + return success('EDIT_SUCCESS'); } /** @@ -55,7 +79,7 @@ class Verifier extends BaseAdminController */ public function del(int $id) { - return success('DELETE_SUCCESS', (new VerifierService())->del($id)); + return success('DELETE_SUCCESS', ( new VerifierService() )->del($id)); } /** diff --git a/niucloud/app/adminapi/controller/verify/Verify.php b/niucloud/app/adminapi/controller/verify/Verify.php index 4bf8e64a4..14b666e31 100644 --- a/niucloud/app/adminapi/controller/verify/Verify.php +++ b/niucloud/app/adminapi/controller/verify/Verify.php @@ -24,13 +24,13 @@ class Verify extends BaseAdminController public function lists() { $data = $this->request->params([ - ['relate_tag', 0], - ['type', ''], - ['code', ''], - ['verifier_member_id', ''], - ['create_time', []] + [ 'relate_tag', 0 ], + [ 'type', '' ], + [ 'code', '' ], + [ 'verifier_member_id', '' ], + [ 'create_time', [] ] ]); - return success((new VerifyService())->getPage($data)); + return success(( new VerifyService() )->getPage($data)); } /** @@ -40,6 +40,6 @@ class Verify extends BaseAdminController */ public function detail(string $verify_code) { - return success((new VerifyService())->getDetail($verify_code)); + return success(( new VerifyService() )->getDetail($verify_code)); } } diff --git a/niucloud/app/adminapi/route/niucloud.php b/niucloud/app/adminapi/route/niucloud.php index c5397b252..67fd355c9 100644 --- a/niucloud/app/adminapi/route/niucloud.php +++ b/niucloud/app/adminapi/route/niucloud.php @@ -42,6 +42,9 @@ Route::group('niucloud', function () { // 获取框架版本更新记录 Route::get('framework/version/list', 'niucloud.Module/getFrameworkVersionList'); + // 获取应用/插件的版本更新记录 + Route::get('app_version/list', 'niucloud.Module/getAppVersionList'); + // 云编译 Route::post('build', 'niucloud.Cloud/build'); // 云编译 diff --git a/niucloud/app/adminapi/route/pay.php b/niucloud/app/adminapi/route/pay.php index dca211ed1..3ea04220c 100644 --- a/niucloud/app/adminapi/route/pay.php +++ b/niucloud/app/adminapi/route/pay.php @@ -52,6 +52,7 @@ Route::group('pay', function () { //退款列表 Route::get('refund', 'pay.PayRefund/pages'); //退款详情 + Route::get('refund/status', 'pay.PayRefund/getStatus'); Route::get('refund/:refund_no', 'pay.PayRefund/detail'); //退款方式 Route::get('refund/type', 'pay.PayRefund/getRefundType'); diff --git a/niucloud/app/adminapi/route/sys.php b/niucloud/app/adminapi/route/sys.php index 533a8249d..99c01564c 100644 --- a/niucloud/app/adminapi/route/sys.php +++ b/niucloud/app/adminapi/route/sys.php @@ -23,6 +23,7 @@ Route::group('sys', function() { //系统信息 Route::get('info', 'sys.System/info'); Route::get('url', 'sys.System/url'); + Route::get('qrcode', 'sys.System/getSpreadQrcode'); /***************************************************** 用户组 ****************************************************/ //用户组列表 Route::get('role', 'sys.Role/lists'); @@ -56,7 +57,7 @@ Route::group('sys', function() { //授权用户菜单 Route::get('authmenu', 'sys.Auth/authMenuList'); // 获取菜单信息 - Route::get('menu/:app_type/info/:menu_key', 'sys.Menu/info'); + Route::get('menu/info/:menu_key', 'sys.Menu/info'); // 初始化菜单 Route::post('menu/refresh', 'sys.Menu/refreshMenu'); @@ -267,7 +268,6 @@ Route::group('sys', function() { // 百度编辑器文件上传 Route::post('ueditor', 'sys.Ueditor/upload'); - /***************************************************** 小票打印管理 ****************************************************/ // 小票打印机分页列表 diff --git a/niucloud/app/adminapi/route/upgrade.php b/niucloud/app/adminapi/route/upgrade.php index 9ba707fe5..ecc4b1c90 100644 --- a/niucloud/app/adminapi/route/upgrade.php +++ b/niucloud/app/adminapi/route/upgrade.php @@ -19,18 +19,59 @@ use think\facade\Route; * 路由 */ Route::group('', function () { + // 获取正在进行的升级任务 Route::get('upgrade/task', 'addon.Upgrade/getUpgradeTask'); + // 执行升级 Route::post('upgrade/execute', 'addon.Upgrade/execute'); + // 清除升级任务 Route::post('upgrade/clear', 'addon.Upgrade/clearUpgradeTask'); + // 升级环境检测 - Route::get('upgrade/check/[:addon]', 'addon.Upgrade/upgradePreCheck'); + Route::get('upgrade/check/[:addon]', 'addon.Upgrade/upgradePreCheck')->pattern(['addon' => '[\w|\,]+']); + // 升级 - Route::post('upgrade/[:addon]', 'addon.Upgrade/upgrade'); + Route::post('upgrade/[:addon]', 'addon.Upgrade/upgrade')->pattern(['addon' => '[\w|\,]+']); + // 获取升级内容 - Route::get('upgrade/[:addon]', 'addon.Upgrade/getUpgradeContent'); + Route::get('upgrade/[:addon]', 'addon.Upgrade/getUpgradeContent')->pattern(['addon' => '[\w|\,]+']); + + Route::post('upgrade/operate/:operate', 'addon.Upgrade/operate'); + + // 升级记录分页列表 + Route::get('upgrade/records', 'addon.Upgrade/getRecords'); + + // 删除升级记录 + Route::delete('upgrade/records', 'addon.Upgrade/delRecords'); + + // 备份记录分页列表 + Route::get('backup/records', 'addon.Backup/getRecords'); + + // 修改备注 + Route::put('backup/remark', 'addon.Backup/modifyRemark'); + + // 恢复前检测文件是否存在,备份 + Route::post('backup/check_dir', 'addon.Backup/checkDirExist'); + + // 检测目录权限 + Route::post('backup/check_permission', 'addon.Backup/checkPermission'); + + // 恢复升级备份 + Route::post('backup/restore', 'addon.Backup/restoreBackup'); + + // 删除升级记录 + Route::post('backup/delete', 'addon.Backup/deleteRecords'); + + // 手动备份 + Route::post('backup/manual', 'addon.Backup/manualBackup'); + + // 获取进行中的恢复 + Route::get('backup/restore_task', 'addon.Backup/getRestoreTask'); + + // 获取进行中的备份 + Route::get('backup/task', 'addon.Backup/getBackupTask'); })->middleware([ AdminCheckToken::class, AdminCheckRole::class, diff --git a/niucloud/app/adminapi/route/verify.php b/niucloud/app/adminapi/route/verify.php index 9de343d5e..23ed3d4c3 100644 --- a/niucloud/app/adminapi/route/verify.php +++ b/niucloud/app/adminapi/route/verify.php @@ -28,6 +28,8 @@ Route::group('verify', function () { /***************************************************** 核销员相关接口 ****************************************************/ // 添加核销员 Route::post('verifier', 'verify.Verifier/add'); + Route::post('verifier/:id', 'verify.Verifier/edit'); + Route::get('verifier/:id', 'verify.Verifier/detail'); // 获取核销员列表 Route::get('verifier', 'verify.Verifier/lists'); // 获取核销员列表 diff --git a/niucloud/app/api/controller/sys/Verify.php b/niucloud/app/api/controller/sys/Verify.php index 67e68251c..1eb32a2bc 100644 --- a/niucloud/app/api/controller/sys/Verify.php +++ b/niucloud/app/api/controller/sys/Verify.php @@ -22,53 +22,60 @@ class Verify extends BaseApiController * 获取验证码 * @return Response */ - public function getVerifyCode(){ + public function getVerifyCode() + { $data = $this->request->params([ - ['data', []], - ['type', ''] + [ 'data', [] ], + [ 'type', '' ] ]); - return success(data:(new VerifyService())->getVerifyCode($data['type'], $data['data'])); + return success(data: ( new VerifyService() )->getVerifyCode($data[ 'type' ], $data[ 'data' ])); } /** * 获取核销码信息 * @return Response */ - public function getInfoByCode(){ + public function getInfoByCode() + { $data = $this->request->params([ - ['code', ''], + [ 'code', '' ], ]); - return success(data:(new VerifyService())->getInfoByCode($data['code'])); + return success(data: ( new VerifyService() )->getInfoByCode($data[ 'code' ])); } + /** * 核销 * @param $code * @return Response */ - public function verify($code){ - return success(data:(new VerifyService())->verify($code)); + public function verify($code) + { + return success(data: ( new VerifyService() )->verify($code)); } + /** * 校验是否是核销员 * @return Response */ - public function checkVerifier(){ - return success(data:(new VerifyService())->checkVerifier()); + public function checkVerifier() + { + return success(data: ( new VerifyService() )->checkVerifier()); } /** * 核销记录 * @return void */ - public function records(){ + public function records() + { $data = $this->request->params([ - ['relate_tag', 0], - ['type', ''], - ['code', ''], - ['keyword', ''], - ['create_time', []] + [ 'relate_tag', 0 ], + [ 'type', '' ], + [ 'code', '' ], + [ 'keyword', '' ], + [ 'create_time', [] ] ]); - return success(data:(new VerifyService())->getRecordsPageByVerifier($data)); + return success(data: ( new VerifyService() )->getRecordsPageByVerifier($data)); } /** @@ -76,8 +83,9 @@ class Verify extends BaseApiController * @param $code * @return Response */ - public function detail(string|int $code){ - return success(data:(new VerifyService())->getRecordsDetailByVerifier($code)); + public function detail(string|int $code) + { + return success(data: ( new VerifyService() )->getRecordsDetailByVerifier($code)); } } diff --git a/niucloud/app/common.php b/niucloud/app/common.php index 312c017fd..900432b8d 100644 --- a/niucloud/app/common.php +++ b/niucloud/app/common.php @@ -554,7 +554,7 @@ function dir_copy(string $src = '', string $dst = '', &$files = [], $exclude_dir if (is_dir($src . '/' . $file)) { // 排除目录 if (count($exclude_dirs) && in_array($file, $exclude_dirs)) continue; - dir_copy($src . '/' . $file, $dst . '/' . $file, $files); + dir_copy($src . '/' . $file, $dst . '/' . $file, $files, $exclude_dirs, $exclude_files); } else { // 排除文件 if (count($exclude_files) && in_array($file, $exclude_files)) continue; @@ -1033,10 +1033,13 @@ function get_last_time($time = null) /** * 检查目录及其子目录的权限 - * @param string $dir 要检查的目录路径 - * @return void + * @param $dir 要检查的目录路径 + * @param $data + * @param $exclude_dir 排除排除无需检测的的文件夹 + * @return array|array[]|mixed */ -function checkDirPermissions($dir, $data = []) { +function checkDirPermissions($dir, $data = [], $exclude_dir = []) +{ if (!is_dir($dir)) { throw new \RuntimeException(sprintf('指定的路径 "%s" 不是一个有效的目录', $dir)); } @@ -1050,33 +1053,83 @@ function checkDirPermissions($dir, $data = []) { try { if (!is_readable($dir)) { - $data['unreadable'][] = $dir; + $data[ 'unreadable' ][] = $dir; } if (!is_writable($dir)) { - $data['not_writable'][] = $dir; + $data[ 'not_writable' ][] = $dir; } if (is_readable($dir)) { $dh = opendir($dir); - while (($file = readdir($dh)) !== false) { + while (( $file = readdir($dh) ) !== false) { if ($file === '.' || $file === '..') { continue; } $fullPath = $dir . DIRECTORY_SEPARATOR . $file; + + // 忽略指定目录 + $is_exclude = false; + foreach ($exclude_dir as $k => $item) { + if (strpos($fullPath, $item)) { + $is_exclude = true; + break; + } + } + + if ($is_exclude) continue; + // 判断是否为目录,如果是则递归调用 if (is_dir($fullPath)) { - $data = checkDirPermissions($fullPath, $data); // 递归调用自身来检查子目录 + $data = checkDirPermissions($fullPath, $data, $exclude_dir); // 递归调用自身来检查子目录 } else { // 如果是文件,则检查其读写权限 - if (!is_readable($fullPath)) $data['unreadable'][] = $fullPath; - if (!is_writable($fullPath)) $data['not_writable'][] = $fullPath; + if (!is_readable($fullPath)) $data[ 'unreadable' ][] = $fullPath; + if (!is_writable($fullPath)) $data[ 'not_writable' ][] = $fullPath; } } closedir($dh); } return $data; } catch (Exception $e) { - $data['unreadable'][] = $dir; - $data['not_writable'][] = $dir; + $data[ 'unreadable' ][] = $dir; + $data[ 'not_writable' ][] = $dir; return $data; } } + +/** + * 下载网络图片 + * @param $img_url 图片URL + * @param $file_name 本地保存位置 + * @return bool + */ +function downloadImage($img_url, $file_name) +{ + + // 初始化 cURL 会话 + $ch = curl_init($img_url); + + // 打开本地文件以写入模式 + $fp = fopen($file_name, 'wb'); + + // 设置 cURL 选项 + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_setopt($ch, CURLOPT_HEADER, 0); + + // 跳过 SSL 验证 + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + + // 执行 cURL 会话 + curl_exec($ch); + + // 检查是否有错误发生 + if (curl_errno($ch)) { +// echo 'Curl error: ' . curl_error($ch); + return false; + } + + // 关闭 cURL 会话和文件句柄 + curl_close($ch); + fclose($fp); + return true; +} \ No newline at end of file diff --git a/niucloud/app/dict/diy_form/ComponentDict.php b/niucloud/app/dict/diy_form/ComponentDict.php index f4d23f48f..b55a8bfb1 100644 --- a/niucloud/app/dict/diy_form/ComponentDict.php +++ b/niucloud/app/dict/diy_form/ComponentDict.php @@ -414,56 +414,57 @@ class ComponentDict return $data; } ], - // 'FormWechatName' => [ - // 'title' => '微信名', - // 'icon' => 'iconfont iconbiaotipc', - // 'path' => 'edit-form-wechat-name', // 编辑组件属性名称 - // 'uses' => 1, // 最大添加数量 - // 'sort' => 10007, - // // 组件属性 - // 'template' => [ - // "textColor" => "#303133", // 文字颜色 - // 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) - // 'pageEndBgColor' => '', // 底部背景颜色(结束) - // 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) - // 'componentBgUrl' => '', // 组件背景图片 - // 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 - // "componentStartBgColor" => '', // 组件背景颜色(开始) - // "componentEndBgColor" => '', // 组件背景颜色(结束) - // "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) - // "topRounded" => 0, // 组件上圆角 - // "bottomRounded" => 0, // 组件下圆角 - // "elementBgColor" => '', // 元素背景颜色 - // "topElementRounded" => 0,// 元素上圆角 - // "bottomElementRounded" => 0, // 元素下圆角 - // "margin" => [ - // "top" => 10, // 上边距 - // "bottom" => 10, // 下边距 - // "both" => 10 // 左右边距 - // ], - // ], - // 'value' => [ - // // 表单的公共属性 - // 'field' => [ - // 'name' => '微信名', // 字段名称 - // // 字段说明,支持修改颜色、大小 - // 'remark' => [ - // 'text' => '', - // 'color' => '#999999', - // "fontSize" => 14, - // ], - // 'required' => false, // 是否必填 true:是,false:否 - // 'unique' => false, // 内容不可重复提交 true:是,false:否 - // 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 - // 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 -// 'cache' => true, // 开启本地数据缓存 true:开启,false:关闭 - // 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 - // 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 - // ], - // "fontSize" => 14, - // "fontWeight" => "normal", - // ] - // ], +// 'FormWechatName' => [ +// 'title' => '微信名', +// 'icon' => 'iconfont iconbiaotipc', +// 'path' => 'edit-form-wechat-name', // 编辑组件属性名称 +// 'uses' => 1, // 最大添加数量 +// 'sort' => 10007, +// // 组件属性 +// 'template' => [ +// "textColor" => "#303133", // 文字颜色 +// 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) +// 'pageEndBgColor' => '', // 底部背景颜色(结束) +// 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) +// 'componentBgUrl' => '', // 组件背景图片 +// 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 +// "componentStartBgColor" => '', // 组件背景颜色(开始) +// "componentEndBgColor" => '', // 组件背景颜色(结束) +// "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) +// "topRounded" => 0, // 组件上圆角 +// "bottomRounded" => 0, // 组件下圆角 +// "elementBgColor" => '', // 元素背景颜色 +// "topElementRounded" => 0,// 元素上圆角 +// "bottomElementRounded" => 0, // 元素下圆角 +// "margin" => [ +// "top" => 10, // 上边距 +// "bottom" => 10, // 下边距 +// "both" => 10 // 左右边距 +// ], +// ], +// 'value' => [ +// // 表单的公共属性 +// 'field' => [ +// 'name' => '微信名', // 字段名称 +// // 字段说明,支持修改颜色、大小 +// 'remark' => [ +// 'text' => '', +// 'color' => '#999999', +// "fontSize" => 14, +// ], +// 'required' => false, // 是否必填 true:是,false:否 +// 'unique' => false, // 内容不可重复提交 true:是,false:否 +// 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 +// 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 +// 'cache' => true, // 开启本地数据缓存 true:开启,false:关闭 +// 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 +// 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 +// ], +// 'placeholder' => '请输入', // 提示语 +// "fontSize" => 14, +// "fontWeight" => "normal", +// ] +// ], 'FormMobile' => [ 'title' => '手机号', 'icon' => 'iconfont icona-shoujipc30', @@ -617,74 +618,84 @@ class ComponentDict "fontWeight" => "normal", ] ], - // 'FormTable' => [ - // 'title' => '表格', - // 'icon' => 'iconfont iconbiaotipc', - // 'path' => 'edit-form-table', // 编辑组件属性名称 - // 'uses' => 0, // 最大添加数量 - // 'sort' => 10011, - // // 组件属性 - // 'template' => [ - // "textColor" => "#303133", // 文字颜色 - // 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) - // 'pageEndBgColor' => '', // 底部背景颜色(结束) - // 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) - // 'componentBgUrl' => '', // 组件背景图片 - // 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 - // "componentStartBgColor" => '', // 组件背景颜色(开始) - // "componentEndBgColor" => '', // 组件背景颜色(结束) - // "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) - // "topRounded" => 0, // 组件上圆角 - // "bottomRounded" => 0, // 组件下圆角 - // "elementBgColor" => '', // 元素背景颜色 - // "topElementRounded" => 0,// 元素上圆角 - // "bottomElementRounded" => 0, // 元素下圆角 - // "margin" => [ - // "top" => 10, // 上边距 - // "bottom" => 10, // 下边距 - // "both" => 10 // 左右边距 - // ], - // ], - // 'value' => [ - // // 表单的公共属性 - // 'field' => [ - // 'name' => '表格', // 字段名称 - // // 字段说明,支持修改颜色、大小 - // 'remark' => [ - // 'text' => '', - // 'color' => '#999999', - // "fontSize" => 14, - // ], - // 'required' => false, // 是否必填 true:是,false:否 - // 'unique' => false, // 内容不可重复提交 true:是,false:否 - // 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 - // 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 -// 'cache' => true, // 开启本地数据缓存 true:开启,false:关闭 - // 'detailComponent' => '/src/app/views/diy_form/components/detail-form-table.vue', // 用于详情展示 - // 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 - // 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 - // ], - // "fontSize" => 14, - // "fontWeight" => "normal", - // // 列设置 - // 'columnList' => [ - // [ - // 'id' => '', // 唯一值,用于排序 - // 'type' => 'text', // 类型,text:文本,number:数字,radio:单选项,checkbox:多选项,todo,不同类型,结构也不一样,这个组件要在前端处理 - // 'name' => '', // 字段名称 - // 'value' => '选项1' // 字段值 - // ], - // ], - // 'autoIncrementControl' => false, // 是否开启自增(展示按钮),添加多个 - // // 填写限制(开启自增才展示) - // 'writeLimit' => [ - // 'default' => 2, // 默认展示 N 项 - // 'min' => 0, // 最少填写 N 项 - // 'max' => 0 // 最多填写 N 项 - // ], - // 'btnText' => '新增一组' - // ] - // ], +// 'FormTable' => [ +// 'title' => '表格', +// 'icon' => 'iconfont iconbiaotipc', +// 'path' => 'edit-form-table', // 编辑组件属性名称 +// 'uses' => 0, // 最大添加数量 +// 'sort' => 10011, +// // 组件属性 +// 'template' => [ +// "textColor" => "#303133", // 文字颜色 +// 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) +// 'pageEndBgColor' => '', // 底部背景颜色(结束) +// 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) +// 'componentBgUrl' => '', // 组件背景图片 +// 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 +// "componentStartBgColor" => '', // 组件背景颜色(开始) +// "componentEndBgColor" => '', // 组件背景颜色(结束) +// "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) +// "topRounded" => 0, // 组件上圆角 +// "bottomRounded" => 0, // 组件下圆角 +// "elementBgColor" => '', // 元素背景颜色 +// "topElementRounded" => 0,// 元素上圆角 +// "bottomElementRounded" => 0, // 元素下圆角 +// "margin" => [ +// "top" => 10, // 上边距 +// "bottom" => 10, // 下边距 +// "both" => 10 // 左右边距 +// ], +// ], +// 'value' => [ +// // 表单的公共属性 +// 'field' => [ +// 'name' => '表格', // 字段名称 +// // 字段说明,支持修改颜色、大小 +// 'remark' => [ +// 'text' => '', +// 'color' => '#999999', +// "fontSize" => 14, +// ], +// 'required' => false, // 是否必填 true:是,false:否 +// 'unique' => false, // 内容不可重复提交 true:是,false:否 +// 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 +// 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 +// 'cache' => true, // 开启本地数据缓存 true:开启,false:关闭 +// 'detailComponent' => '/src/app/views/diy_form/components/detail-form-table.vue', // 用于详情展示 +// 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 +// 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 +// ], +// "fontSize" => 14, +// "fontWeight" => "normal", +// // 列设置 +// 'columnList' => [ +// [ +// 'id' => '', // 唯一值,用于排序 +// 'type' => 'text', // 类型,text:文本,number:数字,radio:单选项,checkbox:多选项,todo,不同类型,结构也不一样,这个组件要在前端处理 +// 'name' => '', // 字段名称 +// 'value' => '选项1' // 字段值 +// ], +// ], +// 'autoIncrementControl' => false, // 是否开启自增(展示按钮),添加多个 +// // 填写限制(开启自增才展示) +// 'writeLimit' => [ +// 'default' => 2, // 默认展示 N 项 +// 'min' => 0, // 最少填写 N 项 +// 'max' => 0 // 最多填写 N 项 +// ], +// 'btnText' => '新增一组' +// ], +// // 渲染值 +// 'render' => function($data) { +// // todo 处理业务数据 +// return ''; +// }, +// // 转换类型 +// 'convert' => function($data) { +// // todo 处理业务数据 +// return $data; +// } +// ], 'FormDate' => [ 'title' => '日期', 'icon' => 'iconfont icona-riqipc30', @@ -997,109 +1008,109 @@ class ComponentDict return $data; } ], - // 'FormLocation' => [ - // 'title' => '定位', - // 'icon' => 'iconfont iconbiaotipc', - // 'path' => 'edit-form-location', // 编辑组件属性名称 - // 'uses' => 1, // 最大添加数量 - // 'sort' => 10016, - // // 组件属性 - // 'template' => [ - // "textColor" => "#303133", // 文字颜色 - // 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) - // 'pageEndBgColor' => '', // 底部背景颜色(结束) - // 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) - // 'componentBgUrl' => '', // 组件背景图片 - // 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 - // "componentStartBgColor" => '', // 组件背景颜色(开始) - // "componentEndBgColor" => '', // 组件背景颜色(结束) - // "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) - // "topRounded" => 0, // 组件上圆角 - // "bottomRounded" => 0, // 组件下圆角 - // "elementBgColor" => '', // 元素背景颜色 - // "topElementRounded" => 0,// 元素上圆角 - // "bottomElementRounded" => 0, // 元素下圆角 - // "margin" => [ - // "top" => 10, // 上边距 - // "bottom" => 10, // 下边距 - // "both" => 10 // 左右边距 - // ], - // ], - // 'value' => [ - // // 表单的公共属性 - // 'field' => [ - // 'name' => '定位', // 字段名称 - // // 字段说明,支持修改颜色、大小 - // 'remark' => [ - // 'text' => '', - // 'color' => '#999999', - // "fontSize" => 14, - // ], - // 'required' => false, // 是否必填 true:是,false:否 - // 'unique' => false, // 内容不可重复提交 true:是,false:否 - // 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 - // 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 -// 'cache' => true, // 开启本地数据缓存 true:开启,false:关闭 - // 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 - // 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 - // ], - // 'placeholder' => '请输入', // 提示语 - // "fontSize" => 14, - // "fontWeight" => "normal", - // 'mode' => 'authorized_wechat_location', // 获取方式,authorized_wechat_location:授权微信定位,open_choose_location:手动选择定位 - // ] - // ], - // 'FormAddress' => [ - // 'title' => '地址', - // 'icon' => 'iconfont iconbiaotipc', - // 'path' => 'edit-form-address', // 编辑组件属性名称 - // 'uses' => 0, // 最大添加数量 - // 'sort' => 10017, - // // 组件属性 - // 'template' => [ - // "textColor" => "#303133", // 文字颜色 - // 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) - // 'pageEndBgColor' => '', // 底部背景颜色(结束) - // 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) - // 'componentBgUrl' => '', // 组件背景图片 - // 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 - // "componentStartBgColor" => '', // 组件背景颜色(开始) - // "componentEndBgColor" => '', // 组件背景颜色(结束) - // "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) - // "topRounded" => 0, // 组件上圆角 - // "bottomRounded" => 0, // 组件下圆角 - // "elementBgColor" => '', // 元素背景颜色 - // "topElementRounded" => 0,// 元素上圆角 - // "bottomElementRounded" => 0, // 元素下圆角 - // "margin" => [ - // "top" => 10, // 上边距 - // "bottom" => 10, // 下边距 - // "both" => 10 // 左右边距 - // ], - // ], - // 'value' => [ - // // 表单的公共属性 - // 'field' => [ - // 'name' => '地址', // 字段名称 - // // 字段说明,支持修改颜色、大小 - // 'remark' => [ - // 'text' => '', - // 'color' => '#999999', - // "fontSize" => 14, - // ], - // 'required' => false, // 是否必填 true:是,false:否 - // 'unique' => false, // 内容不可重复提交 true:是,false:否 - // 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 - // 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 - // 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 todo 设置默认省/市/区/街道 - // 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 - // ], - // 'placeholder' => '请输入', // 提示语 - // "fontSize" => 14, - // "fontWeight" => "normal", - // 'addressFormat' => 'province/city/district/address', // 地址格式 - // ] - // ], +// 'FormLocation' => [ +// 'title' => '定位', +// 'icon' => 'iconfont iconbiaotipc', +// 'path' => 'edit-form-location', // 编辑组件属性名称 +// 'uses' => 1, // 最大添加数量 +// 'sort' => 10016, +// // 组件属性 +// 'template' => [ +// "textColor" => "#303133", // 文字颜色 +// 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) +// 'pageEndBgColor' => '', // 底部背景颜色(结束) +// 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) +// 'componentBgUrl' => '', // 组件背景图片 +// 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 +// "componentStartBgColor" => '', // 组件背景颜色(开始) +// "componentEndBgColor" => '', // 组件背景颜色(结束) +// "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) +// "topRounded" => 0, // 组件上圆角 +// "bottomRounded" => 0, // 组件下圆角 +// "elementBgColor" => '', // 元素背景颜色 +// "topElementRounded" => 0,// 元素上圆角 +// "bottomElementRounded" => 0, // 元素下圆角 +// "margin" => [ +// "top" => 10, // 上边距 +// "bottom" => 10, // 下边距 +// "both" => 10 // 左右边距 +// ], +// ], +// 'value' => [ +// // 表单的公共属性 +// 'field' => [ +// 'name' => '定位', // 字段名称 +// // 字段说明,支持修改颜色、大小 +// 'remark' => [ +// 'text' => '', +// 'color' => '#999999', +// "fontSize" => 14, +// ], +// 'required' => false, // 是否必填 true:是,false:否 +// 'unique' => false, // 内容不可重复提交 true:是,false:否 +// 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 +// 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 +// 'cache' => true, // 开启本地数据缓存 true:开启,false:关闭 +// 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 +// 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 +// ], +// 'placeholder' => '请输入', // 提示语 +// "fontSize" => 14, +// "fontWeight" => "normal", +// 'mode' => 'authorized_wechat_location', // 获取方式,authorized_wechat_location:授权微信定位,open_choose_location:手动选择定位 +// ] +// ], +// 'FormAddress' => [ +// 'title' => '地址', +// 'icon' => 'iconfont iconbiaotipc', +// 'path' => 'edit-form-address', // 编辑组件属性名称 +// 'uses' => 0, // 最大添加数量 +// 'sort' => 10017, +// // 组件属性 +// 'template' => [ +// "textColor" => "#303133", // 文字颜色 +// 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) +// 'pageEndBgColor' => '', // 底部背景颜色(结束) +// 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) +// 'componentBgUrl' => '', // 组件背景图片 +// 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 +// "componentStartBgColor" => '', // 组件背景颜色(开始) +// "componentEndBgColor" => '', // 组件背景颜色(结束) +// "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) +// "topRounded" => 0, // 组件上圆角 +// "bottomRounded" => 0, // 组件下圆角 +// "elementBgColor" => '', // 元素背景颜色 +// "topElementRounded" => 0,// 元素上圆角 +// "bottomElementRounded" => 0, // 元素下圆角 +// "margin" => [ +// "top" => 10, // 上边距 +// "bottom" => 10, // 下边距 +// "both" => 10 // 左右边距 +// ], +// ], +// 'value' => [ +// // 表单的公共属性 +// 'field' => [ +// 'name' => '地址', // 字段名称 +// // 字段说明,支持修改颜色、大小 +// 'remark' => [ +// 'text' => '', +// 'color' => '#999999', +// "fontSize" => 14, +// ], +// 'required' => false, // 是否必填 true:是,false:否 +// 'unique' => false, // 内容不可重复提交 true:是,false:否 +// 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 +// 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 +// 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 todo 设置默认省/市/区/街道 +// 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 +// ], +// 'placeholder' => '请输入', // 提示语 +// "fontSize" => 14, +// "fontWeight" => "normal", +// 'addressFormat' => 'province/city/district/address', // 地址格式 +// ] +// ], 'FormImage' => [ 'title' => '图片', 'icon' => 'iconfont icona-tupianpc30', @@ -1181,115 +1192,115 @@ class ComponentDict return $data; } ], - // 'FormVideo' => [ - // 'title' => '视频', - // 'icon' => 'iconfont iconbiaotipc', - // 'path' => 'edit-form-video', // 编辑组件属性名称 - // 'uses' => 0, // 最大添加数量 - // 'sort' => 10019, - // // 组件属性 - // 'template' => [ - // "textColor" => "#303133", // 文字颜色 - // 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) - // 'pageEndBgColor' => '', // 底部背景颜色(结束) - // 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) - // 'componentBgUrl' => '', // 组件背景图片 - // 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 - // "componentStartBgColor" => '', // 组件背景颜色(开始) - // "componentEndBgColor" => '', // 组件背景颜色(结束) - // "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) - // "topRounded" => 0, // 组件上圆角 - // "bottomRounded" => 0, // 组件下圆角 - // "elementBgColor" => '', // 元素背景颜色 - // "topElementRounded" => 0,// 元素上圆角 - // "bottomElementRounded" => 0, // 元素下圆角 - // "margin" => [ - // "top" => 10, // 上边距 - // "bottom" => 10, // 下边距 - // "both" => 10 // 左右边距 - // ], - // ], - // 'value' => [ - // // 表单的公共属性 - // 'field' => [ - // 'name' => '视频', // 字段名称 - // // 字段说明,支持修改颜色、大小 - // 'remark' => [ - // 'text' => '', - // 'color' => '#999999', - // "fontSize" => 14, - // ], - // 'required' => false, // 是否必填 true:是,false:否 - // 'unique' => false, // 内容不可重复提交 true:是,false:否 - // 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 - // 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 -// 'cache' => true, // 开启本地数据缓存 true:开启,false:关闭 - // 'detailComponent' => '/src/app/views/diy_form/components/detail-form-video.vue', // 用于详情展示 - // 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 - // 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 - // ], - // "fontSize" => 14, - // "fontWeight" => "normal", - // /** - // * 上传方式 - // * shoot_and_album:拍摄和相册 - // * shoot_only:只允许拍摄 - // */ - // 'uploadMode' => 'shoot_and_album', // 上传方式 - // ] - // ], - // 'FormFile' => [ - // 'title' => '文件', - // 'icon' => 'iconfont iconbiaotipc', - // 'path' => 'edit-form-file', // 编辑组件属性名称 - // 'uses' => 0, // 最大添加数量 - // 'sort' => 10020, - // // 组件属性 - // 'template' => [ - // "textColor" => "#303133", // 文字颜色 - // 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) - // 'pageEndBgColor' => '', // 底部背景颜色(结束) - // 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) - // 'componentBgUrl' => '', // 组件背景图片 - // 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 - // "componentStartBgColor" => '', // 组件背景颜色(开始) - // "componentEndBgColor" => '', // 组件背景颜色(结束) - // "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) - // "topRounded" => 0, // 组件上圆角 - // "bottomRounded" => 0, // 组件下圆角 - // "elementBgColor" => '', // 元素背景颜色 - // "topElementRounded" => 0,// 元素上圆角 - // "bottomElementRounded" => 0, // 元素下圆角 - // "margin" => [ - // "top" => 10, // 上边距 - // "bottom" => 10, // 下边距 - // "both" => 10 // 左右边距 - // ], - // ], - // 'value' => [ - // // 表单的公共属性 - // 'field' => [ - // 'name' => '文件', // 字段名称 - // // 字段说明,支持修改颜色、大小 - // 'remark' => [ - // 'text' => '', - // 'color' => '#999999', - // "fontSize" => 14, - // ], - // 'required' => false, // 是否必填 true:是,false:否 - // 'unique' => false, // 内容不可重复提交 true:是,false:否 - // 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 - // 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 -// 'cache' => true, // 开启本地数据缓存 true:开启,false:关闭 - // 'detailComponent' => '/src/app/views/diy_form/components/detail-form-file.vue', // 用于详情展示 - // 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 - // 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 - // ], - // "fontSize" => 14, - // "fontWeight" => "normal", - // 'limitUploadSize' => 30720, // 限制上传大小,30MB - // ] - // ], +// 'FormVideo' => [ +// 'title' => '视频', +// 'icon' => 'iconfont iconbiaotipc', +// 'path' => 'edit-form-video', // 编辑组件属性名称 +// 'uses' => 0, // 最大添加数量 +// 'sort' => 10019, +// // 组件属性 +// 'template' => [ +// "textColor" => "#303133", // 文字颜色 +// 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) +// 'pageEndBgColor' => '', // 底部背景颜色(结束) +// 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) +// 'componentBgUrl' => '', // 组件背景图片 +// 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 +// "componentStartBgColor" => '', // 组件背景颜色(开始) +// "componentEndBgColor" => '', // 组件背景颜色(结束) +// "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) +// "topRounded" => 0, // 组件上圆角 +// "bottomRounded" => 0, // 组件下圆角 +// "elementBgColor" => '', // 元素背景颜色 +// "topElementRounded" => 0,// 元素上圆角 +// "bottomElementRounded" => 0, // 元素下圆角 +// "margin" => [ +// "top" => 10, // 上边距 +// "bottom" => 10, // 下边距 +// "both" => 10 // 左右边距 +// ], +// ], +// 'value' => [ +// // 表单的公共属性 +// 'field' => [ +// 'name' => '视频', // 字段名称 +// // 字段说明,支持修改颜色、大小 +// 'remark' => [ +// 'text' => '', +// 'color' => '#999999', +// "fontSize" => 14, +// ], +// 'required' => false, // 是否必填 true:是,false:否 +// 'unique' => false, // 内容不可重复提交 true:是,false:否 +// 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 +// 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 +// 'cache' => true, // 开启本地数据缓存 true:开启,false:关闭 +// 'detailComponent' => '/src/app/views/diy_form/components/detail-form-video.vue', // 用于详情展示 +// 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 +// 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 +// ], +// "fontSize" => 14, +// "fontWeight" => "normal", +// /** +// * 上传方式 +// * shoot_and_album:拍摄和相册 +// * shoot_only:只允许拍摄 +// */ +// 'uploadMode' => 'shoot_and_album', // 上传方式 +// ] +// ], +// 'FormFile' => [ +// 'title' => '文件', +// 'icon' => 'iconfont iconbiaotipc', +// 'path' => 'edit-form-file', // 编辑组件属性名称 +// 'uses' => 0, // 最大添加数量 +// 'sort' => 10020, +// // 组件属性 +// 'template' => [ +// "textColor" => "#303133", // 文字颜色 +// 'pageStartBgColor' => '#FFFFFF', // 底部背景颜色(开始) +// 'pageEndBgColor' => '', // 底部背景颜色(结束) +// 'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right) +// 'componentBgUrl' => '', // 组件背景图片 +// 'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10 +// "componentStartBgColor" => '', // 组件背景颜色(开始) +// "componentEndBgColor" => '', // 组件背景颜色(结束) +// "componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right) +// "topRounded" => 0, // 组件上圆角 +// "bottomRounded" => 0, // 组件下圆角 +// "elementBgColor" => '', // 元素背景颜色 +// "topElementRounded" => 0,// 元素上圆角 +// "bottomElementRounded" => 0, // 元素下圆角 +// "margin" => [ +// "top" => 10, // 上边距 +// "bottom" => 10, // 下边距 +// "both" => 10 // 左右边距 +// ], +// ], +// 'value' => [ +// // 表单的公共属性 +// 'field' => [ +// 'name' => '文件', // 字段名称 +// // 字段说明,支持修改颜色、大小 +// 'remark' => [ +// 'text' => '', +// 'color' => '#999999', +// "fontSize" => 14, +// ], +// 'required' => false, // 是否必填 true:是,false:否 +// 'unique' => false, // 内容不可重复提交 true:是,false:否 +// 'autofill' => false, // 自动填充上次填写的内容 true:开启,false:关闭 +// 'privacyProtection' => false, // 隐私保护 true:开启,false:关闭,隐藏逻辑各组件自行处理 +// 'cache' => true, // 开启本地数据缓存 true:开启,false:关闭 +// 'detailComponent' => '/src/app/views/diy_form/components/detail-form-file.vue', // 用于详情展示 +// 'default' => '', // 默认值 存储数据类型不同,各组件自行处理 +// 'value' => '', // 字段值 存储数据类型不同,各组件自行处理 +// ], +// "fontSize" => 14, +// "fontWeight" => "normal", +// 'limitUploadSize' => 30720, // 限制上传大小,30MB +// ] +// ], ], ], ]; diff --git a/niucloud/app/dict/diy_form/TemplateDict.php b/niucloud/app/dict/diy_form/TemplateDict.php index 1a307d6d3..f294ed29e 100644 --- a/niucloud/app/dict/diy_form/TemplateDict.php +++ b/niucloud/app/dict/diy_form/TemplateDict.php @@ -381,7 +381,7 @@ class TemplateDict "unique" => false, "autofill" => false, "privacyProtection" => false, - 'cache' => false, + 'cache' => true, "default" => [ "date" => "", "timestamp" => 0 @@ -576,7 +576,7 @@ class TemplateDict "unique" => false, "autofill" => false, "privacyProtection" => false, - 'cache' => false, + 'cache' => true, "default" => [ "start" => [ "date" => "", diff --git a/niucloud/app/dict/menu/admin.php b/niucloud/app/dict/menu/admin.php index 2c6de53e0..02d5cb078 100644 --- a/niucloud/app/dict/menu/admin.php +++ b/niucloud/app/dict/menu/admin.php @@ -1140,6 +1140,20 @@ return [ 'status' => '1', 'is_show' => '1', ], + [ + 'menu_name' => '编辑核销员', + 'menu_key' => 'edit_verifier', + 'menu_short_name' => '编辑核销员', + 'menu_type' => '2', + 'icon' => '', + 'api_url' => 'verify/verifier/', + 'router_path' => '', + 'view_path' => '', + 'methods' => 'post', + 'sort' => '100', + 'status' => '1', + 'is_show' => '1', + ], [ 'menu_name' => '删除核销员', 'menu_key' => 'delete_verifier', @@ -2437,122 +2451,6 @@ return [ ], ], ], - [ - 'menu_name' => '小票打印', - 'menu_key' => 'printer_management', - 'menu_short_name' => '小票打印', - 'menu_type' => '1', - 'icon' => 'element FolderChecked', - 'api_url' => 'printer', - 'router_path' => 'printer/list', - 'view_path' => 'printer/list', - 'methods' => 'get', - 'sort' => '30', - 'status' => '1', - 'is_show' => '1', - 'children' => [ - [ - 'menu_name' => '删除打印机', - 'menu_key' => 'delete_printer', - 'menu_short_name' => '删除打印机', - 'menu_type' => '2', - 'icon' => '', - 'api_url' => 'printer/', - 'router_path' => '', - 'view_path' => '', - 'methods' => 'delete', - 'sort' => '100', - 'status' => '1', - 'is_show' => '1', - ] - ] - ], - [ - 'menu_name' => '添加打印机', - 'menu_key' => 'printer_add', - 'menu_short_name' => '添加打印机', - 'menu_type' => '1', - 'icon' => '', - 'api_url' => 'printer', - 'router_path' => 'printer/add', - 'view_path' => 'printer/edit', - 'methods' => 'post', - 'sort' => '0', - 'status' => '1', - 'is_show' => '0', - ], - [ - 'menu_name' => '编辑打印机', - 'menu_key' => 'printer_edit', - 'menu_short_name' => '添加打印机', - 'menu_type' => '1', - 'icon' => '', - 'api_url' => 'printer/', - 'router_path' => 'printer/edit', - 'view_path' => 'printer/edit', - 'methods' => 'put', - 'sort' => '0', - 'status' => '1', - 'is_show' => '0', - ], - [ - 'menu_name' => '小票打印模板', - 'menu_key' => 'printer_template_management', - 'menu_short_name' => '小票打印模板', - 'menu_type' => '1', - 'icon' => 'element FolderChecked', - 'api_url' => 'printer/template', - 'router_path' => 'printer/template/list', - 'view_path' => 'printer/template_list', - 'methods' => 'get', - 'sort' => '96', - 'status' => '1', - 'is_show' => '0', - 'children' => [ - [ - 'menu_name' => '删除打印模板', - 'menu_key' => 'delete_printer_template', - 'menu_short_name' => '删除打印模板', - 'menu_type' => '2', - 'icon' => '', - 'api_url' => 'printer/template/', - 'router_path' => '', - 'view_path' => '', - 'methods' => 'delete', - 'sort' => '100', - 'status' => '1', - 'is_show' => '1', - ] - ] - ], - [ - 'menu_name' => '添加打印模板', - 'menu_key' => 'printer_template_add', - 'menu_short_name' => '添加打印模板', - 'menu_type' => '1', - 'icon' => '', - 'api_url' => 'printer/template', - 'router_path' => 'printer/template/add', - 'view_path' => 'printer/template_edit', - 'methods' => 'post', - 'sort' => '0', - 'status' => '1', - 'is_show' => '0', - ], - [ - 'menu_name' => '编辑打印模板', - 'menu_key' => 'printer_template_edit', - 'menu_short_name' => '编辑打印模板', - 'menu_type' => '1', - 'icon' => '', - 'api_url' => 'printer/template/', - 'router_path' => 'printer/template/edit', - 'view_path' => 'printer/template_edit', - 'methods' => 'put', - 'sort' => '0', - 'status' => '1', - 'is_show' => '0', - ], [ 'menu_name' => '系统工具', 'menu_key' => 'setting_tool', @@ -2699,36 +2597,6 @@ return [ ] ] ], - [ - 'menu_name' => '数据导出', - 'menu_key' => 'setting_export', - 'menu_short_name' => '数据导出', - 'menu_type' => '1', - 'icon' => 'element FolderChecked', - 'api_url' => 'sys/export', - 'router_path' => 'setting/export', - 'view_path' => 'setting/export', - 'methods' => 'get', - 'sort' => '98', - 'status' => '1', - 'is_show' => '1', - 'children' => [ - [ - 'menu_name' => '删除报表', - 'menu_key' => 'delete_export', - 'menu_short_name' => '删除报表', - 'menu_type' => '2', - 'icon' => '', - 'api_url' => 'sys/export/', - 'router_path' => '', - 'view_path' => '', - 'methods' => 'delete', - 'sort' => '100', - 'status' => '1', - 'is_show' => '1', - ] - ] - ], ] ], @@ -2860,7 +2728,190 @@ return [ ] ], [ - 'menu_name' => '开发', + 'menu_name' => '数据导出', + 'menu_key' => 'setting_export', + 'menu_short_name' => '数据导出', + 'menu_type' => '0', + 'icon' => 'element Files', + 'api_url' => '', + 'router_path' => '', + 'view_path' => '', + 'methods' => '', + 'sort' => '0', + 'status' => '1', + 'is_show' => '1', + 'menu_attr' => 'setting_export', + 'children' => [ + [ + 'menu_name' => '数据导出列表', + 'menu_key' => 'setting_export_list', + 'menu_short_name' => '数据导出列表', + 'menu_type' => '1', + 'icon' => 'element FolderChecked', + 'api_url' => 'sys/export', + 'router_path' => 'setting/export', + 'view_path' => 'setting/export', + 'methods' => 'get', + 'sort' => '98', + 'status' => '1', + 'is_show' => '1', + 'menu_attr' => 'setting_export', + 'children' => [ + [ + 'menu_name' => '删除报表', + 'menu_key' => 'delete_export', + 'menu_short_name' => '删除报表', + 'menu_type' => '2', + 'icon' => '', + 'api_url' => 'sys/export/', + 'router_path' => '', + 'view_path' => '', + 'methods' => 'delete', + 'sort' => '100', + 'status' => '1', + 'is_show' => '1', + 'menu_attr' => 'setting_export', + ] + ] + ], + ] + ], + [ + 'menu_name' => '打印管理', + 'menu_key' => 'printer_management', + 'menu_short_name' => '打印管理', + 'menu_type' => '0', + 'icon' => 'element Files', + 'api_url' => '', + 'router_path' => '', + 'view_path' => '', + 'methods' => '', + 'sort' => '0', + 'status' => '1', + 'is_show' => '1', + 'menu_attr' => 'printer_management', + 'children' => [ + [ + 'menu_name' => '小票打印', + 'menu_key' => 'printer_management_list', + 'menu_short_name' => '小票打印', + 'menu_type' => '1', + 'icon' => 'element FolderChecked', + 'api_url' => 'printer', + 'router_path' => 'printer/list', + 'view_path' => 'printer/list', + 'methods' => 'get', + 'sort' => '30', + 'status' => '1', + 'is_show' => '1', + 'menu_attr' => 'printer_management', + 'children' => [ + [ + 'menu_name' => '删除打印机', + 'menu_key' => 'delete_printer', + 'menu_short_name' => '删除打印机', + 'menu_type' => '2', + 'icon' => '', + 'api_url' => 'printer/', + 'router_path' => '', + 'view_path' => '', + 'methods' => 'delete', + 'sort' => '100', + 'status' => '1', + 'is_show' => '1', + ] + ] + ], + [ + 'menu_name' => '添加打印机', + 'menu_key' => 'printer_add', + 'menu_short_name' => '添加打印机', + 'menu_type' => '1', + 'icon' => '', + 'api_url' => 'printer', + 'router_path' => 'printer/add', + 'view_path' => 'printer/edit', + 'methods' => 'post', + 'sort' => '0', + 'status' => '1', + 'is_show' => '0', + ], + [ + 'menu_name' => '编辑打印机', + 'menu_key' => 'printer_edit', + 'menu_short_name' => '添加打印机', + 'menu_type' => '1', + 'icon' => '', + 'api_url' => 'printer/', + 'router_path' => 'printer/edit', + 'view_path' => 'printer/edit', + 'methods' => 'put', + 'sort' => '0', + 'status' => '1', + 'is_show' => '0', + ], + [ + 'menu_name' => '小票打印模板', + 'menu_key' => 'printer_template_management', + 'menu_short_name' => '小票打印模板', + 'menu_type' => '1', + 'icon' => 'element FolderChecked', + 'api_url' => 'printer/template', + 'router_path' => 'printer/template/list', + 'view_path' => 'printer/template_list', + 'methods' => 'get', + 'sort' => '96', + 'status' => '1', + 'is_show' => '0', + 'children' => [ + [ + 'menu_name' => '删除打印模板', + 'menu_key' => 'delete_printer_template', + 'menu_short_name' => '删除打印模板', + 'menu_type' => '2', + 'icon' => '', + 'api_url' => 'printer/template/', + 'router_path' => '', + 'view_path' => '', + 'methods' => 'delete', + 'sort' => '100', + 'status' => '1', + 'is_show' => '1', + ] + ] + ], + [ + 'menu_name' => '添加打印模板', + 'menu_key' => 'printer_template_add', + 'menu_short_name' => '添加打印模板', + 'menu_type' => '1', + 'icon' => '', + 'api_url' => 'printer/template', + 'router_path' => 'printer/template/add', + 'view_path' => 'printer/template_edit', + 'methods' => 'post', + 'sort' => '0', + 'status' => '1', + 'is_show' => '0', + ], + [ + 'menu_name' => '编辑打印模板', + 'menu_key' => 'printer_template_edit', + 'menu_short_name' => '编辑打印模板', + 'menu_type' => '1', + 'icon' => '', + 'api_url' => 'printer/template/', + 'router_path' => 'printer/template/edit', + 'view_path' => 'printer/template_edit', + 'methods' => 'put', + 'sort' => '0', + 'status' => '1', + 'is_show' => '0', + ], + ] + ], + [ + 'menu_name' => '开发管理', 'menu_key' => 'tool', 'menu_short_name' => '开发', 'parent_key' => '', @@ -2984,7 +3035,7 @@ return [ 'router_path' => 'tools/addon', 'view_path' => 'tools/addon/index', 'methods' => '', - 'sort' => '110', + 'sort' => '119', 'status' => '1', 'is_show' => '1', 'children' => [ @@ -3028,7 +3079,21 @@ return [ 'router_path' => 'tools/code', 'view_path' => 'tools/code/index', 'methods' => 'get', - 'sort' => '100', + 'sort' => '118', + 'status' => '1', + 'is_show' => '1', + ], + [ + 'menu_name' => '更新缓存', + 'menu_key' => 'update_cache', + 'menu_short_name' => '更新缓存', + 'menu_type' => '1', + 'icon' => 'nc-iconfont nc-icon-qingliV6xx', + 'api_url' => 'sys/schema/clear', + 'router_path' => 'tools/update_cache', + 'view_path' => 'tools/updatecache', + 'methods' => 'post', + 'sort' => '117', 'status' => '1', 'is_show' => '1', ], @@ -3042,7 +3107,7 @@ return [ 'router_path' => 'tools/code/edit', 'view_path' => 'tools/code/edit', 'methods' => '', - 'sort' => '99', + 'sort' => '100', 'status' => '1', 'is_show' => '0', 'children' => [ @@ -3114,7 +3179,7 @@ return [ 'router_path' => 'tools/addon_edit', 'view_path' => 'tools/addon/edit', 'methods' => 'get', - 'sort' => '90', + 'sort' => '100', 'status' => '1', 'is_show' => '0', 'children' => [ @@ -3148,20 +3213,6 @@ return [ ], ] ], - [ - 'menu_name' => '更新缓存', - 'menu_key' => 'update_cache', - 'menu_short_name' => '更新缓存', - 'menu_type' => '1', - 'icon' => 'nc-iconfont nc-icon-qingliV6xx', - 'api_url' => 'sys/schema/clear', - 'router_path' => 'tools/update_cache', - 'view_path' => 'tools/updatecache', - 'methods' => 'post', - 'sort' => '98', - 'status' => '1', - 'is_show' => '1', - ], [ 'menu_name' => '数据字典', 'menu_key' => 'sys_dict_dict_dict_list', @@ -3172,7 +3223,7 @@ return [ 'router_path' => 'tools/list', 'view_path' => 'dict/list', 'methods' => 'get', - 'sort' => '90', + 'sort' => '106', 'status' => '1', 'is_show' => '1', 'children' => [ @@ -3230,7 +3281,7 @@ return [ 'router_path' => 'tools/detection', 'view_path' => 'tools/detection', 'methods' => '', - 'sort' => '50', + 'sort' => '105', 'status' => '1', 'is_show' => '1', ], @@ -3244,7 +3295,7 @@ return [ 'router_path' => 'tools/menu', 'view_path' => 'auth/menu', 'methods' => 'get', - 'sort' => '48', + 'sort' => '104', 'status' => '1', 'is_show' => '1', 'children' => [ @@ -3316,7 +3367,7 @@ return [ 'router_path' => 'tools/schedule', 'view_path' => 'tools/schedule', 'methods' => '', - 'sort' => '40', + 'sort' => '103', 'status' => '1', 'is_show' => '1', 'children' => [ @@ -3388,7 +3439,7 @@ return [ 'router_path' => 'tools/schedule_log', 'view_path' => 'tools/schedule_log', 'methods' => '', - 'sort' => '40', + 'sort' => '100', 'status' => '1', 'is_show' => '0' ], @@ -3402,24 +3453,10 @@ return [ 'router_path' => 'tools/authorize', 'view_path' => 'app/authorize', 'methods' => '', - 'sort' => '30', + 'sort' => '102', 'status' => '1', 'is_show' => '1', 'children' => [ - [ - 'menu_name' => '系统升级', - 'menu_key' => 'system_upgrade', - 'menu_short_name' => '系统升级', - 'menu_type' => '2', - 'icon' => '', - 'api_url' => 'upgrade', - 'router_path' => '', - 'view_path' => '', - 'methods' => 'post', - 'sort' => '100', - 'status' => '1', - 'is_show' => '1', - ], [ 'menu_name' => '绑定授权信息', 'menu_key' => 'bind_app_auth', @@ -3436,6 +3473,62 @@ return [ ] ] ], + [ + 'menu_name' => '系统更新', + 'menu_key' => 'system_upgrade', + 'menu_short_name' => '系统更新', + 'menu_type' => '1', + 'icon' => 'iconfont iconxitonggengxin', + 'api_url' => '', + 'router_path' => 'tools/upgrade', + 'view_path' => 'app/upgrade', + 'methods' => '', + 'sort' => '101', + 'status' => '1', + 'is_show' => '1', + ], + [ + 'menu_name' => '升级记录', + 'menu_key' => 'upgrade_records', + 'menu_short_name' => '升级记录', + 'menu_type' => '1', + 'icon' => 'iconfont iconshengjijilu', + 'api_url' => 'upgrade/records', + 'router_path' => 'tools/upgrade_records', + 'view_path' => 'tools/upgrade_records', + 'methods' => 'post', + 'sort' => '100', + 'status' => '1', + 'is_show' => '1', + ], + [ + 'menu_name' => '备份记录', + 'menu_key' => 'backup_records', + 'menu_short_name' => '备份记录', + 'menu_type' => '1', + 'icon' => 'iconfont iconbeifenjiluV6xx', + 'api_url' => 'backup/records', + 'router_path' => 'tools/backup_records', + 'view_path' => 'tools/backup_records', + 'methods' => 'post', + 'sort' => '99', + 'status' => '1', + 'is_show' => '1', + ], + [ + 'menu_name' => '云编译', + 'menu_key' => 'cloud_compile', + 'menu_short_name' => '云编译', + 'menu_type' => '1', + 'icon' => 'iconfont iconyun2', + 'api_url' => '', + 'router_path' => 'tools/cloud_compile', + 'view_path' => 'tools/cloud_compile', + 'methods' => 'post', + 'sort' => '98', + 'status' => '1', + 'is_show' => '1', + ], [ 'menu_name' => '开发者key', 'menu_key' => 'developer_token', @@ -3446,7 +3539,7 @@ return [ 'router_path' => 'tools/developer_token', 'view_path' => 'setting/developer_token', 'methods' => 'get', - 'sort' => '20', + 'sort' => '97', 'status' => '1', 'is_show' => '1', 'children' => [ diff --git a/niucloud/app/dict/schedule/schedule.php b/niucloud/app/dict/schedule/schedule.php index d6822344a..8723cc0fd 100644 --- a/niucloud/app/dict/schedule/schedule.php +++ b/niucloud/app/dict/schedule/schedule.php @@ -12,6 +12,19 @@ return [ 'class' => '', 'function' => '' ], + [ + 'key' => 'auto_clear_schedule_log', + 'name' => '定时清理计划任务日志表', + 'desc' => '', + 'time' => [ + 'type' => 'day', + 'day' => 1, + 'hour' => 1, + 'min' => 1 + ], + 'class' => 'app\job\schedule\AutoClearScheduleLog', + 'function' => '' + ], [ 'key' => 'transfer_check_finish', 'name' => '检验在线转账是否处理完毕', @@ -22,5 +35,18 @@ return [ ], 'class' => 'app\job\transfer\schedule\CheckFinish', 'function' => '' - ] + ], + [ + 'key' => 'auto_clear_upgrade_records', + 'name' => '定时清理升级/备份记录表', + 'desc' => '', + 'time' => [ + 'type' => 'day', + 'day' => 1, + 'hour' => 1, + 'min' => 1 + ], + 'class' => 'app\job\upgrade\AutoClearUpgradeRecords', + 'function' => '' + ], ]; diff --git a/niucloud/app/dict/sys/BackupDict.php b/niucloud/app/dict/sys/BackupDict.php new file mode 100644 index 000000000..ab45262b8 --- /dev/null +++ b/niucloud/app/dict/sys/BackupDict.php @@ -0,0 +1,34 @@ + get_lang('dict_backup.ready'), + self::STATUS_COMPLETE => get_lang('dict_backup.complete'), + self::STATUS_FAIL => get_lang('dict_backup.fail'), + ]; + return $status_list[ $status ] ?? ''; + } +} diff --git a/niucloud/app/dict/sys/CloudDict.php b/niucloud/app/dict/sys/CloudDict.php index f531a14ed..65676ac3a 100644 --- a/niucloud/app/dict/sys/CloudDict.php +++ b/niucloud/app/dict/sys/CloudDict.php @@ -28,7 +28,9 @@ class CloudDict const APPLET_AUDIT_FAIL = -2; - public static function getAppletUploadSatus($status) { + const APPLET_AUDIT_UNDO = -3; + + public static function getAppletUploadStatus($status) { $status_list = [ self::APPLET_UPLOADING => get_lang('dict_cloud_applet.uploading'), self::APPLET_UPLOAD_SUCCESS => get_lang('dict_cloud_applet.upload_success'), @@ -36,6 +38,7 @@ class CloudDict self::APPLET_AUDITING => get_lang('dict_cloud_applet.auditing'), self::APPLET_AUDIT_FAIL => get_lang('dict_cloud_applet.audit_fail'), self::APPLET_PUBLISHED => get_lang('dict_cloud_applet.published'), + self::APPLET_AUDIT_UNDO => get_lang('dict_cloud_applet.undo') ]; return $status_list[$status] ?? ''; } diff --git a/niucloud/app/dict/sys/UpgradeDict.php b/niucloud/app/dict/sys/UpgradeDict.php new file mode 100644 index 000000000..3b201a1c4 --- /dev/null +++ b/niucloud/app/dict/sys/UpgradeDict.php @@ -0,0 +1,40 @@ + get_lang('dict_upgrade.ready'), + self::STATUS_COMPLETE => get_lang('dict_upgrade.complete'), + self::STATUS_FAIL => get_lang('dict_upgrade.fail'), + self::STATUS_CANCEL => get_lang('dict_upgrade.cancel'), + ]; + return $status_list[ $status ] ?? ''; + } +} diff --git a/niucloud/app/install/source/database.sql b/niucloud/app/install/source/database.sql index a46cdb008..bbe59e119 100644 --- a/niucloud/app/install/source/database.sql +++ b/niucloud/app/install/source/database.sql @@ -153,7 +153,7 @@ CREATE TABLE `diy_form_submit_config` ( `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', `form_id` INT(11) NOT NULL DEFAULT 0 COMMENT '所属万能表单id', `submit_after_action` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '填表人提交后操作,text:文字信息,voucher:核销凭证', - `tips_type` VARCHAR(255) NOT NULL COMMENT '提示内容类型,default:默认提示,diy:自定义提示', + `tips_type` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '提示内容类型,default:默认提示,diy:自定义提示', `tips_text` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '自定义提示内容', `time_limit_type` VARCHAR(255) NOT NULL DEFAULT '0' COMMENT '核销凭证有效期限制类型,no_limit:不限制,specify_time:指定固定开始结束时间,submission_time:按提交时间设置有效期', `time_limit_rule` TEXT DEFAULT NULL COMMENT '核销凭证时间限制规则,json格式', @@ -289,7 +289,7 @@ CREATE TABLE `generate_table` ( DROP TABLE IF EXISTS `jobs`; CREATE TABLE `jobs` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `queue` varchar(255) NOT NULL, + `queue` varchar(255) NOT NULL DEFAULT '', `payload` longtext NOT NULL, `attempts` tinyint(4) UNSIGNED NOT NULL DEFAULT 0, `reserve_time` int(11) UNSIGNED NULL DEFAULT 0, @@ -504,7 +504,7 @@ CREATE TABLE `pay` ( `trade_id` int(11) NOT NULL DEFAULT 0 COMMENT '业务id', `trade_no` varchar(255) NOT NULL DEFAULT '' COMMENT '交易单号', `body` varchar(1000) NOT NULL DEFAULT '' COMMENT '支付主体', - `money` decimal(10, 2) NOT NULL COMMENT '支付金额', + `money` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '支付金额', `voucher` varchar(255) NOT NULL DEFAULT '' COMMENT '支付票据', `status` int(11) NOT NULL DEFAULT 0 COMMENT '支付状态(0.待支付 1. 支付中 2. 已支付 -1已取消)', `json` varchar(255) NOT NULL DEFAULT '' COMMENT '支付扩展用支付信息', @@ -700,6 +700,21 @@ CREATE TABLE `sys_attachment_category` ( ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '附件分类表' ROW_FORMAT = Dynamic; +DROP TABLE IF EXISTS `sys_backup_records`; +CREATE TABLE `sys_backup_records` ( + `id` INT NOT NULL AUTO_INCREMENT COMMENT '主键id', + `version` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '备份版本号', + `backup_key` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '备份标识', + `content` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '备份内容', + `status` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '状态', + `fail_reason` LONGTEXT DEFAULT NULL COMMENT '失败原因', + `remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注', + `create_time` INT NOT NULL DEFAULT 0 COMMENT '创建时间', + `complete_time` INT NOT NULL DEFAULT 0 COMMENT '完成时间', + PRIMARY KEY (`id`) +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '备份记录表' ROW_FORMAT = Dynamic; + + DROP TABLE IF EXISTS `sys_config`; CREATE TABLE `sys_config` ( `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', @@ -966,6 +981,22 @@ CREATE TABLE `sys_schedule_log` ( ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '计划任务执行记录' ROW_FORMAT = Dynamic; +DROP TABLE IF EXISTS `sys_upgrade_records`; +CREATE TABLE `sys_upgrade_records` ( + `id` INT NOT NULL AUTO_INCREMENT COMMENT '主键id', + `upgrade_key` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '升级标识', + `app_key` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '插件标识', + `name` LONGTEXT DEFAULT NULL COMMENT '升级名称', + `content` TEXT DEFAULT NULL COMMENT '升级内容', + `prev_version` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '前一版本', + `current_version` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '当前版本', + `status` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '状态', + `fail_reason` LONGTEXT DEFAULT NULL COMMENT '失败原因', + `create_time` INT NOT NULL DEFAULT 0 COMMENT '创建时间', + `complete_time` INT NOT NULL DEFAULT 0 COMMENT '完成时间', + PRIMARY KEY (`id`) +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '升级记录表' ROW_FORMAT = Dynamic; + DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `uid` smallint(5) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '系统用户ID', @@ -974,13 +1005,13 @@ CREATE TABLE `sys_user` ( `password` varchar(100) NOT NULL DEFAULT '' COMMENT '用户密码', `real_name` varchar(16) NOT NULL DEFAULT '' COMMENT '实际姓名', `last_ip` varchar(50) NOT NULL DEFAULT '' COMMENT '最后一次登录ip', - `last_time` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '最后一次登录时间', - `create_time` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '添加时间', - `login_count` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '登录次数', - `is_del` tinyint(3) UNSIGNED NOT NULL DEFAULT 0, + `last_time` int(10) NOT NULL DEFAULT 0 COMMENT '最后一次登录时间', + `create_time` int(10) NOT NULL DEFAULT 0 COMMENT '添加时间', + `login_count` int(10) NOT NULL DEFAULT 0 COMMENT '登录次数', + `is_del` tinyint(3) NOT NULL DEFAULT 0, `delete_time` int(11) NOT NULL DEFAULT 0 COMMENT '删除时间', `update_time` int(11) NOT NULL DEFAULT 0 COMMENT '更新时间', - `status` tinyint(3) UNSIGNED NOT NULL DEFAULT 1 COMMENT '后台管理员状态 1有效0无效', + `status` tinyint(3) NOT NULL DEFAULT 1 COMMENT '后台管理员状态 1有效0无效', `role_ids` varchar(255) NOT NULL DEFAULT '' COMMENT '权限组', `is_admin` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否是管理员', PRIMARY KEY (`uid`) USING BTREE, @@ -1045,9 +1076,9 @@ CREATE TABLE `web_adv` ( DROP TABLE IF EXISTS `web_friendly_link`; CREATE TABLE `web_friendly_link` ( `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '索引id', - `link_title` VARCHAR(100) NOT NULL COMMENT '标题', - `link_url` VARCHAR(100) NOT NULL COMMENT '链接', - `link_pic` VARCHAR(100) NOT NULL COMMENT '图片', + `link_title` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '标题', + `link_url` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '链接', + `link_pic` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '图片', `sort` INT(11) NOT NULL DEFAULT 0 COMMENT '排序号', `is_show` INT(11) NOT NULL DEFAULT 1 COMMENT '是否显示 1.是 2.否', PRIMARY KEY (`id`) diff --git a/niucloud/app/job/schedule/AutoClearScheduleLog.php b/niucloud/app/job/schedule/AutoClearScheduleLog.php new file mode 100644 index 000000000..cf1b56e24 --- /dev/null +++ b/niucloud/app/job/schedule/AutoClearScheduleLog.php @@ -0,0 +1,47 @@ +where([ + [ 'execute_time', '<', time() - self::SUCCESS_SAVE_DAY * 86400 ], + [ 'status', '=', 'success' ], + ])->delete(); + ( new SysScheduleLog() )->where([ + [ 'execute_time', '<', time() - self::ERROR_SAVE_DAY * 86400 ], + [ 'status', '=', 'error' ], + ])->delete(); + return true; + } catch (\Exception $e) { + Log::write('AutoClearScheduleLog 定时清除schedule_log数据失败' . date('Y-m-d h:i:s') . $e->getMessage() . $e->getFile() . $e->getLine()); + return false; + } + + } +} diff --git a/niucloud/app/job/upgrade/AutoClearUpgradeRecords.php b/niucloud/app/job/upgrade/AutoClearUpgradeRecords.php new file mode 100644 index 000000000..99b63dcbb --- /dev/null +++ b/niucloud/app/job/upgrade/AutoClearUpgradeRecords.php @@ -0,0 +1,54 @@ +where([ + [ 'create_time', '<', time() - self::DAY * 86400 ], + [ 'status', 'in', [ UpgradeDict::STATUS_READY, UpgradeDict::STATUS_FAIL ] ] + ])->delete(); + + // 清除7天前的备份记录数据 + $backup_records_service = new BackupRecordsService(); + $backup_records = $backup_records_service->getList([ + [ 'create_time', '<', time() - self::DAY * 86400 ], + [ 'status', 'in', [ BackupDict::STATUS_READY, BackupDict::STATUS_FAIL ] ] + ], 'id'); + + $backup_records_service->del(array_column($backup_records, 'id')); + + return true; + } catch (\Exception $e) { + Log::write('AutoClearScheduleLog 定时清除升级记录、备份记录数据失败' . date('Y-m-d h:i:s') . $e->getMessage() . $e->getFile() . $e->getLine()); + return false; + } + + } +} diff --git a/niucloud/app/job/wxoplatform/GetVersionUploadResult.php b/niucloud/app/job/wxoplatform/GetVersionUploadResult.php new file mode 100644 index 000000000..9097bf09c --- /dev/null +++ b/niucloud/app/job/wxoplatform/GetVersionUploadResult.php @@ -0,0 +1,34 @@ + 'real_name is require', 'password_require' => 'password is require', ], - //站点 - 'validate_site' => [ - 'site_name_require' => 'site_name is require', - 'site_name_max' => 'site_name is not exceed 120 points', - 'keywords_require' => 'keywords is require', - 'keywords_max' => 'site_name is not exceed 30 points', - 'group_id_require' => 'group_id is require', - 'group_id_number' => 'group_id must be a number', - 'expire_time_number' => 'expire_time must be a number', - 'group_name_require' => 'group_name is require', - 'group_name_max' => 'group_name is not exceed 120 points', - 'group_roles_require' => 'group_roles is require' - ], //附件 'validate_attachment' => [ 'name_require' => 'name is require', diff --git a/niucloud/app/lang/zh-cn/api.php b/niucloud/app/lang/zh-cn/api.php index 335ae4a6d..baaed7d29 100644 --- a/niucloud/app/lang/zh-cn/api.php +++ b/niucloud/app/lang/zh-cn/api.php @@ -37,6 +37,7 @@ return [ 'SERVER_CROSS_REQUEST_FAIL' => '服务器跨域请求异常', 'ADDON_INSTALL_NOT_EXIST' => '未找到插件安装任务', 'ADDON_INSTALL_EXECUTED' => '插件安装任务已执行', + 'ADDON_INSTALLING' => '插件安装中', 'INSTALL_CHECK_NOT_PASS' => '安装校验未通过', 'ADDON_SQL_FAIL' => '插件sql执行失败', 'ADDON_DIR_FAIL' => '插件文件操作失败', @@ -56,6 +57,10 @@ return [ 'ADDON_ZIP_ERROR' => '插件压缩失败', 'PHP_SCRIPT_RUNNING_OUT_OF_MEMORY' => 'PHP脚本运行内存不足, 具体操作方法点击查看相关手册', 'BEFORE_UPGRADING_NEED_UPGRADE_FRAMEWORK' => '升级插件前需要先升级框架', + 'UPGRADE_RECORD_NOT_EXIST' => '升级记录不存在', + 'UPGRADE_BACKUP_CODE_NOT_FOUND' => '未找到备份的源码文件', + 'UPGRADE_BACKUP_SQL_NOT_FOUND' => '未找到备份的数据库文件', + 'NOT_EXIST_UPGRADE_CONTENT' => '没有获取到可以升级的内容', //登录注册重置账号.... 'LOGIN_SUCCESS' => '登录成功', @@ -289,6 +294,8 @@ return [ 'VERIFY_TYPE_ERROR' => '核销类型错误', 'VERIFY_CODE_EXPIRED' => '当前核销码已核销或已失效', 'VERIFIER_NOT_EXIST' => '核销员不存在', + 'VERIFIER_EXIST'=>'核销员已存在', + 'VERIFIER_NOT_AUTH' => '该核销员没有权限', //签到相关 'SIGN_NOT_USE' => '签到未开启', @@ -312,7 +319,5 @@ return [ 'DIRECTORY' => '目录', 'WAS_NOT_CREATED' => '创建失败', - /********************************************************* 微信开放平台 **************************************/ - 'PRINTER_NOT_EXIST' => '打印机不存在' ]; diff --git a/niucloud/app/lang/zh-cn/dict.php b/niucloud/app/lang/zh-cn/dict.php index 6be7629c0..0f77f8353 100644 --- a/niucloud/app/lang/zh-cn/dict.php +++ b/niucloud/app/lang/zh-cn/dict.php @@ -376,7 +376,6 @@ return [ 'oct' => '10月', 'nov' => '11月', 'dec' => '12月', - ], 'dict_site_layout' => [ 'default' => '默认' @@ -387,7 +386,8 @@ return [ 'upload_fail' => '上传失败', 'auditing' => '审核中', 'audit_success' => '审核通过', - 'audit_fail' => '审核失败' + 'audit_fail' => '审核失败', + 'published' => '已发布' ], 'dict_wechat_media' => [ 'type_image' => '图片', @@ -414,5 +414,16 @@ return [ // 打印机品牌 'dict_printer' => [ 'yilianyun' => '易联云打印机' + ], + 'dict_upgrade' => [ + 'ready' => '升级中', + 'complete' => '完成', + 'fail' => '失败', + 'cancel' => '已取消' + ], + 'dict_backup' => [ + 'ready' => '准备执行', + 'complete' => '完成', + 'fail' => '失败' ] ]; diff --git a/niucloud/app/lang/zh-cn/validate.php b/niucloud/app/lang/zh-cn/validate.php index ffa6ea5c1..732cedc52 100644 --- a/niucloud/app/lang/zh-cn/validate.php +++ b/niucloud/app/lang/zh-cn/validate.php @@ -36,22 +36,6 @@ return [ 'real_name_require' => '实际姓名必须填写', 'password_require' => '账号密码必须填写', ], - //站点 - 'validate_site' => [ - 'site_name_require' => '网站名称必须填写', - 'site_name_max' => '网站名称最多不能超过20个字符', - 'keywords_require' => '关键字必须填写', - 'keywords_max' => '关键字最多不能超过30个字符', - 'group_id_require' => '站点分组必须填写', - 'group_id_number' => '站点分组必须是整数', - 'expire_time_number' => '到期时间必须是时间戳', - 'group_name_require' => '站点分组名称必须填写', - 'group_name_max' => '站点分组名称不能超过20字符', - 'app_require' => '套餐主应用必须选择', - 'front_end_name_require' => '前台名称必须填写', - 'front_end_name_max' => '前台名称最多不能超过20个字符', - 'site_domain_cannot_repeated' => '站点域名不能重复' - ], //附件 'validate_attachment' => [ 'name_require' => '附件组名称必须填写', diff --git a/niucloud/app/listener/system/ShowAppListener.php b/niucloud/app/listener/system/ShowAppListener.php index 895f0e0ab..c323e61c0 100644 --- a/niucloud/app/listener/system/ShowAppListener.php +++ b/niucloud/app/listener/system/ShowAppListener.php @@ -37,13 +37,20 @@ class ShowAppListener 'key' => 'diy_form', 'url' => '/diy_form/list', ], -// [ -// 'title' => '万能a表单', -// 'desc' => '万能a表单', -// 'icon' => 'static/resource/images/diy_form/icon.png', -// 'key' => 'diy_faorm', -// 'url' => '/diy_faorm/list', -// ] + [ + 'title' => '小票打印', + 'desc' => '支持打印机添加,便捷创建小票打印模板', + 'icon' => 'static/resource/images/tool/printer_icon.png', + 'key' => 'printer_management', + 'url' => '/printer/list', + ], + [ + 'title' => '数据导出', + 'desc' => '展示导出文件,支持删除与下载', + 'icon' => 'static/resource/images/tool/export_icon.png', + 'key' => 'setting_export', + 'url' => '/setting/export', + ], ], // 营销 'promotion' => [ diff --git a/niucloud/app/model/member/Member.php b/niucloud/app/model/member/Member.php index 33bf0ee9e..5facb176f 100644 --- a/niucloud/app/model/member/Member.php +++ b/niucloud/app/model/member/Member.php @@ -202,9 +202,16 @@ class Member extends BaseModel */ public function searchMemberLabelAttr(Query $query, $value, $data) { + if ($value) { - $query->whereLike('member_label', '%"' . $value . '"%'); + if (is_array($value)) { + $temp_where = array_map(function($item) { return '%"' . $item . '"%'; }, $value); + } else { + $temp_where = [ '%"' . $value . '"%' ]; + } + $query->where('member_label', 'like', $temp_where, 'or'); } + } /** @@ -268,4 +275,5 @@ class Member extends BaseModel { return $this->hasOne(MemberLevel::class, 'level_id', 'member_level')->bind([ 'member_level_name' => 'level_name' ]); } + } diff --git a/niucloud/app/model/sys/SysBackupRecords.php b/niucloud/app/model/sys/SysBackupRecords.php new file mode 100644 index 000000000..086aa7631 --- /dev/null +++ b/niucloud/app/model/sys/SysBackupRecords.php @@ -0,0 +1,112 @@ + 'timestamp', + 'complete_time' => 'timestamp' + ]; + + // 设置json类型字段 + protected $json = [ 'fail_reason' ]; + + // 设置JSON数据返回数组 + protected $jsonAssoc = true; + + /** + * 状态字段转化 + * @param $value + * @param $data + * @return mixed + */ + public function getStatusNameAttr($value, $data) + { + if (empty($data[ 'status' ])) return ''; + return UpgradeDict::getStatus($data[ 'status' ]); + } + + /** + * 备份目录 + * @param $value + * @param $data + * @return string + */ + public function getBackupDirAttr($value, $data) + { + if (empty($data[ 'backup_key' ])) return ''; + return 'upgrade' . DIRECTORY_SEPARATOR . $data[ 'backup_key' ]; + } + + /** + * 备份源码目录 + * @param $value + * @param $data + * @return string + */ + public function getBackupCodeDirAttr($value, $data) + { + if (empty($data[ 'backup_key' ])) return ''; + + $root_path = dirname(root_path()) . DIRECTORY_SEPARATOR; + $upgrade_dir = $root_path . 'upgrade' . DIRECTORY_SEPARATOR; + return $upgrade_dir . $data[ 'backup_key' ] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; + } + + /** + * 备份数据库目录 + * @param $value + * @param $data + * @return string + */ + public function getBackupSqlDirAttr($value, $data) + { + if (empty($data[ 'backup_key' ])) return ''; + $root_path = dirname(root_path()) . DIRECTORY_SEPARATOR; + $upgrade_dir = $root_path . 'upgrade' . DIRECTORY_SEPARATOR; + return $upgrade_dir . $data[ 'backup_key' ] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; + } + + /** + * 搜索器:备份内容 + * @param $query + * @param $value + * @param $data + */ + public function searchContentAttr($query, $value, $data) + { + if ($value != '') { + $query->where("content", 'like', '%' . $this->handelSpecialCharacter($value) . '%'); + } + } +} diff --git a/niucloud/app/model/sys/SysUpgradeRecords.php b/niucloud/app/model/sys/SysUpgradeRecords.php new file mode 100644 index 000000000..d5e776ecf --- /dev/null +++ b/niucloud/app/model/sys/SysUpgradeRecords.php @@ -0,0 +1,130 @@ + 'timestamp', + 'complete_time' => 'timestamp' + ]; + + // 设置json类型字段 + protected $json = [ 'fail_reason' ]; + + // 设置JSON数据返回数组 + protected $jsonAssoc = true; + + /** + * 状态字段转化 + * @param $value + * @param $data + * @return mixed + */ + public function getStatusNameAttr($value, $data) + { + if (empty($data[ 'status' ])) return ''; + return UpgradeDict::getStatus($data[ 'status' ]); + } + + /** + * 备份目录 + * @param $value + * @param $data + * @return string + */ + public function getBackupDirAttr($value, $data) + { + if (empty($data[ 'upgrade_key' ])) return ''; + return 'upgrade' . DIRECTORY_SEPARATOR . $data[ 'upgrade_key' ]; + } + + /** + * 备份源码目录 + * @param $value + * @param $data + * @return string + */ + public function getBackupCodeDirAttr($value, $data) + { + if (empty($data[ 'upgrade_key' ])) return ''; + + $root_path = dirname(root_path()) . DIRECTORY_SEPARATOR; + $upgrade_dir = $root_path . 'upgrade' . DIRECTORY_SEPARATOR; + return $upgrade_dir . $data[ 'upgrade_key' ] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; + } + + /** + * 备份数据库目录 + * @param $value + * @param $data + * @return string + */ + public function getBackupSqlDirAttr($value, $data) + { + if (empty($data[ 'upgrade_key' ])) return ''; + $root_path = dirname(root_path()) . DIRECTORY_SEPARATOR; + $upgrade_dir = $root_path . 'upgrade' . DIRECTORY_SEPARATOR; + return $upgrade_dir . $data[ 'upgrade_key' ] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; + } + + /** + * 搜索器:升级名称 + * @param $query + * @param $value + * @param $data + */ + public function searchNameAttr($query, $value, $data) + { + if ($value != '') { + $query->where("name", 'like', '%' . $this->handelSpecialCharacter($value) . '%'); + } + } + + /** + * 关联备份记录 + * @return \think\model\relation\HasOne + */ + public function backupRecord() + { + return $this->hasOne(SysBackupRecords::class, 'backup_key', 'upgrade_key'); + } + + public function getContentAttr($value) { + if (!empty($value)) { + try { + return json_decode($value, true); + } catch (\Exception $e) { + } + } + return $value; + } +} diff --git a/niucloud/app/model/verify/Verify.php b/niucloud/app/model/verify/Verify.php index 5c5585bfc..199fc4cbd 100644 --- a/niucloud/app/model/verify/Verify.php +++ b/niucloud/app/model/verify/Verify.php @@ -18,8 +18,6 @@ use think\db\Query; /** * 核销记录模型 - * Class Poster - * @package app\model\verify */ class Verify extends BaseModel { @@ -37,12 +35,13 @@ class Verify extends BaseModel protected $name = 'verify'; // 设置json类型字段 - protected $json = [ 'data' , 'value']; + protected $json = [ 'data', 'value' ]; // 设置JSON数据返回数组 protected $jsonAssoc = true; - public function member() { + public function member() + { return $this->hasOne(Member::class, 'member_id', 'verifier_member_id'); } @@ -85,6 +84,7 @@ class Verify extends BaseModel $query->where('relate_tag', '=', $value); } } + /** * 核销员 * @param $query @@ -120,14 +120,14 @@ class Verify extends BaseModel */ public function searchCreateTimeAttr(Query $query, $value, $data) { - $start_time = empty($value[0]) ? 0 : strtotime($value[0]); - $end_time = empty($value[1]) ? 0 : strtotime($value[1]); + $start_time = empty($value[ 0 ]) ? 0 : strtotime($value[ 0 ]); + $end_time = empty($value[ 1 ]) ? 0 : strtotime($value[ 1 ]); if ($start_time > 0 && $end_time > 0) { $query->whereBetweenTime('create_time', $start_time, $end_time); } else if ($start_time > 0 && $end_time == 0) { - $query->where([['create_time', '>=', $start_time]]); + $query->where([ [ 'create_time', '>=', $start_time ] ]); } else if ($start_time == 0 && $end_time > 0) { - $query->where([['create_time', '<=', $end_time]]); + $query->where([ [ 'create_time', '<=', $end_time ] ]); } } @@ -136,10 +136,11 @@ class Verify extends BaseModel * @param $value * @return void */ - public function getTypeNameAttr($value, $data) { - if (empty($data['type'])) + public function getTypeNameAttr($value, $data) + { + if (empty($data[ 'type' ])) return ''; - return VerifyDict::getType()[$data['type']]['name'] ?? ''; + return VerifyDict::getType()[ $data[ 'type' ] ][ 'name' ] ?? ''; } } diff --git a/niucloud/app/model/weapp/WeappVersion.php b/niucloud/app/model/weapp/WeappVersion.php index 73d169d72..b67da1df4 100644 --- a/niucloud/app/model/weapp/WeappVersion.php +++ b/niucloud/app/model/weapp/WeappVersion.php @@ -35,6 +35,6 @@ class WeappVersion extends BaseModel protected $name = 'weapp_version'; public function getStatusNameAttr($value, $data) { - if (isset($data['status'])) return CloudDict::getAppletUploadSatus($data['status']); + if (isset($data['status'])) return CloudDict::getAppletUploadStatus($data['status']); } } diff --git a/niucloud/app/service/admin/diy_form/DiyFormService.php b/niucloud/app/service/admin/diy_form/DiyFormService.php index ae72c5e76..369dfa5f7 100644 --- a/niucloud/app/service/admin/diy_form/DiyFormService.php +++ b/niucloud/app/service/admin/diy_form/DiyFormService.php @@ -623,39 +623,6 @@ class DiyFormService extends BaseAdminService return ( new DiyFormFields() )->where([ [ 'field_id', '>', 0 ] ])->withSearch([ 'form_id' ], $where)->field($field)->order($order)->select()->toArray(); } - /** - * 获取万能表单微信小程序二维码 - * @param $form_id - * @return array - */ - public function getQrcode($form_id) - { - if (empty($form_id)) { - throw new AdminException('缺少参考form_id'); - } - - $page = 'app/pages/index/diy_form'; - - $data = [ - [ - 'key' => 'form_id', - 'value' => $form_id - ], - ]; - $dir = 'upload/diy_form_qrcode'; - - $path = ''; - try { - $path = qrcode('', $page, $data, $dir, 'weapp'); - } catch (\Exception $e) { - Log::write('万能表单微信小程序二维码生成error' . $e->getMessage() . $e->getFile() . $e->getLine()); - } - - return [ - 'path' => $path - ]; - } - /** * 检测表单名称唯一性 * @param array $data diff --git a/niucloud/app/service/admin/generator/vm/search/select2.vm b/niucloud/app/service/admin/generator/vm/search/select2.vm index 6e78d6fed..15cdc6c01 100644 --- a/niucloud/app/service/admin/generator/vm/search/select2.vm +++ b/niucloud/app/service/admin/generator/vm/search/select2.vm @@ -1,5 +1,5 @@ - + diff --git a/niucloud/app/service/admin/member/MemberService.php b/niucloud/app/service/admin/member/MemberService.php index 14636da1f..cfdabc691 100644 --- a/niucloud/app/service/admin/member/MemberService.php +++ b/niucloud/app/service/admin/member/MemberService.php @@ -44,11 +44,11 @@ class MemberService extends BaseAdminService public function getPage(array $where = []) { $field = 'member_id, member_no, username, mobile, password, register_channel, register_type, nickname, headimg, member_level, member_label, wx_openid, weapp_openid, wx_unionid, ali_openid, douyin_openid, login_ip, login_type, login_channel, login_count, login_time, create_time, last_visit_time, last_consum_time, sex, status, birthday, point, point_get, balance, balance_get, growth, growth_get, is_member, member_time, is_del, province_id, city_id, district_id, address, location, delete_time, money, money_get, commission, commission_get, commission_cash_outing'; - $search_model = $this->model->withSearch(['keyword','register_type', 'create_time', 'is_del', 'member_label', 'register_channel','member_level'],$where) + $search_model = $this->model->withSearch([ 'keyword', 'register_type', 'create_time', 'is_del', 'member_label', 'register_channel', 'member_level' ], $where) ->field($field) ->order('member_id desc') ->with('member_level_name_bind') - ->append(['register_channel_name', 'register_type_name', 'sex_name', 'login_channel_name', 'login_type_name', 'status_name']); + ->append([ 'register_channel_name', 'register_type_name', 'sex_name', 'login_channel_name', 'login_type_name', 'status_name' ]); return $this->pageQuery($search_model, function ($item, $key) { $item = $this->makeUp($item); }); @@ -65,8 +65,13 @@ class MemberService extends BaseAdminService public function getList(array $where = []) { $field = 'member_id, nickname, headimg'; - return $this->model->withSearch(['keyword'],$where)->field($field)->order('member_id desc')->limit($this->getPageParam()['limit'] ?? 0)->select()->toArray(); + $temp_where[] = []; + if (!empty($where[ 'member_ids' ])) { + $temp_where[] = [ 'member_id', 'in', implode(',', $where[ 'member_ids' ]) ]; + } + return $this->model->where($temp_where)->withSearch([ 'keyword' ], $where)->field($field)->order('member_id desc')->limit($this->getPageParam()[ 'limit' ] ?? 0)->select()->toArray(); } + /** * 会员详情 * @param int $member_id @@ -75,7 +80,7 @@ class MemberService extends BaseAdminService public function getInfo(int $member_id) { $field = 'member_id,member_no, username, mobile, password, register_channel, register_type, nickname, headimg, member_level, member_label, wx_openid, weapp_openid, wx_unionid, ali_openid, douyin_openid, login_ip, login_type, login_channel, login_count, login_time, create_time, last_visit_time, last_consum_time, sex, status, birthday, point, point_get, balance, balance_get, growth, growth_get, is_member, member_time, is_del, province_id, city_id, district_id, address, location, delete_time, money, money_get, commission, commission_get, commission_cash_outing'; - return $this->makeUp($this->model->where([['member_id', '=', $member_id]])->field($field)->with('member_level_name_bind')->append(['register_channel_name', 'register_type_name', 'sex_name', 'login_channel_name', 'login_type_name', 'status_name'])->findOrEmpty()->toArray()); + return $this->makeUp($this->model->where([ [ 'member_id', '=', $member_id ] ])->field($field)->with('member_level_name_bind')->append([ 'register_channel_name', 'register_type_name', 'sex_name', 'login_channel_name', 'login_type_name', 'status_name' ])->findOrEmpty()->toArray()); } /** @@ -87,36 +92,36 @@ class MemberService extends BaseAdminService { //检测手机是否重复 - if(!empty($data['mobile'])){ - if(!$this->model->where([['mobile', '=', $data['mobile']]])->findOrEmpty()->isEmpty()) - throw new AdminException('MOBILE_IS_EXIST'); + if (!empty($data[ 'mobile' ])) { + if (!$this->model->where([ [ 'mobile', '=', $data[ 'mobile' ] ] ])->findOrEmpty()->isEmpty()) + throw new AdminException('MOBILE_IS_EXIST'); } - if($data['init_member_no'] != $data['member_no']){ - if(!$this->model->where([['member_no', '=', $data['member_no']]])->findOrEmpty()->isEmpty()) + if ($data[ 'init_member_no' ] != $data[ 'member_no' ]) { + if (!$this->model->where([ [ 'member_no', '=', $data[ 'member_no' ] ] ])->findOrEmpty()->isEmpty()) throw new AdminException('MEMBER_NO_IS_EXIST'); - }else{ - if(!$this->model->where([['member_no', '=', $data['member_no']]])->findOrEmpty()->isEmpty()){ - $data['member_no'] = $this->getMemberNo(); + } else { + if (!$this->model->where([ [ 'member_no', '=', $data[ 'member_no' ] ] ])->findOrEmpty()->isEmpty()) { + $data[ 'member_no' ] = $this->getMemberNo(); } } - $data['username'] = $data['mobile']; - if(!empty($data['username'])){ - if(!$this->model->where([['username', '=', $data['username']]])->findOrEmpty()->isEmpty()) + $data[ 'username' ] = $data[ 'mobile' ]; + if (!empty($data[ 'username' ])) { + if (!$this->model->where([ [ 'username', '=', $data[ 'username' ] ] ])->findOrEmpty()->isEmpty()) throw new AdminException('MEMBER_IS_EXIST'); } - if (empty($data[ 'nickname' ]) && !empty($data['mobile'])) { - $data[ 'nickname' ] = substr_replace($data['mobile'], '****', 3, 4); + if (empty($data[ 'nickname' ]) && !empty($data[ 'mobile' ])) { + $data[ 'nickname' ] = substr_replace($data[ 'mobile' ], '****', 3, 4); } - $password_hash = create_password($data['password']); - $data['password'] = $password_hash; - $data['register_type'] = MemberRegisterTypeDict::MANUAL; - $data['register_channel'] = MemberRegisterChannelDict::MANUAL; // todo 公共化渠道 + $password_hash = create_password($data[ 'password' ]); + $data[ 'password' ] = $password_hash; + $data[ 'register_type' ] = MemberRegisterTypeDict::MANUAL; + $data[ 'register_channel' ] = MemberRegisterChannelDict::MANUAL; // todo 公共化渠道 $member = $this->model->create($data); - $data['member_id'] = $member->member_id; + $data[ 'member_id' ] = $member->member_id; event("MemberRegister", $data); return $member->member_id; } @@ -130,10 +135,10 @@ class MemberService extends BaseAdminService public function edit(int $member_id, array $data) { $where = array( - ['member_id', '=', $member_id], + [ 'member_id', '=', $member_id ], ); - if(!empty($data['password'])){ - $data['password'] = create_password($data['password']); + if (!empty($data[ 'password' ])) { + $data[ 'password' ] = create_password($data[ 'password' ]); } $this->model->where($where)->update($data); return true; @@ -147,17 +152,18 @@ class MemberService extends BaseAdminService */ public function modify(int $member_id, string $field, $data) { - return (new CoreMemberService())->modify($member_id, $field, $data); + return ( new CoreMemberService() )->modify($member_id, $field, $data); } /** * 组合整理数据 * @param $data */ - public function makeUp($data){ + public function makeUp($data) + { //会员标签 - if(!empty($data['member_label'])){ - $data['member_label_array'] = (new MemberLabelService())->getMemberLabelListByLabelIds($data['member_label']); + if (!empty($data[ 'member_label' ])) { + $data[ 'member_label_array' ] = ( new MemberLabelService() )->getMemberLabelListByLabelIds($data[ 'member_label' ]); } return $data; } @@ -167,8 +173,9 @@ class MemberService extends BaseAdminService * @return int * @throws DbException */ - public function getCount(array $where = []){ - $where[] = ['is_del', '=', 0]; + public function getCount(array $where = []) + { + $where[] = [ 'is_del', '=', 0 ]; return $this->model->where($where)->count(); } @@ -178,9 +185,10 @@ class MemberService extends BaseAdminService * @param int $status * @return true */ - public function setStatus(array $member_ids, int $status){ + public function setStatus(array $member_ids, int $status) + { $where = array( - ['member_id', 'in', $member_ids], + [ 'member_id', 'in', $member_ids ], ); $data = array( 'status' => $status @@ -196,7 +204,7 @@ class MemberService extends BaseAdminService */ public function getSum($field) { - return $this->model->where([ ['member_id', '>', 0] ])->sum($field); + return $this->model->where([ [ 'member_id', '>', 0 ] ])->sum($field); } /** @@ -205,7 +213,7 @@ class MemberService extends BaseAdminService */ public function getMemberNo() { - return (new CoreMemberService())->createMemberNo(); + return ( new CoreMemberService() )->createMemberNo(); } /** @@ -215,8 +223,8 @@ class MemberService extends BaseAdminService */ public function deleteMember(int $member_id) { - $this->model->destroy(function($query) use($member_id){ - $query->where([['member_id', '=', $member_id]]); + $this->model->destroy(function ($query) use ($member_id) { + $query->where([ [ 'member_id', '=', $member_id ] ]); }); return true; } @@ -230,9 +238,9 @@ class MemberService extends BaseAdminService { $field = 'member_id, member_no, username, mobile, nickname, point, balance, money, growth, commission, register_channel, status, create_time, last_visit_time'; //查询导出数据 - $data = $this->model->withSearch(['keyword','register_type', 'create_time', 'is_del', 'member_label', 'register_channel'],$where)->field($field)->append(['register_channel_name', 'status_name'])->select()->toArray(); + $data = $this->model->withSearch([ 'keyword', 'register_type', 'create_time', 'is_del', 'member_label', 'register_channel' ], $where)->field($field)->append([ 'register_channel_name', 'status_name' ])->select()->toArray(); //执行导出 - (new ExportService())->exportData('member', $data); + ( new ExportService() )->exportData('member', $data); return true; } @@ -240,32 +248,36 @@ class MemberService extends BaseAdminService * 获取会员权益字典 * @return mixed */ - public function getMemberBenefitsDict() { - return (new DictLoader("MemberBenefits"))->load(); + public function getMemberBenefitsDict() + { + return ( new DictLoader("MemberBenefits") )->load(); } /** * 获取会员礼包字典 * @return array|null */ - public function getMemberGiftDict() { - return (new DictLoader("MemberGift"))->load(); + public function getMemberGiftDict() + { + return ( new DictLoader("MemberGift") )->load(); } /** * 获取成长值规则字典 * @return array|null */ - public function getGrowthRuleDict() { - return (new DictLoader("GrowthRule"))->load(); + public function getGrowthRuleDict() + { + return ( new DictLoader("GrowthRule") )->load(); } /** * 获取积分规则字典 * @return array|null */ - public function getPointRuleDict() { - return (new DictLoader("PointRule"))->load(); + public function getPointRuleDict() + { + return ( new DictLoader("PointRule") )->load(); } /** @@ -273,8 +285,9 @@ class MemberService extends BaseAdminService * @param array $benefits * @return array|null */ - public function getMemberBenefitsContent(array $benefits) { - return (new CoreMemberService())->getBenefitsContent($benefits); + public function getMemberBenefitsContent(array $benefits) + { + return ( new CoreMemberService() )->getBenefitsContent($benefits); } /** @@ -282,7 +295,8 @@ class MemberService extends BaseAdminService * @param array $benefits * @return array|null */ - public function getMemberGiftsContent(array $gifts) { - return (new CoreMemberService())->getGiftContent($gifts); + public function getMemberGiftsContent(array $gifts) + { + return ( new CoreMemberService() )->getGiftContent($gifts); } } diff --git a/niucloud/app/service/admin/niucloud/NiucloudService.php b/niucloud/app/service/admin/niucloud/NiucloudService.php index ccb90e0f8..6b01f7138 100644 --- a/niucloud/app/service/admin/niucloud/NiucloudService.php +++ b/niucloud/app/service/admin/niucloud/NiucloudService.php @@ -37,14 +37,15 @@ class NiucloudService extends BaseAdminService * @param $data * @return \app\model\sys\SysConfig|bool|\think\Model */ - public function setAuthorize($data){ + public function setAuthorize($data) + { $data = [ - 'auth_code' => $data['auth_code'], - 'auth_secret' => $data['auth_secret'] + 'auth_code' => $data[ 'auth_code' ], + 'auth_secret' => $data[ 'auth_secret' ] ]; - $service = (new CoreAuthService($data['auth_code'], $data['auth_secret'])); - $auth_info = $service->getAuthInfo()['data'] ?? []; + $service = ( new CoreAuthService($data[ 'auth_code' ], $data[ 'auth_secret' ]) ); + $auth_info = $service->getAuthInfo()[ 'data' ] ?? []; if (empty($auth_info)) throw new CommonException('AUTH_NOT_EXISTS'); $service->clearAccessToken(); return $this->core_config_service->setConfig(ConfigKeyDict::NIUCLOUD_CONFIG, $data); @@ -54,34 +55,45 @@ class NiucloudService extends BaseAdminService * 获取授权信息 * @return mixed|string[] */ - public function getAuthorize(){ + public function getAuthorize() + { $info = $this->core_config_service->getConfig(ConfigKeyDict::NIUCLOUD_CONFIG); - if(empty($info)) - { + if (empty($info)) { $info = []; - $info['value'] = [ + $info[ 'value' ] = [ 'auth_code' => '', 'auth_secret' => '' ]; } - return $info['value']; + return $info[ 'value' ]; } /** * 获取框架最新版本 */ - public function getFrameworkLastVersion() { - return (new CoreModuleService())->getFrameworkLastVersion(); + public function getFrameworkLastVersion() + { + return ( new CoreModuleService() )->getFrameworkLastVersion(); } /** * 获取框架版本更新记录 */ - public function getFrameworkVersionList() { - return (new CoreModuleService())->getFrameworkVersionList(); + public function getFrameworkVersionList() + { + return ( new CoreModuleService() )->getFrameworkVersionList(); } - public function applyExperience() { - return (new CoreModuleService())->applyExperience(); + public function applyExperience() + { + return ( new CoreModuleService() )->applyExperience(); + } + + /** + * 获取应用/插件的版本更新记录 + */ + public function getAppVersionList($app_key) + { + return ( new CoreModuleService() )->getAppVersionList($app_key); } } diff --git a/niucloud/app/service/admin/sys/ConfigService.php b/niucloud/app/service/admin/sys/ConfigService.php index f48f0a2fb..db4cb4e38 100644 --- a/niucloud/app/service/admin/sys/ConfigService.php +++ b/niucloud/app/service/admin/sys/ConfigService.php @@ -118,16 +118,12 @@ class ConfigService extends BaseAdminService */ public function getService() { - $info = ( new CoreConfigService() )->getConfig('SERVICE_INFO'); - if (empty($info)) { - $info = []; - $info[ 'value' ] = [ - 'wechat_code' => '', - 'enterprise_wechat' => '', - 'tel' => '', - ]; - } - return $info[ 'value' ]; + $info = ( new CoreConfigService() )->getConfig('SERVICE_INFO')[ 'value' ] ?? []; + return [ + 'wechat_code' => $info[ 'wechat_code' ] ?? '', + 'enterprise_wechat' => $info[ 'enterprise_wechat' ] ?? '', + 'tel' => $info[ 'tel' ] ?? '' + ]; } /** @@ -171,7 +167,7 @@ class ConfigService extends BaseAdminService if (empty($info)) { $info = []; $info[ 'value' ] = [ - 'key' => 'IZQBZ-3UHEU-WTCVD-2464U-I5N4V-ZFFU3', + 'key' => '', 'is_open' => 1, // 是否开启定位 'valid_time' => 5 // 定位有效期/分钟,过期后将重新获取定位信息,0为不过期 ]; diff --git a/niucloud/app/service/admin/sys/SystemService.php b/niucloud/app/service/admin/sys/SystemService.php index b98d19b19..08c220e4e 100644 --- a/niucloud/app/service/admin/sys/SystemService.php +++ b/niucloud/app/service/admin/sys/SystemService.php @@ -14,8 +14,10 @@ namespace app\service\admin\sys; use app\job\sys\CheckJob; use app\service\core\sys\CoreSysConfigService; use core\base\BaseAdminService; +use core\exception\AdminException; use think\facade\Cache; use think\facade\Db; +use think\facade\Log; use Throwable; /** @@ -49,7 +51,7 @@ class SystemService extends BaseAdminService */ public function getUrl() { - return (new CoreSysConfigService())->getSceneDomain(); + return ( new CoreSysConfigService() )->getSceneDomain(); } /** @@ -61,7 +63,7 @@ class SystemService extends BaseAdminService $server = []; $server[] = [ "name" => get_lang('dict_setting.server_system'), "server" => PHP_OS ]; $server[] = [ "name" => get_lang('dict_setting.server_setting'), "server" => PHP_SAPI ]; - $server[] = [ "name" => get_lang('dict_setting.php_version'), "server" => PHP_VERSION]; + $server[] = [ "name" => get_lang('dict_setting.php_version'), "server" => PHP_VERSION ]; //环境权限 $system_variables = []; @@ -104,7 +106,7 @@ class SystemService extends BaseAdminService //获取环境版本 $server_version = []; $row = (array) Db::query("select VERSION() as verson"); - $server_version[] = [ "name" => get_lang('dict_setting.php_version'), "demand" => get_lang('dict_setting.php_ask'), "server" => PHP_VERSION]; + $server_version[] = [ "name" => get_lang('dict_setting.php_version'), "demand" => get_lang('dict_setting.php_ask'), "server" => PHP_VERSION ]; $server_version[] = [ "name" => get_lang('dict_setting.mysql_version'), "demand" => get_lang('dict_setting.mysql_ask'), "server" => $row[ 0 ][ 'verson' ] ]; // 进程 @@ -144,7 +146,7 @@ class SystemService extends BaseAdminService $file = root_path('runtime') . $secret . '.job'; try { CheckJob::dispatch([ 'file' => $file ]); - } catch ( Throwable $e) { + } catch (Throwable $e) { return false; } // $timeout = 0; @@ -179,4 +181,37 @@ class SystemService extends BaseAdminService } return false; } + + /** + * 获取二维码 + * @param $data + * @return array + */ + public function getQrcode($data) + { + $page = $data[ 'page' ];//'app/pages/index/diy_form'; + $qrcode_data = []; + foreach ($data[ 'params' ] as $item) { + $qrcode_data[] = [ + 'key' => $item[ 'column_name' ], + 'value' => $item[ 'column_value' ] + ]; + } + $dir = 'upload/' . $data[ 'folder' ] . '_qrcode'; + + try { + // h5 + //$h5_path = qrcode('', $page, $data, $dir); + + // 微信小程序 + $weapp_path = qrcode('', $page, $qrcode_data, $dir, 'weapp'); + return [ + 'h5_path' => '', + 'weapp_path' => $weapp_path + ]; + } catch (AdminException $e) { + Log::write('获取推广微信小程序二维码error' . $e->getMessage() . $e->getFile() . $e->getLine() . 'params:' . json_encode($data, 256)); + throw new AdminException($e->getMessage() . $e->getFile() . $e->getLine() . 'params:' . json_encode($data, 256)); + } + } } diff --git a/niucloud/app/service/admin/upgrade/BackupRecordsService.php b/niucloud/app/service/admin/upgrade/BackupRecordsService.php new file mode 100644 index 000000000..49357b8df --- /dev/null +++ b/niucloud/app/service/admin/upgrade/BackupRecordsService.php @@ -0,0 +1,662 @@ +model = new SysBackupRecords(); + $this->root_path = dirname(root_path()) . DIRECTORY_SEPARATOR; + $this->upgrade_dir = $this->root_path . 'upgrade' . DIRECTORY_SEPARATOR; + } + + /** + * 添加备份记录 + * @param array $data + * @return mixed + */ + public function add(array $data) + { + $data[ 'status' ] = BackupDict::STATUS_READY; + $data[ 'create_time' ] = time(); + $res = $this->model->create($data); + return $res->id; + } + + /** + * 编辑备份记录 + * @param array $condition + * @param array $data + * @return true + */ + public function edit($condition, array $data) + { + $this->model->where($condition)->update($data); + return true; + } + + /** + * 修改备注 + * @param $params + * @return true + */ + public function modifyRemark($params) + { + return $this->edit([ + [ 'id', '=', $params[ 'id' ] ] + ], [ 'remark' => $params[ 'remark' ] ]); + } + + /** + * 执行完成,更新备份记录的状态 + * @param $backup_key + * @return void + */ + public function complete($backup_key) + { + $this->model->where([ + [ 'backup_key', '=', $backup_key ], + ])->update([ + 'status' => BackupDict::STATUS_COMPLETE, + 'complete_time' => time() + ]); + } + + /** + * 执行失败,更新备份记录的状态 + * @param $backup_key + * @return void + */ + public function failed($backup_key) + { + $info = $this->getInfo([ + [ 'backup_key', '=', $backup_key ] + ], 'id,backup_key'); + if (!empty($info)) { + $this->del($info[ 'id' ]); + } + } + + /** + * 删除备份记录 + * @param $ids + * @return true + */ + public function del($ids) + { + $list = $this->model->field('id,backup_key')->where([ [ 'id', 'in', $ids ] ])->select()->toArray(); + if (empty($list)) { + throw new AdminException('UPGRADE_RECORD_NOT_EXIST'); + } + try { + Db::startTrans(); + + foreach ($list as $k => $v) { + // 删除备份文件 + $upgrade_dir = project_path() . 'upgrade' . DIRECTORY_SEPARATOR . $v[ 'backup_key' ] . DIRECTORY_SEPARATOR; + if (is_dir($upgrade_dir)) { + del_target_dir($upgrade_dir, true); + } + } + + $this->model->where([ [ 'id', 'in', $ids ] ])->delete(); + Db::commit(); + return true; + } catch (\Exception $e) { + Db::rollback(); + throw new CommonException($e->getMessage()); + } + } + + /** + * 恢复前检测文件是否存在 + * @param $id + * @return void + */ + public function checkDirExist($id) + { + $field = 'id, version, backup_key'; + $info = $this->model->where([ + [ 'id', '=', $id ], + [ 'status', '=', BackupDict::STATUS_COMPLETE ] + ])->field($field)->append([ 'backup_dir', 'backup_code_dir', 'backup_sql_dir' ])->findOrEmpty()->toArray(); + + if (empty($info)) { + throw new AdminException('UPGRADE_RECORD_NOT_EXIST'); + } + + // 检测源码目录是否存在 + if (!is_dir($info[ 'backup_code_dir' ])) { + throw new AdminException('UPGRADE_BACKUP_CODE_NOT_FOUND'); + } + + // 检测数据库目录是否存在 + if (!is_dir($info[ 'backup_sql_dir' ])) { + throw new AdminException('UPGRADE_BACKUP_SQL_NOT_FOUND'); + } + } + + /** + * 检测目录权限 + * @return void + */ + public function checkPermission() + { + $niucloud_dir = $this->root_path . 'niucloud' . DIRECTORY_SEPARATOR; + $admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR; + $web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR; + $wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR; + + if (!is_dir($admin_dir)) throw new CommonException('ADMIN_DIR_NOT_EXIST'); + if (!is_dir($web_dir)) throw new CommonException('WEB_DIR_NOT_EXIST'); + if (!is_dir($wap_dir)) throw new CommonException('UNIAPP_DIR_NOT_EXIST'); + + $data = [ + // 目录检测 + 'dir' => [ + // 要求可读权限 + 'is_readable' => [], + // 要求可写权限 + 'is_write' => [] + ] + ]; + + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $niucloud_dir), 'status' => is_readable($niucloud_dir) ]; + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $admin_dir), 'status' => is_readable($admin_dir) ]; + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $web_dir), 'status' => is_readable($web_dir) ]; + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $wap_dir), 'status' => is_readable($wap_dir) ]; + + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $niucloud_dir), 'status' => is_write($niucloud_dir) ]; + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $admin_dir), 'status' => is_write($admin_dir) ]; + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $web_dir), 'status' => is_write($web_dir) ]; + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $wap_dir), 'status' => is_write($wap_dir) ]; + + // 检测全部目录及文件是否可读可写,忽略指定目录 + + // 忽略指定目录,admin + $exclude_admin_dir = [ 'dist', 'node_modules' ]; + $check_res = checkDirPermissions(project_path() . 'admin', [], $exclude_admin_dir); + + // 忽略指定目录,uni-app + $exclude_uniapp_dir = [ 'dist', 'node_modules' ]; + $check_res = array_merge2($check_res, checkDirPermissions(project_path() . 'uni-app', [], $exclude_uniapp_dir)); + + // 忽略指定目录,web + $exclude_web_dir = [ '.nuxt', '.output', 'dist', 'node_modules' ]; + $check_res = array_merge2($check_res, checkDirPermissions(project_path() . 'web', [], $exclude_web_dir)); + + // 忽略指定目录,niucloud + $exclude_niucloud_dir = [ + 'public' . DIRECTORY_SEPARATOR . 'admin', + 'public' . DIRECTORY_SEPARATOR . 'wap', + 'public' . DIRECTORY_SEPARATOR . 'web', + 'public' . DIRECTORY_SEPARATOR . 'upload', + 'public' . DIRECTORY_SEPARATOR . 'file', + 'runtime', + 'vendor' + ]; + $check_res = array_merge2($check_res, checkDirPermissions(project_path() . 'niucloud', [], $exclude_niucloud_dir)); + + if (!empty($check_res[ 'unreadable' ])) { + foreach ($check_res[ 'unreadable' ] as $item) { + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $item), 'status' => false ]; + } + } + if (!empty($check_res[ 'not_writable' ])) { + foreach ($check_res[ 'not_writable' ] as $item) { + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $item), 'status' => false ]; + } + } + + $check_res = array_merge( + array_column($data[ 'dir' ][ 'is_readable' ], 'status'), + array_column($data[ 'dir' ][ 'is_write' ], 'status') + ); + + // 是否通过校验 + $data[ 'is_pass' ] = !in_array(false, $check_res); + + return $data; + } + + /** + * 备份恢复 + * @param $data + * @return array + */ + public function restore($data) + { + + $field = 'id, version, backup_key'; + $info = $this->model->where([ + [ 'id', '=', $data[ 'id' ] ], + [ 'status', '=', BackupDict::STATUS_COMPLETE ] + ])->field($field)->append([ 'backup_dir', 'backup_code_dir', 'backup_sql_dir' ])->findOrEmpty()->toArray(); + + if (empty($info)) { + throw new AdminException('UPGRADE_RECORD_NOT_EXIST'); + } + + // 恢复源码备份 + if (!is_dir($info[ 'backup_code_dir' ])) { + throw new AdminException('UPGRADE_BACKUP_CODE_NOT_FOUND'); + } + + // 恢复数据库备份 + if (!is_dir($info[ 'backup_sql_dir' ])) { + throw new AdminException('UPGRADE_BACKUP_SQL_NOT_FOUND'); + } + + $res = [ 'code' => 1, 'data' => [], 'msg' => '' ]; + $cache_data = Cache::get($this->cache_restore_key); + if (!empty($cache_data) && !empty($cache_data[ 'key' ])) { + $key = $cache_data[ 'key' ]; + } else { + $key = uniqid(); + } + + try { + if ($data[ 'task' ] == '') { + + $key = uniqid(); + + $res[ 'data' ] = [ + 'content' => '开始恢复备份', + 'task' => 'backupCode' + ]; + + $temp = [ + 'key' => $key, + 'data' => [ $res[ 'data' ] ] + ]; + + Cache::set($this->cache_key, null); + + Cache::set($this->cache_restore_key, $temp); + + // 添加恢复日志 + $this->add([ + 'backup_key' => $key, + 'content' => "自动备份", + 'version' => $info[ 'version' ] + ]); + + } elseif ($data[ 'task' ] == 'backupCode') { + $res[ 'data' ] = [ + 'content' => '备份源码', + 'task' => 'backupSql' + ]; + + $temp = Cache::get($this->cache_restore_key); + $temp[ 'data' ][] = $res[ 'data' ]; + Cache::set($this->cache_restore_key, $temp); + + //备份源码 + $this->backupCode($key); + + } elseif ($data[ 'task' ] == 'backupSql') { + $backup_result = $this->backupSql($key); + if ($backup_result === true) { + //备份数据库 + $res[ 'data' ] = [ + 'content' => '数据库备份完成', + 'task' => 'restoreCode' + ]; + } else { + $res[ 'data' ] = [ + 'content' => '', + 'task' => 'backupSql' + ]; + if ($backup_result % 5 == 0) { + $res[ 'data' ][ 'content' ] = $backup_result == 0 ? '数据库开始备份' : '数据库备份中已备份' . $backup_result . '%'; + } + } + + $temp = Cache::get($this->cache_restore_key); + $temp[ 'data' ][] = $res[ 'data' ]; + Cache::set($this->cache_restore_key, $temp); + } elseif ($data[ 'task' ] == 'restoreCode') { + + $res[ 'data' ] = [ + 'content' => '恢复源码备份', + 'task' => 'restoreSql' + ]; + + $temp = Cache::get($this->cache_restore_key); + $temp[ 'data' ][] = $res[ 'data' ]; + Cache::set($this->cache_restore_key, $temp); + + // 恢复源码备份 + $root_path = dirname(root_path()) . DIRECTORY_SEPARATOR; + dir_copy($info[ 'backup_code_dir' ], rtrim($root_path, DIRECTORY_SEPARATOR)); + + } elseif ($data[ 'task' ] == 'restoreSql') { + // 恢复数据库备份 + $db = new DbBackup($info[ 'backup_sql_dir' ]); + $restore_result = $db->restoreDatabase(); + + if ($restore_result === true) { + $res[ 'data' ] = [ + 'content' => '恢复数据库备份', + 'task' => 'restoreData' + ]; + } else { + $res[ 'data' ] = [ + 'content' => '', + 'task' => 'restoreSql' + ]; + } + + $temp = Cache::get($this->cache_restore_key); + $temp[ 'data' ][] = $res[ 'data' ]; + Cache::set($this->cache_restore_key, $temp); + } elseif ($data[ 'task' ] == 'restoreData') { + + $res[ 'data' ] = [ + 'content' => '恢复数据', + 'task' => 'restoreComplete' + ]; + + $temp = Cache::get($this->cache_restore_key); + $temp[ 'data' ][] = $res[ 'data' ]; + Cache::set($this->cache_restore_key, $temp); + // todo 恢复数据 + + } elseif ($data[ 'task' ] == 'restoreComplete') { + + $res[ 'data' ] = [ + 'content' => '备份恢复完成', + 'task' => 'end' + ]; + + // 修改备份记录状态 + $this->edit([ + [ 'backup_key', '=', Cache::get($this->cache_restore_key)[ 'key' ] ], + ], [ + 'status' => BackupDict::STATUS_COMPLETE, + 'complete_time' => time() + ]); + + Cache::set($this->cache_restore_key, null); + + ( new SystemService() )->clearCache(); // 清除缓存 + } + return $res; + } catch (\Exception $e) { + $res[ 'data' ] = [ + 'content' => '备份恢复失败,稍后请手动恢复,备份文件路径:' . $info[ 'backup_dir' ] . ',失败原因:' . $e->getMessage() . $e->getFile() . $e->getLine(), + 'task' => 'fail' + ]; + + $fail_reason = [ + 'Message' => '失败原因:' . $e->getMessage(), + 'File' => '文件:' . $e->getFile(), + 'Line' => '代码行号:' . $e->getLine(), + 'Trace' => $e->getTrace() + ]; + + // 修改备份记录状态 + $this->edit([ + [ 'backup_key', '=', Cache::get($this->cache_restore_key)[ 'key' ] ], + ], [ + 'fail_reason' => $fail_reason, + 'status' => BackupDict::STATUS_FAIL, + 'complete_time' => time() + ]); + Cache::set($this->cache_restore_key, null); + + return $res; + } + } + + /** + * 手动备份 + * @param $data + * @return array + */ + public function manualBackup($data) + { + $res = [ 'code' => 1, 'data' => [], 'msg' => '' ]; + $key = uniqid(); + $cache_data = Cache::get($this->cache_key); + if ($cache_data) { + $key = $cache_data[ 'key' ]; + } + try { + if ($data[ 'task' ] == '') { + + $key = uniqid(); + + $res[ 'data' ] = [ + 'content' => '开始备份', + 'task' => 'backupCode' + ]; + + $temp = [ + 'key' => $key, + 'data' => [ $res[ 'data' ] ] + ]; + + Cache::set($this->cache_key, null); + + Cache::set($this->cache_key, $temp); + // 添加备份日志 + $this->add([ + 'backup_key' => $key, + 'content' => "手动备份", + 'version' => "v" . config('version.version'), + ]); + + } elseif ($data[ 'task' ] == 'backupCode') { + + $res[ 'data' ] = [ + 'content' => '备份源码', + 'task' => 'backupSql' + ]; + $temp = Cache::get($this->cache_key); + $temp[ 'data' ][] = $res[ 'data' ]; + Cache::set($this->cache_key, $temp); + + //备份源码 + $this->backupCode($key); + + } elseif ($data[ 'task' ] == 'backupSql') { + $backup_result = $this->backupSql($key); + if ($backup_result === true || $backup_result == 100) { + //备份数据库 + $res[ 'data' ] = [ + 'content' => '数据库备份完成', + 'task' => 'backComplete' + ]; + } else { + $res[ 'data' ] = [ + 'content' => $backup_result == 0 ? '数据库开始备份' : '数据库备份已备份' . $backup_result . '%', + 'task' => 'backupSql' + ]; + } + + $temp = Cache::get($this->cache_restore_key); + $temp[ 'data' ][] = $res[ 'data' ]; + Cache::set($this->cache_restore_key, $temp); + } elseif ($data[ 'task' ] == 'backComplete') { + + $res[ 'data' ] = [ + 'content' => '备份完成', + 'task' => 'end' + ]; + + // 修改备份记录状态 + $this->complete(Cache::get($this->cache_key)[ 'key' ]); + + Cache::set($this->cache_key, null); + } + return $res; + } catch (\Exception $e) { + + $res[ 'data' ] = [ + 'content' => '备份失败,稍后请重新手动备份,失败原因:' . $e->getMessage() . $e->getFile() . $e->getLine(), + 'task' => 'fail' + ]; + + // 修改备份记录状态 + $this->failed(Cache::get($this->cache_key)[ 'key' ]); + + Cache::set($this->cache_key, null); + return $res; + } + } + + /** + * 获取正在进行的恢复任务 + * @return mixed|null + */ + public function getRestoreTask() + { + $task_data = Cache::get($this->cache_restore_key) ?? []; + return $task_data; + } + + /** + * 获取正在进行的备份任务 + * @return mixed|null + */ + public function getBackupTask() + { + $task_data = Cache::get($this->cache_key) ?? []; + return $task_data; + } + + /** + * 获取备份记录信息 + * @param array $condition + * @param $field + * @return array + */ + public function getInfo(array $condition, $field = 'id, version, backup_key, content, status, fail_reason, create_time, complete_time') + { + return $this->model->field($field)->where($condition)->findOrEmpty()->toArray(); + } + + /** + * 备份记录列表 + * @param $condition + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function getList($condition = [], $field = 'id, version, backup_key, content, status, fail_reason, create_time, complete_time') + { + $order = "id desc"; + return $this->model->where($condition)->field($field)->order($order)->select()->toArray(); + } + + /** + * 备份记录分页列表 + * @param array $where + * @return array + */ + public function getPage(array $where = []) + { + $field = 'id, version, backup_key, content, remark, complete_time'; + $order = "id desc"; + $search_model = $this->model->where([ + [ 'status', '=', BackupDict::STATUS_COMPLETE ], + [ 'content|version', 'like', '%' . $where[ 'content' ] . '%' ] + ])->append([ 'backup_dir' ])->field($field)->order($order); + return $this->pageQuery($search_model); + } + + /** + * 备份代码 + * @param $backup_key + * @return void + */ + public function backupCode($backup_key) + { + $backup_dir = $this->upgrade_dir . $backup_key . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; + + // 创建目录 + dir_mkdir($backup_dir); + + // 备份admin + dir_copy($this->root_path . 'admin', $backup_dir . 'admin', exclude_dirs: [ '.vscode', 'node_modules', 'dist' ]); + + // 备份uni-app + dir_copy($this->root_path . 'uni-app', $backup_dir . 'uni-app', exclude_dirs: [ 'node_modules', 'dist' ]); + + // 备份web + dir_copy($this->root_path . 'web', $backup_dir . 'web', exclude_dirs: [ 'node_modules', '.nuxt', '.output', 'dist' ]); + + // 备份niucloud全部代码 + $niucloud_dir = $backup_dir . 'niucloud' . DIRECTORY_SEPARATOR; + + dir_copy($this->root_path . 'niucloud', $niucloud_dir, exclude_dirs: [ 'runtime', 'upload' ]); + return true; + } + + /** + * 备份数据库 + * @param $backup_key + * @return void + */ + public function backupSql($backup_key) + { + $backup_dir = $this->upgrade_dir . $backup_key . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; + // 创建目录 + dir_mkdir($backup_dir); + + $prefix = config('database.connections.' . config('database.default'))[ 'prefix' ]; + + // 不需要备份的表 + $not_need_backup = [ + "{$prefix}sys_schedule_log", + "{$prefix}sys_user_log", + "{$prefix}jobs", + "{$prefix}jobs_failed", + "{$prefix}sys_upgrade_records", + "{$prefix}sys_backup_records" + ]; + + $db = new DbBackup($backup_dir, 1024 * 1024 * 2, $not_need_backup, key: $backup_key); + + $result = $db->backupDatabaseSegment(); + if ($result === true) return true; + + return $db->getBackupProgress(); + } + +} diff --git a/niucloud/app/service/admin/upgrade/BackupService.php b/niucloud/app/service/admin/upgrade/BackupService.php index 69d82757f..6ab75ec2a 100644 --- a/niucloud/app/service/admin/upgrade/BackupService.php +++ b/niucloud/app/service/admin/upgrade/BackupService.php @@ -11,10 +11,6 @@ namespace app\service\admin\upgrade; -use app\dict\addon\AddonDict; -use app\service\admin\generator\GenerateService; -use core\util\DbBackup; - /** * 框架及插件升级备份 * @package app\service\core\upgrade @@ -31,92 +27,21 @@ class BackupService extends UpgradeService // 创建目录 dir_mkdir($backup_dir); + // 备份admin - dir_copy($this->root_path . 'admin', $backup_dir . 'admin', exclude_dirs:[ '.vscode', 'node_modules', 'dist' ]); + dir_copy($this->root_path . 'admin', $backup_dir . 'admin', exclude_dirs: [ '.vscode', 'node_modules', 'dist' ]); + // 备份uni-app - dir_copy($this->root_path . 'uni-app', $backup_dir . 'uni-app', exclude_dirs:[ 'node_modules', 'dist' ]); + dir_copy($this->root_path . 'uni-app', $backup_dir . 'uni-app', exclude_dirs: [ 'node_modules', 'dist' ]); + // 备份web - dir_copy($this->root_path . 'web', $backup_dir . 'web', exclude_dirs:[ 'node_modules', '.nuxt', '.output' ]); + dir_copy($this->root_path . 'web', $backup_dir . 'web', exclude_dirs: [ 'node_modules', '.nuxt', '.output', 'dist' ]); - // 备份niucloud + // 备份niucloud全部代码 $niucloud_dir = $backup_dir . 'niucloud' . DIRECTORY_SEPARATOR; - if ($this->upgrade_task[ 'upgrade' ][ 'app_key' ] == AddonDict::FRAMEWORK_KEY) { - dir_copy($this->root_path . 'niucloud', $niucloud_dir, exclude_dirs:[ 'addon', 'config', 'public', 'vendor', 'runtime' ]); - // 备份版本文件 - $version_file = $this->root_path . 'niucloud' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'version.php'; - $to_version_file = $niucloud_dir . 'config' . DIRECTORY_SEPARATOR . 'version.php'; - file_copy($version_file, $to_version_file); - } else { - $addon = $this->upgrade_task[ 'upgrade' ][ 'app_key' ]; - $addon_dir = $this->root_path . 'niucloud' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $addon; - $to_addon_dir = $niucloud_dir . 'addon' . DIRECTORY_SEPARATOR . $addon; - dir_copy($addon_dir, $to_addon_dir); - } - // 备份前端文件 - if (is_dir(public_path() . 'admin')) { - dir_copy(public_path() . 'admin', $niucloud_dir . 'public' . DIRECTORY_SEPARATOR . 'admin'); - } - if (is_dir(public_path() . 'wap')) { - dir_copy(public_path() . 'wap', $niucloud_dir . 'public' . DIRECTORY_SEPARATOR . 'wap'); - } - if (is_dir(public_path() . 'web')) { - dir_copy(public_path() . 'web', $niucloud_dir . 'public' . DIRECTORY_SEPARATOR . 'web'); - } - return true; - } + dir_copy($this->root_path . 'niucloud', $niucloud_dir, exclude_dirs: [ 'runtime', 'upload' ]); - /** - * 备份数据库 - * @return void - */ - public function backupSql() - { - $backup_dir = $this->upgrade_dir . $this->upgrade_task[ 'key' ] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; - // 创建目录 - dir_mkdir($backup_dir); - - $db = new DbBackup([ - 'path' => $backup_dir,//数据库备份路径 - 'part' => 1048576,//数据库备份卷大小 - 'compress' => 0,//数据库备份文件是否启用压缩 0不压缩 1 压缩 - 'level' => 9 //数据库备份文件压缩级别 1普通 4 一般 9最高 - ]); - - $tables = []; - $prefix = config('database.connections.' . config('database.default'))[ 'prefix' ]; - if ($this->upgrade_task[ 'upgrade' ][ 'app_key' ] == AddonDict::FRAMEWORK_KEY) { - // 不需要备份的表 - $noot_need_backup = [ "{$prefix}sys_schedule_log", "{$prefix}sys_user_log", "{$prefix}jobs", "{$prefix}jobs_failed" ]; - $sys_models = ( new GenerateService() )->getModels([ 'addon' => 'system' ]); - foreach ($sys_models as $model) { - $name = "\\$model"; - $class = new $name(); - - if (!in_array($class->getTable(), $noot_need_backup)) { - $tables[] = $class->getTable(); - } - } - } else { - $addon_models = ( new GenerateService() )->getModels([ 'addon' => $this->upgrade_task[ 'upgrade' ][ 'app_key' ] ]); - foreach ($addon_models as $model) { - try { - // 不需要备份的表 - $noot_need_backup = [ "{$prefix}shop_stat", "{$prefix}shop_goods_stat", "{$prefix}shop_goods_browse" ]; - $name = "\\$model"; - $class = new $name(); - - if (!in_array($class->getTable(), $noot_need_backup)) { - $tables[] = $class->getTable(); - } - } catch (\Exception $e) { - } - } - } - - foreach ($tables as $table) { - $db->setFile()->backup($table); - } return true; } } diff --git a/niucloud/app/service/admin/upgrade/RestoreService.php b/niucloud/app/service/admin/upgrade/RestoreService.php index f9ddfdf43..53adfd600 100644 --- a/niucloud/app/service/admin/upgrade/RestoreService.php +++ b/niucloud/app/service/admin/upgrade/RestoreService.php @@ -11,50 +11,10 @@ namespace app\service\admin\upgrade; - -use core\util\DbBackup; - /** * 框架及插件升级恢复备份 * @package app\service\core\upgrade */ class RestoreService extends UpgradeService { - /** - * 恢复代码备份 - * @return true - */ - public function restoreCode() { - $backup_dir = $this->upgrade_dir .$this->upgrade_task['key'] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; - if (is_dir($backup_dir)) { - // 删除前端文件 -// if (is_dir(public_path() . 'admin')) del_target_dir(public_path() . 'admin', true); -// if (is_dir(public_path() . 'wap')) del_target_dir(public_path() . 'wap', true); -// if (is_dir(public_path() . 'web')) del_target_dir(public_path() . 'web', true); - - dir_copy($backup_dir, rtrim($this->root_path, DIRECTORY_SEPARATOR)); - } - return true; - } - - /** - * 恢复数据库备份 - * @return true - */ - public function restoreSql() { - $backup_dir = $this->upgrade_dir .$this->upgrade_task['key'] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; - if (is_dir($backup_dir)) { - $db = new DbBackup([ - 'path' => $backup_dir //数据库备份路径 - ]); - $file_list = $db->fileList(); - if (!empty($file_list)) { - $db->setSqlMode(); - foreach ($file_list as $file) { - $db->setFile($file)->import(0, $file['time']); - } - } - } - return true; - } } diff --git a/niucloud/app/service/admin/upgrade/UpgradeRecordsService.php b/niucloud/app/service/admin/upgrade/UpgradeRecordsService.php new file mode 100644 index 000000000..90f7b7e02 --- /dev/null +++ b/niucloud/app/service/admin/upgrade/UpgradeRecordsService.php @@ -0,0 +1,128 @@ +model = new SysUpgradeRecords(); + } + + /** + * 添加升级记录 + * @param array $data + * @return mixed + */ + public function add(array $data) + { + $data[ 'create_time' ] = time(); + $res = $this->model->create($data); + + // 关联备份记录 + $is_need_backup = $data['is_need_backup'] ?? true; + if ($is_need_backup) { + ( new BackupRecordsService() )->add([ + 'version' => $data[ 'current_version' ], + 'backup_key' => $data[ 'upgrade_key' ], + 'content' => '自动备份' + ]); + } + return $res->id; + } + + /** + * 编辑升级记录 + * @param array $condition + * @param array $data + * @return true + */ + public function edit($condition, array $data) + { + $this->model->where($condition)->update($data); + return true; + } + + /** + * 执行完成,更新升级记录状态,备份记录状态 + * @param $upgrade_key + * @return void + */ + public function complete($upgrade_key) + { + // 记录升级日志 + $this->edit([ + [ 'upgrade_key', '=', $upgrade_key ] + ], [ + 'status' => UpgradeDict::STATUS_COMPLETE, + 'complete_time' => time() + ]); + ( new BackupRecordsService() )->complete($upgrade_key); + } + + /** + * 执行失败,更新升级记录状态,备份记录状态 + * @param $fail_reason + * @return void + */ + public function failed($upgrade_key, $fail_reason = []) + { + $this->model->where([ [ 'upgrade_key', '=', $upgrade_key ] ])->update(['status' => UpgradeDict::STATUS_FAIL, 'fail_reason' => $fail_reason ]); + ( new BackupRecordsService() )->failed($upgrade_key); + } + + /** + * 获取升级记录信息 + * @param array $condition + * @param $field + * @return array + */ + public function getInfo(array $condition, $field = 'id, upgrade_key, app_key, name, content, prev_version, current_version, status, fail_reason, create_time, complete_time') + { + return $this->model->field($field)->where($condition)->findOrEmpty()->toArray(); + } + + /** + * 升级记录分页列表 + * @param array $where + * @return array + */ + public function getPage(array $where = []) + { + $field = 'id, upgrade_key, app_key, name, content, prev_version, current_version, complete_time, create_time, status, fail_reason'; + $order = "id desc"; + $search_model = $this->model->where([ +// [ 'status', '=', UpgradeDict::STATUS_COMPLETE ], + [ 'name|content|current_version', 'like', '%' . $where[ 'name' ] . '%' ] + ])->field($field)->order($order)->append(['status_name']); + return $this->pageQuery($search_model); + } + + /** + * 刪除升级记录 + * @param $ids + * @return void + */ + public function del($ids) { + $this->model->where([['id', 'in', $ids]])->delete(); + } +} diff --git a/niucloud/app/service/admin/upgrade/UpgradeService.php b/niucloud/app/service/admin/upgrade/UpgradeService.php index fac6ced1f..fc5aca1fb 100644 --- a/niucloud/app/service/admin/upgrade/UpgradeService.php +++ b/niucloud/app/service/admin/upgrade/UpgradeService.php @@ -12,7 +12,10 @@ namespace app\service\admin\upgrade; use app\dict\addon\AddonDict; +use app\dict\sys\BackupDict; +use app\dict\sys\UpgradeDict; use app\model\addon\Addon; +use app\model\sys\SysBackupRecords; use app\service\admin\install\InstallSystemService; use app\service\admin\sys\ConfigService; use app\service\core\addon\CoreAddonCloudService; @@ -22,13 +25,17 @@ use app\service\core\addon\CoreDependService; use app\service\core\addon\WapTrait; use app\service\core\channel\CoreH5Service; use app\service\core\menu\CoreMenuService; +use app\service\core\niucloud\CoreCloudBuildService; use app\service\core\niucloud\CoreModuleService; use app\service\core\schedule\CoreScheduleInstallService; use core\base\BaseAdminService; +use core\exception\CloudBuildException; use core\exception\CommonException; +use core\util\DbBackup; use core\util\niucloud\BaseNiucloudClient; use think\facade\Cache; use think\facade\Db; +use think\facade\Log; /** * 框架及插件升级 @@ -50,15 +57,17 @@ class UpgradeService extends BaseAdminService protected $addon = ''; private $steps = [ - 'requestUpgrade' => ['step' => 'requestUpgrade', 'title' => '请求升级'], - 'downloadFile' => ['step' => 'downloadFile', 'title' => '下载更新文件'], - 'backupCode' => ['step' => 'backupCode', 'title' => '备份源码'], - 'backupSql' => ['step' => 'backupSql', 'title' => '备份数据库'], - 'coverCode' => ['step' => 'coverCode', 'title' => '合并更新文件'], - 'handleUniapp' => ['step' => 'handleUniapp', 'title' => '处理uniapp'], - 'refreshMenu' => ['step' => 'refreshMenu', 'title' => '刷新菜单'], - 'installSchedule' => ['step' => 'installSchedule', 'title' => '安装计划任务'], - 'upgradeComplete' => ['step' => 'upgradeComplete', 'title' => '升级完成'] + 'requestUpgrade' => [ 'step' => 'requestUpgrade', 'title' => '请求升级' ], + 'downloadFile' => [ 'step' => 'downloadFile', 'title' => '' ], + 'backupCode' => [ 'step' => 'backupCode', 'title' => '备份源码' ], + 'backupSql' => [ 'step' => 'backupSql', 'title' => '' ], + 'coverCode' => [ 'step' => 'coverCode', 'title' => '合并更新文件' ], + 'handleUniapp' => [ 'step' => 'handleUniapp', 'title' => '处理uniapp' ], + 'refreshMenu' => [ 'step' => 'refreshMenu', 'title' => '刷新菜单' ], + 'installSchedule' => [ 'step' => 'installSchedule', 'title' => '安装计划任务' ], + 'cloudBuild' => [ 'step' => 'cloudBuild', 'title' => '开始云编译' ], + 'gteCloudBuildLog' => [ 'step' => 'gteCloudBuildLog', 'title' => '' ], + 'upgradeComplete' => [ 'step' => 'upgradeComplete', 'title' => '升级完成' ] ]; public function __construct() @@ -68,6 +77,10 @@ class UpgradeService extends BaseAdminService $this->root_path = dirname(root_path()) . DIRECTORY_SEPARATOR; $this->upgrade_dir = $this->root_path . 'upgrade' . DIRECTORY_SEPARATOR; $this->upgrade_task = Cache::get($this->cache_key); + + if (!empty($this->upgrade_task) && !isset($this->upgrade_task[ 'upgrade_apps' ])) { + $this->upgrade_task[ 'upgrade_apps' ] = [ AddonDict::FRAMEWORK_KEY ]; + } } /** @@ -75,7 +88,8 @@ class UpgradeService extends BaseAdminService * @param string $addon * @return void */ - public function upgradePreCheck(string $addon = '') { + public function upgradePreCheck(string $addon = '') + { $niucloud_dir = $this->root_path . 'niucloud' . DIRECTORY_SEPARATOR; $admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR; $web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR; @@ -95,39 +109,62 @@ class UpgradeService extends BaseAdminService ] ]; - $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $niucloud_dir), 'status' => is_readable($niucloud_dir)]; - $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $admin_dir), 'status' => is_readable($admin_dir)]; - $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $web_dir), 'status' => is_readable($web_dir)]; - $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $wap_dir), 'status' => is_readable($wap_dir)]; + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $niucloud_dir), 'status' => is_readable($niucloud_dir) ]; + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $admin_dir), 'status' => is_readable($admin_dir) ]; + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $web_dir), 'status' => is_readable($web_dir) ]; + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $wap_dir), 'status' => is_readable($wap_dir) ]; - $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $niucloud_dir), 'status' => is_write($niucloud_dir) ]; - $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $admin_dir), 'status' => is_write($admin_dir) ]; - $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $web_dir), 'status' => is_write($web_dir) ]; - $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $wap_dir), 'status' => is_write($wap_dir) ]; + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $niucloud_dir), 'status' => is_write($niucloud_dir) ]; + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $admin_dir), 'status' => is_write($admin_dir) ]; + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $web_dir), 'status' => is_write($web_dir) ]; + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $wap_dir), 'status' => is_write($wap_dir) ]; - // 校验niucloud/public下 wap web admin 目录及文件是否可读可写 - $check_res = checkDirPermissions(public_path() . 'wap'); - $check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'admin')); - $check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'web')); + // 检测全部目录及文件是否可读可写,忽略指定目录 - if (!empty($check_res['unreadable'])) { - foreach ($check_res['unreadable'] as $item) { - $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $item),'status' => false]; + // 忽略指定目录,admin + $exclude_admin_dir = [ 'dist', 'node_modules' ]; + $check_res = checkDirPermissions(project_path() . 'admin', [], $exclude_admin_dir); + + // 忽略指定目录,uni-app + $exclude_uniapp_dir = [ 'dist', 'node_modules' ]; + $check_res = array_merge2($check_res, checkDirPermissions(project_path() . 'uni-app', [], $exclude_uniapp_dir)); + + // 忽略指定目录,web + $exclude_web_dir = [ '.nuxt', '.output', 'dist', 'node_modules' ]; + $check_res = array_merge2($check_res, checkDirPermissions(project_path() . 'web', [], $exclude_web_dir)); + + // 忽略指定目录,niucloud + $exclude_niucloud_dir = [ + 'public' . DIRECTORY_SEPARATOR . 'admin', + 'public' . DIRECTORY_SEPARATOR . 'wap', + 'public' . DIRECTORY_SEPARATOR . 'web', + 'public' . DIRECTORY_SEPARATOR . 'upload', + 'public' . DIRECTORY_SEPARATOR . 'file', + 'runtime', + 'vendor', + '.user.ini' + ]; + $check_res = array_merge2($check_res, checkDirPermissions(project_path() . 'niucloud', [], $exclude_niucloud_dir)); + + if (!empty($check_res[ 'unreadable' ])) { + foreach ($check_res[ 'unreadable' ] as $item) { + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $item), 'status' => false ]; } } - if (!empty($check_res['not_writable'])) { - foreach ($check_res['not_writable'] as $item) { - $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $item),'status' => false]; + if (!empty($check_res[ 'not_writable' ])) { + foreach ($check_res[ 'not_writable' ] as $item) { + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $item), 'status' => false ]; } } $check_res = array_merge( - array_column($data['dir']['is_readable'], 'status'), - array_column($data['dir']['is_write'], 'status') + array_column($data[ 'dir' ][ 'is_readable' ], 'status'), + array_column($data[ 'dir' ][ 'is_write' ], 'status') ); // 是否通过校验 - $data['is_pass'] = !in_array(false, $check_res); + $data[ 'is_pass' ] = !in_array(false, $check_res); + return $data; } @@ -136,31 +173,40 @@ class UpgradeService extends BaseAdminService * @param $addon * @return array */ - public function upgrade(string $addon = '') { + public function upgrade(string $addon = '', $data = []) + { if ($this->upgrade_task) throw new CommonException('UPGRADE_TASK_EXIST'); $upgrade_content = $this->getUpgradeContent($addon); + if (empty($upgrade_content[ 'content' ])) throw new CommonException("NOT_EXIST_UPGRADE_CONTENT"); $upgrade = [ 'product_key' => BaseNiucloudClient::PRODUCT, 'framework_version' => config('version.version') ]; - if (!$addon) { - $upgrade['app_key'] = AddonDict::FRAMEWORK_KEY; - $upgrade['version'] = config('version.version'); - } else { - $upgrade['app_key'] = $addon; - $upgrade['version'] = (new Addon())->where([ ['key', '=', $addon] ])->value('version'); - // 判断框架版本是否低于插件支持版本 - $last_version = $upgrade_content['version_list'][ count($upgrade_content['version_list']) - 1]; - if (str_replace('.', '', config('version.version')) < str_replace('.', '', $last_version['niucloud_version']['version_no'])) { - throw new CommonException('BEFORE_UPGRADING_NEED_UPGRADE_FRAMEWORK'); - } + $upgrade[ 'app_key' ] = $upgrade_content[ 'content' ][ 0 ][ 'app' ][ 'app_key' ]; + $upgrade[ 'version' ] = $upgrade_content[ 'content' ][ 0 ][ 'version' ]; + + if (!$addon) { + $upgrade_title = '框架'; +// $upgrade[ 'app_key' ] = AddonDict::FRAMEWORK_KEY; + $upgrade[ 'version' ] = config('version.version'); + } else { +// $upgrade[ 'app_key' ] = $addon; +// $upgrade[ 'version' ] = ( new Addon() )->where([ [ 'key', '=', $addon ] ])->value('version'); + $upgrade_title = ( new Addon() )->where([ [ 'key', 'in', $addon ] ])->field('title')->select()->toArray(); + $upgrade_title = implode(',', array_column($upgrade_title, 'title')); +// +// // 判断框架版本是否低于插件支持版本 +// $last_version = $upgrade_content[ 'version_list' ][ count($upgrade_content[ 'version_list' ]) - 1 ]; +// if (str_replace('.', '', config('version.version')) < str_replace('.', '', $last_version[ 'niucloud_version' ][ 'version_no' ])) { +// throw new CommonException('BEFORE_UPGRADING_NEED_UPGRADE_FRAMEWORK'); +// } } - $response = (new CoreAddonCloudService())->upgradeAddon($upgrade); - if (isset($response['code']) && $response['code'] == 0) throw new CommonException($response['msg']); + $response = ( new CoreAddonCloudService() )->upgradeAddon($upgrade); + if (isset($response[ 'code' ]) && $response[ 'code' ] == 0) throw new CommonException($response[ 'msg' ]); try { $key = uniqid(); @@ -170,17 +216,42 @@ class UpgradeService extends BaseAdminService dir_mkdir($upgrade_dir); } + // 是否需要备份 + $is_need_backup = $data[ 'is_need_backup' ] ?? true; + if (!$is_need_backup) { + unset($this->steps[ 'backupCode' ]); + unset($this->steps[ 'backupSql' ]); + } + $upgrade_task = [ 'key' => $key, 'upgrade' => $upgrade, 'steps' => $this->steps, 'step' => 'requestUpgrade', - 'executed' => ['requestUpgrade'], - 'log' => [ $this->steps['requestUpgrade']['title'] ], - 'params' => ['token' => $response['token'] ], - 'upgrade_content' => $upgrade_content + 'executed' => [ 'requestUpgrade' ], + 'log' => [ $this->steps[ 'requestUpgrade' ][ 'title' ] ], + 'params' => [ 'app_key' => $upgrade[ 'app_key' ], 'token' => $response[ 'token' ] ], + 'upgrade_content' => $upgrade_content, + 'upgrade_apps' => $upgrade_content[ 'upgrade_apps' ], + 'is_need_backup' => $is_need_backup ]; + foreach ($upgrade_content[ 'content' ] as $k => $v) { + unset($upgrade_content[ 'content' ][ $k ][ 'version_list' ]); + } + + // 记录升级日志 + ( new UpgradeRecordsService() )->add([ + 'upgrade_key' => $upgrade_task[ 'key' ], + 'app_key' => $upgrade[ 'app_key' ], + 'name' => $upgrade_title, + 'content' => json_encode($upgrade_content), + 'prev_version' => "", + 'current_version' => "", + 'status' => UpgradeDict::STATUS_READY, + 'is_need_backup' => $is_need_backup + ]); + Cache::set($this->cache_key, $upgrade_task); return $upgrade_task; } catch (\Exception $e) { @@ -192,33 +263,59 @@ class UpgradeService extends BaseAdminService * 执行升级 * @return true */ - public function execute() { + public function execute() + { if (!$this->upgrade_task) return true; - $steps = isset($this->upgrade_task['steps']) ? array_keys($this->upgrade_task['steps']) : array_keys($this->steps); - if (isset($this->upgrade_task['steps'])) $this->steps = $this->upgrade_task['steps']; - $index = array_search($this->upgrade_task['step'], $steps); + $steps = isset($this->upgrade_task[ 'steps' ]) ? array_keys($this->upgrade_task[ 'steps' ]) : array_keys($this->steps); + if (isset($this->upgrade_task[ 'steps' ])) $this->steps = $this->upgrade_task[ 'steps' ]; + $index = array_search($this->upgrade_task[ 'step' ], $steps); $step = $steps[ $index + 1 ] ?? ''; - $params = $this->upgrade_task['params'] ?? []; + $params = $this->upgrade_task[ 'params' ] ?? []; if ($step) { try { $res = $this->$step(...$params); if (is_array($res)) { - $this->upgrade_task['params'] = $res; + $this->upgrade_task[ 'params' ] = $res; } else { - $this->upgrade_task['step'] = $step; - $this->upgrade_task['params'] = []; - $this->upgrade_task['executed'][] = $step; - $this->upgrade_task['log'][] = $this->steps[$step]['title']; + $this->upgrade_task[ 'step' ] = $step; + $this->upgrade_task[ 'params' ] = []; + $this->upgrade_task[ 'executed' ][] = $step; + if (!empty($this->steps[ $step ][ 'title' ])) { + $this->upgrade_task[ 'log' ][] = $this->steps[ $step ][ 'title' ]; + } } - Cache::set($this->cache_key, $this->upgrade_task); + if (!in_array($step, [ 'upgradeComplete', 'restoreComplete' ])) { + Cache::set($this->cache_key, $this->upgrade_task); + } else { + $this->clearUpgradeTask(2); + } + } catch (CloudBuildException $e) { + if (strpos($e->getMessage(), '队列') !== false) { + throw new CloudBuildException($e->getMessage()); + } + $this->upgrade_task[ 'step' ] = $step; + $this->upgrade_task[ 'error' ][] = '升级失败,失败原因:' . $e->getMessage() . $e->getFile() . $e->getLine(); + + $fail_reason = [ + 'Message' => '失败原因:' . $e->getMessage(), + 'File' => '文件:' . $e->getFile(), + 'Line' => '代码行号:' . $e->getLine(), + 'Trace' => $e->getTrace() + ]; + $this->upgradeErrorHandle($fail_reason); } catch (\Exception $e) { - $this->upgrade_task['step'] = $step; - $this->upgrade_task['error'][] = '升级失败,失败原因:' . $e->getMessage().$e->getFile().$e->getLine(); - Cache::set($this->cache_key, $this->upgrade_task); - $this->upgradeErrorHandle(); + $this->upgrade_task[ 'step' ] = $step; + $this->upgrade_task[ 'error' ][] = '升级失败,失败原因:' . $e->getMessage() . $e->getFile() . $e->getLine(); + $fail_reason = [ + 'Message' => '失败原因:' . $e->getMessage(), + 'File' => '文件:' . $e->getFile(), + 'Line' => '代码行号:' . $e->getLine(), + 'Trace' => $e->getTrace() + ]; + $this->upgradeErrorHandle($fail_reason); } return true; } else { @@ -234,12 +331,35 @@ class UpgradeService extends BaseAdminService * @param $step * @return true|null */ - public function downloadFile(string $token, string $dir = '', int $index = -1, $step = 0, $length = 0) { + public function downloadFile(string $app_key, string $token, string $dir = '', int $index = -1, $step = 0, $length = 0) + { if (!$dir) { - $dir = $this->upgrade_dir .$this->upgrade_task['key'] . DIRECTORY_SEPARATOR . 'download' . DIRECTORY_SEPARATOR; + $dir = $this->upgrade_dir . $this->upgrade_task[ 'key' ] . DIRECTORY_SEPARATOR . 'download' . DIRECTORY_SEPARATOR . $app_key . DIRECTORY_SEPARATOR; dir_mkdir($dir); } - $res = (new CoreAddonCloudService())->downloadUpgradeFile($token, $dir, $index, $step, $length); + $res = ( new CoreAddonCloudService() )->downloadUpgradeFile($app_key, $token, $dir, $index, $step, $length); + + if ($res === true) { + $index = array_search($app_key, $this->upgrade_task[ 'upgrade_apps' ]); + if ($app_key == AddonDict::FRAMEWORK_KEY) { + $this->upgrade_task[ 'log' ][] = "下载更新文件"; + } else { + $this->upgrade_task[ 'log' ][] = "下载" . $this->upgrade_task[ 'upgrade_content' ][ 'content' ][ $index ][ 'app' ][ 'app_name' ] . "更新文件"; + } + $index++; + if (isset($this->upgrade_task[ 'upgrade_apps' ][ $index ])) { + $upgrade = [ + 'product_key' => BaseNiucloudClient::PRODUCT, + 'framework_version' => config('version.version'), + 'app_key' => $this->upgrade_task[ 'upgrade_content' ][ 'content' ][ $index ][ 'app' ][ 'app_key' ], + 'version' => $this->upgrade_task[ 'upgrade_content' ][ 'content' ][ $index ][ 'version' ] + ]; + $response = ( new CoreAddonCloudService() )->upgradeAddon($upgrade); + if (isset($response[ 'code' ]) && $response[ 'code' ] == 0) throw new CommonException($response[ 'msg' ]); + + return [ 'app_key' => $upgrade[ 'app_key' ], 'token' => $response[ 'token' ] ]; + } + } return $res; } @@ -247,8 +367,9 @@ class UpgradeService extends BaseAdminService * 备份源码 * @return true */ - public function backupCode() { - (new BackupService())->backupCode(); + public function backupCode() + { + ( new BackupService() )->backupCode(); return true; } @@ -256,24 +377,52 @@ class UpgradeService extends BaseAdminService * 备份数据库 * @return true */ - public function backupSql() { - (new BackupService())->backupSql(); - return true; + public function backupSql($index = 0) + { + $backup_dir = $this->upgrade_dir . $this->upgrade_task[ 'key' ] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; + // 创建目录 + dir_mkdir($backup_dir); + + $db = new DbBackup($backup_dir, 1024 * 1024 * 2, key: $this->upgrade_task[ 'key' ]); + + $prefix = config('database.connections.' . config('database.default'))[ 'prefix' ]; + + // 不需要备份的表 + $not_need_backup = [ + "{$prefix}sys_schedule_log", + "{$prefix}sys_user_log", + "{$prefix}jobs", + "{$prefix}jobs_failed", + "{$prefix}sys_upgrade_records", + "{$prefix}sys_backup_records" + ]; + + $result = $db->setExcludeTables($not_need_backup)->backupDatabaseSegment(); + if ($db->getBackupProgress() == 100) { + $this->upgrade_task[ 'log' ][] = "数据库备份完成"; + } else { + $this->upgrade_task[ 'log' ][] = $db->getBackupProgress() == 0 ? '数据库开始备份' : '数据库备份已备份' . $db->getBackupProgress() . '%'; + } + if ($result === true) return true; + return [ 'index' => $result ]; } /** * 覆盖更新升级的代码 * @return void */ - public function coverCode($index = 0) { - $this->upgrade_task['is_cover'] = 1; - $addon = $this->upgrade_task['upgrade']['app_key']; + public function coverCode($index = 0, $addon = "") + { + $this->upgrade_task[ 'is_cover' ] = 1; + if (empty($addon)) $addon = $this->upgrade_task[ 'upgrade_apps' ][ 0 ]; - $version_list = array_reverse($this->upgrade_task['upgrade_content']['version_list']); - $code_dir = $this->upgrade_dir .$this->upgrade_task['key'] . DIRECTORY_SEPARATOR . 'download' . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; + $app_index = array_search($addon, $this->upgrade_task[ 'upgrade_apps' ]); - $version_item = $version_list[$index]; - $version_no = $version_item['version_no']; + $version_list = array_reverse($this->upgrade_task[ 'upgrade_content' ][ 'content' ][ $app_index ][ 'version_list' ]); + $code_dir = $this->upgrade_dir . $this->upgrade_task[ 'key' ] . DIRECTORY_SEPARATOR . 'download' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; + + $version_item = $version_list[ $index ]; + $version_no = $version_item[ 'version_no' ]; $to_dir = $addon == AddonDict::FRAMEWORK_KEY ? rtrim($this->root_path, DIRECTORY_SEPARATOR) : $this->root_path . 'niucloud' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $addon; @@ -293,20 +442,20 @@ class UpgradeService extends BaseAdminService // 覆盖文件 if (is_dir($code_dir . $version_no)) { // 忽略环境变量文件 - $exclude_files = ['.env.development', '.env.production', '.env', '.env.dev', '.env.product']; - dir_copy($code_dir . $version_no, $to_dir, exclude_files:$exclude_files); + $exclude_files = [ '.env.development', '.env.production', '.env', '.env.dev', '.env.product' ]; + dir_copy($code_dir . $version_no, $to_dir, exclude_files: $exclude_files); if ($addon != AddonDict::FRAMEWORK_KEY) { - (new CoreAddonInstallService($addon))->installDir(); + ( new CoreAddonInstallService($addon) )->installDir(); } } $upgrade_file_dir = 'v' . str_replace('.', '', $version_no); if ($addon == AddonDict::FRAMEWORK_KEY) { $class_path = "\\app\\upgrade\\{$upgrade_file_dir}\\Upgrade"; - $sql_file = root_path() . 'app' . DIRECTORY_SEPARATOR . 'upgrade' . DIRECTORY_SEPARATOR . $upgrade_file_dir . DIRECTORY_SEPARATOR . 'upgrade.sql'; + $sql_file = root_path() . 'app' . DIRECTORY_SEPARATOR . 'upgrade' . DIRECTORY_SEPARATOR . $upgrade_file_dir . DIRECTORY_SEPARATOR . 'upgrade.sql'; } else { $class_path = "\\addon\\{$addon}\\app\\upgrade\\{$upgrade_file_dir}\\Upgrade"; - $sql_file = root_path() . 'addon' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'upgrade' . DIRECTORY_SEPARATOR . $upgrade_file_dir . DIRECTORY_SEPARATOR . 'upgrade.sql'; + $sql_file = root_path() . 'addon' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'upgrade' . DIRECTORY_SEPARATOR . $upgrade_file_dir . DIRECTORY_SEPARATOR . 'upgrade.sql'; } // 执行升级sql @@ -316,13 +465,17 @@ class UpgradeService extends BaseAdminService // 执行升级方法 if (class_exists($class_path)) { - (new $class_path())->handle(); + ( new $class_path() )->handle(); } - $index ++; + $index++; if ($index < count($version_list)) { - return compact('index'); + return compact('index', 'addon'); } else { + $app_index++; + if (isset($this->upgrade_task[ 'upgrade_apps' ][ $app_index ])) { + return [ 'index' => 0, 'addon' => $this->upgrade_task[ 'upgrade_apps' ][ $app_index ] ]; + } return true; } } @@ -332,8 +485,9 @@ class UpgradeService extends BaseAdminService * @param string $version_no * @return void */ - public function installDepend(string $dir, array $change_files) { - $addon = $this->upgrade_task['upgrade']['app_key']; + public function installDepend(string $dir, array $change_files) + { + $addon = $this->upgrade_task[ 'upgrade' ][ 'app_key' ]; $depend_service = new CoreDependService(); if ($addon == AddonDict::FRAMEWORK_KEY) { @@ -352,7 +506,7 @@ class UpgradeService extends BaseAdminService $original = $depend_service->getComposerContent(); $new = $depend_service->jsonFileToArray($dir . $composer); foreach ($new as $name => $value) { - $original[$name] = isset($original[$name]) && is_array($original[$name]) ? array_merge($original[$name], $new[$name]) : $new[$name]; + $original[ $name ] = isset($original[ $name ]) && is_array($original[ $name ]) ? array_map('unserialize', array_unique(array_map('serialize', array_merge($original[ $name ], $new[ $name ])))) : $new[ $name ]; } $depend_service->writeArrayToJsonFile($original, $dir . $composer); } @@ -361,7 +515,7 @@ class UpgradeService extends BaseAdminService $new = $depend_service->jsonFileToArray($dir . $admin_package); foreach ($new as $name => $value) { - $original[$name] = isset($original[$name]) && is_array($original[$name]) ? array_merge($original[$name], $new[$name]) : $new[$name]; + $original[ $name ] = isset($original[ $name ]) && is_array($original[ $name ]) ? array_merge($original[ $name ], $new[ $name ]) : $new[ $name ]; } $depend_service->writeArrayToJsonFile($original, $dir . $admin_package); } @@ -370,7 +524,7 @@ class UpgradeService extends BaseAdminService $new = $depend_service->jsonFileToArray($dir . $web_package); foreach ($new as $name => $value) { - $original[$name] = isset($original[$name]) && is_array($original[$name]) ? array_merge($original[$name], $new[$name]) : $new[$name]; + $original[ $name ] = isset($original[ $name ]) && is_array($original[ $name ]) ? array_merge($original[ $name ], $new[ $name ]) : $new[ $name ]; } $depend_service->writeArrayToJsonFile($original, $dir . $web_package); } @@ -379,7 +533,7 @@ class UpgradeService extends BaseAdminService $new = $depend_service->jsonFileToArray($dir . $uniapp_package); foreach ($new as $name => $value) { - $original[$name] = isset($original[$name]) && is_array($original[$name]) ? array_merge($original[$name], $new[$name]) : $new[$name]; + $original[ $name ] = isset($original[ $name ]) && is_array($original[ $name ]) ? array_merge($original[ $name ], $new[ $name ]) : $new[ $name ]; } $depend_service->writeArrayToJsonFile($original, $dir . $uniapp_package); } @@ -390,12 +544,15 @@ class UpgradeService extends BaseAdminService * @param string $verson_no * @return true */ - public function handleUniapp() { - $code_dir = $this->upgrade_dir .$this->upgrade_task['key'] . DIRECTORY_SEPARATOR . 'download' . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; - $exclude_files = ['.env.development', '.env.production', 'manifest.json']; - dir_copy($code_dir . 'uni-app', $this->root_path . 'uni-app', exclude_files:$exclude_files); + public function handleUniapp() + { + $key = end($this->upgrade_task[ 'upgrade_apps' ]); - $addon_list = (new CoreAddonService())->getInstallAddonList(); + $code_dir = $this->upgrade_dir . $this->upgrade_task[ 'key' ] . DIRECTORY_SEPARATOR . 'download' . DIRECTORY_SEPARATOR . $key . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; + $exclude_files = [ '.env.development', '.env.production', 'manifest.json' ]; + dir_copy($code_dir . 'uni-app', $this->root_path . 'uni-app', exclude_files: $exclude_files); + + $addon_list = ( new CoreAddonService() )->getInstallAddonList(); $depend_service = new CoreDependService(); if (!empty($addon_list)) { @@ -420,7 +577,7 @@ class UpgradeService extends BaseAdminService $new = $depend_service->jsonFileToArray($addon_uniapp_package); foreach ($new as $name => $value) { - $original[$name] = isset($original[$name]) && is_array($original[$name]) ? array_merge($original[$name], $new[$name]) : $new[$name]; + $original[ $name ] = isset($original[ $name ]) && is_array($original[ $name ]) ? array_merge($original[ $name ], $new[ $name ]) : $new[ $name ]; } $uniapp_package = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'package.json'; @@ -429,7 +586,7 @@ class UpgradeService extends BaseAdminService } } - $map = (new ConfigService())->getMap(); + $map = ( new ConfigService() )->getMap(); ( new CoreH5Service() )->mapKeyChange($map[ 'key' ]); return true; @@ -440,7 +597,8 @@ class UpgradeService extends BaseAdminService * @param string $sql_file * @return true */ - private function executeSql(string $sql_file) { + private function executeSql(string $sql_file) + { $sql_content = file_get_contents($sql_file); if (!empty($sql_content)) { @@ -461,11 +619,20 @@ class UpgradeService extends BaseAdminService * 刷新菜单 * @return void */ - public function refreshMenu() { - if ($this->upgrade_task['upgrade']['app_key'] == AddonDict::FRAMEWORK_KEY) { - (new InstallSystemService())->installMenu(); + public function refreshMenu($addon = "") + { + if (empty($addon)) $addon = $this->upgrade_task[ 'upgrade_apps' ][ 0 ]; + $app_index = array_search($addon, $this->upgrade_task[ 'upgrade_apps' ]); + + if ($addon == AddonDict::FRAMEWORK_KEY) { + ( new InstallSystemService() )->installMenu(); } else { - (new CoreMenuService())->refreshAddonMenu($this->upgrade_task['upgrade']['app_key']); + ( new CoreMenuService() )->refreshAddonMenu($addon); + } + + $app_index++; + if (isset($this->upgrade_task[ 'upgrade_apps' ][ $app_index ])) { + return [ 'addon' => $this->upgrade_task[ 'upgrade_apps' ][ $app_index ] ]; } return true; } @@ -474,28 +641,88 @@ class UpgradeService extends BaseAdminService * 安装计划任务 * @return true */ - public function installSchedule() { - if ($this->upgrade_task['upgrade']['app_key'] == AddonDict::FRAMEWORK_KEY) { - (new CoreScheduleInstallService())->installSystemSchedule(); + public function installSchedule($addon = "") + { + if (empty($addon)) $addon = $this->upgrade_task[ 'upgrade_apps' ][ 0 ]; + $app_index = array_search($addon, $this->upgrade_task[ 'upgrade_apps' ]); + + if ($addon == AddonDict::FRAMEWORK_KEY) { + ( new CoreScheduleInstallService() )->installSystemSchedule(); } else { - (new CoreScheduleInstallService())->installAddonSchedule($this->upgrade_task['upgrade']['app_key']); + ( new CoreScheduleInstallService() )->installAddonSchedule($addon); + } + + $app_index++; + if (isset($this->upgrade_task[ 'upgrade_apps' ][ $app_index ])) { + return [ 'addon' => $this->upgrade_task[ 'upgrade_apps' ][ $app_index ] ]; } return true; } + /** + * 云编译 + * @return void + */ + public function cloudBuild() + { + ( new CoreCloudBuildService() )->cloudBuild(); + } + + /** + * 获取云编译日志 + * @return void + */ + public function gteCloudBuildLog() + { + $log = ( new CoreCloudBuildService() )->getBuildLog(); + if (empty($log)) return true; + + foreach ($log[ 'data' ][ 0 ] as $item) { + if ($item[ 'code' ] == 0) { + $this->upgrade_task[ 'step' ] = 'gteCloudBuildLog'; + $this->upgrade_task[ 'error' ][] = $item[ 'msg' ]; + Cache::set($this->cache_key, $this->upgrade_task); + + $fail_reason = [ + 'Message' => '失败原因 云编译错误:' . $item[ 'msg' ], + 'File' => '', + 'Line' => '', + 'Trace' => '' + ]; + + ( new CoreCloudBuildService() )->clearTask(); + + $this->upgradeErrorHandle($fail_reason); + + return true; + } + if (!in_array($item[ 'action' ], $this->upgrade_task[ 'log' ])) { + $this->upgrade_task[ 'log' ][] = $item[ 'action' ]; + Cache::set($this->cache_key, $this->upgrade_task); + } + } + + sleep(2); + return []; + } + /** * 更新完成 * @return void */ - public function upgradeComplete() { - $addon = $this->upgrade_task['upgrade']['app_key']; - if ($addon != AddonDict::FRAMEWORK_KEY) { - $core_addon_service = new CoreAddonService(); - $install_data = $core_addon_service->getAddonConfig($addon); - $install_data['icon'] = 'addon/' . $addon . '/icon.png'; - $core_addon_service->set($install_data); + public function upgradeComplete() + { + foreach ($this->upgrade_task[ 'upgrade_apps' ] as $addon) { + if ($addon != AddonDict::FRAMEWORK_KEY) { + $core_addon_service = new CoreAddonService(); + $install_data = $core_addon_service->getAddonConfig($addon); + $install_data[ 'icon' ] = 'addon/' . $addon . '/icon.png'; + $core_addon_service->set($install_data); + } } - $this->clearUpgradeTask(5); + // 执行完成,更新升级记录状态,备份记录状态 + ( new UpgradeRecordsService() )->complete($this->upgrade_task[ 'key' ]); + $this->clearUpgradeTask(2); return true; } @@ -503,30 +730,41 @@ class UpgradeService extends BaseAdminService * 升级出错之后的处理 * @return true|void */ - public function upgradeErrorHandle() { + public function upgradeErrorHandle($fail_reason = []) + { $steps = []; - $steps[$this->upgrade_task['step']] = []; + $steps[ $this->upgrade_task[ 'step' ] ] = []; - if (isset($this->upgrade_task['is_cover'])) { - $steps['restoreCode'] = ['step' => 'restoreCode', 'title' => '恢复源码备份']; - $steps['restoreSql'] = ['step' => 'restoreSql', 'title' => '恢复数据库备份']; + if (isset($this->upgrade_task[ 'is_cover' ])) { + $steps[ 'restoreCode' ] = [ 'step' => 'restoreCode', 'title' => '恢复源码备份' ]; + $steps[ 'restoreSql' ] = [ 'step' => 'restoreSql', 'title' => '恢复数据库备份' ]; } - $steps['restoreComplete'] = ['step' => 'restoreComplete', 'title' => '备份恢复完成']; - $this->upgrade_task['steps'] = $steps; + $steps[ 'restoreComplete' ] = [ 'step' => 'restoreComplete', 'title' => '备份恢复完成' ]; + $this->upgrade_task[ 'steps' ] = $steps; + $this->upgrade_task[ 'params' ] = []; Cache::set($this->cache_key, $this->upgrade_task); + + Log::write('升级出错之后的处理:' . json_encode($fail_reason)); } /** * 恢复源码 * @return void */ - public function restoreCode() { + public function restoreCode() + { + if ($this->upgrade_task[ 'is_need_backup' ]) { + $backup_dir = $this->upgrade_dir . $this->upgrade_task[ 'key' ] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; + } else { + $backup_dir = $this->upgrade_dir . $this->upgrade_task[ 'upgrade_content' ][ 'last_backup' ][ 'key' ] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; + } try { - (new RestoreService())->restoreCode(); + if (is_dir($backup_dir)) { + dir_copy($backup_dir, rtrim($this->root_path, DIRECTORY_SEPARATOR)); + } return true; } catch (\Exception $e) { - $backup_dir = $this->upgrade_dir .$this->upgrade_task['key'] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR; - $this->upgrade_task['error'][] = '源码备份恢复失败稍后请手动恢复,源码备份文件路径:'. $backup_dir .',失败原因:' . $e->getMessage().$e->getFile().$e->getLine(); + $this->upgrade_task[ 'error' ][] = '源码备份恢复失败稍后请手动恢复,源码备份文件路径:' . $backup_dir . ',失败原因:' . $e->getMessage() . $e->getFile() . $e->getLine(); Cache::set($this->cache_key, $this->upgrade_task); return true; } @@ -536,20 +774,32 @@ class UpgradeService extends BaseAdminService * 恢复数据库 * @return void */ - public function restoreSql() { + public function restoreSql($index = 0) + { + if ($this->upgrade_task[ 'is_need_backup' ]) { + $backup_dir = $this->upgrade_dir . $this->upgrade_task[ 'key' ] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; + } else { + $backup_dir = $this->upgrade_dir . $this->upgrade_task[ 'upgrade_content' ][ 'last_backup' ][ 'key' ] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; + } try { - (new RestoreService())->restoreSql(); + if (is_dir($backup_dir)) { + $db = new DbBackup($backup_dir, key: $this->upgrade_task[ 'key' ]); + $result = $db->restoreDatabase(); + if ($result !== true) return [ 'index' => $result ]; + } + return true; } catch (\Exception $e) { - $backup_dir = $this->upgrade_dir .$this->upgrade_task['key'] . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; - $this->upgrade_task['error'][] = '数据库备份恢复失败稍后请手动恢复,数据库备份文件路径:'. $backup_dir .',失败原因:' . $e->getMessage().$e->getFile().$e->getLine(); + $this->upgrade_task[ 'error' ][] = '数据库备份恢复失败稍后请手动恢复,数据库备份文件路径:' . $backup_dir . ',失败原因:' . $e->getMessage() . $e->getFile() . $e->getLine(); Cache::set($this->cache_key, $this->upgrade_task); return true; } } - public function restoreComplete() { - $this->clearUpgradeTask(5); + public function restoreComplete() + { + ( new UpgradeRecordsService() )->failed($this->upgrade_task[ 'key' ], $this->upgrade_task[ 'error' ]); + $this->clearUpgradeTask(2); return true; } @@ -559,26 +809,56 @@ class UpgradeService extends BaseAdminService * @return array|\core\util\niucloud\Response|object|\Psr\Http\Message\ResponseInterface * @throws \GuzzleHttp\Exception\GuzzleException */ - public function getUpgradeContent(string $addon = '') { + public function getUpgradeContent(string $addon = '') + { + $content = [ + 'content' => [], + 'upgrade_apps' => [] + ]; + $upgrade = [ 'product_key' => BaseNiucloudClient::PRODUCT ]; + $apps = []; if (!$addon) { - $upgrade['app_key'] = AddonDict::FRAMEWORK_KEY; - $upgrade['version'] = config('version.version'); + $upgrade[ 'app_key' ] = AddonDict::FRAMEWORK_KEY; + $upgrade[ 'version' ] = config('version.version'); + array_push($apps, $upgrade); } else { - $upgrade['app_key'] = $addon; - $upgrade['version'] = (new Addon())->where([ ['key', '=', $addon] ])->value('version'); + $addons = array_filter(explode(',', $addon)); + foreach ($addons as $key) { + $info = ( new Addon() )->where([ [ 'key', '=', $key ] ])->field('version,type')->find(); + $upgrade[ 'app_key' ] = $key; + $upgrade[ 'version' ] = $info[ 'version' ]; + if ($info[ 'type' ] == 'app') { + array_unshift($apps, $upgrade); + } else { + array_push($apps, $upgrade); + } + } } - return (new CoreModuleService())->getUpgradeContent($upgrade)['data'] ?? []; + foreach ($apps as $item) { + $upgrade_content = ( new CoreModuleService() )->getUpgradeContent($item)[ 'data' ] ?? []; + if (!empty($upgrade_content)) { + $content[ 'content' ][] = $upgrade_content; + $content[ 'upgrade_apps' ][] = $upgrade_content[ 'app' ][ 'app_key' ]; + } + } + + if (!empty($content[ 'content' ])) { + $content[ 'last_backup' ] = ( new SysBackupRecords() )->where([ [ 'status', '=', BackupDict::STATUS_COMPLETE ] ])->order('complete_time desc')->find(); + } + + return $content; } /** * 获取正在进行的升级任务 * @return mixed|null */ - public function getUpgradeTask() { + public function getUpgradeTask() + { return $this->upgrade_task; } @@ -586,12 +866,20 @@ class UpgradeService extends BaseAdminService * 清除升级任务 * @return true */ - public function clearUpgradeTask(int $delayed = 0) { + public function clearUpgradeTask(int $delayed = 0, int $is_active = 0) + { + // 主动取消升级 + if ($is_active && $this->upgrade_task && !empty($this->upgrade_task[ 'key' ])) { + ( new UpgradeRecordsService() )->edit([ [ 'upgrade_key', '=', $this->upgrade_task[ 'key' ] ], [ 'status', '=', UpgradeDict::STATUS_READY ] ], [ 'status' => UpgradeDict::STATUS_CANCEL ]); + } + if ($delayed) { Cache::set($this->cache_key, $this->upgrade_task, $delayed); } else { Cache::set($this->cache_key, null); } + // 清除云编译的任务缓存 + ( new CoreCloudBuildService() )->clearTask(); return true; } @@ -602,6 +890,32 @@ class UpgradeService extends BaseAdminService */ public function geAddonPackagePath(string $addon) { - return root_path() . 'addon' .DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR . 'package' . DIRECTORY_SEPARATOR; + return root_path() . 'addon' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR . 'package' . DIRECTORY_SEPARATOR; + } + + /** + * 用户操作 + * @param $operate + * @return void + */ + public function operate($operate) + { + if (!$this->upgrade_task) return true; + + switch ($operate) { + case 'local': + $this->upgrade_task[ 'step' ] = 'gteCloudBuildLog'; + Cache::set($this->cache_key, $this->upgrade_task); + break; + case 'rollback': + $fail_reason = [ + 'Message' => '失败原因:一键云编译队列任务过多', + 'File' => '', + 'Line' => '', + 'Trace' => '' + ]; + $this->upgradeErrorHandle($fail_reason); + break; + } } } diff --git a/niucloud/app/service/admin/verify/VerifierService.php b/niucloud/app/service/admin/verify/VerifierService.php index e9e252f13..88c3a7e28 100644 --- a/niucloud/app/service/admin/verify/VerifierService.php +++ b/niucloud/app/service/admin/verify/VerifierService.php @@ -37,9 +37,9 @@ class VerifierService extends BaseAdminService */ public function getPage(array $where = []) { - $search_model = $this->model->where([ ['id', '>', 0] ])->with(['member' => function($query){ + $search_model = $this->model->where([ [ 'id', '>', 0 ] ])->with([ 'member' => function ($query) { $query->field('member_id, nickname, mobile, headimg'); - }])->field('*')->order('create_time desc'); + } ])->field('*')->order('create_time desc'); return $this->pageQuery($search_model, function ($item, $key) { $item = $this->makeUp($item); }); @@ -52,31 +52,39 @@ class VerifierService extends BaseAdminService */ public function getList(array $where = []) { - return $this->model->where([['id', '>', 0]])->with(['member' => function ($query) { + return $this->model->where([ [ 'id', '>', 0 ] ])->with([ 'member' => function ($query) { $query->field('member_id, nickname, mobile, headimg'); - }])->field('*')->order('create_time desc')->select()->toArray(); + } ])->field('*')->order('create_time desc')->select()->toArray(); } /** * 组合整理数据 * @param $data */ - public function makeUp($data){ + public function makeUp($data) + { //核销类型 - if(!empty($data['verify_type'])){ + if (!empty($data[ 'verify_type' ])) { $type = VerifyDict::getType(); $type_array = []; - foreach ($data['verify_type'] as $key => $value) { + foreach ($data[ 'verify_type' ] as $key => $value) { if (array_key_exists($value, $type)) { - $type_array[$key]['verify_type'] = $value; - $type_array[$key]['verify_type_name'] = $type[$value]['name']; + $type_array[ $key ][ 'verify_type' ] = $value; + $type_array[ $key ][ 'verify_type_name' ] = $type[ $value ][ 'name' ]; } } - $data['verify_type_array'] = $type_array; + $data[ 'verify_type_array' ] = $type_array; } return $data; } + public function getDetail($id) + { + return $this->model->with([ 'member' => function ($query) { + $query->field('member_id, nickname, mobile, headimg'); + } ])->field('')->findOrEmpty($id)->toArray(); + } + /** * 添加核销员 * @param array $data @@ -84,17 +92,27 @@ class VerifierService extends BaseAdminService */ public function add(array $data) { - $member = (new Member())->where([ ['member_id', '=', $data['member_id'] ] ])->findOrEmpty(); + $member = ( new Member() )->where([ [ 'member_id', '=', $data[ 'member_id' ] ] ])->findOrEmpty(); if ($member->isEmpty()) throw new CommonException('MEMBER_NOT_EXIST'); - $model = $this->model->where([ ['member_id', '=', $data['member_id'] ] ])->findOrEmpty(); - if (!$model->isEmpty()) return $model->id; + $model = $this->model->where([ [ 'member_id', '=', $data[ 'member_id' ] ] ])->findOrEmpty(); + if (!$model->isEmpty()) throw new CommonException('VERIFIER_EXIST'); - $data['create_time'] = time(); + $data[ 'create_time' ] = time(); $res = $this->model->create($data); return $res->id; } + /** + * 编辑核销员 + * @param array $data + * @return mixed + */ + public function edit($id, $data) + { + $this->model->where([ [ 'id', '=', $id ] ])->update($data); + } + /** * 删除核销员 * @param int $id @@ -102,7 +120,7 @@ class VerifierService extends BaseAdminService */ public function del(int $id) { - $res = $this->model->where([['id', '=', $id] ])->delete(); + $res = $this->model->where([ [ 'id', '=', $id ] ])->delete(); return $res; } } diff --git a/niucloud/app/service/admin/verify/VerifyService.php b/niucloud/app/service/admin/verify/VerifyService.php index dcb7711e7..a1d103ec6 100644 --- a/niucloud/app/service/admin/verify/VerifyService.php +++ b/niucloud/app/service/admin/verify/VerifyService.php @@ -33,11 +33,12 @@ class VerifyService extends BaseAdminService * @return array * @throws \think\db\exception\DbException */ - public function getPage(array $where = []) { - $search_model = $this->model->where([['id', '>', 0]])->withSearch(['code', 'type', 'create_time', 'verifier_member_id'], $where) - ->with(['member' => function($query){ + public function getPage(array $where = []) + { + $search_model = $this->model->where([ [ 'id', '>', 0 ] ])->withSearch([ 'code', 'type', 'create_time', 'verifier_member_id' ], $where) + ->with([ 'member' => function($query) { $query->field('member_id, nickname, mobile, headimg'); - }])->field('*')->order('create_time desc')->append(['type_name']); + } ])->field('*')->order('create_time desc')->append([ 'type_name' ]); $list = $this->pageQuery($search_model); return $list; } @@ -47,15 +48,16 @@ class VerifyService extends BaseAdminService * @param string $verify_code * @return array */ - public function getDetail(string $verify_code) { + public function getDetail(string $verify_code) + { $info = $this->model->where([ - ['code', '=', $verify_code] + [ 'code', '=', $verify_code ] ])->field('*') - ->with(['member' => function($query){ - $query->field('member_id, nickname, mobile, headimg'); - }])->append(['type_name'])->findOrEmpty()->toArray(); + ->with([ 'member' => function($query) { + $query->field('member_id, nickname, mobile, headimg'); + } ])->append([ 'type_name' ])->findOrEmpty()->toArray(); - $info['verify_info'] = event('VerifyInfo',$info); + $info[ 'verify_info' ] = event('VerifyInfo', $info); return $info; } diff --git a/niucloud/app/service/api/diy/DiyConfigService.php b/niucloud/app/service/api/diy/DiyConfigService.php index fe868ef6b..085674a82 100644 --- a/niucloud/app/service/api/diy/DiyConfigService.php +++ b/niucloud/app/service/api/diy/DiyConfigService.php @@ -71,16 +71,15 @@ class DiyConfigService extends BaseApiService // 检测当前站点是多应用还是单应用 if ($key == 'app') { $apps = ( new CoreAddonService() )->getList([ [ 'type', '=', 'app' ] ]); + $list = ( new CoreDiyConfigService() )->getBottomList(); $bottom_list_keys = array_column($list, 'key'); - // 排除没有底部导航的应用 foreach ($apps as $k => $v) { if (!in_array($v[ 'key' ], $bottom_list_keys)) { unset($apps[ $k ]); } } - $apps = array_values($apps); if (count($apps) == 1) { $key = $apps[ 0 ][ 'key' ]; } diff --git a/niucloud/app/service/api/diy/DiyService.php b/niucloud/app/service/api/diy/DiyService.php index c606eb4b9..0cb34b5c4 100644 --- a/niucloud/app/service/api/diy/DiyService.php +++ b/niucloud/app/service/api/diy/DiyService.php @@ -151,32 +151,32 @@ class DiyService extends BaseApiService */ public function getDiyTheme() { - $addon_list = (new CoreAddonService())->getInstallAddonList(); - $apps=[]; - foreach ($addon_list as $k=>$v){ - if($v['type']=='app'){ - $apps[]=$v; + $addon_list = ( new CoreAddonService() )->getInstallAddonList(); + $apps = []; + foreach ($addon_list as $k => $v) { + if ($v[ 'type' ] == 'app') { + $apps[] = $v; } } - $theme_data = (new DiyTheme())->where([['is_selected', '=', 1]])->column('id,title,theme,new_theme','addon'); - $system_theme = array_values(array_filter(event('ThemeColor', [ 'key' => 'app'])))[0] ?? []; - $app_theme['app'] = [ - 'title' => $theme_data['app']['title'] ?? (!empty($system_theme) ? $system_theme['theme_color'][0]['title'] : ''), - 'theme' => $theme_data['app']['theme'] ?? (!empty($system_theme) ? $system_theme['theme_color'][0]['theme'] : ''), - 'new_theme' => $theme_data['app']['new_theme'] ?? '', + $theme_data = ( new DiyTheme() )->where([ [ 'is_selected', '=', 1 ] ])->column('id,title,theme,new_theme', 'addon'); + $system_theme = array_values(array_filter(event('ThemeColor', [ 'key' => 'app' ])))[ 0 ] ?? []; + $app_theme[ 'app' ] = [ + 'title' => $theme_data[ 'app' ][ 'title' ] ?? ( !empty($system_theme) ? $system_theme[ 'theme_color' ][ 0 ][ 'title' ] : '' ), + 'theme' => $theme_data[ 'app' ][ 'theme' ] ?? ( !empty($system_theme) ? $system_theme[ 'theme_color' ][ 0 ][ 'theme' ] : '' ), + 'new_theme' => $theme_data[ 'app' ][ 'new_theme' ] ?? '', ]; $data = []; - foreach ($addon_list as $key => $value){ - if (isset($value['support_app']) && empty($value['support_app']) && $value['type'] == 'addon'){ + foreach ($addon_list as $key => $value) { + if (isset($value[ 'support_app' ]) && empty($value[ 'support_app' ]) && $value[ 'type' ] == 'addon') { continue; } - $addon_theme = array_values(array_filter(event('ThemeColor', [ 'key' => $value['key']])))[0] ?? []; - $data[$value['key']]['title'] = $theme_data[$value['key']]['title'] ?? (!empty($addon_theme) ? $addon_theme['theme_color'][0][ 'title' ] : ''); - $data[$value['key']]['theme'] = $theme_data[$value['key']]['theme'] ?? (!empty($addon_theme) ? $addon_theme['theme_color'][0][ 'theme' ] : ''); - $data[$value['key']]['new_theme'] = $theme_data[$value['key']]['new_theme'] ?? ''; + $addon_theme = array_values(array_filter(event('ThemeColor', [ 'key' => $value[ 'key' ] ])))[ 0 ] ?? []; + $data[ $value[ 'key' ] ][ 'title' ] = $theme_data[ $value[ 'key' ] ][ 'title' ] ?? ( !empty($addon_theme) ? $addon_theme[ 'theme_color' ][ 0 ][ 'title' ] : '' ); + $data[ $value[ 'key' ] ][ 'theme' ] = $theme_data[ $value[ 'key' ] ][ 'theme' ] ?? ( !empty($addon_theme) ? $addon_theme[ 'theme_color' ][ 0 ][ 'theme' ] : '' ); + $data[ $value[ 'key' ] ][ 'new_theme' ] = $theme_data[ $value[ 'key' ] ][ 'new_theme' ] ?? ''; } if (count($apps) > 1) {// 应用数量大于1时,展示系统主题色设置,只有一个应用时,不展示系统主题色设置 - $data = array_merge($app_theme,$data); + $data = array_merge($app_theme, $data); } return $data; } diff --git a/niucloud/app/service/api/sys/AreaService.php b/niucloud/app/service/api/sys/AreaService.php index 53aef545f..c559760fb 100644 --- a/niucloud/app/service/api/sys/AreaService.php +++ b/niucloud/app/service/api/sys/AreaService.php @@ -220,7 +220,7 @@ class AreaService extends BaseApiService 'formatted_addresses' => $address_data[ 'formatted_addresses' ] ]; } else { - throw new ApiException($res[ 'message' ]); + throw new ApiException('请检查地图配置:'.$res[ 'message' ]); } } else { diff --git a/niucloud/app/service/api/verify/VerifyService.php b/niucloud/app/service/api/verify/VerifyService.php index 98d9511e2..f64756daf 100644 --- a/niucloud/app/service/api/verify/VerifyService.php +++ b/niucloud/app/service/api/verify/VerifyService.php @@ -22,7 +22,6 @@ use core\base\BaseApiService; class VerifyService extends BaseApiService { - /** * 获取核销码(对应业务调用) * @param $type @@ -49,7 +48,7 @@ class VerifyService extends BaseApiService */ public function getInfoByCode($code) { - return ( new CoreVerifyService() )->getInfoByCode($code); + return ( new CoreVerifyService() )->getInfoByCode($this->member_id,$code); } /** @@ -114,4 +113,4 @@ class VerifyService extends BaseApiService ])->field($field)->append([ 'type_name' ])->findOrEmpty()->toArray(); } -} \ No newline at end of file +} diff --git a/niucloud/app/service/core/addon/CoreAddonCloudService.php b/niucloud/app/service/core/addon/CoreAddonCloudService.php index e6b835a8a..216961681 100644 --- a/niucloud/app/service/core/addon/CoreAddonCloudService.php +++ b/niucloud/app/service/core/addon/CoreAddonCloudService.php @@ -35,7 +35,10 @@ class CoreAddonCloudService extends CoreCloudBaseService $package_dir = $temp_dir . 'package' . DIRECTORY_SEPARATOR; dir_mkdir($package_dir); - $compile = (new CoreAddonService())->getAddonConfig($addon)['compile'] ?? []; + + $addon_config = (new CoreAddonService())->getAddonConfig($addon); + $compile = $addon_config['compile'] ?? []; + $custom_port = $addon_config['port']?? []; $need_build = false; // 拷贝composer文件 @@ -60,6 +63,19 @@ class CoreAddonCloudService extends CoreCloudBaseService $need_build = true; } + // 自定义端口 + if (!empty($custom_port)) { + $addon_path = $this->addonPath($addon); + foreach ($custom_port as $port) { + if (is_dir($addon_path . $port[ 'name' ])) { + dir_copy($addon_path . $port[ 'name' ], $package_dir . $port[ 'name' ]); + $json_path = $package_dir . $port[ 'name' ] . DIRECTORY_SEPARATOR . 'info.json'; + file_put_contents($json_path, json_encode($port)); + } + } + $need_build = true; + } + if ($need_build) { // 将临时目录下文件生成压缩包 $zip_file = $temp_dir . DIRECTORY_SEPARATOR . 'build.zip'; @@ -224,10 +240,6 @@ class CoreAddonCloudService extends CoreCloudBaseService */ public function downloadAddon(string $addon, string $version) { $action_token = (new CoreModuleService())->getActionToken('download', ['data' => ['app_key' => $addon, 'version' => $version, 'product_key' => BaseNiucloudClient::PRODUCT ]]); - if (isset($action_token['code']) && $action_token['code'] != 1) { - if ($action_token['code'] == 401) $action_token = (new CoreModuleService())->getActionToken('download', ['data' => ['app_key' => $addon, 'version' => $version, 'product_key' => BaseNiucloudClient::PRODUCT]]); - if ($action_token['code'] != 1) throw new CommonException($action_token['msg']); - } $query = [ 'authorize_code' => $this->auth_code, @@ -265,10 +277,6 @@ class CoreAddonCloudService extends CoreCloudBaseService */ public function upgradeAddon(array $data = []) { $action_token = (new CoreModuleService())->getActionToken('upgrade', ['data' => $data ]); - if (isset($action_token['code']) && $action_token['code'] != 1) { - if ($action_token['code'] == 401) $action_token = (new CoreModuleService())->getActionToken('upgrade', ['data' => $data ]); - if ($action_token['code'] != 1) throw new CommonException($action_token['msg']); - } $query = [ 'authorize_code' => $this->auth_code, @@ -286,7 +294,7 @@ class CoreAddonCloudService extends CoreCloudBaseService * @param string $token * @return void */ - public function downloadUpgradeFile(string $token, string $dir = '', int $index = -1, $step = 0, $length = 0) { + public function downloadUpgradeFile(string $app_key, string $token, string $dir = '', int $index = -1, $step = 0, $length = 0) { $query = [ 'authorize_code' => $this->auth_code, 'token' => $token @@ -302,7 +310,7 @@ class CoreAddonCloudService extends CoreCloudBaseService $step = (int)ceil($length / $chunk_size); $index++; - return compact('token', 'dir', 'index', 'step', 'length'); + return compact('app_key', 'token', 'dir', 'index', 'step', 'length'); } else { $zip_file = $dir . 'upgrade.zip'; $zip_resource = fopen($zip_file, 'a'); @@ -319,7 +327,7 @@ class CoreAddonCloudService extends CoreCloudBaseService fclose($zip_resource); $index++; - return compact('token', 'dir', 'index', 'step', 'length'); + return compact('app_key', 'token', 'dir', 'index', 'step', 'length'); } else { $zip = new \ZipArchive(); if ($zip->open($zip_file) === true) { diff --git a/niucloud/app/service/core/addon/CoreAddonDevelopService.php b/niucloud/app/service/core/addon/CoreAddonDevelopService.php index 08ca6273a..9be457b87 100644 --- a/niucloud/app/service/core/addon/CoreAddonDevelopService.php +++ b/niucloud/app/service/core/addon/CoreAddonDevelopService.php @@ -366,6 +366,7 @@ class CoreAddonDevelopService extends CoreAddonBaseService if (empty($image)) return true; if (check_file_is_remote($image)) { try { + downloadImage($image,$file); // 将云存储的图片下载到本地 (new CoreFetchService())->setRootPath($dir)->setRename($name)->image($image, 0, FileDict::LOCAL); } catch ( UploadFileException $e ) { return true; diff --git a/niucloud/app/service/core/addon/WapTrait.php b/niucloud/app/service/core/addon/WapTrait.php index 8628037c7..96db5254c 100644 --- a/niucloud/app/service/core/addon/WapTrait.php +++ b/niucloud/app/service/core/addon/WapTrait.php @@ -83,6 +83,7 @@ trait WapTrait $addon_arr[] = $addon; // 追加新装插件 } $addon_arr = array_unique($addon_arr); + foreach ($addon_arr as $k => $v) { $addon_path = $compile_path . str_replace('/', DIRECTORY_SEPARATOR, 'addon/' . $v . '/components/diy'); // 插件自定义组件根目录 $addon_file_arr = getFileMap($addon_path); diff --git a/niucloud/app/service/core/diy/CoreDiyService.php b/niucloud/app/service/core/diy/CoreDiyService.php index cd0815c42..e5954e099 100644 --- a/niucloud/app/service/core/diy/CoreDiyService.php +++ b/niucloud/app/service/core/diy/CoreDiyService.php @@ -40,52 +40,52 @@ class CoreDiyService extends BaseCoreService */ public function initDefaultDiyTheme() { - $addon_list = (new CoreAddonService())->getInstallAddonList(); - $apps=[]; - foreach ($addon_list as $k=>$v){ - if($v['type']=='app'){ - $apps[]=$v; + $addon_list = ( new CoreAddonService() )->getInstallAddonList(); + $apps = []; + foreach ($addon_list as $k => $v) { + if ($v[ 'type' ] == 'app') { + $apps[] = $v; } } - $system_theme = array_values(array_filter(event('ThemeColor', [ 'key' => 'app'])))[0] ?? []; - foreach ($system_theme['theme_color'] as $k => $v) { + $system_theme = array_values(array_filter(event('ThemeColor', [ 'key' => 'app' ])))[ 0 ] ?? []; + foreach ($system_theme[ 'theme_color' ] as $k => $v) { $data[] = [ 'type' => 'app', 'addon' => 'app', - 'title' => $v['title'], - 'theme' => $v['theme'], - 'default_theme' => $v['theme'], + 'title' => $v[ 'title' ], + 'theme' => $v[ 'theme' ], + 'default_theme' => $v[ 'theme' ], 'theme_type' => 'default', 'is_selected' => $k == 0 ? 1 : 0, 'create_time' => time(), ]; } - foreach ($apps as $value){ - $addon_theme = array_values(array_filter(event('ThemeColor', [ 'key' => $value['key'] ])))[0] ?? []; + foreach ($apps as $value) { + $addon_theme = array_values(array_filter(event('ThemeColor', [ 'key' => $value[ 'key' ] ])))[ 0 ] ?? []; if (empty($addon_theme)) continue; - foreach ($addon_theme['theme_color'] as $k => $v){ + foreach ($addon_theme[ 'theme_color' ] as $k => $v) { $data[] = [ 'type' => 'app', - 'addon' => $value['key'], - 'title' => $v['title'], - 'theme' => $v['theme'], - 'default_theme' => $v['theme'], + 'addon' => $value[ 'key' ], + 'title' => $v[ 'title' ], + 'theme' => $v[ 'theme' ], + 'default_theme' => $v[ 'theme' ], 'theme_type' => 'default', 'is_selected' => $k == 0 ? 1 : 0, 'create_time' => time(), ]; } - $addon_data = (new addon())->field('key')->where([['support_app', '=', $value['key']]])->select()->toArray(); - if (!empty($addon_data)){ - foreach ($addon_data as $v){ - foreach ($addon_theme['theme_color'] as $theme_k => $theme_v){ + $addon_data = ( new addon() )->field('key')->where([ [ 'support_app', '=', $value[ 'key' ] ] ])->select()->toArray(); + if (!empty($addon_data)) { + foreach ($addon_data as $v) { + foreach ($addon_theme[ 'theme_color' ] as $theme_k => $theme_v) { $data[] = [ 'type' => 'addon', - 'addon' => $v['key'], - 'title' => $theme_v['title'], - 'theme' => $theme_v['theme'], - 'default_theme' => $theme_v['theme'], + 'addon' => $v[ 'key' ], + 'title' => $theme_v[ 'title' ], + 'theme' => $theme_v[ 'theme' ], + 'default_theme' => $theme_v[ 'theme' ], 'theme_type' => 'default', 'is_selected' => $theme_k == 0 ? 1 : 0, 'create_time' => time(), @@ -98,7 +98,7 @@ class CoreDiyService extends BaseCoreService foreach ($data as $k => &$v) { $theme_count = $diy_theme_model->where([ [ 'title', "=", $v[ 'title' ] ], - [ 'addon', "=", $v['addon'] ] + [ 'addon', "=", $v[ 'addon' ] ] ])->count(); // 如果已有该主题风格颜色则不再添加 if ($theme_count > 0) { diff --git a/niucloud/app/service/core/menu/CoreMenuService.php b/niucloud/app/service/core/menu/CoreMenuService.php index 24b298dbd..96cd152e5 100644 --- a/niucloud/app/service/core/menu/CoreMenuService.php +++ b/niucloud/app/service/core/menu/CoreMenuService.php @@ -90,10 +90,15 @@ class CoreMenuService extends BaseCoreService $addon_admin_tree = $addon_loader->load(["addon" => $addon, "app_type" => "admin"]); if (isset($addon_admin_tree['delete'])) unset($addon_admin_tree['delete']); - - $admin_menu = $this->loadMenu($addon_admin_tree, "admin", $addon); + $menu_list = []; + if (!empty($addon_admin_tree)) { + $menu_list = array_merge($menu_list, $this->loadMenu($addon_admin_tree, "admin", $addon)); + } $this->deleteByAddon($addon, false); - $this->install($admin_menu); + if(!empty($menu_list)) + { + $this->install($menu_list); + } return true; diff --git a/niucloud/app/service/core/niucloud/CoreCloudBuildService.php b/niucloud/app/service/core/niucloud/CoreCloudBuildService.php index e5b93f5ef..1e410db80 100644 --- a/niucloud/app/service/core/niucloud/CoreCloudBuildService.php +++ b/niucloud/app/service/core/niucloud/CoreCloudBuildService.php @@ -17,6 +17,7 @@ use app\service\core\addon\CoreAddonBaseService; use app\service\core\addon\CoreAddonDevelopDownloadService; use app\service\core\addon\WapTrait; use core\base\BaseCoreService; +use core\exception\CloudBuildException; use core\exception\CommonException; use core\util\niucloud\BaseNiucloudClient; use core\util\niucloud\CloudService; @@ -42,14 +43,15 @@ class CoreCloudBuildService extends BaseCoreService parent::__construct(); $this->root_path = project_path(); $this->build_task = Cache::get($this->cache_key); - $this->auth_code = (new CoreNiucloudConfigService())->getNiucloudConfig()['auth_code'] ?? ''; + $this->auth_code = ( new CoreNiucloudConfigService() )->getNiucloudConfig()[ 'auth_code' ] ?? ''; } /** * 编译前环境检测 * @return array|array[] */ - public function buildPreCheck() { + public function buildPreCheck() + { $niucloud_dir = $this->root_path . 'niucloud' . DIRECTORY_SEPARATOR; $admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR; $web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR; @@ -76,35 +78,35 @@ class CoreCloudBuildService extends BaseCoreService clearstatcache(); // 校验niucloud/public niucloud/vendor 目录是否可读可写 - $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', public_path()), 'status' => is_readable(public_path())]; - $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $niucloud_dir . 'vendor'), 'status' => is_readable($niucloud_dir . 'vendor')]; + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', public_path()), 'status' => is_readable(public_path()) ]; + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $niucloud_dir . 'vendor'), 'status' => is_readable($niucloud_dir . 'vendor') ]; - $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', public_path()), 'status' => is_write(public_path())]; - $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $niucloud_dir . 'vendor'), 'status' => is_write($niucloud_dir . 'vendor')]; + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', public_path()), 'status' => is_write(public_path()) ]; + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $niucloud_dir . 'vendor'), 'status' => is_write($niucloud_dir . 'vendor') ]; // 校验niucloud/public下 wap web admin 目录及文件是否可读可写 $check_res = checkDirPermissions(public_path() . 'wap'); $check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'admin')); $check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'web')); - if (!empty($check_res['unreadable'])) { - foreach ($check_res['unreadable'] as $item) { - $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $item),'status' => false]; + if (!empty($check_res[ 'unreadable' ])) { + foreach ($check_res[ 'unreadable' ] as $item) { + $data[ 'dir' ][ 'is_readable' ][] = [ 'dir' => str_replace(project_path(), '', $item), 'status' => false ]; } } - if (!empty($check_res['not_writable'])) { - foreach ($check_res['not_writable'] as $item) { - $data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $item),'status' => false]; + if (!empty($check_res[ 'not_writable' ])) { + foreach ($check_res[ 'not_writable' ] as $item) { + $data[ 'dir' ][ 'is_write' ][] = [ 'dir' => str_replace(project_path(), '', $item), 'status' => false ]; } } $check_res = array_merge( - array_column($data['dir']['is_readable'], 'status'), - array_column($data['dir']['is_write'], 'status') + array_column($data[ 'dir' ][ 'is_readable' ], 'status'), + array_column($data[ 'dir' ][ 'is_write' ], 'status') ); // 是否通过校验 - $data['is_pass'] = !in_array(false, $check_res); + $data[ 'is_pass' ] = !in_array(false, $check_res); return $data; } @@ -113,10 +115,11 @@ class CoreCloudBuildService extends BaseCoreService * @param $addon * @return void */ - public function cloudBuild() { + public function cloudBuild() + { if ($this->build_task) throw new CommonException('CLOUD_BUILD_TASK_EXIST'); - $action_token = (new CoreModuleService())->getActionToken('cloudbuild', ['data' => [ 'product_key' => BaseNiucloudClient::PRODUCT ]]); + $action_token = ( new CoreModuleService() )->getActionToken('cloudbuild', [ 'data' => [ 'product_key' => BaseNiucloudClient::PRODUCT ] ]); // 上传任务key $task_key = uniqid(); @@ -128,69 +131,71 @@ class CoreCloudBuildService extends BaseCoreService // 拷贝composer文件 file_put_contents($package_dir . 'composer.json', file_get_contents(root_path() . 'composer.json')); // 拷贝手机端文件 - $wap_is_compile = (new Addon())->where([ ['compile', 'like', '%wap%'] ])->field('id')->findOrEmpty(); + $wap_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%wap%' ] ])->field('id')->findOrEmpty(); if ($wap_is_compile->isEmpty()) { - dir_copy($this->root_path . 'uni-app', $package_dir . 'uni-app', exclude_dirs:['node_modules', 'unpackage', 'dist']); + dir_copy($this->root_path . 'uni-app', $package_dir . 'uni-app', exclude_dirs: [ 'node_modules', 'unpackage', 'dist' ]); $this->handleUniapp($package_dir . 'uni-app'); } // 拷贝admin端文件 - $admin_is_compile = (new Addon())->where([ ['compile', 'like', '%admin%'] ])->field('id')->findOrEmpty(); + $admin_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%admin%' ] ])->field('id')->findOrEmpty(); if ($admin_is_compile->isEmpty()) { - dir_copy($this->root_path . 'admin', $package_dir . 'admin', exclude_dirs:['node_modules', 'dist', '.vscode', '.idea']); + dir_copy($this->root_path . 'admin', $package_dir . 'admin', exclude_dirs: [ 'node_modules', 'dist', '.vscode', '.idea' ]); } // 拷贝web端文件 - $web_is_compile = (new Addon())->where([ ['compile', 'like', '%web%'] ])->field('id')->findOrEmpty(); + $web_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%web%' ] ])->field('id')->findOrEmpty(); if ($web_is_compile->isEmpty()) { - dir_copy($this->root_path . 'web', $package_dir . 'web', exclude_dirs:['node_modules', '.output', '.nuxt']); + dir_copy($this->root_path . 'web', $package_dir . 'web', exclude_dirs: [ 'node_modules', '.output', '.nuxt' ]); } $this->handleCustomPort($package_dir); $zip_file = $temp_dir . DIRECTORY_SEPARATOR . 'build.zip'; - (new CoreAddonDevelopDownloadService(''))->compressToZip($package_dir, $zip_file); + ( new CoreAddonDevelopDownloadService('') )->compressToZip($package_dir, $zip_file); $query = [ 'authorize_code' => $this->auth_code, 'timestamp' => time(), - 'token' => $action_token['data']['token'] ?? '' + 'token' => $action_token[ 'data' ][ 'token' ] ?? '' ]; - $response = (new CloudService())->httpPost('cloud/build?' . http_build_query($query), [ + $response = ( new CloudService() )->httpPost('cloud/build?' . http_build_query($query), [ 'multipart' => [ [ - 'name' => 'file', + 'name' => 'file', 'contents' => fopen($zip_file, 'r'), 'filename' => 'build.zip' ] ], 'timeout' => 300.0 ]); - if (isset($response['code']) && $response['code'] == 0) throw new CommonException($response['msg']); + if (isset($response[ 'code' ]) && $response[ 'code' ] == 0) throw new CloudBuildException($response[ 'msg' ]); $this->build_task = [ 'task_key' => $task_key, - 'timestamp' => $query['timestamp'] + 'timestamp' => $query[ 'timestamp' ] ]; Cache::set($this->cache_key, $this->build_task); return $this->build_task; } - private function handleUniapp(string $dir) { + private function handleUniapp(string $dir) + { $addon = ( new Addon() )->where([ [ 'status', '=', AddonDict::ON ] ])->value('key', ''); $this->compileDiyComponentsCode($dir . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $addon); } - private function handleCustomPort(string $package_dir) { + private function handleCustomPort(string $package_dir) + { $addons = get_site_addons(); foreach ($addons as $addon) { - $custom_port = (new CoreAddonBaseService())->getAddonConfig($addon)['port'] ?? []; + $custom_port = ( new CoreAddonBaseService() )->getAddonConfig($addon)[ 'port' ] ?? []; if (!empty($custom_port)) { $addon_path = root_path() . 'addon' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR; foreach ($custom_port as $port) { - if (is_dir($addon_path . $port['name'])) { - dir_copy($addon_path . $port['name'], $package_dir . $port['name']); - $json_path = $package_dir . $port['name'] . DIRECTORY_SEPARATOR . 'info.json'; + if (is_dir($addon_path . $port[ 'name' ])) { + dir_copy($addon_path . $port[ 'name' ], $package_dir . $port[ 'name' ]); + $json_path = $package_dir . $port[ 'name' ] . DIRECTORY_SEPARATOR . 'info.json'; file_put_contents($json_path, json_encode($port)); } } @@ -202,7 +207,8 @@ class CoreCloudBuildService extends BaseCoreService * 安装时云编译 * @return void */ - public function installBuild() { + public function installBuild() + { if ($this->build_task) throw new CommonException('CLOUD_BUILD_TASK_EXIST'); // 上传任务key @@ -215,50 +221,50 @@ class CoreCloudBuildService extends BaseCoreService // 拷贝composer文件 file_put_contents($package_dir . 'composer.json', file_get_contents(root_path() . 'composer.json')); // 拷贝手机端文件 - $wap_is_compile = (new Addon())->where([ ['compile', 'like', '%wap%'] ])->field('id')->findOrEmpty(); + $wap_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%wap%' ] ])->field('id')->findOrEmpty(); if ($wap_is_compile->isEmpty()) { - dir_copy($this->root_path . 'uni-app', $package_dir . 'uni-app', exclude_dirs:['node_modules', 'unpackage', 'dist']); + dir_copy($this->root_path . 'uni-app', $package_dir . 'uni-app', exclude_dirs: [ 'node_modules', 'unpackage', 'dist' ]); } // 拷贝admin端文件 - $admin_is_compile = (new Addon())->where([ ['compile', 'like', '%admin%'] ])->field('id')->findOrEmpty(); + $admin_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%admin%' ] ])->field('id')->findOrEmpty(); if ($admin_is_compile->isEmpty()) { - dir_copy($this->root_path . 'admin', $package_dir . 'admin', exclude_dirs:['node_modules', 'dist', '.vscode', '.idea']); + dir_copy($this->root_path . 'admin', $package_dir . 'admin', exclude_dirs: [ 'node_modules', 'dist', '.vscode', '.idea' ]); } // 拷贝web端文件 - $web_is_compile = (new Addon())->where([ ['compile', 'like', '%web%'] ])->field('id')->findOrEmpty(); + $web_is_compile = ( new Addon() )->where([ [ 'compile', 'like', '%web%' ] ])->field('id')->findOrEmpty(); if ($web_is_compile->isEmpty()) { - dir_copy($this->root_path . 'web', $package_dir . 'web', exclude_dirs:['node_modules', '.output', '.nuxt']); + dir_copy($this->root_path . 'web', $package_dir . 'web', exclude_dirs: [ 'node_modules', '.output', '.nuxt' ]); } $this->handleCustomPort($package_dir); $zip_file = $temp_dir . DIRECTORY_SEPARATOR . 'build.zip'; - (new CoreAddonDevelopDownloadService(''))->compressToZip($package_dir, $zip_file); + ( new CoreAddonDevelopDownloadService('') )->compressToZip($package_dir, $zip_file); $query = [ 'authorize_code' => $this->auth_code, 'timestamp' => time() ]; - $versions = array_merge(['niucloud-admin' => config('version.version')], ((new Addon())->column('version', 'key'))); + $versions = array_merge([ 'niucloud-admin' => config('version.version') ], ( ( new Addon() )->column('version', 'key') )); ksort($versions); - $query['version'] = md5(json_encode($versions) . BaseNiucloudClient::PRODUCT); + $query[ 'version' ] = md5(json_encode($versions) . BaseNiucloudClient::PRODUCT); - $response = (new CloudService())->httpPost('cloud/install?' . http_build_query($query), [ + $response = ( new CloudService() )->httpPost('cloud/install?' . http_build_query($query), [ 'multipart' => [ [ - 'name' => 'file', + 'name' => 'file', 'contents' => fopen($zip_file, 'r'), 'filename' => 'build.zip' ] ], 'timeout' => 300.0 ]); - if (isset($response['code']) && $response['code'] == 0) throw new CommonException($response['msg']); + if (isset($response[ 'code' ]) && $response[ 'code' ] == 0) throw new CommonException($response[ 'msg' ]); $this->build_task = [ 'task_key' => $task_key, - 'timestamp' => $query['timestamp'], - 'version' => $query['version'] + 'timestamp' => $query[ 'timestamp' ], + 'version' => $query[ 'version' ] ]; Cache::set($this->cache_key, $this->build_task); @@ -269,7 +275,8 @@ class CoreCloudBuildService extends BaseCoreService * 获取编译任务 * @return mixed */ - public function getBuildTask() { + public function getBuildTask() + { return $this->build_task; } @@ -277,19 +284,20 @@ class CoreCloudBuildService extends BaseCoreService * 获取编译执行日志 * @return void */ - public function getBuildLog() { + public function getBuildLog() + { if (!$this->build_task) return; $query = [ 'authorize_code' => $this->auth_code, - 'timestamp' => $this->build_task['timestamp'] + 'timestamp' => $this->build_task[ 'timestamp' ] ]; - $build_log = (new CloudService())->httpGet('cloud/get_build_logs?' . http_build_query($query)); + $build_log = ( new CloudService() )->httpGet('cloud/get_build_logs?' . http_build_query($query)); - if (isset($build_log['data']) && isset($build_log['data'][0]) && is_array($build_log['data'][0])) { - $last = end($build_log['data'][0]); - if ($last['percent'] == 100 && $last['code'] == 1) { - $build_log['data'][0] = $this->buildSuccess($build_log['data'][0]); + if (isset($build_log[ 'data' ]) && isset($build_log[ 'data' ][ 0 ]) && is_array($build_log[ 'data' ][ 0 ])) { + $last = end($build_log[ 'data' ][ 0 ]); + if ($last[ 'percent' ] == 100 && $last[ 'code' ] == 1) { + $build_log[ 'data' ][ 0 ] = $this->buildSuccess($build_log[ 'data' ][ 0 ]); } } return $build_log; @@ -300,45 +308,46 @@ class CoreCloudBuildService extends BaseCoreService * @param array $log * @return array */ - public function buildSuccess(array $log) { + public function buildSuccess(array $log) + { try { $query = [ 'authorize_code' => $this->auth_code, - 'timestamp' => $this->build_task['timestamp'] + 'timestamp' => $this->build_task[ 'timestamp' ] ]; - if (isset($this->build_task['version'])) $query['version'] = $this->build_task['version']; + if (isset($this->build_task[ 'version' ])) $query[ 'version' ] = $this->build_task[ 'version' ]; $chunk_size = 1 * 1024 * 1024; - $temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $this->build_task['task_key'] . DIRECTORY_SEPARATOR; + $temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $this->build_task[ 'task_key' ] . DIRECTORY_SEPARATOR; - if (!isset($this->build_task['index'])) { - $response = (new CloudService())->request('HEAD','cloud/build_download?' . http_build_query($query), [ - 'headers' => ['Range' => 'bytes=0-'] + if (!isset($this->build_task[ 'index' ])) { + $response = ( new CloudService() )->request('HEAD', 'cloud/build_download?' . http_build_query($query), [ + 'headers' => [ 'Range' => 'bytes=0-' ] ]); $length = $response->getHeader('Content-range'); - $length = (int)explode("/", $length[0])[1]; - $step = (int)ceil($length / $chunk_size); + $length = (int) explode("/", $length[ 0 ])[ 1 ]; + $step = (int) ceil($length / $chunk_size); - $this->build_task = array_merge($this->build_task, ['step' => $step, 'index' => 0, 'length' => $length]); + $this->build_task = array_merge($this->build_task, [ 'step' => $step, 'index' => 0, 'length' => $length ]); Cache::set($this->cache_key, $this->build_task); } else { $zip_file = $temp_dir . 'download.zip'; $zip_resource = fopen($zip_file, 'a'); - if (($this->build_task['index'] + 1) <= $this->build_task['step']) { - $start = $this->build_task['index'] * $chunk_size; - $end = ($this->build_task['index'] + 1) * $chunk_size; - $end = min($end, $this->build_task['length']); + if (( $this->build_task[ 'index' ] + 1 ) <= $this->build_task[ 'step' ]) { + $start = $this->build_task[ 'index' ] * $chunk_size; + $end = ( $this->build_task[ 'index' ] + 1 ) * $chunk_size; + $end = min($end, $this->build_task[ 'length' ]); - $response = (new CloudService())->request('GET','cloud/build_download?' . http_build_query($query), [ - 'headers' => ['Range' => "bytes={$start}-{$end}"] + $response = ( new CloudService() )->request('GET', 'cloud/build_download?' . http_build_query($query), [ + 'headers' => [ 'Range' => "bytes={$start}-{$end}" ] ]); fwrite($zip_resource, $response->getBody()); fclose($zip_resource); - $this->build_task['index'] += 1; + $this->build_task[ 'index' ] += 1; Cache::set($this->cache_key, $this->build_task); - $log[] = [ 'code' => 1, 'action' => '编译包下载中,已下载' . round($this->build_task['index'] / $this->build_task['step'] * 100) . '%', 'percent' => '100' ]; + $log[] = [ 'code' => 1, 'action' => '编译包下载中,已下载' . round($this->build_task[ 'index' ] / $this->build_task[ 'step' ] * 100) . '%', 'percent' => '100' ]; } else { // 解压文件 $zip = new \ZipArchive(); @@ -377,9 +386,10 @@ class CoreCloudBuildService extends BaseCoreService * 清除任务 * @return void */ - public function clearTask() { + public function clearTask() + { if (!$this->build_task) return; - $temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $this->build_task['task_key'] . DIRECTORY_SEPARATOR;; + $temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $this->build_task[ 'task_key' ] . DIRECTORY_SEPARATOR;; @del_target_dir($temp_dir, true); Cache::set($this->cache_key, null); } diff --git a/niucloud/app/service/core/niucloud/CoreModuleService.php b/niucloud/app/service/core/niucloud/CoreModuleService.php index 4bfd7d9b4..e4f4aa32d 100644 --- a/niucloud/app/service/core/niucloud/CoreModuleService.php +++ b/niucloud/app/service/core/niucloud/CoreModuleService.php @@ -73,7 +73,6 @@ class CoreModuleService extends BaseNiucloudClient } - /** * 操作token * @param $action @@ -83,7 +82,7 @@ class CoreModuleService extends BaseNiucloudClient */ public function getActionToken($action, $data) { - return $this->httpGet('member_app_action/'.$action, $data); + return $this->httpGet('member_app_action/' . $action, $data); } /** @@ -92,7 +91,8 @@ class CoreModuleService extends BaseNiucloudClient * @return array|\core\util\niucloud\Response|object|ResponseInterface * @throws GuzzleException */ - public function getUpgradeContent($data) { + public function getUpgradeContent($data) + { return $this->httpGet('member_app_upgrade/content', $data); } @@ -104,7 +104,7 @@ class CoreModuleService extends BaseNiucloudClient */ public function checkKey($key) { - return $this->httpGet('store/app_check/'.$key, ['product_key' => self::PRODUCT])['data'] ?? false; + return $this->httpGet('store/app_check/' . $key, [ 'product_key' => self::PRODUCT ])[ 'data' ] ?? false; } /** @@ -112,8 +112,9 @@ class CoreModuleService extends BaseNiucloudClient * @return array|\core\util\niucloud\Response|object|ResponseInterface * @throws GuzzleException */ - public function getFrameworkLastVersion() { - return $this->httpGet('store/framework/lastversion', ['product_key' => self::PRODUCT])['data'] ?? false; + public function getFrameworkLastVersion() + { + return $this->httpGet('store/framework/lastversion', [ 'product_key' => self::PRODUCT ])[ 'data' ] ?? false; } /** @@ -121,24 +122,37 @@ class CoreModuleService extends BaseNiucloudClient * @return false|mixed * @throws GuzzleException */ - public function getFrameworkVersionList() { - return $this->httpGet('store/framework/version', ['product_key' => self::PRODUCT])['data'] ?? false; + public function getFrameworkVersionList() + { + return $this->httpGet('store/framework/version', [ 'product_key' => self::PRODUCT ])[ 'data' ] ?? false; } /** * 申请体验 + * @return array|false|mixed * @throws GuzzleException */ - public function applyExperience() { - $data = $this->httpGet('apply/experience', ['product_key' => self::PRODUCT])['data'] ?? []; + public function applyExperience() + { + $data = $this->httpGet('apply/experience', [ 'product_key' => self::PRODUCT ])[ 'data' ] ?? []; if (!empty($data)) { - (new CoreConfigService())->setConfig(ConfigKeyDict::NIUCLOUD_CONFIG, [ - 'auth_code' => $data['auth_code'], - 'auth_secret' => $data['auth_secret'] + ( new CoreConfigService() )->setConfig(ConfigKeyDict::NIUCLOUD_CONFIG, [ + 'auth_code' => $data[ 'auth_code' ], + 'auth_secret' => $data[ 'auth_secret' ] ]); return $data; } else { return false; } } + + /** + * 获取应用/插件的版本更新记录 + * @return false|mixed + * @throws GuzzleException + */ + public function getAppVersionList($app_key) + { + return $this->httpGet('store/app_version/list', [ 'product_key' => self::PRODUCT, 'app_key' => $app_key ])[ 'data' ] ?? false; + } } diff --git a/niucloud/app/service/core/pay/CorePayService.php b/niucloud/app/service/core/pay/CorePayService.php index 9de6b30ce..b8dfd60f5 100644 --- a/niucloud/app/service/core/pay/CorePayService.php +++ b/niucloud/app/service/core/pay/CorePayService.php @@ -169,9 +169,9 @@ class CorePayService extends BaseCoreService //todo 校验场景控制支付方式 $pay_type_list = ( new CorePayChannelService() )->getAllowPayTypeByChannel($channel, $pay[ 'trade_type' ]); //找朋友帮忙付时不支持找朋友帮忙付 - if(!empty($pay_type_list) && !empty($pay_type_list[PayDict::FRIENDSPAY]) && $scene == PaySceneDict::FRIENDSPAY){ - $pay[ 'config' ] = $pay_type_list[PayDict::FRIENDSPAY]['config']; - unset($pay_type_list[PayDict::FRIENDSPAY]); + if (!empty($pay_type_list) && !empty($pay_type_list[ PayDict::FRIENDSPAY ]) && $scene == PaySceneDict::FRIENDSPAY) { + $pay[ 'config' ] = $pay_type_list[ PayDict::FRIENDSPAY ][ 'config' ]; + unset($pay_type_list[ PayDict::FRIENDSPAY ]); } $pay[ 'pay_type_list' ] = array_values($pay_type_list); } @@ -251,7 +251,7 @@ class CorePayService extends BaseCoreService event('OfflinePayAfter', [ 'trade_type' => $trade_type, 'trade_id' => $trade_id, - 'out_trade_no' => $out_trade_no, + 'out_trade_no' => $out_trade_no ]); } else { //将支付设置为支付中 @@ -263,7 +263,7 @@ class CorePayService extends BaseCoreService ] ); if (env('queue.state', true)) { - PayReturnTo::dispatch([ 'out_trade_no' => $out_trade_no ], secs: 15); + PayReturnTo::dispatch([ 'out_trade_no' => $out_trade_no ], secs: 60); } } return $pay_result; @@ -456,7 +456,7 @@ class CorePayService extends BaseCoreService */ public function notify(string $channel, string $type, string $action) { - $callback = function($out_trade_no, $params) use ($type, $action) { + $callback = function ($out_trade_no, $params) use ($type, $action) { try { switch ($action) { case 'pay'://支付结果通知 @@ -476,7 +476,7 @@ class CorePayService extends BaseCoreService } }; - Log::write('业务'.'_'.$channel.'_'.$type.'_'.$action); + Log::write('业务_' . $channel . '_' . $type . '_' . $action); return $this->pay_event->init($channel, $type)->notify($action, $callback); } diff --git a/niucloud/app/service/core/pay/CoreRefundService.php b/niucloud/app/service/core/pay/CoreRefundService.php index 7bd12a937..b9e7165a3 100644 --- a/niucloud/app/service/core/pay/CoreRefundService.php +++ b/niucloud/app/service/core/pay/CoreRefundService.php @@ -45,6 +45,13 @@ class CoreRefundService extends BaseCoreService //通过交易流水号获取支付单据 $pay = (new CorePayService())->findPayInfoByOutTradeNo($out_trade_no); if($pay->isEmpty()) throw new PayException('ALIPAY_TRANSACTION_NO_NOT_EXIST');//单据不存在 + + //查询当前支付已存在的退狂单据,所有的退款总额不能超过支付单据的支付金额 + $total_refund_money = $this->model->where([['out_trade_no', '=', $out_trade_no], ['status', '<>', RefundDict::FAIL]])->sum('money'); + + $comparison = bccomp(bcadd($total_refund_money, $money), $pay['money']);//浮点数直接进行比较会出现精度问题 + if ($comparison > 0) throw new PayException('退款金额不能超过支付总额');//退款金额不能超过支付总额 + //校验当前数据是否存在 //存在就修改,不存在就创建 $refund_no = create_no(); diff --git a/niucloud/app/service/core/pay/CoreTransferSceneService.php b/niucloud/app/service/core/pay/CoreTransferSceneService.php index c736e0b1f..938c15d56 100644 --- a/niucloud/app/service/core/pay/CoreTransferSceneService.php +++ b/niucloud/app/service/core/pay/CoreTransferSceneService.php @@ -71,78 +71,11 @@ class CoreTransferSceneService extends BaseCoreService $config = $this->getWechatTransferSceneConfig(); //查询业务和场景的对应关系表 -// $trade_scene_event_array = [ -// 'shop_fenxiao' => [ -// 'name' => '分销', -// 'scene' => TransferDict::XJYX, -// 'perception' => '', -// 'infos' => [ -// '活动名称' => '分销佣金', -// '奖励说明' => '分销佣金奖励' -// ] -// ] -// ]; $trade_scene_event_array = event('GetWechatTransferTradeScene', []); - -// [ -// 'xjyx' => [ -// 'name' => '现金营销', -// 'scene_id' => 1001, -// 'user_recv_perception' => [//收款感知 -// '活动奖励', -// '现金奖励', -// ], -// 'transfer_scene_report_infos' => [//报备背景信息 -// '活动名称', -// '奖励说明' -// ], -// 'trade_scene_data' => [ -// 'shop_fenxiao' => [ -// 'name' => '分销', -// 'scene' => TransferDict::XJYX, -// 'infos' => [ -// '活动名称' => '分销佣金', -// '奖励说明' => '分销佣金奖励' -// ], -// 'perception' => '活动奖励' -// ] -// ] -// ], -// 'qypf' => [ -// 'name' => '企业赔付', -// 'scene_id' => 1002, -// 'user_recv_perception' => [ -// '退款', -// '商家赔付', -// ], -// 'transfer_scene_report_infos' => [ -// '赔付原因', -// ] -// ], -// 'yjbc' => [ -// 'name' => '佣金报酬', -// 'scene_id' => 1005, -// 'user_recv_perception' => [ -// '劳务报酬', -// '报销款', -// '企业补贴', -// '开工利是' -// ], -// 'transfer_scene_report_infos' => [ -// '岗位类型', -// '报酬说明' -// ] -// ], -// -// ]; $trade_scene_column = ( new TransferScene() )->where([ [ 'id', '=', 0 ] ])->column('*', 'type'); $trade_scene_list = []; foreach ($trade_scene_event_array as $trade_scene_item) { foreach ($trade_scene_item as $trade_scene_key => $trade_scene_item_item) { -// $trade_scene_select_data = $trade_scene_item_item; -// foreach($trade_scene_column as $trade_scene_column_item){ -// if($trade_scene_column_item['type'] == ) -// } $trade_scene_select_data = $trade_scene_column[ $trade_scene_key ] ?? $trade_scene_item_item; $trade_scene_select_data = array_merge($trade_scene_item_item, $trade_scene_select_data); if (!isset($trade_scene_list[ $trade_scene_item_item[ 'scene' ] ])) $trade_scene_list[ $trade_scene_item_item[ 'scene' ] ] = []; @@ -153,14 +86,8 @@ class CoreTransferSceneService extends BaseCoreService foreach ($list as $key => &$v) { $v[ 'scene_id' ] = $config[ $key ] ?? ''; -// $item_transfer_scene_report_infos = $v['transfer_scene_report_infos'] ?? []; $trade_scene_data = $trade_scene_list[ $key ] ?? []; $v[ 'trade_scene_data' ] = $trade_scene_data; -// foreach($item_transfer_scene_report_infos as $item_k => $item_v){ -// -// } - - // $trade_scene_list = $trade_scene_list[$key] ?? []; } //然后根据支持的业务来完善业务场景备注 diff --git a/niucloud/app/service/core/pay/CoreTransferService.php b/niucloud/app/service/core/pay/CoreTransferService.php index 5a17c7184..22317e2ff 100644 --- a/niucloud/app/service/core/pay/CoreTransferService.php +++ b/niucloud/app/service/core/pay/CoreTransferService.php @@ -32,6 +32,7 @@ use Throwable; class CoreTransferService extends BaseCoreService { protected $pay_event; + public function __construct() { parent::__construct(); @@ -49,7 +50,8 @@ class CoreTransferService extends BaseCoreService * @return string|null * @throws Exception */ - public function create(string $main_type, int $main_id, float $money, string $trade_type, string $remark){ + public function create(string $main_type, int $main_id, float $money, string $trade_type, string $remark) + { $transfer_no = create_no(); $transfer_data = array( 'money' => $money, @@ -72,77 +74,78 @@ class CoreTransferService extends BaseCoreService * @param array $data * @return true */ - public function transfer(string $transfer_no, string $transfer_type, array $data){ + public function transfer(string $transfer_no, string $transfer_type, array $data) + { $transfer = $this->findTransferByTransferNo($transfer_no); - if($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); - if(!in_array($transfer['transfer_status'], [TransferDict::WAIT, TransferDict::FAIL])) throw new PayException('TRANFER_STATUS_NOT_IN_WAIT_TANSFER'); + if ($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); + if (!in_array($transfer[ 'transfer_status' ], [ TransferDict::WAIT, TransferDict::FAIL ])) throw new PayException('TRANFER_STATUS_NOT_IN_WAIT_TANSFER'); - $transfer_account = $data['transfer_account'] ?? ''; - $transfer_realname = $data['transfer_realname'] ?? ''; + $transfer_account = $data[ 'transfer_account' ] ?? ''; + $transfer_realname = $data[ 'transfer_realname' ] ?? ''; $transfer_data = array( 'transfer_type' => $transfer_type,//转账方式 'transfer_realname' => $transfer_realname,//名称 - 'transfer_mobile' => $data['transfer_mobile'] ?? '',//手机号 - 'transfer_bank' => $data['transfer_bank'] ?? '',//转账银行 + 'transfer_mobile' => $data[ 'transfer_mobile' ] ?? '',//手机号 + 'transfer_bank' => $data[ 'transfer_bank' ] ?? '',//转账银行 'transfer_account' => $transfer_account,//转账账号 - 'openid' => $data['openid'] ?? '', - 'transfer_voucher' => $data['transfer_voucher'] ?? '', - 'transfer_remark' => $data['transfer_remark'] ?? '', - 'transfer_payee' => $data['transfer_payee'] ?? [], - 'transfer_payment_code' => $data['transfer_payment_code'] ?? '' + 'openid' => $data[ 'openid' ] ?? '', + 'transfer_voucher' => $data[ 'transfer_voucher' ] ?? '', + 'transfer_remark' => $data[ 'transfer_remark' ] ?? '', + 'transfer_payee' => $data[ 'transfer_payee' ] ?? [], + 'transfer_payment_code' => $data[ 'transfer_payment_code' ] ?? '' ); $transfer->save($transfer_data); - switch($transfer_type){ + switch ($transfer_type) { case TransferDict::WECHAT: // $out_batch_no = create_no(); - $transfer_account = $data['transfer_payee'] ?? []; - $scene_data = (new CoreTransferSceneService())->getSceneInfoByType($transfer['trade_type']); + $transfer_account = $data[ 'transfer_payee' ] ?? []; + $scene_data = ( new CoreTransferSceneService() )->getSceneInfoByType($transfer[ 'trade_type' ]); //通过业务获取业务场景 - $temp_infos = $scene_data['infos'] ?? [];//转账场景信息 - if(!empty($temp_infos)){ + $temp_infos = $scene_data[ 'infos' ] ?? [];//转账场景信息 + if (!empty($temp_infos)) { $transfer_scene_report_infos = []; - foreach($temp_infos as $key => $item){ + foreach ($temp_infos as $key => $item) { $transfer_scene_report_infos[] = [ 'info_type' => $key, 'info_content' => $item ]; } } - $transfer_account['transfer_scene_report_infos'] = $transfer_scene_report_infos ?? [];// - $transfer_account['user_recv_perception'] = $scene_data['perception'];//收款感知 - $transfer_account['transfer_scene_id'] = $scene_data['scene_id']; + $transfer_account[ 'transfer_scene_report_infos' ] = $transfer_scene_report_infos ?? [];// + $transfer_account[ 'user_recv_perception' ] = $scene_data[ 'perception' ];//收款感知 + $transfer_account[ 'transfer_scene_id' ] = $scene_data[ 'scene_id' ]; // $transfer_account['out_batch_no'] = $out_batch_no; break; } $params = []; $return_result = []; - if(TransferDict::getTransferType()[$transfer_type]['is_online']){ + if (TransferDict::getTransferType()[ $transfer_type ][ 'is_online' ]) { try { - $result = $this->pay_event->init('transfer', $transfer_type)->transfer($transfer['money'], $transfer_no, $transfer_account, $transfer_realname, $transfer['remark']); + $result = $this->pay_event->init('transfer', $transfer_type)->transfer($transfer[ 'money' ], $transfer_no, $transfer_account, $transfer_realname, $transfer[ 'remark' ]); // $params['batch_id'] = $result['batch_id']; // $params['out_batch_no'] = $result['out_batch_no']; //将返回的数据交给转账通知 - if($transfer_type == TransferDict::WECHAT){ + if ($transfer_type == TransferDict::WECHAT) { $update_data = [ - 'out_batch_no' => $result['transfer_bill_no'] ?? '', - 'package_info' => $result['package_info'] ?? '', - 'extra' => $result['extra'] ?? [], + 'out_batch_no' => $result[ 'transfer_bill_no' ] ?? '', + 'package_info' => $result[ 'package_info' ] ?? '', + 'extra' => $result[ 'extra' ] ?? [], ]; $transfer->save($update_data); - $return_result['status'] = $result['status']; - $return_result['package_info'] = $result['package_info']; - $return_result['extra'] = $result['extra'] ?? []; + $return_result[ 'status' ] = $result[ 'status' ]; + $return_result[ 'package_info' ] = $result[ 'package_info' ]; + $return_result[ 'extra' ] = $result[ 'extra' ] ?? []; } $this->transferNotify($transfer_no, $result); // return true; - }catch( Throwable $e){ - $this->fail($transfer_no, ['reason' => get_lang($e->getMessage())]); + } catch (Throwable $e) { + $this->fail($transfer_no, [ 'reason' => get_lang($e->getMessage()) ]); throw new PayException($e->getMessage()); } - }else{ + } else { $return_result = [ 'status' => TransferDict::SUCCESS, ]; @@ -151,14 +154,16 @@ class CoreTransferService extends BaseCoreService return $return_result; } + /** * 通过转账单号查询转账 * @param string $transfer_no * @return Pay|array|mixed|Model */ - public function findTransferByTransferNo(string $transfer_no){ + public function findTransferByTransferNo(string $transfer_no) + { $where = array( - ['transfer_no', '=', $transfer_no] + [ 'transfer_no', '=', $transfer_no ] ); return $this->model->where($where)->findOrEmpty(); } @@ -170,16 +175,17 @@ class CoreTransferService extends BaseCoreService * @param $params * @return true */ - public function transferNotify(string $transfer_no, $params){ - Log::write('transferNotify'.$transfer_no); + public function transferNotify(string $transfer_no, $params) + { + Log::write('transferNotify' . $transfer_no); $transfer = $this->findTransferByTransferNo($transfer_no); - if($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); - if(!in_array($transfer['transfer_status'], [TransferDict::WAIT, TransferDict::DEALING, TransferDict::FAIL, TransferDict::WAIT_USER, TransferDict::WAIT_USER_ING, TransferDict::FAIL_ING])) throw new PayException('TRANFER_STATUS_NOT_IN_WAIT_TANSFER'); - $status = $params['status'] ?? TransferDict::DEALING; - Log::write('transferNotifyStatus'.$status); - switch($status){ + if ($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); + if (!in_array($transfer[ 'transfer_status' ], [ TransferDict::WAIT, TransferDict::DEALING, TransferDict::FAIL, TransferDict::WAIT_USER, TransferDict::WAIT_USER_ING, TransferDict::FAIL_ING ])) throw new PayException('TRANFER_STATUS_NOT_IN_WAIT_TANSFER'); + $status = $params[ 'status' ] ?? TransferDict::DEALING; + Log::write('transferNotifyStatus' . $status); + switch ($status) { case TransferDict::SUCCESS: - Log::write('transferNotifyStatus1'.$status); + Log::write('transferNotifyStatus1' . $status); $this->success($transfer_no); break; case TransferDict::FAIL: @@ -194,6 +200,7 @@ class CoreTransferService extends BaseCoreService } return true; } + /** * 转账完成 * @param string $transfer_no @@ -201,11 +208,12 @@ class CoreTransferService extends BaseCoreService * @param array $params * @return bool */ - public function success(string $transfer_no, array $params = []){ + public function success(string $transfer_no, array $params = []) + { $transfer = $this->findTransferByTransferNo($transfer_no); - Log::write('transferNotifyStatus2'.$transfer['transfer_status']); - if($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); - if(!in_array($transfer['transfer_status'], [TransferDict::WAIT, TransferDict::DEALING, TransferDict::FAIL,TransferDict::WAIT_USER, TransferDict::WAIT_USER_ING, TransferDict::FAIL_ING])) throw new PayException('TRANFER_STATUS_NOT_IN_WAIT_TANSFER'); + Log::write('transferNotifyStatus2' . $transfer[ 'transfer_status' ]); + if ($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); + if (!in_array($transfer[ 'transfer_status' ], [ TransferDict::WAIT, TransferDict::DEALING, TransferDict::FAIL, TransferDict::WAIT_USER, TransferDict::WAIT_USER_ING, TransferDict::FAIL_ING ])) throw new PayException('TRANFER_STATUS_NOT_IN_WAIT_TANSFER'); $trade_type = $transfer->trade_type; $data = [ @@ -219,16 +227,16 @@ class CoreTransferService extends BaseCoreService Db::startTrans(); try { $transfer->save($data); - Log::write('transferNotifyStatus3'.TransferDict::SUCCESS); - $result = event('TransferSuccess', ['transfer_no' => $transfer_no, 'trade_type' => $trade_type]); - if(!check_event_result($result)){ + Log::write('transferNotifyStatus3' . TransferDict::SUCCESS); + $result = event('TransferSuccess', [ 'transfer_no' => $transfer_no, 'trade_type' => $trade_type ]); + if (!check_event_result($result)) { Db::rollback(); return false; } // 提交事务 Db::commit(); return true; - } catch ( Throwable $e) { + } catch (Throwable $e) { // 回滚事务 Db::rollback(); throw new PayException($e->getMessage()); @@ -243,15 +251,16 @@ class CoreTransferService extends BaseCoreService * @param array $params * @return true */ - public function fail(string $transfer_no, array $params = []){ + public function fail(string $transfer_no, array $params = []) + { $transfer = $this->findTransferByTransferNo($transfer_no); - if($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); - if(!in_array($transfer['transfer_status'], [TransferDict::WAIT, TransferDict::DEALING, TransferDict::FAIL,TransferDict::WAIT_USER, TransferDict::WAIT_USER_ING, TransferDict::FAIL_ING])) throw new PayException('TRANFER_STATUS_NOT_IN_WAIT_TANSFER'); + if ($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); + if (!in_array($transfer[ 'transfer_status' ], [ TransferDict::WAIT, TransferDict::DEALING, TransferDict::FAIL, TransferDict::WAIT_USER, TransferDict::WAIT_USER_ING, TransferDict::FAIL_ING ])) throw new PayException('TRANFER_STATUS_NOT_IN_WAIT_TANSFER'); $data = array( 'transfer_time' => time(), 'transfer_status' => TransferDict::FAIL, - 'transfer_fail_reason' => $params['reason'] ?? '' + 'transfer_fail_reason' => $params[ 'reason' ] ?? '' ); //允许修改的值 @@ -260,17 +269,18 @@ class CoreTransferService extends BaseCoreService } - public function check(array $data){ - $transfer_no = $data['transfer_no']; + public function check(array $data) + { + $transfer_no = $data[ 'transfer_no' ]; $transfer = $this->findTransferByTransferNo($transfer_no); - if($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); - if(!in_array($transfer['transfer_status'], [TransferDict::WAIT, TransferDict::DEALING, TransferDict::FAIL,TransferDict::WAIT_USER, TransferDict::WAIT_USER_ING, TransferDict::FAIL_ING]) ) throw new PayException('TRANFER_IS_CHANGE');//只有待转账和转账中的订单可以校验 + if ($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); + if (!in_array($transfer[ 'transfer_status' ], [ TransferDict::WAIT, TransferDict::DEALING, TransferDict::FAIL, TransferDict::WAIT_USER, TransferDict::WAIT_USER_ING, TransferDict::FAIL_ING ])) throw new PayException('TRANFER_IS_CHANGE');//只有待转账和转账中的订单可以校验 //查询第三方支付单据 - $transfer_info = $this->pay_event->init('transfer', $transfer->transfer_type)->getTransfer($transfer_no, $transfer['out_batch_no'] ?? ''); - if(empty($transfer_info)) throw new PayException('TRANSFER_ORDER_INVALID');//查询不到转账信息 - $status = $transfer_info['status']; - switch($status){ + $transfer_info = $this->pay_event->init('transfer', $transfer->transfer_type)->getTransfer($transfer_no, $transfer[ 'out_batch_no' ] ?? ''); + if (empty($transfer_info)) throw new PayException('TRANSFER_ORDER_INVALID');//查询不到转账信息 + $status = $transfer_info[ 'status' ]; + switch ($status) { case TransferDict::SUCCESS: $this->success($transfer_no); break; @@ -292,9 +302,10 @@ class CoreTransferService extends BaseCoreService * @param $type * @return true */ - public function dealing($transfer_no, $status){ + public function dealing($transfer_no, $status) + { $this->model->where([ - ['transfer_no', '=', $transfer_no] + [ 'transfer_no', '=', $transfer_no ] ])->update( [ // 'transfer_status' => TransferDict::DEALING, @@ -330,29 +341,27 @@ class CoreTransferService extends BaseCoreService * @param string $transfer_no * @return void */ - public function cancel(string $transfer_no){ + public function cancel(string $transfer_no) + { try { - $transfer_no = $transfer_no; $transfer = $this->findTransferByTransferNo($transfer_no); - if($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); - if(!in_array($transfer['transfer_status'], [TransferDict::WAIT, TransferDict::DEALING, TransferDict::FAIL,TransferDict::WAIT_USER, TransferDict::WAIT_USER_ING, TransferDict::FAIL_ING]) ) throw new PayException('TRANFER_IS_CHANGE');//只有待转账和转账中的订单可以校验 + if ($transfer->isEmpty()) throw new PayException('TRANSFER_ORDER_INVALID'); + if (!in_array($transfer[ 'transfer_status' ], [ TransferDict::WAIT, TransferDict::DEALING, TransferDict::FAIL, TransferDict::WAIT_USER, TransferDict::WAIT_USER_ING, TransferDict::FAIL_ING ])) throw new PayException('TRANFER_IS_CHANGE');//只有待转账和转账中的订单可以校验 //查询第三方支付单据 $result = $this->pay_event->init('transfer', $transfer->transfer_type)->transferCancel([ 'transfer_no' => $transfer_no ]); $this->transferNotify($transfer_no, $result); - if($result['status'] == TransferDict::FAIL_ING){//撤销中的话也要返回错误,不能让业务认为撤销成功了 + if ($result[ 'status' ] == TransferDict::FAIL_ING) {//撤销中的话也要返回错误,不能让业务认为撤销成功了 throw new PayException('TRANSFER_IS_FAILING'); } return true; - }catch( Throwable $e){ - + } catch (Throwable $e) { throw new PayException($e->getMessage()); } } - } diff --git a/niucloud/app/service/core/verify/CoreVerifyService.php b/niucloud/app/service/core/verify/CoreVerifyService.php index ef57eb984..1a335a610 100644 --- a/niucloud/app/service/core/verify/CoreVerifyService.php +++ b/niucloud/app/service/core/verify/CoreVerifyService.php @@ -35,21 +35,21 @@ class CoreVerifyService extends BaseCoreService { if (!array_key_exists($type, VerifyDict::getType())) throw new CommonException('VERIFY_TYPE_ERROR');//核销类型错误 //遇到错误直接抛出即可 - $result = array_filter(event('VerifyCreate', ['type' => $type, 'member_id' => $member_id, 'data' => $param]))[ 0 ] ?? []; + $result = array_filter(event('VerifyCreate', [ 'type' => $type, 'member_id' => $member_id, 'data' => $param ]))[ 0 ] ?? []; $data = []; - if(empty($result)){ + if (empty($result)) { $count = 1; - }else{ - $count = $result['count'] ?? 1; - $data = $result['data'] ?? []; - $body = $result['body'] ?? ''; - $relate_tag = $result['relate_tag'] ?? 0; - $expire_time = $result['expire_time'] ?? null; + } else { + $count = $result[ 'count' ] ?? 1; + $data = $result[ 'data' ] ?? []; + $body = $result[ 'body' ] ?? ''; + $relate_tag = $result[ 'relate_tag' ] ?? 0; + $expire_time = $result[ 'expire_time' ] ?? null; } $strData = json_encode($param); $value = [ 'type' => $type, - 'type_name' => VerifyDict::getType()[$type]['name'] ?? '', + 'type_name' => VerifyDict::getType()[ $type ][ 'name' ] ?? '', 'data' => $param, 'value' => $data, 'body' => $body ?? '', @@ -72,10 +72,23 @@ class CoreVerifyService extends BaseCoreService * @param string $verify_code * @return array */ - public function getInfoByCode(string $verify_code) + public function getInfoByCode(string $member_id, $verify_code) { //获取核销码数据 $value = $this->getCodeData($verify_code); + $data = event('VerifyCheck', $value); + if (!empty($data)) { + $value = end($data); + } + + // 检测核销员身份,是否有核销权限 + $verifier = ( new Verifier() )->where([ [ 'member_id', '=', $member_id ] ])->field('id,verify_type')->findOrEmpty()->toArray(); + if (!empty($verifier)) { + if (!in_array($value[ 'type' ], $verifier[ 'verify_type' ])) { + throw new CommonException('VERIFIER_NOT_AUTH'); + } + } + return $value; } @@ -89,16 +102,16 @@ class CoreVerifyService extends BaseCoreService $value = $this->getCodeData($verify_code); //检测核销员身份 $verifierModel = new Verifier(); - $verifier = $verifierModel->where([['member_id', '=', $verify_member_id]])->findOrEmpty()->toArray(); + $verifier = $verifierModel->where([ [ 'member_id', '=', $verify_member_id ] ])->findOrEmpty()->toArray(); if (empty($verifier)) throw new CommonException('VERIFIER_NOT_EXIST'); $verify_data = [ 'code' => $verify_code, - 'data' => $value['data'], - 'value' => $value['value'], - 'type' => $value['type'], - 'body' => $value['body'], - 'relate_tag' => $value['relate_tag'], + 'data' => $value[ 'data' ], + 'value' => $value[ 'value' ], + 'type' => $value[ 'type' ], + 'body' => $value[ 'body' ], + 'relate_tag' => $value[ 'relate_tag' ], 'create_time' => time(), 'verifier_member_id' => $verify_member_id, ]; @@ -109,7 +122,6 @@ class CoreVerifyService extends BaseCoreService //是核销码失效 $this->clearCode($verify_code); - return true; } diff --git a/niucloud/app/service/core/weapp/CoreWeappCloudService.php b/niucloud/app/service/core/weapp/CoreWeappCloudService.php index e540fc5b4..a9673810d 100644 --- a/niucloud/app/service/core/weapp/CoreWeappCloudService.php +++ b/niucloud/app/service/core/weapp/CoreWeappCloudService.php @@ -14,6 +14,7 @@ namespace app\service\core\weapp; use app\dict\sys\CloudDict; use app\model\addon\Addon; use app\model\weapp\WeappVersion; +use app\service\api\diy\DiyConfigService; use app\service\core\addon\CoreAddonDevelopDownloadService; use app\service\core\addon\WapTrait; use app\service\core\niucloud\CoreCloudBaseService; @@ -44,15 +45,16 @@ class CoreWeappCloudService extends CoreCloudBaseService * 上传小程序 * @param $addon */ - public function uploadWeapp(array $data) { + public function uploadWeapp(array $data) + { if (!request()->isSsl()) throw new CommonException('CURR_SITE_IS_NOT_OPEN_SSL'); - $config = (new CoreWeappConfigService())->getWeappConfig(); - if (empty($config['app_id'])) throw new CommonException('WEAPP_APPID_EMPTY'); - if (empty($config['upload_private_key'])) throw new CommonException('UPLOAD_KEY_EMPTY'); - if (!file_exists($config['upload_private_key'])) throw new CommonException('UPLOAD_KEY_NOT_EXIST'); + $config = ( new CoreWeappConfigService() )->getWeappConfig(); + if (empty($config[ 'app_id' ])) throw new CommonException('WEAPP_APPID_EMPTY'); + if (empty($config[ 'upload_private_key' ])) throw new CommonException('UPLOAD_KEY_EMPTY'); + if (!file_exists($config[ 'upload_private_key' ])) throw new CommonException('UPLOAD_KEY_NOT_EXIST'); - $compile_addon = (new Addon())->where([ ['compile', 'like', "%weapp%"] ])->field('key')->findOrEmpty(); + $compile_addon = ( new Addon() )->where([ [ 'compile', 'like', "%weapp%" ] ])->field('key')->findOrEmpty(); // 上传任务key $task_key = uniqid(); // 此次上传任务临时目录 @@ -64,7 +66,8 @@ class CoreWeappCloudService extends CoreCloudBaseService // 如果不存在编译版小程序 if ($compile_addon->isEmpty()) { - dir_copy($this->root_path . 'uni-app', $uni_dir, exclude_dirs:['node_modules', 'unpackage', 'dist']); + dir_copy($this->root_path . 'uni-app', $uni_dir, exclude_dirs: [ 'node_modules', 'unpackage', 'dist' ]); +// $this->handleTabbar($uni_dir . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR); // 替换env文件 $this->weappEnvReplace($uni_dir . DIRECTORY_SEPARATOR . '.env.production'); } else { @@ -73,25 +76,25 @@ class CoreWeappCloudService extends CoreCloudBaseService dir_copy($compile_dir, $uni_dir); $this->weappCompileReplace($uni_dir); } - file_put_contents($package_dir . 'private.key', file_get_contents($config['upload_private_key'])); + file_put_contents($package_dir . 'private.key', file_get_contents($config[ 'upload_private_key' ])); // 将临时目录下文件生成压缩包 $zip_file = $temp_dir . DIRECTORY_SEPARATOR . 'weapp.zip'; - (new CoreAddonDevelopDownloadService(''))->compressToZip($package_dir, $zip_file); + ( new CoreAddonDevelopDownloadService('') )->compressToZip($package_dir, $zip_file); $query = [ 'compile' => $compile_addon->isEmpty() ? 0 : 1, 'authorize_code' => $this->auth_code, - 'appid' => $config['app_id'], - 'version' => $data['version'] ?? '', - 'desc' => $data['desc'] ?? '', + 'appid' => $config[ 'app_id' ], + 'version' => $data[ 'version' ] ?? '', + 'desc' => $data[ 'desc' ] ?? '', 'do' => 1, 'timestamp' => time() ]; - $response = (new CloudService())->httpPost('cloud/weapp?' . http_build_query($query), [ + $response = ( new CloudService() )->httpPost('cloud/weapp?' . http_build_query($query), [ 'multipart' => [ [ - 'name' => 'file', + 'name' => 'file', 'contents' => fopen($zip_file, 'r'), 'filename' => 'weapp.zip' ] @@ -101,9 +104,45 @@ class CoreWeappCloudService extends CoreCloudBaseService // 删除临时文件 del_target_dir(runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'weapp', true); - if (isset($response['code']) && $response['code'] == 0) throw new CommonException($response['msg']); + if (isset($response[ 'code' ]) && $response[ 'code' ] == 0) throw new CommonException($response[ 'msg' ]); - return ['key' => $query['timestamp'] ]; + return [ 'key' => $query[ 'timestamp' ] ]; + } + + /** + * 处理底部导航 + * @param $compile_path + * @return void + */ + public function handleTabbar($compile_path) + { + $bottomList = array_column(( new DiyConfigService() )->getBottomList(), null, 'key'); + $tabbarList = []; + foreach ($bottomList as $app_item) { + array_push($tabbarList, ...$app_item[ 'value' ][ 'list' ]); + } + + $tabbarList = array_map(function ($item) { + $link = array_filter(explode('/', $item[ 'link' ][ 'url' ])); + $item[ 'link' ] = $item[ 'link' ][ 'url' ]; + $item[ 'component' ] = implode('-', $link); + $item[ 'name' ] = lcfirst(implode('', array_map(function ($str) { + return ucfirst($str); + }, $link))); + return $item; + }, $tabbarList); + $tabbarList = array_column($tabbarList, null, 'name'); + + if (isset($tabbarList[ 'appPagesIndexIndex' ])) unset($tabbarList[ 'appPagesIndexIndex' ]); + if (isset($tabbarList[ 'appPagesMemberIndex' ])) unset($tabbarList[ 'appPagesMemberIndex' ]); + + // 处理vue文件 + $tpl = str_replace('/', DIRECTORY_SEPARATOR, public_path() . 'static/tpl/tabbar.tpl'); + $content = view($tpl, [ 'tabbarList' => $tabbarList ])->getContent(); + file_put_contents(str_replace('/', DIRECTORY_SEPARATOR, $compile_path . 'app/pages/index/tabbar.vue'), $content); + + // 处理tabbar.json + file_put_contents($compile_path . 'tabbar.json', json_encode(array_column($tabbarList, 'link'), JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); } /** @@ -111,10 +150,11 @@ class CoreWeappCloudService extends CoreCloudBaseService * @param string $env_file * @return void */ - private function weappEnvReplace(string $env_file) { + private function weappEnvReplace(string $env_file) + { $env = file_get_contents($env_file); - $env = str_replace("VITE_APP_BASE_URL=''", "VITE_APP_BASE_URL='" . (string)url('/api/', [], '', true) . "'", $env); - $env = str_replace("VITE_IMG_DOMAIN=''", "VITE_IMG_DOMAIN='" . (string)url('/', [], '', true) . "'", $env); + $env = str_replace("VITE_APP_BASE_URL=''", "VITE_APP_BASE_URL='" . (string) url('/api/', [], '', true) . "'", $env); + $env = str_replace("VITE_IMG_DOMAIN=''", "VITE_IMG_DOMAIN='" . (string) url('/', [], '', true) . "'", $env); file_put_contents($env_file, $env); } @@ -123,17 +163,18 @@ class CoreWeappCloudService extends CoreCloudBaseService * @param string $vendor_file * @return void */ - private function weappCompileReplace(string $path) { + private function weappCompileReplace(string $path) + { // 替换request.js $request_file = $path . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'request.js'; $content = file_get_contents($request_file); - $content = str_replace('{{$baseUrl}}', (string)url('/api/', [], '', true), $content); + $content = str_replace('{{$baseUrl}}', (string) url('/api/', [], '', true), $content); file_put_contents($request_file, $content); // 替换common.js $common_file = $path . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'common.js'; $content = file_get_contents($common_file); - $content = str_replace('{{$imgUrl}}', (string)url('/', [], '', true), $content); + $content = str_replace('{{$imgUrl}}', (string) url('/', [], '', true), $content); file_put_contents($common_file, $content); } @@ -141,11 +182,12 @@ class CoreWeappCloudService extends CoreCloudBaseService * 获取微信小程序预览码 * @return void */ - public function getWeappPreviewImage() { + public function getWeappPreviewImage() + { $query = [ 'authorize_code' => $this->auth_code, ]; - $preview_url = (new CloudService())->getUrl('cloud/get_weapp_preview?' . http_build_query($query)); + $preview_url = ( new CloudService() )->getUrl('cloud/get_weapp_preview?' . http_build_query($query)); try { $path = runtime_path() . uniqid() . '.jpg'; @@ -161,21 +203,22 @@ class CoreWeappCloudService extends CoreCloudBaseService * @param string $timestamp * @return void */ - public function getWeappCompileLog(string $timestamp) { + public function getWeappCompileLog(string $timestamp) + { $query = [ 'authorize_code' => $this->auth_code, 'timestamp' => $timestamp ]; - $build_log = (new CloudService())->httpGet('cloud/get_weapp_logs?' . http_build_query($query)); + $build_log = ( new CloudService() )->httpGet('cloud/get_weapp_logs?' . http_build_query($query)); - if (isset($build_log['data']) && isset($build_log['data'][0]) && is_array($build_log['data'][0])) { - $last = end($build_log['data'][0]); - if ($last['code'] == 0) { - (new WeappVersion())->update(['status' => CloudDict::APPLET_UPLOAD_FAIL, 'fail_reason' => $last['msg'] ?? '', 'update_time' => time() ], ['task_key' => $timestamp]); + if (isset($build_log[ 'data' ]) && isset($build_log[ 'data' ][ 0 ]) && is_array($build_log[ 'data' ][ 0 ])) { + $last = end($build_log[ 'data' ][ 0 ]); + if ($last[ 'code' ] == 0) { + ( new WeappVersion() )->update([ 'status' => CloudDict::APPLET_UPLOAD_FAIL, 'fail_reason' => $last[ 'msg' ] ?? '', 'update_time' => time() ], [ 'task_key' => $timestamp ]); return $build_log; } - if ($last['percent'] == 100) { - (new WeappVersion())->update(['status' => CloudDict::APPLET_UPLOAD_SUCCESS, 'update_time' => time() ], ['task_key' => $timestamp]); + if ($last[ 'percent' ] == 100) { + ( new WeappVersion() )->update([ 'status' => CloudDict::APPLET_UPLOAD_SUCCESS, 'update_time' => time() ], [ 'task_key' => $timestamp ]); } } return $build_log; diff --git a/niucloud/app/service/core/weapp/CoreWeappDeliveryService.php b/niucloud/app/service/core/weapp/CoreWeappDeliveryService.php index ee0f760d0..1d24fb744 100644 --- a/niucloud/app/service/core/weapp/CoreWeappDeliveryService.php +++ b/niucloud/app/service/core/weapp/CoreWeappDeliveryService.php @@ -102,6 +102,9 @@ class CoreWeappDeliveryService extends BaseCoreService Log::write('发货信息录入接口,参数打印:' . json_encode($data)); + //微信订单录入有时差 延时3秒执行发货通知 + sleep(3); + $api = CoreWeappService::appApiClient(); $result = $api->postJson('wxa/sec/order/upload_shipping_info', $data)->toArray(); @@ -149,6 +152,9 @@ class CoreWeappDeliveryService extends BaseCoreService Log::write('确认收货提醒接口,参数打印:' . json_encode($data)); + //微信订单录入有时差 延时3秒执行发货通知 + sleep(3); + $api = CoreWeappService::appApiClient(); $result = $api->postJson('wxa/sec/order/notify_confirm_receive', $data)->toArray(); @@ -167,7 +173,7 @@ class CoreWeappDeliveryService extends BaseCoreService * 1、如设置为空路径或小程序中不存在的路径,将仍然跳转平台默认的确认收货页面,不会进入你的小程序。 * 2、平台会在路径后面增加支付单的 transaction_id、merchant_id、merchant_trade_no 作为query参数,如果存在二级商户号则还会再增加 sub_merchant_id 参数,开发者可以在小程序中通过onLaunch等方式获取。 * 3、如你需要在path中携带自定义的query参数,请注意与上面的参数进行区分 - * @param int $type + * @param string $type * @return mixed * @throws InvalidArgumentException */ @@ -264,4 +270,4 @@ class CoreWeappDeliveryService extends BaseCoreService return $res; } -} \ No newline at end of file +} diff --git a/niucloud/app/service/core/weapp/CoreWeappService.php b/niucloud/app/service/core/weapp/CoreWeappService.php index cf02263c0..268021ccf 100644 --- a/niucloud/app/service/core/weapp/CoreWeappService.php +++ b/niucloud/app/service/core/weapp/CoreWeappService.php @@ -86,7 +86,7 @@ class CoreWeappService extends BaseCoreService ]); if ($response->isFailed()) { // 出错了,处理异常 - throw new CommonException('WECHAT_MINI_PROGRAM_CODE_GENERATION_FAILED'); + throw new CommonException('微信小程序码生成失败:errcode:' . $response[ 'errcode' ] . 'errmsg:' . $response[ 'errmsg' ]); } $response->saveAs($filepath); return $filepath; diff --git a/niucloud/app/upgrade/v152/Upgrade.php b/niucloud/app/upgrade/v152/Upgrade.php index 33edf4394..85043b0d0 100644 --- a/niucloud/app/upgrade/v152/Upgrade.php +++ b/niucloud/app/upgrade/v152/Upgrade.php @@ -351,11 +351,11 @@ class Upgrade */ private function initDefaultDiyTheme() { - $addon_list = (new CoreAddonService())->getInstallAddonList(); - $apps=[]; - foreach ($addon_list as $k=>$v){ - if($v['type']=='app'){ - $apps[]=$v; + $addon_list = ( new CoreAddonService() )->getInstallAddonList(); + $apps = []; + foreach ($addon_list as $k => $v) { + if ($v[ 'type' ] == 'app') { + $apps[] = $v; } } $system_theme = $this->getAppTheme(); @@ -423,19 +423,22 @@ class Upgrade } } } - if (!empty($data)) { - $diy_theme_model = new DiyTheme(); - foreach ($data as $k => &$v) { - $theme_count = $diy_theme_model->where([ - [ 'title', "=", $v[ 'title' ] ], - [ 'addon', "=", $v[ 'addon' ] ] - ])->count(); - // 如果已有该主题风格颜色则不再添加 - if ($theme_count > 0) { - unset($data[ $k ]); + try { + if (!empty($data)) { + $diy_theme_model = new DiyTheme(); + foreach ($data as $k => &$v) { + $theme_count = $diy_theme_model->where([ + [ 'title', "=", $v[ 'title' ] ], + [ 'addon', "=", $v[ 'addon' ] ] + ])->count(); + // 如果已有该主题风格颜色则不再添加 + if ($theme_count > 0) { + unset($data[ $k ]); + } } + $diy_theme_model->insertAll($data); } - $diy_theme_model->insertAll($data); + } catch (\Exception $e) { } return true; } diff --git a/niucloud/app/upgrade/v153/upgrade.sql b/niucloud/app/upgrade/v153/upgrade.sql new file mode 100644 index 000000000..382f85d08 --- /dev/null +++ b/niucloud/app/upgrade/v153/upgrade.sql @@ -0,0 +1,48 @@ + +ALTER TABLE `web_friendly_link` MODIFY COLUMN link_title VARCHAR (100) NOT NULL DEFAULT '' COMMENT '标题'; + +ALTER TABLE `web_friendly_link` MODIFY COLUMN link_url VARCHAR (100) NOT NULL DEFAULT '' COMMENT '链接'; + +ALTER TABLE `web_friendly_link` MODIFY COLUMN link_pic VARCHAR (100) NOT NULL DEFAULT '' COMMENT '图片'; + +ALTER TABLE `pay_transfer` CHANGE COLUMN `extra` `extra` VARCHAR (1000) NOT NULL DEFAULT '' COMMENT '扩展信息'; + +DROP TABLE IF EXISTS `sys_backup_records`; +CREATE TABLE `sys_backup_records` +( + `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `version` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '备份版本号', + `backup_key` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '备份标识', + `content` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '备份内容', + `status` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '状态', + `fail_reason` LONGTEXT DEFAULT NULL COMMENT '失败原因', + `remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注', + `create_time` INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间', + `complete_time` INT(11) NOT NULL DEFAULT 0 COMMENT '完成时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='备份记录表'; + +DROP TABLE IF EXISTS `sys_upgrade_records`; +CREATE TABLE `sys_upgrade_records` +( + `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `upgrade_key` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '升级标识', + `app_key` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '插件标识', + `name` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '升级名称', + `content` LONGTEXT DEFAULT NULL COMMENT '升级内容', + `prev_version` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '前一版本', + `current_version` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '当前版本', + `status` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '状态', + `fail_reason` LONGTEXT DEFAULT NULL COMMENT '失败原因', + `create_time` INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间', + `complete_time` INT(11) NOT NULL DEFAULT 0 COMMENT '完成时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='升级记录表'; + +ALTER TABLE `pay` MODIFY COLUMN `money` DECIMAL (10, 2) NOT NULL DEFAULT 0.00 COMMENT '支付金额'; + +ALTER TABLE `jobs` MODIFY COLUMN `queue` VARCHAR (255) NOT NULL DEFAULT ''; + +ALTER TABLE `diy_form_submit_config` MODIFY COLUMN `tips_type` VARCHAR (255) NOT NULL DEFAULT '' COMMENT '提示内容类型,default:默认提示,diy:自定义提示'; + +ALTER TABLE `diy_theme` CHANGE COLUMN `title` `title` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '标题'; diff --git a/niucloud/app/validate/member/CashOutConfig.php b/niucloud/app/validate/member/CashOutConfig.php index ba66d6075..67d30b1c9 100644 --- a/niucloud/app/validate/member/CashOutConfig.php +++ b/niucloud/app/validate/member/CashOutConfig.php @@ -26,7 +26,7 @@ class CashOutConfig extends Validate 'rate' => 'between:0,100', //提现手续费比率 'is_auto_verify' => 'in:0,1', //是否自动审核 'is_auto_transfer' => 'in:0,1', //是否自动转账 - 'transfer_type' => 'require', + 'transfer_type' => 'requireIf:is_open,1', ]; protected $message = [ @@ -41,4 +41,4 @@ class CashOutConfig extends Validate protected $scene = [ 'set' => ['is_open', 'min', 'rate', 'is_auto_verify', 'is_auto_transfer', 'transfer_type'], ]; -} +} \ No newline at end of file diff --git a/niucloud/config/version.php b/niucloud/config/version.php index 7d0290deb..870975364 100644 --- a/niucloud/config/version.php +++ b/niucloud/config/version.php @@ -1,6 +1,6 @@ '1.5.2', - 'code' => '2025031402' + 'version' => '1.5.3', + 'code' => '2025052201' ]; diff --git a/niucloud/core/dict/PackageGift.php b/niucloud/core/dict/PackageGift.php deleted file mode 100644 index f790da461..000000000 --- a/niucloud/core/dict/PackageGift.php +++ /dev/null @@ -1 +0,0 @@ -// | 官方网址:https://www.niucloud.com diff --git a/niucloud/core/exception/CloudBuildException.php b/niucloud/core/exception/CloudBuildException.php new file mode 100644 index 000000000..ec447f5e1 --- /dev/null +++ b/niucloud/core/exception/CloudBuildException.php @@ -0,0 +1,18 @@ + 'refund', 'transaction_id' => $out_trade_no, 'out_refund_no' => $refund_no, - '' ]; $result = Pay::wechat()->query($order); if (empty($result)) diff --git a/niucloud/core/util/DbBackup.php b/niucloud/core/util/DbBackup.php index 5bad871b7..cd28ef75e 100644 --- a/niucloud/core/util/DbBackup.php +++ b/niucloud/core/util/DbBackup.php @@ -1,532 +1,216 @@ './backup/', - // 数据库备份卷大小 - 'part' => 20971520, - // 数据库备份文件是否启用压缩 0不压缩 1 压缩 - 'compress' => 0, - // 数据库备份文件压缩级别 1普通 4 一般 9最高 - 'level' => 9, - ); + private $startime = 0; - /** - * 数据库备份构造方法 - * @param array $file 备份或还原的文件信息 - * @param array $config 备份配置信息 - */ - public function __construct($config = []) + private $maxExecuteTime = 10; + + public function __construct($backupPath, $maxFileSize = 1024 * 1024, $excludeTables = [], $key = '') { - $this->config = is_array($config) && !empty($config) ? array_merge($this->config, $config) : $this->config; - //初始化文件名 - $this->setFile(); - //初始化数据库连接参数 - $this->setDbConn(); - //检查文件是否可写 - if (!$this->checkPath($this->config['path'])) { - throw new \Exception("The current directory is not writable"); + $this->key = $key; + $cache = $this->getCache(); + $this->backupPath = $backupPath; + $this->maxFileSize = $maxFileSize; + $this->excludeTables = $excludeTables; + if (!is_dir($this->backupPath)) { + mkdir($this->backupPath, 0777, true); } + $this->currentFileIndex = $cache['currentFileIndex'] ?? 0; + $this->currentFile = $this->backupPath . '/backup_' . $this->currentFileIndex . '.sql'; + $this->tables = $cache['tables'] ?? []; + $this->totalTables = count($this->getAllTables()); + $this->processedTables = $cache['processedTables'] ?? 0; + $this->tableOffset = $cache['tableOffset'] ?? []; + $this->currentFileSize = $cache['currentFileSize'] ?? 0; + $this->restoreIndex = $cache['restoreIndex'] ?? 0; + $this->startime = time(); } - /** - * 设置脚本运行超时时间 - * 0表示不限制,支持连贯操作 - */ - public function setTimeout($time = null) - { - if (!is_null($time)) { - set_time_limit($time) || ini_set("max_execution_time", $time); - } + private function getCache() { + $cache = Cache::get('db_backup_' . $this->key, []); + return $cache; + } + + private function setCache() { + $cache = [ + 'currentFileIndex' => $this->currentFileIndex, + 'processedTables' => $this->processedTables, + 'tableOffset' => $this->tableOffset, + 'currentFileSize' => $this->currentFileSize, + 'restoreIndex' => $this->restoreIndex, + 'tables' => $this->tables + ]; + Cache::set('db_backup_' . $this->key, $cache, 3600); + } + + public function setExcludeTables($tables) { + $this->tables = []; + $this->excludeTables = $tables; + $this->totalTables = count($this->getAllTables()); return $this; } - /** - * 设置数据库连接必备参数 - * @param array $dbconfig 数据库连接配置信息 - * @return object - */ - public function setDbConn($dbconfig = []) + public function backupDatabaseSegment($limit = 1000) { - if (empty($dbconfig)) { - $this->dbconfig = config('database.connections.'.config('database.default')); - } else { - $this->dbconfig = $dbconfig; - } - return $this; - } - - /** - * 设置备份文件名 - * - * @param Array $file 文件名字 - * @return object - */ - public function setFile($file = null) - { - if (is_null($file)) { - $this->file = ['name' => date('Ymd-His'), 'part' => 1]; - } else { - if (!array_key_exists("name", $file) && !array_key_exists("part", $file)) { - $this->file = $file['1']; - } else { - $this->file = $file; - } - } - return $this; - } - - /** - * 数据库表列表 - * - * @param null $table - * @param int $type - * @return array - */ - public function dataList($table = null, $type = 1) - { - if (is_null($table)) { - $list = Db::query("SHOW TABLE STATUS"); - } else { - if ($type) { - $list = Db::query("SHOW FULL COLUMNS FROM {$table}"); - } else { - $list = Db::query("show columns from {$table}"); - } - } - - return array_map('array_change_key_case', $list); - } - - /** - * 数据库备份文件列表 - * - * @return array - */ - public function fileList() - { - if (!is_dir($this->config['path'])) { - mkdir($this->config['path'], 0755, true); - } - $path = realpath($this->config['path']); - $flag = \FilesystemIterator::KEY_AS_FILENAME; - $glob = new \FilesystemIterator($path, $flag); - $list = array(); - foreach ($glob as $name => $file) { - if (preg_match('/^\\d{8,8}-\\d{6,6}-\\d+\\.sql(?:\\.gz)?$/', $name)) { - $name1 = $name; - $name = sscanf($name, '%4s%2s%2s-%2s%2s%2s-%d'); - $date = "{$name[0]}-{$name[1]}-{$name[2]}"; - $time = "{$name[3]}:{$name[4]}:{$name[5]}"; - $part = $name[6]; - if (isset($list["{$date} {$time}"])) { - $info = $list["{$date} {$time}"]; - $info['part'] = max($info['part'], $part); - $info['size'] = $info['size'] + $file->getSize(); - } else { - $info['part'] = $part; - $info['size'] = $file->getSize(); + $tables = array_slice($this->getAllTables(), $this->processedTables); + if (!empty($tables)) { + foreach ($tables as $table) { + if (!isset($this->tableOffset[$table])) { + $this->tableOffset[$table] = 0; + $this->backupTableStructure($table); } - $extension = strtoupper(pathinfo($file->getFilename(), PATHINFO_EXTENSION)); - $info['name'] = $name1; - $info['compress'] = $extension === 'SQL' ? '-' : $extension; - $info['time'] = strtotime("{$date} {$time}"); - $list["{$date} {$time}"] = $info; + + while (true) { + $data = Db::table($table)->limit($this->tableOffset[$table], $limit)->select()->toArray(); + if (empty($data)) { + break; + } + $this->backupTableData($table, $data); + $this->tableOffset[$table] += $limit; + + if (time() - $this->startime > $this->maxExecuteTime) { + $this->setCache(); + return $this->processedTables; + } + } + + if (time() - $this->startime > $this->maxExecuteTime) { + $this->setCache(); + return $this->processedTables; + } + + $this->processedTables++; } } - return $list; - } - - /** - * 获取文件名称 - * - * @param string $type - * @param int $time - * @return array|false|mixed|string - * @throws \Exception - */ - public function getFile($type = '', $time = 0) - { - // - if (!is_numeric($time)) { - throw new \Exception("{$time} Illegal data type"); - } - switch ($type) { - case 'time': - $name = date('Ymd-His', $time).'-*.sql*'; - $path = realpath($this->config['path']).DIRECTORY_SEPARATOR.$name; - return glob($path); - break; - case 'timeverif': - $name = date('Ymd-His', $time).'-*.sql*'; - $path = realpath($this->config['path']).DIRECTORY_SEPARATOR.$name; - $files = glob($path); - $list = array(); - foreach ($files as $name) { - $basename = basename($name); - $match = sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d'); - $gz = preg_match('/^\\d{8,8}-\\d{6,6}-\\d+\\.sql.gz$/', $basename); - $list[$match[6]] = array($match[6], $name, $gz); - } - $last = end($list); - if (count($list) === $last[0]) { - return $list; - } else { - throw new \Exception("File {$files['0']} may be damaged, please check again"); - } - break; - case 'pathname': - return "{$this->config['path']}{$this->file['name']}-{$this->file['part']}.sql"; - break; - case 'filename': - return "{$this->file['name']}-{$this->file['part']}.sql"; - break; - case 'filepath': - return $this->config['path']; - break; - default: - $arr = array( - 'pathname' => "{$this->config['path']}{$this->file['name']}-{$this->file['part']}.sql", - 'filename' => "{$this->file['name']}-{$this->file['part']}.sql", - 'filepath' => $this->config['path'], 'file' => $this->file - ); - return $arr; - } - } - - /** - * 删除备份文件 - * - * @param $time - * @return mixed - * @throws \Exception - */ - public function delFile($time) - { - if ($time) { - $file = $this->getFile('time', $time); - array_map("unlink", $file); - $file = $this->getFile('time', $time); - if (count($file)) { - throw new \Exception("File ".implode('##', $file)." deleted failed"); - } else { - return $time; - } - } else { - throw new \Exception("{$time} Time parameter is incorrect"); - } - } - - /** - * 下载备份 - * - * @param string $time - * @param integer $part - * @return array|mixed|string - */ - public function downloadFile($time, $part = 0) - { - $file = $this->getFile('time', $time); - $fileName = $file[$part]; - if (file_exists($fileName)) { - ob_end_clean(); - header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); - header('Content-Description: File Transfer'); - header('Content-Type: application/octet-stream'); - header('Content-Length: '.filesize($fileName)); - header('Content-Disposition: attachment; filename='.basename($fileName)); - readfile($fileName); - } else { - throw new \Exception("{$time} File is abnormal"); - } - } - - public function setSqlMode() { - Db::query("SET sql_mode = '';"); return true; } - /** - * 导入表 - * - * @param $start - * @param $time - * @return array|false|int - * @throws Exception - */ - public function import($start, $time) + public function getBackupProgress() { + return round($this->processedTables / $this->totalTables * 100); + } + + private function backupTableStructure($table) { - //还原数据 - $this->file = $this->getFile('time', $time); - if ($this->config['compress']) { - $gz = gzopen($this->file[0], 'r'); - $size = 0; - } else { - $size = filesize($this->file[0]); - $gz = fopen($this->file[0], 'r'); + $dropTableQuery = "DROP TABLE IF EXISTS `$table`;\n"; + $dropLength = strlen($dropTableQuery); + if ($this->currentFileSize + $dropLength > $this->maxFileSize) { + $this->startNewFile(); } - $sql = ''; - if ($start) { - $this->config['compress'] ? gzseek($gz, $start) : fseek($gz, $start); + $fp = fopen($this->currentFile, 'a'); + fwrite($fp, $dropTableQuery); + $this->currentFileSize += $dropLength; + + $createTableQuery = $this->getTableCreateQuery($table); + $query = $createTableQuery . ";\n"; + $queryLength = strlen($query); + if ($this->currentFileSize + $queryLength > $this->maxFileSize) { + $this->startNewFile(); + $fp = fopen($this->currentFile, 'a'); } - for ($i = 0; $i < 1000; $i++) { - $sql .= $this->config['compress'] ? gzgets($gz) : fgets($gz); - if (preg_match('/.*;$/', trim($sql))) { - if (false !== Db::query($sql)) { - $start += strlen($sql); + fwrite($fp, $query); + fclose($fp); + $this->currentFileSize += $queryLength; + } + + private function backupTableData($table, $data) + { + $columns = implode(', ', array_map(function ($column){ + return "`{$column}`"; + }, array_keys($data[0]))); + $valueSets = []; + foreach ($data as $row) { + $values = []; + foreach ($row as $value) { + if (is_int($value)) { + $values[] = (string)$value; // 整数类型直接转换为字符串 + } elseif (is_float($value)) { + $values[] = (string)$value; // 浮点数类型直接转换为字符串 + } elseif (is_bool($value)) { + $values[] = $value ? '1' : '0'; // 布尔类型转换为 1 或 0 + } elseif (is_null($value)) { + $values[] = 'NULL'; // 空值使用 NULL } else { - return false; + $values[] = Db::getPdo()->quote($value); // 其他类型使用 quote 方法处理 } - $sql = ''; - } elseif ($this->config['compress'] ? gzeof($gz) : feof($gz)) { - return 0; } + $valueSets[] = '(' . implode(', ', $values) . ')'; } - return array($start, $size); + $insertQuery = "INSERT INTO `$table` ($columns) VALUES\n" . implode(",\n", $valueSets) . ";\n"; + $queryLength = strlen($insertQuery); + if ($this->currentFileSize + $queryLength > $this->maxFileSize) { + $this->startNewFile(); + } + $fp = fopen($this->currentFile, 'a'); + fwrite($fp, $insertQuery); + fclose($fp); + $this->currentFileSize += $queryLength; } - /** - * 写入初始数据 - * - * @return boolean true - 写入成功,false - 写入失败 - */ - public function backupInit() + private function getAllTables() { - $sql = "-- -----------------------------\n"; - $sql .= "-- Think MySQL Data Transfer \n"; - $sql .= "-- \n"; - $sql .= "-- Host : ".$this->dbconfig['hostname']."\n"; - $sql .= "-- Port : ".$this->dbconfig['hostport']."\n"; - $sql .= "-- Database : ".$this->dbconfig['database']."\n"; - $sql .= "-- \n"; - $sql .= "-- Part : #{$this->file['part']}\n"; - $sql .= "-- Date : ".date("Y-m-d H:i:s")."\n"; - $sql .= "-- -----------------------------\n\n"; - $sql .= "SET FOREIGN_KEY_CHECKS = 0;\n\n"; - return $this->write($sql); + if (!empty($this->tables)) return $this->tables; + + $tables = Db::query('SHOW TABLES'); + $this->tables = []; + foreach ($tables as $table) { + $table_name = current($table); + if (in_array($table_name, $this->excludeTables)) { + continue; + } + $this->tables[] = $table_name; + } + return $this->tables; } - /** - * 查询单条 - * @param $sql - * @return array|mixed - */ - public function selectOne($sql) { - $result = Db::query($sql); - return $result[0] ?? []; - } - - /** - * 备份表结构 - * - * @param string $table 表名 - * @param integer $start 起始行数 - * @return boolean false - 备份失败 - */ - public function backup($table, $start = 0) + private function getTableCreateQuery($tableName) { - // 备份表结构 - if (0 == $start) { - $result = $this->selectOne("SHOW CREATE TABLE `{$table}`"); - $sql = "\n"; - $sql .= "-- -----------------------------\n"; - $sql .= "-- Table structure for `{$table}`\n"; - $sql .= "-- -----------------------------\n"; - $sql .= "DROP TABLE IF EXISTS `{$table}`;\n"; - $sql .= trim($result['Create Table']).";\n\n"; - if (false === $this->write($sql)) { - return false; - } - } - //数据总数 - $result = $this->selectOne("SELECT COUNT(*) AS count FROM `{$table}`"); - $count = $result['count']; - //备份表数据 - if ($count) { - //写入数据注释 - if (0 == $start) { - $sql = "-- -----------------------------\n"; - $sql .= "-- Records of `{$table}`\n"; - $sql .= "-- -----------------------------\n"; - $this->write($sql); - } - //备份数据记录 - $result = Db::query("SELECT * FROM `{$table}` LIMIT {$start}, 1000"); - $sql = "INSERT INTO `{$table}` VALUES\n"; - foreach ($result as $index => $row) { - $row = array_map(function ($item){ - return is_string($item) ? addslashes($item) : $item; - }, $row); - $sql .= "('".str_replace(array("\r", "\n"), array('\\r', '\\n'), - implode("', '", $row))."')"; - $sql .= $index < (count($result) - 1) ? ",\n" : ";\n"; - } - - if (false === $this->write($sql)) { - return false; - } - //还有更多数据 - if ($count > $start + 1000) { - return $this->backup($table, $start + 1000); - } - } - //备份下一表 - return true; + $result = Db::query("SHOW CREATE TABLE $tableName"); + return $result[0]['Create Table']; } - /** - * 优化表 - * - * @param String $tables 表名 - * @return String $tables - */ - public function optimize($tables = null) + private function startNewFile() { - if ($tables) { - if (is_array($tables)) { - $tables = implode('`,`', $tables); - $list = db ::select("OPTIMIZE TABLE `{$tables}`"); - } else { - $list = Db::query("OPTIMIZE TABLE `{$tables}`"); - } - if ($list) { - return $tables; - } else { - throw new \Exception("data sheet'{$tables}'Repair mistakes please try again!"); - } - } else { - throw new \Exception("Please specify the table to be repaired!"); - } + $this->currentFileIndex++; + $this->currentFile = $this->backupPath . '/backup_' . $this->currentFileIndex . '.sql'; + $this->currentFileSize = 0; } - /** - * 修复表 - * - * @param String $tables 表名 - * @return String $tables - */ - public function repair($tables = null) + public function restoreDatabase() { - if ($tables) { - if (is_array($tables)) { - $tables = implode('`,`', $tables); - $list = Db::query("REPAIR TABLE `{$tables}`"); - } else { - $list = Db::query("REPAIR TABLE `{$tables}`"); + $backupFiles = glob($this->backupPath . '/backup_*.sql'); + natsort($backupFiles); + $backupFiles = array_values($backupFiles); + + if ($this->restoreIndex >= count($backupFiles)) return true; + $backupFile = $backupFiles[$this->restoreIndex]; + + $sql = file_get_contents($backupFile); + $queries = explode(";\n", $sql); + foreach ($queries as $query) { + if (trim($query) !== '') { + Db::execute($query); } - if ($list) { - - return $list; - } else { - throw new \Exception("data sheet'{$tables}'Repair mistakes please try again!"); - } - } else { - throw new \Exception("Please specify the table to be repaired!"); } + $this->restoreIndex++; + $this->setCache(); + return $this->restoreIndex; } - - /** - * 写入SQL语句 - * - * @param string $sql 要写入的SQL语句 - * @return boolean true - 写入成功,false - 写入失败! - */ - private function write($sql) - { - $size = strlen($sql); - //由于压缩原因,无法计算出压缩后的长度,这里假设压缩率为50%, - //一般情况压缩率都会高于50%; - $size = $this->config['compress'] ? $size / 2 : $size; - $this->open($size); - return $this->config['compress'] ? @gzwrite($this->fp, $sql) : @fwrite($this->fp, $sql); - } - - /** - * 打开一个卷,用于写入数据 - * - * @param integer $size 写入数据的大小 - */ - private function open($size) - { - if ($this->fp) { - $this->size += $size; - if ($this->size > $this->config['part']) { - $this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp); - $this->fp = null; - $this->file['part']++; - session('backup_file', $this->file); - $this->backupInit(); - } - } else { - $backuppath = $this->config['path']; - $filename = "{$backuppath}{$this->file['name']}-{$this->file['part']}.sql"; - if ($this->config['compress']) { - $filename = "{$filename}.gz"; - $this->fp = @gzopen($filename, "a{$this->config['level']}"); - } else { - $this->fp = @fopen($filename, 'a'); - } - $this->size = filesize($filename) + $size; - } - } - - /** - * 检查目录是否可写 - * - * @param string $path 目录 - * @return boolean - */ - protected function checkPath($path) - { - if (is_dir($path)) { - return true; - } - if (mkdir($path, 0755, true)) { - return true; - } else { - return false; - } - } - - /** - * 析构方法,用于关闭文件资源 - */ - public function __destruct() - { - if ($this->fp) { - $this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp); - } - } - }