diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dffa84a --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Build and Release Folders +bin-debug/ +bin-release/ +[Oo]bj/ +[Bb]in/ + +# Other files and folders +.settings/ + +# Executables +*.swf +*.air +*.ipa +*.apk + +# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` +# should NOT be excluded as they contain compiler settings and other important +# information for Eclipse / Flash Builder. + +/.idea +/upgrade +niucloud/public/.htaccess +uni-app/* +web/* +IM/* diff --git a/niucloud/.env b/niucloud/.env new file mode 100644 index 0000000..3402a62 --- /dev/null +++ b/niucloud/.env @@ -0,0 +1 @@ +APP_DEBUG = true [APP] DEFAULT_TIMEZONE = Asia/Shanghai AUTH_KEY = nzpawfdodlftgvqgbjaeskihscuhxymr [DATABASE] TYPE = mysql HOSTNAME = 82.157.42.191 DATABASE = zhifuguanli_zeya USERNAME = zhifuguanli_zeya PASSWORD = XNfnWG2DGF6GQh27 HOSTPORT = 3306 PREFIX = hy_ CHARSET = utf8 DEBUG = false [REDIS] REDIS_HOSTNAME = 127.0.0.1 PORT = 6379 REDIS_PASSWORD = SELECT = 0 [LANG] default_lang = zh-cn [SYSTEM] ADMIN_TOKEN_NAME = token API_TOKEN_NAME = token ADMIN_SITE_ID_NAME = site-id API_SITE_ID_NAME = site-id ADMIN_TOKEN_EXPIRE_TIME = 604800 API_TOKEN_EXPIRE_TIME = 86400 LANG_NAME = lang CHANNEL_NAME = channel ADMIN_DOMAIN = WAP_DOMAIN = WEB_DOMAIN = [NIUCLOUD] code = secret = \ No newline at end of file diff --git a/niucloud/.example.env b/niucloud/.example.env new file mode 100644 index 0000000..4709442 --- /dev/null +++ b/niucloud/.example.env @@ -0,0 +1 @@ +APP_DEBUG = true [APP] DEFAULT_TIMEZONE = Asia/Shanghai AUTH_KEY = {auth_key} [DATABASE] TYPE = mysql HOSTNAME = {dbhost} DATABASE = {dbname} USERNAME = {dbuser} PASSWORD = {dbpwd} HOSTPORT = {dbport} PREFIX = {dbprefix} CHARSET = utf8 DEBUG = false [REDIS] REDIS_HOSTNAME = 127.0.0.1 PORT = 6379 REDIS_PASSWORD = SELECT = 0 [LANG] default_lang = zh-cn [SYSTEM] ADMIN_TOKEN_NAME = token API_TOKEN_NAME = token ADMIN_SITE_ID_NAME = site-id API_SITE_ID_NAME = site-id ADMIN_TOKEN_EXPIRE_TIME = 604800 API_TOKEN_EXPIRE_TIME = 86400 LANG_NAME = lang CHANNEL_NAME = channel ADMIN_DOMAIN = WAP_DOMAIN = WEB_DOMAIN = [NIUCLOUD] code = secret = \ No newline at end of file diff --git a/niucloud/.gitignore b/niucloud/.gitignore new file mode 100644 index 0000000..33a5a07 --- /dev/null +++ b/niucloud/.gitignore @@ -0,0 +1,7 @@ +/.idea +/.vscode +*.log +/runtime +install.lock +/vendor +composer.lock \ No newline at end of file diff --git a/niucloud/.htaccess b/niucloud/.htaccess new file mode 100644 index 0000000..e69de29 diff --git a/niucloud/.travis.yml b/niucloud/.travis.yml new file mode 100644 index 0000000..36f7b6f --- /dev/null +++ b/niucloud/.travis.yml @@ -0,0 +1,42 @@ +sudo: false + +language: php + +branches: + only: + - stable + +cache: + directories: + - $HOME/.composer/cache + +before_install: + - composer self-update + +install: + - composer install --no-dev --no-interaction --ignore-platform-reqs + - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip . + - composer require --update-no-dev --no-interaction "topthink/think-image:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0" + - composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0" + - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip . + +script: + - php think unit + +deploy: + provider: releases + api_key: + secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw= + file: + - ThinkPHP_Core.zip + - ThinkPHP_Full.zip + skip_cleanup: true + on: + tags: true diff --git a/niucloud/LICENSE.txt b/niucloud/LICENSE.txt new file mode 100644 index 0000000..574a39c --- /dev/null +++ b/niucloud/LICENSE.txt @@ -0,0 +1,32 @@ + +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 +版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn) +All rights reserved。 +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 + +Apache Licence是著名的非盈利开源组织Apache采用的协议。 +该协议和BSD类似,鼓励代码共享和尊重原作者的著作权, +允许代码修改,再作为开源或商业软件发布。需要满足 +的条件: +1. 需要给代码的用户一份Apache Licence ; +2. 如果你修改了代码,需要在被修改的文件中说明; +3. 在延伸的代码中(修改和有源代码衍生的代码中)需要 +带有原来代码中的协议,商标,专利声明和其他原来作者规 +定需要包含的说明; +4. 如果再发布的产品中包含一个Notice文件,则在Notice文 +件中需要带有本协议内容。你可以在Notice中增加自己的 +许可,但不可以表现为对Apache Licence构成更改。 +具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0 + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/niucloud/README.md b/niucloud/README.md new file mode 100644 index 0000000..a8c4d1c --- /dev/null +++ b/niucloud/README.md @@ -0,0 +1,56 @@ +ThinkPHP 6.0 +=============== + +> 运行环境要求PHP7.2+,兼容PHP8.1 + +[官方应用服务市场](https://market.topthink.com) | [`ThinkAPI`——官方统一API服务](https://docs.topthink.com/think-api) + +ThinkPHPV6.0版本由[亿速云](https://www.yisu.com/)独家赞助发布。 + +## 主要新特性 + +* 采用`PHP7`强类型(严格模式) +* 支持更多的`PSR`规范 +* 原生多应用支持 +* 更强大和易用的查询 +* 全新的事件系统 +* 模型事件和数据库事件统一纳入事件系统 +* 模板引擎分离出核心 +* 内部功能中间件化 +* SESSION/Cookie机制改进 +* 对Swoole以及协程支持改进 +* 对IDE更加友好 +* 统一和精简大量用法 + +## 安装 + +~~~ +composer create-project topthink/think tp 6.0.* +~~~ + +如果需要更新框架使用 +~~~ +composer update topthink/framework +~~~ + +## 文档 + +[完全开发手册](https://www.kancloud.cn/manual/thinkphp6_0/content) + +## 参与开发 + +请参阅 [ThinkPHP 核心框架包](https://github.com/top-think/framework)。 + +## 版权信息 + +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 + +本项目包含的第三方源码和二进制文件之版权信息另行标注。 + +版权所有Copyright © 2006-2021 by ThinkPHP (http://thinkphp.cn) + +All rights reserved。 + +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 + +更多细节参阅 [LICENSE.txt](LICENSE.txt) diff --git a/niucloud/addon/hello_world/Addon.php b/niucloud/addon/hello_world/Addon.php new file mode 100644 index 0000000..e4a8850 --- /dev/null +++ b/niucloud/addon/hello_world/Addon.php @@ -0,0 +1,36 @@ + + +
+ 感谢您选择niucloud-admin【以下简称niucloud】,niucloud-admin后台采用thinkphp6+php8+mysql,前端采用uniapp前后端分离的技术开发,全部源码开放。
+ 为了使您正确并合法的使用本软件,请您在使用前务必阅读清楚下面的协议条款:
+
+ 一、本协议适用于niucloud-admin框架以及框架内所有应用,使用前请您务必仔细阅读本协议须知并勾选接受或者不接受,如不接受此协议,那么您无权利继续注册并使用本协议涉及的所有服务,如果您继续注册,登录,订阅等行为,则视为默认接受本协议。niucloud官方对本授权协议拥有最终解释权。 +
++ 二、协议许可权利 +
+ 三、协议规定的约束和限制 +
+ 四、知识产权声明 +
五、有限担保和免责声明
+
+ 本软件及所附带的文件是作为不提供任何明确的或隐含的赔偿或担保的形式提供的。
+ 用户出于自愿而使用本软件,您必须了解使用本软件的风险,在尚未购买产品技术服务之前,我们不承诺对免费用户提供任何形式的技术支持、使用担保,也不承担任何因使用本软件而产生问题的相关责任。
+ 电子文本形式的授权协议如同双方书面签署的协议一样,具有完全的和等同的法律效力。您一旦开始确认本协议并安装niucloud-admin框架,即被视为完全理解并接受本协议的各项条款,在享有上述条款授予的权力的同时,受到相关的约束和限制。协议许可范围以外的行为,将直接违反本授权协议并构成侵权,我们有权随时终止授权,责令停止损害,并保留追究相关责任的权力。
+
| 需开启的变量或函数 | +要求 | +实际状态及建议 | +
|---|---|---|
| php版本 | +php8.0.0及以上 | +{$phpv} | +
| {$variables_item.name} | +{$variables_item.need} | +![]() |
+
| 目录名 | +读取权限 | +写入权限 | +
|---|---|---|
| {$dirs_item.path_name} | +
+
+ |
+
+
+ |
+
+ 恭喜您!已成功安装niucloud-admin。
+建议删除安装目录install后使用
+您现在可以访问:
+
+
+
+
+
+ Niucloud-admin特点介绍
1.采用的技术栈
1.1 后台php采用thinkphp6+php8+mysql,支持composer快速安装扩展,支持redis缓存以及消息队列,支持多语言设计开发,同时开发采用严格的restful的api设计开发。
1.2 后台前后端分离采用element-plus、vue3.0、typescript、vite、pina等前端技术,同时使用i18n支持国际化多语言开发。
1.3 手机端采用uniapp前后端分离,同时使用uview、vue3.0、typescript、vite、pina等前端技术,同时使用i18n支持国际化多语言开发,可以灵活编译成h5,微信小程序,支付宝小程序,抖音小程序等使用场景。
2.技术特点
2.1niucloud-admin采用多租户的saas系统设计,能够提供企业级软件服务运营 ,同时满足用户多站点,多商户,多门店等系统开发需求。
2.2niucloud-admin结合当前市面上很多框架结构不规范,导致基础结构不稳定等情况,严格定义了分层设计的开发规范,同时api接口严格采用restful的开发规范,能够满足大型业务系统或者微服务的开发需求。
2.3 niucloud-admin前端以及后端采用严格的多语言开发规范,包括前端展示,api接口返回,数据验证,错误返回等全部使用多语言设计规范,使开发者能够真生意义上实现多语言的开发需求。
2.4 Niucloud-admin已经搭建好常规系统的开发底层,具体的底层功能包括:管理员管理,权限管理,网站设置,计划任务管理,素材管理,会员管理,会员账户管理,微信公众号以及小程序管理,支付管理,第三方登录管理,消息管理,短信管理,文章管理,前端装修等全面的基础功能,这样开发者不需要开发基础的结构而专心开发业务。
2.5 niucloud-admin系统内置支持微信/支付宝支付,微信公众号/小程序/短信消息管理,阿里云/腾讯云短信,七牛云/阿里云存储等基础的功能扩展,后续会根据实际业务不断扩展基础组件。
2.6 niucloud-admin结合系统结构特点专门开发了代码生成器,这样开发者根据数据表就可以一键生成基础的业务代码,包括:后台php业务代码以及对应的前端vue代码。
2.7 前端采用标准的element-plus,开发者不需要详细了解前端,只需要用标准的element组件就可以。
2.8 手机端设计开发了自定义装修,同时提供了基础的开发组件,方便开发者设计开发手机自定义页面装修的开发需求。
2.9 手机端使用uniapp ,同时使用uview页面展示,可以开发出丰富的手机样式,同时不需要专门学习小程序,app等开发语言,只需要通过uniapp编译就可以。
', + 'is_show' => 1, + 'create_time' => time() + ], + [ + 'category_id' => $category_id, + 'site_id' => $params[ 'site_id' ], + 'title' => 'NiuCloud-admin 开发者联盟', + 'intro' => 'Niucloud-admin 开发者联盟招募', + 'summary' => '', + 'image' => 'static/resource/images/article/niucloud_admin_developer.png', + 'author' => 'NiuCloud', + 'content' => 'Niucloud-admin 开发者联盟招募
近几年,我们看到很多企业都在做自己的研发,有的是企业和内部使用,有的是帮助别人定制开发,也有的已经成功走向商业化,对软件开发的学习和钻研成为了行业圈内发展很有前景的方向。同时我们也看到,大家的开发之路都多多少少遇到了各自的瓶颈。或者是接触不到真实项目需求、只能闭门造车;或者是产品研发出来,没有变现的销路;或者技术遇到了瓶颈,没办法走的更深入;或者几个人自己钻研,水平提升很慢。无论属于哪种,亲爱的开发者,如果你也正在为自己怀才不遇无处施展,或者感觉优质的技术内容没有让更多的人知道而苦恼,那么现在,机会来啦~~niucloud-admin框架为你提供优质平台,公开招募开发爱好者。今天,大牛哥把一大波福利搬来,希望可以在学习、交流和市场拓展等方面帮助大家。在针对那些想提高技术水平的个人或团队,想要基于niucloud-admin框架开发自己的产品的伙伴 ,联盟会免费提供一些列的培训或辅导答疑。针对那些渴望交流、认识同路人的小伙伴,会有线上交流会让大家互通想法、互相引荐高人。
说了这么多,那么niucloud-admin到底是什么呢?且听小编来介绍~
Niucloud-admin是一款快速开发通用管理后台框架,前端采用最新的技术栈Vite+TypeScript+Vue3+ElementPlus最流行技术架构,后台结合PHP8、Java SDK、Python等主流后端语言搭建,内置集成用户权限、代码生成器、表单设计、云存储、短信发送、素材中心、微信及公众号、Api模块一系列开箱即用功能,是一款快速可以开发企业级应用的软件系统。
听完介绍是不是都有点马上可以从小白变成大牛的感觉了,“开箱即用”,那不是小白都可以开发出属于自己的插件了吗?对,你没听错~ 具体怎么生成,那就赶快加入niucloud-admin开发者联盟来亲身体验下吧~~
有态度,有深度,niucloud-admin咱们下次见~
', + 'is_show' => 1, + 'create_time' => time() + ] + ]; + $article->insertAll($article_list); + + return true; + } + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/install/InstallSystemService.php b/niucloud/app/service/admin/install/InstallSystemService.php new file mode 100644 index 0000000..20f0339 --- /dev/null +++ b/niucloud/app/service/admin/install/InstallSystemService.php @@ -0,0 +1,115 @@ +installMenu(); + return true; + } + + /** + * 菜单安装 + */ + public function installMenu() + { + $sys_menu = new SysMenu(); + + //系统菜单 + $admin_menus = $this->loadMenu(AppTypeDict::ADMIN); + $site_menus = $this->loadMenu(AppTypeDict::SITE); + $menus = array_merge($admin_menus, $site_menus); + Db::name("sys_menu")->where([ [ 'addon', '=', '' ], ['source', '=', MenuDict::SYSTEM] ])->delete(); + $sys_menu->replace()->insertAll($menus); + //插件菜单 + (new CoreMenuService())->refreshAllAddonMenu(); + // 清除缓存 + Cache::tag(MenuService::$cache_tag_name)->clear(); + return true; + } + + /** + * 加载菜单 + * @return array + */ + public function loadMenu($app_type) + { + //加载系统 + $system_tree = include root_path() . str_replace('/', DIRECTORY_SEPARATOR, "app/dict/menu/" . $app_type . ".php"); + $this->menuTreeToList($system_tree, '', $app_type); + $menu_list = $this->menu_list; + $this->menu_list = []; + return $menu_list; + } + + /** + * 菜单数转为列表 + * @param array $tree + * @param string $parent_key + * @param string $app_type + */ + private function menuTreeToList(array $tree, string $parent_key = '', string $app_type = AppTypeDict::ADMIN) + { + if (is_array($tree)) { + foreach ($tree as $key => $value) { + $item = [ + 'menu_name' => $value[ 'menu_name' ], + 'menu_short_name' => $value[ 'menu_short_name' ] ?? '', + 'menu_key' => $value[ 'menu_key' ], + 'app_type' => $app_type, + 'parent_key' => $value[ 'parent_key' ] ?? $parent_key, + 'menu_type' => $value[ 'menu_type' ], + 'icon' => $value[ 'icon' ] ?? '', + 'api_url' => $value[ 'api_url' ] ?? '', + 'router_path' => $value[ 'router_path' ] ?? '', + 'view_path' => $value[ 'view_path' ] ?? '', + 'methods' => $value[ 'methods' ] ?? '', + 'sort' => $value[ 'sort' ] ?? '', + 'status' => 1, + 'is_show' => $value[ 'is_show' ] ?? 1 + ]; + $refer = $value; + if (isset($refer[ 'children' ])) { + unset($refer[ 'children' ]); + $this->menu_list[] = $item; + $p_key = $refer[ 'menu_key' ]; + $this->menuTreeToList($value[ 'children' ], $p_key, $app_type); + } else { + $this->menu_list[] = $item; + } + } + } + } + +} diff --git a/niucloud/app/service/admin/member/MemberAccountService.php b/niucloud/app/service/admin/member/MemberAccountService.php new file mode 100644 index 0000000..c09df64 --- /dev/null +++ b/niucloud/app/service/admin/member/MemberAccountService.php @@ -0,0 +1,154 @@ +model = new MemberAccountLog(); + } + + /** + * 会员账户流水列表 + * @param array $where + * @return array + */ + public function getPage(array $where = []) + { + + $field = 'member_account_log.id, member_account_log.member_id, member_account_log.site_id, member_account_log.account_type, member_account_log.account_data,member_account_log.account_sum, member_account_log.from_type, member_account_log.related_id, member_account_log.create_time, member_account_log.memo'; + $member_where = []; + if (!empty($where[ 'keywords' ])) { + $member_where[] = [ "member.member_no|member.nickname|member.mobile", 'like', '%' . $where[ 'keywords' ] . '%' ]; + } + $search_model = $this->model->where([ [ 'member_account_log.site_id', '=', $this->site_id ] ])->withSearch([ 'join_member_id' => 'member_id', 'account_type', 'from_type', 'join_create_time' => 'create_time' ], $where)->withJoin([ 'member' => function($query) { + $query->field("member.nickname, member.headimg, member.mobile, member.member_id, member.member_no"); + } + ])->where($member_where)->field($field)->order('create_time desc')->append([ 'from_type_name', 'account_type_name' ]); + return $this->pageQuery($search_model); + } + + /** + * 账户流水详情 + * @param int $id + * @return array + */ + public function getInfo(int $id) + { + $field = 'id, member_id, site_id, account_type, account_data, from_type, related_id, create_time, memo'; + return $this->model->where([ [ 'id', '=', $id ], [ 'site_id', '=', $this->site_id ] ])->with('memberInfo')->field($field)->append([ 'from_type_name', 'account_type_name' ])->findOrEmpty()->toArray(); + } + + /** + * 添加调整积分数据 + * @param array $data + * @return mixed + */ + public function adjustPoint(array $data) + { + return ( new CoreMemberAccountService() )->addLog($this->site_id, $data[ 'member_id' ], 'point', $data[ 'account_data' ], 'adjust', $data[ 'memo' ]); + } + + /** + * 添加调整余额账户 + * @param array $data + * @return bool + */ + public function adjustBalance(array $data) + { + return ( new CoreMemberAccountService() )->addLog($this->site_id, $data[ 'member_id' ], 'balance', $data[ 'account_data' ], 'adjust', $data[ 'memo' ]); + } + + public function adjustMoney(array $data) + { + return ( new CoreMemberAccountService() )->addLog($this->site_id, $data[ 'member_id' ], MemberAccountTypeDict::MONEY, $data[ 'account_data' ], 'adjust', $data[ 'memo' ]); + } + + /** + * 获取账户类型的变动方式 + * @param $account_type + * @return array|mixed|string + */ + public function getFromType($account_type) + { + if (!array_key_exists($account_type, MemberAccountTypeDict::getType())) throw new AdminException('MEMBER_TYPE_NOT_EXIST'); + return MemberAccountChangeTypeDict::getType($account_type); + } + + /** + * 获取账户数据和 + * @param string $account_type (注意查询对应账户) + */ + public function getSumAccount(string $account_type) + { + return $this->model->where([ [ 'site_id', '=', $this->site_id ], [ 'account_type', '=', $account_type ] ])->sum('account_data'); + } + + /** + * 会员账户详情 + * @param int $member_id + * @return array + */ + public function getMemberAccountInfo(int $member_id) + { + $field = 'point, point_get, balance, balance_get, growth, growth_get, money, money_get, commission, commission_get'; + return ( new Member() )->where([ [ 'member_id', '=', $member_id ], [ 'site_id', '=', $this->site_id ] ])->field($field)->findOrEmpty()->toArray(); + } + + /** + * 已提现佣金 + * @return float + */ + public function getWithdrawnCommission(int $member_id = 0) + { + $condition = [ + [ 'site_id', '=', $this->site_id ], + [ 'account_type', '=', MemberAccountTypeDict::COMMISSION ], + [ 'from_type', '=', 'cash_out' ] + ]; + if (!empty($member_id)) $condition[] = [ 'member_id', '=', $member_id ]; + + return $this->model->where($condition)->sum('account_data'); + } + + /** + * 账户支出总额 + * @return float + */ + public function getExpensesSumAccount(string $account_type, int $member_id = 0) + { + $condition = [ + [ 'site_id', '=', $this->site_id ], + [ 'account_type', '=', $account_type ], + [ 'account_data', '<', '0' ] + ]; + if (!empty($member_id)) $condition[] = [ 'member_id', '=', $member_id ]; + + return $this->model->where($condition)->sum('account_data'); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/member/MemberCashOutConfigService.php b/niucloud/app/service/admin/member/MemberCashOutConfigService.php new file mode 100644 index 0000000..064758b --- /dev/null +++ b/niucloud/app/service/admin/member/MemberCashOutConfigService.php @@ -0,0 +1,38 @@ +model = new MemberCashOut(); + } + + + public function getConfig(){ + return (new CoreMemberCashOutConfigService())->getMemberCashOutConfig($this->site_id); + } + + public function setConfig(array $data){ + (new CoreMemberCashOutConfigService())->setMemberCashOutConfig($this->site_id, $data); + return true; + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/member/MemberCashOutService.php b/niucloud/app/service/admin/member/MemberCashOutService.php new file mode 100644 index 0000000..765cc1b --- /dev/null +++ b/niucloud/app/service/admin/member/MemberCashOutService.php @@ -0,0 +1,100 @@ +model = new MemberCashOut(); + } + + /** + * 会员提现列表 + * @param array $where + * @return array + */ + public function getPage(array $where = []) + { + + $field = 'id,member_cash_out.site_id,cash_out_no,member_cash_out.member_id,account_type,transfer_type,transfer_realname,transfer_mobile,transfer_bank,transfer_account,transfer_fail_reason,transfer_status,transfer_time,apply_money,rate,service_money,member_cash_out.money,audit_time,member_cash_out.status,remark,member_cash_out.create_time,refuse_reason,transfer_no'; + $member_where = []; + if(!empty($where['keywords'])) + { + $member_where = [['member.member_no|member.nickname|member.mobile', '=', $where['keywords']]]; + } + $search_model = $this->model->where([['member_cash_out.site_id', '=', $this->site_id]])->withSearch(['member_id','status', 'join_create_time' => 'create_time', 'audit_time', 'transfer_time', 'transfer_type', 'cash_out_no'],$where)->with(['transfer'])->withJoin(["member" => function($query){ + $query->field("member.nickname, member.headimg, member.mobile, member.member_id, member.member_no"); + }])->where($member_where)->field($field)->order('create_time desc')->append(['status_name', 'transfer_status_name', 'transfer_type_name', 'account_type_name']); + return $this->pageQuery($search_model); + } + + /** + * 提现详情 + * @param int $id + * @return array + */ + public function getInfo(int $id) + { + $field = 'id,site_id,cash_out_no,member_id,account_type,transfer_type,transfer_realname,transfer_mobile,transfer_bank,transfer_account,transfer_fail_reason,transfer_status,transfer_time,apply_money,rate,service_money,money,audit_time,status,remark,create_time,refuse_reason,transfer_no'; + return $this->model->where([['id', '=', $id], ['site_id', '=', $this->site_id]])->with(['memberInfo', 'transfer'])->field($field)->append(['status_name', 'transfer_status_name', 'transfer_type_name', 'account_type_name'])->findOrEmpty()->toArray(); + } + + /** + * @param int $id + * @param string $action + * @param $data + * @return true|null + */ + public function audit(int $id, string $action, $data){ + $core_member_cash_out_service = new CoreMemberCashOutService(); + return $core_member_cash_out_service->audit($this->site_id, $id, $action, $data); + } + + + /** + * 转账 + * @param int $id + * @param array $data + * @return true + */ + public function transfer(int $id, array $data){ + $core_member_cash_out_service = new CoreMemberCashOutService(); + return $core_member_cash_out_service->transfer($this->site_id, $id, $data); + } + + /** + * 统计数据 + * @return array + */ + public function stat() + { + $stat = []; + //已提现 + $stat['transfered'] = $this->model->where([['status', '=', MemberCashOutDict::TRANSFERED], ['site_id', '=', $this->site_id]])->sum("apply_money"); + //所有金额(包括提现中,已提现) + $all_money = $this->model->where([['status', '>=', 0], ['site_id', '=', $this->site_id]])->sum("apply_money"); + + $stat['cash_outing'] = $all_money - $stat['transfered']; + return $stat; + } + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/member/MemberConfigService.php b/niucloud/app/service/admin/member/MemberConfigService.php new file mode 100644 index 0000000..9b6efbf --- /dev/null +++ b/niucloud/app/service/admin/member/MemberConfigService.php @@ -0,0 +1,74 @@ +getLoginConfig($this->site_id); + } + + /** + * 注册登录设置 + * @param array $data + * @return true + */ + public function setLoginConfig(array $data){ + return (new CoreMemberConfigService())->setLoginConfig($this->site_id, $data); + } + /** + * 获取提现设置 + */ + public function getCashOutConfig(){ + + return (new CoreMemberConfigService())->getCashOutConfig($this->site_id); + } + + /** + * 提现设置 + * @param array $data + * @return true + */ + public function setCashOutConfig(array $data){ + return (new CoreMemberConfigService())->setCashOutConfig($this->site_id, $data); + } + + /** + * 获取会员设置 + */ + public function getMemberConfig(){ + return (new CoreMemberConfigService())->getMemberConfig($this->site_id); + } + + /** + * 会员设置 + * @param array $data + * @return true + */ + public function setMemberConfig(array $data){ + return (new CoreMemberConfigService())->setMemberConfig($this->site_id, $data); + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/member/MemberLabelService.php b/niucloud/app/service/admin/member/MemberLabelService.php new file mode 100644 index 0000000..7fe1b56 --- /dev/null +++ b/niucloud/app/service/admin/member/MemberLabelService.php @@ -0,0 +1,123 @@ +model = new MemberLabel(); + } + + /** + * 获取会员标签列表 + * @param array $where + * @param string $order + * @return array + */ + public function getPage(array $where = [], string $order = 'create_time desc') + { + $field = 'label_id, site_id, label_name, memo, sort, create_time, update_time'; + $search_model = $this->model->where([ [ 'site_id', '=', $this->site_id ] ])->withSearch([ 'label_name'], $where)->field($field)->append(["member_num"])->order($order); + return $this->pageQuery($search_model); + } + + /** + * 获取会员标签信息 + * @param int $label_id + * @return array + */ + public function getInfo(int $label_id) + { + $field = 'label_id, site_id, label_name, memo, sort, create_time, update_time'; + + return $this->model->field($field)->where([['label_id', '=', $label_id], ['site_id', '=', $this->site_id]])->findOrEmpty()->toArray(); + } + + /** + * 获取标签 + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getAll(){ + return (new CoreMemberLabelService())->getAll($this->site_id); + } + + /** + * 添加会员标签 + * @param array $data + * @return mixed + */ + public function add(array $data) + { + $data['site_id'] = $this->site_id; + $res = $this->model->create($data); + (new CoreMemberLabelService())->clearCache($this->site_id); + return $res->label_id; + + } + + /** + * 会员标签编辑 + * @param int $label_id + * @param array $data + * @return true + */ + public function edit(int $label_id, array $data) + { + $data['update_time'] = time(); + $this->model->where([['label_id', '=', $label_id], ['site_id', '=', $this->site_id]])->save($data); + (new CoreMemberLabelService())->clearCache($this->site_id); + return true; + } + + /** + * 删除会员标签 + * @param int $label_id + * @return bool + */ + public function del(int $label_id) + { + $res = $this->model->where([['label_id', '=', $label_id], ['site_id', '=', $this->site_id]])->delete(); + (new CoreMemberLabelService())->clearCache($this->site_id); + return $res; + } + + /** + * 通过标签id获取标签列表 + * @param array $label_ids + * @return Response + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getMemberLabelListByLabelIds(array $label_ids){ + return (new CoreMemberLabelService())->getMemberLabelListByLabelIds($this->site_id, $label_ids); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/member/MemberService.php b/niucloud/app/service/admin/member/MemberService.php new file mode 100644 index 0000000..534f068 --- /dev/null +++ b/niucloud/app/service/admin/member/MemberService.php @@ -0,0 +1,218 @@ +model = new Member(); + } + + /** + * 会员列表 + * @param array $where + * @return array + */ + public function getPage(array $where = []) + { + + $field = 'member_id, member_no, site_id, 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->where([['site_id', '=', $this->site_id]])->withSearch(['keyword','register_type', 'create_time', 'is_del', 'member_label', 'register_channel'],$where)->field($field)->order('member_id desc')->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); + }); + } + + /** + * 查询会员列表 + * @param array $where + * @return array + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + */ + public function getList(array $where = []) + { + $field = 'member_id, nickname, headimg'; + return $this->model->where([['site_id', '=', $this->site_id]])->withSearch(['keyword'],$where)->field($field)->order('member_id desc')->limit($this->getPageParam()['limit'] ?? 0)->select()->toArray(); + } + /** + * 会员详情 + * @param int $member_id + * @return array|null + */ + public function getInfo(int $member_id) + { + $field = 'member_id,member_no, site_id, 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], ['site_id', '=', $this->site_id]])->field($field)->append(['register_channel_name', 'register_type_name', 'sex_name', 'login_channel_name', 'login_type_name', 'status_name'])->findOrEmpty()->toArray()); + } + + /** + * 添加会员 + * @param array $data + * @return mixed + */ + public function add(array $data) + { + + //检测手机是否重复 + if(!empty($data['mobile'])){ + if(!$this->model->where([['site_id', '=', $this->site_id], ['mobile', '=', $data['mobile']]])->findOrEmpty()->isEmpty()) + throw new AdminException('MOBILE_IS_EXIST'); + } + if($data['init_member_no'] != $data['member_no']){ + if(!$this->model->where([['site_id', '=', $this->site_id], ['member_no', '=', $data['member_no']]])->findOrEmpty()->isEmpty()) + throw new AdminException('MEMBER_NO_IS_EXIST'); + }else{ + if(!$this->model->where([['site_id', '=', $this->site_id], ['member_no', '=', $data['member_no']]])->findOrEmpty()->isEmpty()){ + $data['member_no'] = $this->getMemberNo(); + } + } + + $data['username'] = $data['member_no']; + if(!empty($data['username'])){ + if(!$this->model->where([['site_id', '=', $this->site_id], ['username', '=', $data['username']]])->findOrEmpty()->isEmpty()) + throw new AdminException('MEMBER_IS_EXIST'); + } + $data['site_id'] = $this->site_id; + $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; + event("MemberRegister", $data); + return $member->member_id; + } + + /** + * 更新会员 + * @param int $member_id + * @param array $data + * @return true + */ + public function edit(int $member_id, array $data) + { + $where = array( + ['site_id', '=', $this->site_id], + ['member_id', '=', $member_id], + ); + if(!empty($data['password'])){ + $data['password'] = create_password($data['password']); + } + $this->model->where($where)->update($data); + return true; + } + + /** + * 修改字段 + * @param int $member_id + * @param string $field + * @param $data + */ + public function modify(int $member_id, string $field, $data) + { + return (new CoreMemberService())->modify($this->site_id, $member_id, $field, $data); + } + + /** + * 组合整理数据 + * @param $data + */ + public function makeUp($data){ + //会员标签 + if(!empty($data['member_label'])){ + $data['member_label_array'] = (new MemberLabelService())->getMemberLabelListByLabelIds($data['member_label']); + } + return $data; + } + + /** + * 会员数量 + * @return int + * @throws DbException + */ + public function getCount(array $where = []){ + $where[] = ['site_id', '=', $this->site_id]; + $where[] = ['is_del', '=', 0]; + return $this->model->where($where)->count(); + } + + /** + * 设置状态 + * @param array $member_ids + * @param int $status + * @return true + */ + public function setStatus(array $member_ids, int $status){ + $where = array( + ['site_id', '=', $this->site_id], + ['member_id', 'in', $member_ids], + ); + $data = array( + 'status' => $status + ); + $this->model->where($where)->update($data); + return true; + } + + /** + * 会员数据 + * @param $field + * @return float + */ + public function getSum($field) + { + return $this->model->where([['site_id', '=', $this->site_id] ])->sum($field); + } + + /** + * 创建会员编码 + * @return string|null + */ + public function getMemberNo() + { + return (new CoreMemberService())->createMemberNo($this->site_id); + } + + /** + * 删除会员 + * @param int $member_id + * @return true + */ + public function deleteMember(int $member_id) + { + $this->model->destroy(function($query) use($member_id){ + $query->where([['member_id', '=', $member_id], ['site_id', '=', $this->site_id]]); + }); + return true; + } + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/niucloud/NiucloudService.php b/niucloud/app/service/admin/niucloud/NiucloudService.php new file mode 100644 index 0000000..befe10b --- /dev/null +++ b/niucloud/app/service/admin/niucloud/NiucloudService.php @@ -0,0 +1,83 @@ +core_config_service = new CoreConfigService(); + + } + + /** + * 设置 授权信息 + * @param $data + * @return \app\model\sys\SysConfig|bool|\think\Model + */ + public function setAuthorize($data){ + + $data = [ + 'auth_code' => $data['auth_code'], + 'auth_secret' => $data['auth_secret'] + ]; + $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(0,ConfigKeyDict::NIUCLOUD_CONFIG, $data); + } + + /** + * 获取授权信息 + * @return mixed|string[] + */ + public function getAuthorize(){ + $info = $this->core_config_service->getConfig(0, ConfigKeyDict::NIUCLOUD_CONFIG); + if(empty($info)) + { + $info = []; + $info['value'] = [ + 'auth_code' => '', + 'auth_secret' => '' + ]; + } + return $info['value']; + } + + /** + * 获取框架最新版本 + */ + public function getFrameworkLastVersion() { + return (new CoreModuleService())->getFrameworkLastVersion(); + } + + /** + * 获取框架版本更新记录 + */ + public function getFrameworkVersionList() { + return (new CoreModuleService())->getFrameworkVersionList(); + } +} diff --git a/niucloud/app/service/admin/notice/NoticeLogService.php b/niucloud/app/service/admin/notice/NoticeLogService.php new file mode 100644 index 0000000..75cde20 --- /dev/null +++ b/niucloud/app/service/admin/notice/NoticeLogService.php @@ -0,0 +1,48 @@ +model = new SysNoticeLog(); + } + + /** + * 消息发送记录 + * @param $where + * @return array + */ + public function getPage($where) + { + return (new CoreNoticeLogService())->getPage($this->site_id, $where); + } + + /** + * 获取消息发送记录详情 + * @param string $id + * @return array + */ + public function getInfo(string $id) + { + return (new CoreNoticeLogService())->getInfo($this->site_id, $id); + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/notice/NoticeService.php b/niucloud/app/service/admin/notice/NoticeService.php new file mode 100644 index 0000000..aed05bf --- /dev/null +++ b/niucloud/app/service/admin/notice/NoticeService.php @@ -0,0 +1,107 @@ +model = new SysNotice(); + } + + /** + * 获取当前站点消息 + * @return array + */ + public function getList() + { + return (new CoreNoticeService())->getList($this->site_id); + } + + /** + * 获取消息内容 + * @param string $key + * @return array + */ + public function getInfo(string $key) + { + return (new CoreNoticeService())->getInfo($this->site_id, $key); + } + + /** + * 修改消息模板字段(todo 注意 仅限程序内部调用,故不做验证) + * @param string $key + * @param string $field_type + * @param $value + * @return bool + */ + public function modify(string $key, string $field_type, $value){ + $data = array( + $field_type => $value + ); + return (new CoreNoticeService())->edit($this->site_id, $key, $data); + } + + /** + * 修改消息状态 + * @param string $key + * @param string $type + * @param int $status + */ + public function editMessageStatus(string $key, string $type, int $status) + { + if(!array_key_exists($type, NoticeTypeDict::getType())) throw new AdminException('NOTICE_TYPE_NOT_EXIST'); + if(!array_key_exists($key, NoticeDict::getNotice())) return fail('NOTICE_TYPE_NOT_EXIST'); + return (new CoreNoticeService())->edit($this->site_id, $key, ['is_'.$type => $status]); + } + + /** + * 消息编辑 + * @param string $key + * @param string $type + * @param array $data + */ + public function edit(string $key, string $type, array $data) + { + if(!array_key_exists($type, NoticeTypeDict::getType())) throw new AdminException('NOTICE_TYPE_NOT_EXIST'); + if(!array_key_exists($key, NoticeDict::getNotice())) return fail('NOTICE_TYPE_NOT_EXIST'); + $save_data = ['is_'.$type => $data['status']]; + switch ($type) + { + case NoticeTypeDict::SMS: + $save_data['sms_id'] = $data['sms_id'] ?? ''; + break; + case NoticeTypeDict::WECHAT: + $save_data['wechat_first'] = $data['wechat_first'] ?? ''; + $save_data['wechat_remark'] = $data['wechat_remark'] ?? ''; + break; + case NoticeTypeDict::WEAPP: + break; + } + return (new CoreNoticeService())->edit($this->site_id, $key, $save_data); + } + + + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/notice/NoticeSmsLogService.php b/niucloud/app/service/admin/notice/NoticeSmsLogService.php new file mode 100644 index 0000000..ca0abac --- /dev/null +++ b/niucloud/app/service/admin/notice/NoticeSmsLogService.php @@ -0,0 +1,47 @@ +model = new SysNoticeLog(); + } + + /** + * 获取当前站点消息 + * @return array + */ + public function getPage($where) + { + return (new CoreNoticeSmsLogService())->getPage($this->site_id, $where); + } + + /** + * 获取消息内容 + * @param int $id + * @return array + */ + public function getInfo(int $id) + { + return (new CoreNoticeSmsLogService())->getInfo($this->site_id, $id); + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/notice/SmsService.php b/niucloud/app/service/admin/notice/SmsService.php new file mode 100644 index 0000000..ea43b3e --- /dev/null +++ b/niucloud/app/service/admin/notice/SmsService.php @@ -0,0 +1,128 @@ +getConfig($this->site_id, 'SMS'); + if(empty($info)) + { + $config_type = ['default' => ''];//初始化 + }else + $config_type = $info['value']; + + $list = []; + foreach($sms_type_list as $k => $v) + { + $data = []; + $data['sms_type'] = $k; + $data['is_use'] = $k == $config_type['default'] ? 1 : 0; + $data['name'] = $v['name']; + foreach ($v['params'] as $k_param => $v_param) + { + $data['params'][$k_param] = [ + 'name' => $v_param, + 'value' => $config_type[$k][$k_param] ?? '' + ]; + } + $list[] = $data; + } + return $list; + } + + /** + * 获取短信配置 + * @param string $sms_type + * @return array + */ + public function getConfig(string $sms_type) + { + $sms_type_list = SmsDict::getType(); + if(!array_key_exists($sms_type, $sms_type_list)) throw new AdminException('SMS_TYPE_NOT_EXIST'); + $info = (new CoreConfigService())->getConfig($this->site_id, 'SMS'); + if(empty($info)) + { + $config_type = ['default' => ''];//初始化 + }else + $config_type = $info['value']; + + $data = [ + 'sms_type' => $sms_type, + 'is_use' => $sms_type == $config_type['default'] ? 1 : 0, + 'name' => $sms_type_list[$sms_type]['name'], + ]; + foreach ($sms_type_list[$sms_type]['params'] as $k_param => $v_param) + { + $data['params'][$k_param] = [ + 'name' => $v_param, + 'value' => $config_type[$sms_type][$k_param] ?? '' + ]; + } + return $data; + + } + + /** + * 短信配置 + * @param string $sms_type + * @param array $data + * @return bool + */ + public function setConfig(string $sms_type, array $data) + { + $sms_type_list = SmsDict::getType(); + if(!array_key_exists($sms_type, $sms_type_list)) throw new AdminException('SMS_TYPE_NOT_EXIST'); + $info = (new CoreConfigService())->getConfig($this->site_id, 'SMS'); + if(empty($info)) + { + $config['default'] = ''; + + }else{ + $config = $info['value']; + } + //初始化数据 + if($data['is_use']) + { + $config['default'] = $sms_type; + }else{ + $config['default'] = ''; + } + foreach ($sms_type_list[$sms_type]['params'] as $k_param => $v_param) + { + $config[$sms_type][$k_param] = $data[$k_param] ?? ''; + } + + return (new CoreConfigService())->setConfig($this->site_id, 'SMS', $config); + } + + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/order/RechargeOrderRefundService.php b/niucloud/app/service/admin/order/RechargeOrderRefundService.php new file mode 100644 index 0000000..54de197 --- /dev/null +++ b/niucloud/app/service/admin/order/RechargeOrderRefundService.php @@ -0,0 +1,123 @@ +model = new RechargeOrderItemRefund(); + } + + public function create($order_id) { + try { + (new CoreRechargeRefundService())->create($this->site_id, $order_id); + return true; + } catch ( Exception $e) { + return $e->getMessage(); + } + } + + /** + * 查询退款列表 + * @param array $where + * @return array + */ + public function getPage(array $where) { + + $field = 'recharge_order_item_refund.refund_id,recharge_order_item_refund.num,recharge_order_item_refund.money,recharge_order_item_refund.refund_no,recharge_order_item_refund.status,recharge_order_item_refund.create_time,recharge_order_item_refund.audit_time,recharge_order_item_refund.transfer_time,recharge_order_item_refund.item_type,recharge_order_item_refund.order_item_id, recharge_order_item_refund.order_id,recharge_order_item_refund.member_id,recharge_order_item_refund.order_no'; + $member_where = []; + if(!empty($where['keywords'])) + { + $member_where[] = ["member.member_id|member.nickname|member.mobile", '=', $where['keywords']]; + } + $search_model = $this->model->where([['recharge_order_item_refund.site_id', '=', $this->site_id]])->with(['item' => function($query) { + $query->with('orderNo')->field('order_id, order_item_id, item_name, item_image'); + }])->withSearch(['join_order_no' => 'order_no', 'join_status' => 'status', 'join_member_id' => 'member_id', 'refund_no' => 'refund_no', 'join_create_time' => 'create_time'],$where)->withJoin(['member' => function($query){ + $query->field("member.nickname, member.headimg, member.mobile, member.member_id"); + } + ])->where($member_where)->field($field)->order('create_time desc')->append(['status_name', 'payrefund.type_name']); + + return $this->pageQuery($search_model); + } + + /** + * 查询退款详情 + * @param int $refund_id + * @return array + */ + public function getDetail(int $refund_id) { + $field = 'refund_id,num,money,refund_no,status,create_time,audit_time,transfer_time,item_type,order_item_id, order_id,member_id'; + return $this->model->where([ ['site_id', '=', $this->site_id], ['refund_id', '=', $refund_id]])->field($field)->with(['item' => function($query) { + $query->field('order_item_id, item_name, item_image'); + }, 'member' => function($query) { + $query->field('member_id, nickname, mobile, headimg'); + }, 'payrefund' => function($query) { + $query->field('refund_no'); + }])->append(['status_name', 'payrefund.type_name'])->findOrEmpty()->toArray(); + } + + /** + * 获取退款状态 + * @return array|array[]|string + */ + public function getStatus(){ + return RechargeOrderDict::getRefundStatus(); + } + + /** + * 退款统计数据(根据状态查询) + */ + public function stat() + { + $status = RechargeOrderDict::getRefundStatus(); + $all = 0; + $have = 0; + foreach ($status as $k => &$v) + { + $money = $this->model->where([['status', '=', $v['status']], ['site_id', '=', $this->site_id]])->sum("money"); + if($money == null) + { + $money = 0; + } + if($k == 1 || $k == 2){ + $have += $money; + } + $v['money'] = number_format($money, 2); + $all += $money; + } + $status['all'] = [ + 'name' => get_lang('dict_refund.all'), + 'key' => 'all', + 'money' => number_format($all, 2) + ]; + $status['have'] = [ + 'name' => get_lang('dict_refund.have'), + 'key' => 'all', + 'money' => number_format($have, 2) + ]; + return $status; + + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/order/RechargeOrderService.php b/niucloud/app/service/admin/order/RechargeOrderService.php new file mode 100644 index 0000000..500afa5 --- /dev/null +++ b/niucloud/app/service/admin/order/RechargeOrderService.php @@ -0,0 +1,124 @@ +model = new RechargeOrder(); + } + + /** + * 充值订单分页列表 + * @param array $where + * @return array + */ + public function getPage(array $where) + { + $field = 'order_id, site_id, order_no, order_from, order_type, out_trade_no, order_status, refund_status, member_id, ip, member_message, order_item_money, order_discount_money, order_money, create_time, pay_time, close_time, is_delete, is_enable_refund, remark, invoice_id, close_reason'; + $order = 'create_time desc'; + $where['order_type'] = 'recharge'; + $search_model = $this->model->where([['site_id', '=', $this->site_id]])->withSearch(['order_no', 'order_money', 'order_from', 'order_status', 'order_type', 'member_id', 'out_trade_no', 'create_time', 'pay_time'], $where)->field($field)->with(['item' => function($query) { + $query->field('order_item_id, order_id, member_id, item_id, item_type, item_name, item_image, price, num, item_money, is_refund, refund_no, refund_status, create_time'); + }, 'member' => function($query) { + $query->field('member_id, nickname, mobile, headimg'); + }, 'pay' => function($query) { + $query->field(''); + } ])->order($order)->append(['order_from_name' ]); + $list = $this->pageQuery($search_model); + $order_status = RechargeOrderDict::getStatus(); + $refund_status = RechargeOrderDict::getRefundStatus(); + foreach ($list['data'] as $k => $v) + { + $list['data'][$k]['order_status_info'] = $order_status[$v['order_status']] ?? []; + $list['data'][$k]['refund_status_name'] = $refund_status[$v['refund_status']]['name'] ?? ''; + } + return $list; + } + + /** + * 充值订单详情 + * @param int $order_id + * @return array + */ + public function getDetail(int $order_id) + { + $field = 'order_id, site_id, order_no, order_from, order_type, out_trade_no, order_status, refund_status, member_id, ip, member_message, order_item_money, order_discount_money, order_money, create_time, pay_time, close_time, is_delete, is_enable_refund, remark, invoice_id, close_reason'; + $detail = $this->model->where([['order_type', '=', 'recharge'], ['site_id', '=', $this->site_id], ['order_id', '=', $order_id]])->field($field)->with(['item' => function($query) { + $query->field('order_item_id, order_id, member_id, item_id, item_type, item_name, item_image, price, num, item_money, is_refund, refund_no, refund_status, create_time'); + }, 'member' => function($query) { + $query->field('member_id, nickname, mobile, headimg'); + }, 'pay' => function($query) { + $query->field(''); + } ])->append(['order_from_name'])->findOrEmpty()->toArray(); + if(!empty($detail)) + { + $detail['order_status_info'] = RechargeOrderDict::getStatus($detail['order_status']) ?? []; + } + return $detail; + } + + /** + * 充值订单状态 + * @return array|array[]|string + */ + public function getStatus() + { + return RechargeOrderDict::getStatus(); + } + + + /** + * 充值订单 + * @param array $data + * @return int[] + */ + public function stat(array $data = []) + { + $res = [ + 'recharge_money' => 0, + 'recharge_refund_money' => 0 + ]; + $where = [ + ['site_id', '=', $this->site_id], + ['order_type', '=', 'recharge'], + ['order_status', '=', RechargeOrderDict::FINISH], + ]; + if(!empty($data['member_id'])) $where[] = ['member_id', '=', $data['member_id']]; + + $res['recharge_money'] = $this->model->where($where)->sum('order_money'); + + $where = [ + ['site_id', '=', $this->site_id], + ['order_type', '=', 'recharge'], + ['refund_status', '=', RechargeOrderDict::REFUND_COMPLETED], + ]; + if(!empty($data['member_id'])) $where[] = ['member_id', '=', $data['member_id']]; + $res['recharge_refund_money'] = $this->model->where($where)->sum('order_money'); + return $res; + } + + + + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/pay/PayChannelService.php b/niucloud/app/service/admin/pay/PayChannelService.php new file mode 100644 index 0000000..1fdff43 --- /dev/null +++ b/niucloud/app/service/admin/pay/PayChannelService.php @@ -0,0 +1,197 @@ +model = new PayChannel(); + $this->core_pay_channel_service = new CorePayChannelService(); + } + + /** + * 添加模板 + * @param string $channel + * @param string $type + * @param array $data + * @return true + */ + public function set(string $channel, string $type, array $data) + { + $where = array( + 'type' => $type, + 'channel' => $channel + ); + if (!array_key_exists($type, PayDict::getPayType())) throw new PayException('PATMENT_METHOD_INVALID'); + if ($channel != 'transfer') { + if (!array_key_exists($channel, ChannelDict::getType())) throw new PayException('CHANNEL_MARK_INVALID'); + } + $pay_channel = $this->core_pay_channel_service->find($this->site_id, $where); + if ($pay_channel->isEmpty()) { + $data['channel'] = $channel; + $data['type'] = $type; + $data['site_id'] = $this->site_id; + $data['config'] = $this->getConfigByPayType($data['config'], $type); + $res = $this->model->create($data); + } else { + $data['config'] = $this->getConfigByPayType($data['config'], $type); + $pay_channel->save($data); + } + return true; + } + + /** + * 用于后端支付渠道 + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getChannelList() + { + $channel_list = PayChannelDict::getPayChannel(); + $where = array( + 'site_id' => $this->site_id, + ); + $pay_channel_list_temp = $this->model->where($where)->field('type, channel, config, sort, status')->select()->toArray(); + + $pay_channel_list = []; + foreach ($pay_channel_list_temp as $v) { + $pay_channel_list[$v['channel']][$v['type']] = $v; + } + foreach ($channel_list as $k => $v) { + $temp_item = $pay_channel_list[$k] ?? []; + foreach ($v['pay_type'] as $item_k => $item_v) { + $temp_v_item = $temp_item[$item_k] ?? ['status' => 0, 'config' => [], 'sort' => 0]; + $item_v['config'] = $temp_v_item['config']; + $item_v['status'] = $temp_v_item['status']; + $item_v['sort'] = $temp_v_item['sort']; + $channel_list[$k]['pay_type'][$item_k] = $item_v; + } + $temp_pay_type = array_values($channel_list[$k]['pay_type']); + $sort = array_column($temp_pay_type, 'sort'); + array_multisort($sort, SORT_ASC, $temp_pay_type); + $channel_list[$k]['pay_type'] = $temp_pay_type; + } + return $channel_list; + } + + /** + * 通过渠道获取配置 + * @param string $channel + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getListByChannel(string $channel) + { + $where = array( + 'site_id' => $this->site_id, + 'channel' => $channel + ); + return $this->model->where($where)->field('type, channel, config, sort, status')->select()->toArray(); + } + + /** + * 通过支付方式获取配置格式 + * @param $data + * @param $type + * @return array + */ + public function getConfigByPayType($data, $type) + { + $config = []; + switch ($type) { + case PayDict::WECHATPAY: + $config = [ + 'mch_id' => $data['mch_id'] ?? '',//商户号 + 'mch_secret_key' => $data['mch_secret_key'] ?? '',//商户秘钥 现在默认认为是v3版 + 'mch_secret_cert' => $data['mch_secret_cert'] ?? '',//商户私钥 字符串或路径 + 'mch_public_cert_path' => $data['mch_public_cert_path'] ?? '',//商户公钥证书路径 + ]; + break; + case PayDict::ALIPAY: + $config = [ + 'app_id' => $data['app_id'] ?? '',// 必填-支付宝分配的 app_id + 'app_secret_cert' => $data['app_secret_cert'] ?? '',// 必填-应用私钥 字符串或路径 + 'app_public_cert_path' => $data['app_public_cert_path'] ?? '',//必填-应用公钥证书 路径 + 'alipay_public_cert_path' => $data['alipay_public_cert_path'] ?? '',//必填-支付宝公钥证书 路径 + 'alipay_root_cert_path' => $data['alipay_root_cert_path'] ?? '',// 必填-支付宝根证书 路径 + ]; + break; + case PayDict::OFFLINEPAY: + $config = [ + 'collection_name' => $data['collection_name'] ?? '',// 必填-收款账户名称 + 'collection_bank' => $data['collection_bank'] ?? '',//必填-收款银行 + 'collection_account' => $data['collection_account'] ?? '',//必填-收款账号 + 'collection_desc' => $data['collection_desc'] ?? '',// 必填-转账说明 + ]; + break; + } + return $config; + } + + /** + * 设置打款设置 + * @param $data + * @return true + */ + public function setTransfer($data) + { + $wechatpay_config = $data['wechatpay_config']; + $alipay_config = $data['alipay_config']; + $this->set('transfer', PayDict::WECHATPAY, [ + 'config' => $wechatpay_config, + 'status' => 1, + ]); + $this->set('transfer', PayDict::ALIPAY, [ + 'config' => $alipay_config, + 'status' => 1, + ]); + return true; + } + + public function setAll($data){ + foreach($data as $k => $v){ + $temp_v = $v['pay_type']; + foreach($temp_v as $item_k => $item){ + $this->set($k, $item['key'], [ + 'config' => $item['config'] ?? [], + 'status' => $item['status'] ?? 0, + 'sort' => $item['sort'] ?? 0, + ]); + } + } + return true; + } + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/pay/PayService.php b/niucloud/app/service/admin/pay/PayService.php new file mode 100644 index 0000000..4cdde91 --- /dev/null +++ b/niucloud/app/service/admin/pay/PayService.php @@ -0,0 +1,84 @@ +model = new Pay(); + } + + /** + * 待审核支付记录 + * @param array $where + * @return mixed + */ + public function getAuditPage(array $where){ + $field = 'id, out_trade_no, type, money, body, voucher, create_time, trade_id, trade_type, status'; + $search_model = $this->model->where([ [ 'site_id', '=', $this->site_id ], ['type', '=', PayDict::OFFLINEPAY] ])->withSearch([ 'create_time', 'out_trade_no', 'status' ], $where)->field($field)->append([ 'type_name' ])->order('create_time desc'); + return $this->pageQuery($search_model); + } + + /** + * 获取交易详情 + * @param int $id + * @return void + */ + public function getDetail(int $id){ + $field = 'id,out_trade_no,trade_type,trade_id,trade_no,body,money,voucher,status,create_time,pay_time,cancel_time,type,channel,fail_reason'; + return $this->model->where([ [ 'site_id', '=', $this->site_id ], ['id', '=', $id ] ]) + ->field($field) + ->append([ 'type_name', 'channel_name', 'status_name' ]) + ->findOrEmpty() + ->toArray(); + } + + /** + * 支付审核通过 + * @param string $out_trade_no + * @return null + */ + public function pass(string $out_trade_no) { + return (new CoreOfflineService())->pass($this->site_id, $out_trade_no); + } + + /** + * 支付审核未通过 + * @param string $out_trade_no + * @param string $reason + */ + public function refuse(string $out_trade_no, string $reason) { + return (new CoreOfflineService())->refuse($this->site_id, $out_trade_no, $reason); + } + + /** + * 统计支付数据 + * @param $where + * @return int + * @throws \think\db\exception\DbException + */ + public function payCount($where) + { + return $this->model->where($where)->count(); + } +} diff --git a/niucloud/app/service/admin/pay/RefundService.php b/niucloud/app/service/admin/pay/RefundService.php new file mode 100644 index 0000000..27dc52f --- /dev/null +++ b/niucloud/app/service/admin/pay/RefundService.php @@ -0,0 +1,67 @@ +model = new Refund(); + } + + /** + * 退款账户记录 + * @param array $where + * @return mixed + */ + public function getPage(array $where){ + $field = 'id,refund_no,out_trade_no,type,channel,money,reason,status,create_time,refund_time,close_time,fail_reason,voucher,trade_type,trade_id,refund_type,main_type,main_id'; + $search_model = $this->model->where([ [ 'site_id', '=', $this->site_id ] ])->withSearch([ 'create_time', 'out_trade_no', 'refund_no', 'status' ], $where)->field($field)->append([ 'type_name', 'status_name' ])->order('create_time desc'); + return $this->pageQuery($search_model); + } + + /** + * 获取退款详情 + * @param string $refund_no + * @return array + */ + public function getDetail(string $refund_no){ + $field = 'id,refund_no,out_trade_no,type,channel,money,reason,status,create_time,refund_time,close_time,fail_reason,voucher,trade_type,trade_id,refund_type,main_type,main_id'; + return $this->model->where([ ['refund_no', '=', $refund_no ], [ 'site_id', '=', $this->site_id ] ]) + ->field($field) + ->append([ 'type_name', 'status_name', 'refund_type_name' ]) + ->findOrEmpty() + ->toArray(); + } + + /** + * 支付审核通过 + * @param array $data + * @return bool + */ + public function refund(array $data) { + return (new CoreRefundService())->refund($this->site_id, $data['refund_no'], $data['voucher'], $data['refund_type'], PayDict::USER, $this->uid); + } + +} diff --git a/niucloud/app/service/admin/schedule/ScheduleService.php b/niucloud/app/service/admin/schedule/ScheduleService.php new file mode 100644 index 0000000..de3734f --- /dev/null +++ b/niucloud/app/service/admin/schedule/ScheduleService.php @@ -0,0 +1,105 @@ +getPage($data); + } + + /** + * 获取信息 + * @param int $id + * @return array + */ + public function getInfo(int $id){ + return (new CoreScheduleService())->getInfo($id); + } + /** + * 启用或关闭 + * @param int $id + * @param $status + * @return true + */ + public function modifyStatus(int $id, $status) + { + return (new CoreScheduleService())->modifyStatus($id, $status); + } + + /** + * 添加 + * @param array $data + * @return true + */ + public function add(array $data) + { + $res = (new CoreScheduleService())->add($data); + return true; + + } + + /** + * 编辑 + * @param int $id + * @param array $data + * @return true + */ + public function edit(int $id, array $data) + { + (new CoreScheduleService())->edit($id, $data); + return true; + } + + /** + * 删除 + * @param int $id + * @return true + */ + public function del(int $id) + { + (new CoreScheduleService())->del($id); + return true; + } + + /** + * 计划任务模板 + * @return array|null + */ + public function getTemplateList(){ + return (new CoreScheduleService())->getTemplateList(); + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/site/SiteAccountLogService.php b/niucloud/app/service/admin/site/SiteAccountLogService.php new file mode 100644 index 0000000..56c1d38 --- /dev/null +++ b/niucloud/app/service/admin/site/SiteAccountLogService.php @@ -0,0 +1,71 @@ +model = new SiteAccountLog(); + } + + /** + * 获取账单列表 + * @param array $where + * @return array + * @throws DbException + */ + public function getPage(array $where = []) + { + + $field = 'id, site_id, type, money, trade_no, create_time'; + $search_model = $this->model->where([ [ 'site_id', '=', $this->site_id ] ])->withSearch([ 'create_time', 'type', 'trade_no' ], $where)->field($field)->append([ 'type_name', 'pay_info', 'money' ])->order('create_time desc'); + return $this->pageQuery($search_model); + } + + /** + * 获取账单详情 + * @param int $id + * @return array + */ + public function getInfo(int $id) + { + $field = 'id, site_id, type, money, trade_no, create_time'; + return $this->model->where([ [ 'site_id', '=', $this->site_id ], ['id', '=', $id]])->field($field)->append([ 'type_name', 'pay_info' ])->findOrEmpty()->toArray(); + + } + + /** + * 统计数据 + * @return array + */ + public function stat() + { + return [ + 'pay' => $this->model->where([[ 'site_id', '=', $this->site_id ], ['type', '=', 'pay']])->sum("money")*1, + 'refund' => $this->model->where([[ 'site_id', '=', $this->site_id ], ['type', '=', 'refund']])->sum("money")*-1, + 'transfer' => $this->model->where([[ 'site_id', '=', $this->site_id ], ['type', '=', 'transfer']])->sum("money")*-1, + ]; + } + +} diff --git a/niucloud/app/service/admin/site/SiteGroupService.php b/niucloud/app/service/admin/site/SiteGroupService.php new file mode 100644 index 0000000..dc5ab13 --- /dev/null +++ b/niucloud/app/service/admin/site/SiteGroupService.php @@ -0,0 +1,179 @@ +model = new SiteGroup(); + } + + /** + * 站点分组列表 + * @param array $where + * @return array + */ + public function getPage(array $where = []) + { + $field = 'group_id, group_name, group_desc, app, addon, create_time, update_time'; + $search_model = $this->model->withSearch(['keywords'],$where)->field($field)->append(['app_name', 'addon_name'])->order('create_time desc'); + $list = $this->pageQuery($search_model); + return $list; + } + + /** + * 获取所有分组 + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getAll() + { + $field = 'group_id, group_name, group_desc, create_time, update_time, app'; + return $this->model->field($field)->select()->toArray(); + } + + /** + * 分组详情 + * @param int $group_id + * @return array + */ + public function getInfo(int $group_id) + { + $field = 'group_id, group_name, group_desc, app, addon, create_time, update_time'; + return $this->model->where([['group_id', '=', $group_id]])->field($field)->findOrEmpty()->toArray(); + + } + + /** + * 添加站点分组 + * @param array $data + * @return mixed + */ + public function add(array $data) + { + //判断应用是否全部是有效的已安装应用 + $this->checkAddon(array_merge($data['app'], $data['addon'])); + $res = $this->model->create($data); + return $res->group_id; + } + + /** + * 修改站点分组 + * @param int $group_id + * @param array $data + * @return true + */ + public function edit(int $group_id, array $data){ + //判断应用是否全部是有效的已安装应用 + $this->checkAddon(array_merge($data['app'], $data['addon'])); + $this->model->update($data, [['group_id', '=', $group_id]]); + //删除缓存 + $cache_name = self::$cache_name . $group_id; + Cache::delete($cache_name); + + $site_list = (new Site())->field('site_id')->where([ ['group_id', '=', $group_id] ])->select()->toArray(); + if (!empty($site_list)) { + foreach ($site_list as $site) { + Cache::tag(CoreSiteService::$cache_tag_name . $site['site_id'])->clear(); + } + } + return true; + } + + public function checkAddon($group_roles){ + $install_addon_list = (new CoreAddonService())->getInstallAddonList(); + $install_addon_keys = array_column($install_addon_list, 'key'); + if(count(array_intersect($install_addon_keys, $group_roles)) != count($group_roles)) throw new AdminException('SITE_GROUP_APP_NOT_EXIST'); + return true; + } + /** + * 删除分组 + * @param int $group_id + * @return bool + * @throws DbException + */ + public function del(int $group_id) + { + $count = (new Site())->where([['group_id', '=', $group_id]])->count(); + if($count > 0) + { + throw new CommonException('SITE_GROUP_IS_EXIST'); + } + $res = $this->model->where([['group_id', '=', $group_id]])->delete(); + + $cache_name = self::$cache_name . $group_id; + Cache::delete($cache_name); + return $res; + } + + /** + * 通过站点分组获取站点包含的权限和应用 + * @param $group_id + * @return void + */ + public function getGroupAddon($group_id){ + $cache_name = self::$cache_name . $group_id; + return cache_remember( + $cache_name, + function () use ($group_id) { + $group = $this->model->findOrEmpty($group_id); + $addon = []; + if (!$group->isEmpty()) { + $addon = array_merge([ $group['app'] ], $group['addon']); + } + return $addon; + }, + [MenuService::$cache_tag_name,self::$cache_tag_name] + ); + } + + /** + * 创建所有权限的菜单 + */ + public function addAllMenuGroup() + { +// $menus = (new SysMenu())->where([['app_type', '=', 'site']])->column("menu_key"); + $data = [ + 'group_name' => "默认套餐", + 'group_desc' => '', + 'app' => '', + 'addon' => [] + ]; + return $this->add($data); + } +} diff --git a/niucloud/app/service/admin/site/SiteService.php b/niucloud/app/service/admin/site/SiteService.php new file mode 100644 index 0000000..e38a41b --- /dev/null +++ b/niucloud/app/service/admin/site/SiteService.php @@ -0,0 +1,318 @@ +model = new Site(); + } + + /** + * 获取站点列表 + * @param array $where + * @return array + * @throws DbException + */ + public function getPage(array $where = []) + { + + $field = 'site_id, site_name, front_end_name, front_end_logo, app_type, keywords, logo, icon, `desc`, status, latitude, longitude, province_id, city_id, + district_id, address, full_address, phone, business_hours, create_time, expire_time, group_id, app, addons'; + $condition = [ + [ 'app_type', '<>', 'admin' ] + ]; + $search_model = $this->model->where($condition)->withSearch([ 'create_time', 'expire_time', 'keywords', 'status', 'group_id', 'app' ], $where)->with(['groupName'])->field($field)->append([ 'status_name' ])->order('create_time desc'); + return $this->pageQuery($search_model, function ($item){ + $item['admin'] = (new SysUserRole())->where([ ['site_id', '=', $item['site_id'] ], ['is_admin', '=', 1] ]) + ->field('uid') + ->with(['userinfo']) + ->find()->toArray(); + }); + } + + /** + * 站点信息 + * @param int $site_id + * @return array + */ + public function getInfo(int $site_id) + { + $field = 'site_id, site_name, front_end_name, front_end_logo, app_type, keywords, logo, icon, `desc`, status, latitude, longitude, province_id, city_id, + district_id, address, full_address, phone, business_hours, create_time, expire_time, group_id, app, addons'; + $info = $this->model->where([ [ 'site_id', '=', $site_id ] ])->with([ 'groupName' ])->field($field)->append([ 'status_name' ])->findOrEmpty()->toArray(); + if (!empty($info)) { + $site_addons = (new CoreSiteService())->getAddonKeysBySiteId($site_id); + $info['site_addons'] = (new Addon())->where([ ['key', 'in', $site_addons]])->field('key,title,desc,icon,type')->select()->toArray(); + } + return $info; + } + + /** + * 添加站点(平台端添加站点,同时添加用户以及密码) + * @param array $data + * ['site_name' => '', 'username' => '', 'head_img' => '', 'real_name' => '', 'password' => ''] + * @return mixed + * @throws DbException + */ + public function add(array $data) + { + $user_service = new UserService(); + if ($user_service->checkUsername($data[ 'username' ])) throw new AdminException('USERNAME_REPEAT'); + + $site_group = (new SiteGroup())->where([ ['group_id', '=', $data[ 'group_id' ] ] ])->field('app,addon')->findOrEmpty(); + + $data[ 'app_type' ] = 'site'; + //添加站点 + $data_site = [ + 'site_name' => $data[ 'site_name' ], + 'app_type' => $data[ 'app_type' ], + 'group_id' => $data[ 'group_id' ], + 'create_time' => time(), + 'expire_time' => $data[ 'expire_time' ], + 'app' => $site_group['app'], + 'addons' => '' + ]; + Db::startTrans(); + try { + $site = $this->model->create($data_site); + $site_id = $site->site_id; + + if ($data['uid']) { + (new UserRoleService())->add($data['uid'], ['role_ids' => '', 'is_admin' => 1], $site_id); + } else { + //添加用户 + $data_user = [ + 'username' => $data[ 'username' ], + 'head_img' => $data[ 'head_img' ] ?? '', + 'status' => $data[ 'status' ] ?? 1, + 'real_name' => $data[ 'real_name' ] ?? '', + 'password' => $data[ 'password' ], + 'role_ids' => '', + 'is_admin' => 1 + ]; + $data['uid'] = ( new UserService() )->addSiteUser($data_user, $site_id); + } + + //添加站点成功事件 + event("AddSiteAfter", [ 'site_id' => $site_id, 'main_app' => $site_group['app'], 'site_addons' => $site_group['addon'] ]); + + Cache::delete('user_role_list_' . $data['uid']); + + Db::commit(); + return $site_id; + } catch ( Exception $e) { + Db::rollback(); + throw new AdminException($e->getMessage().$e->getFile().$e->getLine()); + } + } + + /** + * 修改站点 + * @param int $site_id + * @param array $data + * @return bool + */ + public function edit(int $site_id, array $data) + { + //获取套餐类型 + if (isset($data[ 'group_id' ])) { + $site_group = (new SiteGroup())->where([ ['group_id', '=', $data[ 'group_id' ] ] ])->field('app,addon')->findOrEmpty(); + $data['app'] = $site_group['app']; + } + $this->model->update($data, [ [ 'site_id', '=', $site_id ] ]); + Cache::tag(self::$cache_tag_name . $site_id)->clear(); + return true; + } + + /** + * 删除站点 + * @param int $site_id + */ + public function del(int $site_id) { + Db::startTrans(); + try { + $site = $this->model->where([ [ 'site_id', '=', $site_id ] ])->findOrEmpty()->toArray(); + + // 删除站点相关数据 + $sys_models = (new GenerateService())->getModels(['addon' => 'system']); + $addon_models = []; + $addons = (new CoreSiteService())->getAddonKeysBySiteId($site_id); + foreach($addons as $addon) { + $addon_models[] = (new GenerateService())->getModels(['addon' => $addon ]); + } + $models = array_merge($sys_models, ...$addon_models); + + foreach ($models as $model) { + $name = "\\$model"; + $class = new $name(); + + if (in_array('site_id', $class->getTableFields())) { + $class->where([ ['site_id', '=', $site['site_id'] ] ])->delete(); + } + } + + Cache::tag(self::$cache_tag_name . $site_id)->clear(); + Db::commit(); + return true; + } catch (\Exception $e) { + Db::rollback(); + throw new CommonException($e->getMessage()); + } + } + + /** + * 站点数量 + * @return int + * @throws DbException + */ + public function getCount(array $where = []) + { + return $this->model->where($where)->withSearch([ 'create_time', 'group_id' ], $where)->count(); + } + + + /** + * 获取授权当前站点信息(用做缓存) + * @return mixed + */ + public function getSiteCache(int $site_id) + { + return (new CoreSiteService())->getSiteCache($site_id); + } + + + /** + * 通过站点id获取菜单列表 + * @param int $site_id + * @param $is_tree + * @param $status + * @param $addon 所以应用名一般不建议叫all + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getMenuList(int $site_id, $is_tree, $status, $addon = 'all', int $is_button = 1) + { + $site_info = $this->getSiteCache($site_id); + if (empty($site_info)) + return []; + $app_type = $site_info[ 'app_type' ]; + if ($app_type == AppTypeDict::ADMIN) { + return ( new MenuService() )->getAllMenuList($app_type, $status, $is_tree, $is_button); + } else { + $addons = ( new AddonService() )->getAddonKeysBySiteId($site_id); + $addons[] = ''; + if($addon != 'all'){ + $addons = [$addon]; + } + return ( new MenuService() )->getMenuListBySystem($this->app_type, $addons, $is_tree, $is_button); + } + + + } + + /** + * 通过站点id获取站点菜单极限 + * @param int $site_id + * @param $status + * @return array|mixed|string|null + */ + public function getMenuIdsBySiteId(int $site_id, $status) + { + $site_info = $this->getSiteCache($site_id); + if (empty($site_info)) + return []; + $app_type = $site_info[ 'app_type' ]; + if ($app_type == AppTypeDict::ADMIN) { + return ( new MenuService() )->getAllMenuIdsByAppType($app_type, $status); + } else { + + $addons = ( new AddonService() )->getAddonKeysBySiteId($site_id); + return ( new MenuService() )->getMenuKeysBySystem($app_type, $addons); + + } + } + + /** + * 通过站点id获取菜单列表 + * @param int $site_id + * @param $status + * @return mixed + */ + public function getApiList(int $site_id, $status) + { + $site_info = $this->getSiteCache($site_id); + if (empty($site_info)) + return []; + $app_type = $site_info[ 'app_type' ]; + if ($app_type == AppTypeDict::ADMIN) { + return ( new MenuService() )->getAllApiList($app_type, $status); + } else { + $addons = ( new AddonService() )->getAddonKeysBySiteId($site_id); + return ( new MenuService() )->getApiListBySystem($app_type, $addons); + } + } + + /** + * 站点过期时间 + * @param int $site_id + * @return array + */ + public function getExpireTime(int $site_id) + { + $field = 'expire_time'; + return $this->model->where([ [ 'site_id', '=', $site_id ] ])->field($field)->findOrEmpty()->toArray(); + + } + + /** + * 获取站点的插件 + * @return array + */ + public function getSiteAddons(array $where) { + $site_addon = (new CoreSiteService())->getAddonKeysBySiteId($this->site_id); + return (new Addon())->where([['type', '=', AddonDict::ADDON], ['status', '=', AddonDict::ON], ['key', 'in', $site_addon ]])->withSearch(['title'], $where)->append(['status_name'])->field('title, icon, key, desc, status, type, support_app')->select()->toArray(); + } +} diff --git a/niucloud/app/service/admin/site/SiteUserService.php b/niucloud/app/service/admin/site/SiteUserService.php new file mode 100644 index 0000000..c84a502 --- /dev/null +++ b/niucloud/app/service/admin/site/SiteUserService.php @@ -0,0 +1,166 @@ +model = new SysUser(); + } + + /** + * 管理端获取用户列表(对应站点用户列表) + * @param array $where + * @return array + */ + public function getPage(array $where) + { + $site_id = $this->site_id; + $field = 'id,SysUserRole.uid,site_id,role_ids,SysUserRole.create_time,is_admin,SysUserRole.status,count(site_id) as site_num'; + $order = 'SysUserRole.create_time desc'; + $search_model = (new SysUserRole()) + ->field($field) + ->order($order) + ->with('userinfo') + ->hasWhere('userinfo', function ($query) use ($where, $site_id) { + $condition = [ + ['SysUserRole.site_id', '>', 0 ] + ]; + if (!empty($where['username'])) $condition[] = ['username', 'like', "%{$where['username']}%"]; + if (!empty($where['realname'])) $condition[] = ['realname', 'like', "%{$where['realname']}%"]; + + //最后登录时间 + if (!empty($where['last_time'])) { + $start_time = empty($where['last_time'][0]) ? 0 : strtotime($where['last_time'][0]); + $end_time = empty($where['last_time'][1]) ? 0 : strtotime($where['last_time'][1]); + if ($start_time > 0 && $end_time > 0) { + $condition[] = ['last_time', 'between', [$start_time, $end_time]]; + } else if ($start_time > 0 && $end_time == 0) { + $condition[] = ['last_time', '>=', $start_time]; + } else if ($start_time == 0 && $end_time > 0) { + $condition[] = ['last_time', '<=', $end_time]; + } + } + $query->where($condition); + }) + ->group('SysUserRole.uid') + ->append(['status_name']); + + return $this->pageQuery($search_model); + } + + /** + * 用户详情(站点用户详情) + * @param int $uid + * @return array + */ + public function getInfo(int $uid) + { + $field = 'uid, username, head_img, real_name, last_ip, last_time, create_time, login_count, delete_time, update_time'; + $info = $this->model->where([ ['uid', '=', $uid] ])->field($field)->with(['roles' => function($query) { + $query->field('uid, site_id, is_admin')->with('siteInfo'); + }])->findOrEmpty()->toArray(); + if (!empty($info)) { + $info['roles'] = array_values(array_filter(array_map(function ($item) { + if ($item['site_id']) return $item; + }, $info['roles']))); + } + return $info; + } + + /** + * 添加当前站点用户 + * @param array $data + * @return bool + */ + public function add(array $data) + { + return (new UserService())->addSiteUser($data, $this->site_id); + } + + /** + * 编辑站点用户 + * @param int $uid + * @param array $data + * @return true + */ + public function edit(int $uid, array $data) + { + return (new UserService())->editSiteUser($uid, $data, $this->site_id); + } + + /** + * 修改字段 + * @param int $uid + * @param string $field + * @param $data + * @return bool|true + */ + public function modify(int $uid, string $field, $data) + { + $field_name = match ($field) { + 'password' => 'password', + 'real_name' => 'real_name', + 'head_img' => 'head_img', + }; + return (new UserService())->edit($uid, [$field_name => $data]); + } + + /** + * 删除 + * @param int $uid + * @return true + */ + public function del(int $uid) + { + $where = [ + ['uid', '=', $uid], + ['site_id', '=', $this->site_id] + ]; + SysUserRole::where($where)->delete(); + return true; + } + + /** + * 锁定 + * @param int $uid + * @return bool|true + */ + public function lock(int $uid){ + return (new UserService())->statusChange($uid, UserDict::OFF); + } + + /** + * 解锁 + * @param int $uid + * @return bool|true + */ + public function unlock(int $uid){ + return (new UserService())->statusChange($uid, UserDict::ON); + } +} diff --git a/niucloud/app/service/admin/site/UserLogService.php b/niucloud/app/service/admin/site/UserLogService.php new file mode 100644 index 0000000..2163c95 --- /dev/null +++ b/niucloud/app/service/admin/site/UserLogService.php @@ -0,0 +1,71 @@ +model = new SysUserLog(); + } + + /** + * 获取用户日志 + * @param array $where + * @return array + */ + public function getPage(array $where) + { + $field = 'id, ip, site_id, uid, username, url, params, type, create_time'; + $order = 'create_time desc'; + $search_model = $this->model->where([['site_id', '=', $this->site_id]])->withSearch(['username', 'create_time', 'uid', 'ip', 'type', 'url'], $where)->field($field)->order($order); + return $this->pageQuery($search_model); + } + + /** + * 日志详情 + * @param int $id + * @return array + */ + public function getInfo(int $id){ + $where = array( + ['id', '=', $id], + ['site_id', '=', $this->site_id] + ); + $field = 'id, ip, site_id, uid, username, url, params, type, create_time'; + return $this->model->where($where)->field($field)->findOrEmpty()->toArray(); + } + + /** + * 添加用户(添加用户,不添加站点) + * @param array $data + * @return bool + * @throws Exception + */ + public function add(array $data){ + $data['site_id'] = $this->site_id; + $res = $this->model->create($data); + return $res->id; + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/stat/SiteStatService.php b/niucloud/app/service/admin/stat/SiteStatService.php new file mode 100644 index 0000000..2cd7225 --- /dev/null +++ b/niucloud/app/service/admin/stat/SiteStatService.php @@ -0,0 +1,89 @@ + '', + + ]; + $data['site_info'] = (new SiteService())->getInfo($this->site_id); + $site_create_time = strtotime($data['site_info']['create_time']); + $site_expire_time = strtotime($data['site_info']['expire_time']); + $data['site_info']['mix'] = (number_format((time() - $site_create_time) / ($site_expire_time - $site_create_time), 2) * 100).'%'; + $data['site_info']['over_date'] = $site_expire_time - time() > 0 ? number_format(($site_expire_time - time())/ 86400, 2) : 0; + + return $data; + } + + /** + * 订单金额 + * @param $start_time + * @param $end_time + * @return float + */ + public function orderMoney($start_time, $end_time) + { + $where[] = [ + ['site_id', '=', $this->site_id], + ['order_status', '>', 0], + ['create_time', 'between', [$start_time, $end_time]] + ]; + return (new RechargeOrder())->where($where)->sum('order_money'); + } + + /** + * 订单数量 + * @param $start_time + * @param $end_time + * @return int + * @throws DbException + */ + public function orderCount($start_time, $end_time) + { + $where[] = [ + ['site_id', '=', $this->site_id], + ['order_status', '>', 0], + ['create_time', 'between', [$start_time, $end_time]] + ]; + return (new RechargeOrder())->where($where)->count('order_id'); + } + + + + + + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/stat/StatService.php b/niucloud/app/service/admin/stat/StatService.php new file mode 100644 index 0000000..2316b59 --- /dev/null +++ b/niucloud/app/service/admin/stat/StatService.php @@ -0,0 +1,131 @@ + [ + 'member_count' => 1, + 'site_count' => 2, + 'visit_count' => 675, + 'total_member_count' => 0, + 'total_site_count' => 0, + 'total_visit_count' => 6840, + ], + 'system' => [], + 'version' => [], +// 'visit_stat' => [ +// 'date' => [], +// 'value' => [980, 1323, 882, 762, 865, 923, 1105] +// ], + 'site_stat' => [ + 'date' => [], + 'value' => [] + ], + 'member_stat' => [ + 'type' => ['男', '女', '未知'], + 'value' => [] + ], + 'site_group_stat' => [ + 'type' => [], + 'value' => [] + ], + 'about' => [ + [ + 'name' => 'Niucloud官方公众号', + 'image' => 'static/resource/icon/index_icon/wx_qrcode.jpg', + 'desc' => '微信扫码关注' + ], + [ + 'name' => '添加企业微信群', + 'image' => 'static/resource/icon/index_icon/wework_qrcode.png', + 'desc' => '更多内容请扫码加入' + ] + ] + ]; + + $day_start_time = strtotime(date('Y-m-d')); + //当天结束之间 + $day_end_time = $day_start_time + 86400; + $data['today_data']['total_member_count'] = (new CoreMemberService())->getCount(); + $data['today_data']['today_member_count'] = (new CoreMemberService())->getCount(['create_time' => get_start_and_end_time_by_day()]); + $data['today_data']['total_site_count'] = (new SiteService())->getCount(); + $data['today_data']['today_site_count'] = (new SiteService())->getCount(['create_time' => [$day_start_time, $day_end_time]]); + $data['today_data']['norma_site_count'] = (new SiteService())->getCount(['status' => [1],'app_type' => ['site']]); + $data['today_data']['expire_site_count'] = (new SiteService())->getCount(['status' => [2]]); + + $data['system'] = (new SystemService())->getInfo(); + $data['version'] = $data['system']['version'] ?? []; + $time = time(); + for ($i = 1; $i <= 7; $i++){ + $item_day = date('Y-m-d', strtotime('+' . $i - 7 . ' days', $time)); + $data['site_stat']['date'][] = $item_day; + $data['site_stat']['value'][] = (new Site())->where([['create_time','between',get_start_and_end_time_by_day($item_day)]])->count(); + } + $man_count = (new CoreMemberService())->getCount(['sex' => '1']); + $woman_count = (new CoreMemberService())->getCount(['sex' => '2']); + $data['member_stat']['value'] = [$man_count, $woman_count, (int)($data['today_data']['total_member_count'] - $man_count - $woman_count)]; + + $site_group_list = (new SiteGroupService())->getAll([]); + + if(!empty($site_group_list)){ + foreach($site_group_list as $v){ + $data['site_group_stat']['type'][] = $v['group_name']; + $data['site_group_stat']['value'][] = (new SiteService())->getCount(['group_id' => $v['group_id']]); + } + } + $app_count = (new CoreAddonService())->getLocalAddonCount(); + $app_installed_count = (new CoreAddonService())->getCount(); + $app = [ + 'app_count' => $app_count, + 'app_no_installed_count' => $app_count-$app_installed_count, + 'app_installed_count' => $app_installed_count, + ]; + $data['app'] = $app; + return $data; + } + + +} diff --git a/niucloud/app/service/admin/sys/AgreementService.php b/niucloud/app/service/admin/sys/AgreementService.php new file mode 100644 index 0000000..8442a5e --- /dev/null +++ b/niucloud/app/service/admin/sys/AgreementService.php @@ -0,0 +1,63 @@ + $v) + { + $list[$k] = $this->getAgreement($k); + $list[$k]['type_name'] = $v; + } + return $list; + } + /** + * 获取协议内容 + * @param string $key + * @return array + */ + public function getAgreement(string $key) + { + return (new CoreAgreementService())->getAgreement($this->site_id, $key); + } + + /** + * 设置协议 + * @param string $key + * @param string $title + * @param string $content + * @return bool + */ + public function setAgreement(string $key, string $title, string $content) + { + return (new CoreAgreementService())->setAgreement($this->site_id, $key, $title, $content); + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/sys/AppService.php b/niucloud/app/service/admin/sys/AppService.php new file mode 100644 index 0000000..81b89b2 --- /dev/null +++ b/niucloud/app/service/admin/sys/AppService.php @@ -0,0 +1,73 @@ + $category) + { + $category_list[$k_category]['sort'] = $category['sort'] ?? 100; + $category_list[$k_category]['app_list'] = []; + foreach ($list as $app) + { + $app_category = $app['category'] ?? "basic"; + + if($app_category == $category['key']) + { + $category_list[$k_category]['app_list'][] = $app; + } + + } + } + + $sort = array_column($category_list, 'sort'); + array_multisort($category_list, $sort); + + return $category_list; + } + + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/sys/AreaService.php b/niucloud/app/service/admin/sys/AreaService.php new file mode 100644 index 0000000..6ea60b5 --- /dev/null +++ b/niucloud/app/service/admin/sys/AreaService.php @@ -0,0 +1,169 @@ +model = new SysArea(); + } + + /** + * 获取地区信息 + * @param int $pid //上级pid + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getListByPid(int $pid = 0) + { + + $cache_name = self::$cache_tag_name.'_pid_'.$pid; + return cache_remember( + $cache_name, + function() use($pid) { + return $this->model->where([['pid', '=', $pid]])->field('id, pid, name, shortname, longitude, latitude, level, sort, status')->select()->toArray(); + }, + [self::$cache_tag_name] + ); + } + + /** + * 查询地区树列表 + * @param int $level //层级1,2,3 + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getAreaTree(int $level = 3) + { + $cache_name = self::$cache_tag_name.'_tree_'.$level; + return cache_remember( + $cache_name, + function() use($level) { + $list = $this->model->where([['level', '<=', $level]])->field('id, pid, name, shortname, longitude, latitude, level, sort, status')->select()->toArray(); + return list_to_tree($list); + }, + [self::$cache_tag_name] + ); + } + + public function getAreaByAreaCode($id) { + $cache_name = self::$cache_tag_name.'_area_'. $id; + return cache_remember( + $cache_name, + function() use($id) { + $level = [1 => 'province', 2 => 'city', 3 => 'district']; + $tree = []; + $area = $this->model->where([ ['id', '=', $id] ])->field('id,level,pid,name')->findOrEmpty(); + + if (!$area->isEmpty()) { + $tree[ $level[ $area['level'] ] ] = $area->toArray(); + + while ($area['level'] > 1) { + $area = $this->model->where([ ['id', '=', $area['pid'] ] ])->field('id,level,pid,name')->findOrEmpty(); + $tree[ $level[ $area['level'] ] ] = $area->toArray(); + } + } + return $tree; + }, + [self::$cache_tag_name] + ); + } + + /** + * @param string $address + * @return int|mixed + * 地址解析 + */ + public function getAddress(string $address){ + $map = (new ConfigService())->getMap(); + $url = "https://apis.map.qq.com/ws/geocoder/v1/?address=".$address."&key=".$map['key']; + $curl = curl_init(); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_TIMEOUT, 1); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); + + $res = curl_exec($curl); + $res = json_decode($res, true); + if($res){ + curl_close($curl); + return $res; + }else { + $error = curl_errno($curl); + curl_close($curl); + return $error; + } + } + + /** + * @param string $location + * @return int|mixed + * 逆地址解析 + */ + public function getAddressInfo(string $location){ + $map = (new ConfigService())->getMap(); + $url = "https://apis.map.qq.com/ws/geocoder/v1/?location=".$location."&key=".$map['key']; + $curl = curl_init(); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_TIMEOUT, 1); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); + + $res = curl_exec($curl); + $res = json_decode($res, true); + if($res){ + curl_close($curl); + return $res; + }else { + $error = curl_errno($curl); + curl_close($curl); + return $error; + } + } + + public function getAreaId($name, $level){ + $field = 'id'; + $info = $this->model->field($field)->where([['name', 'like', '%' . $name . '%' ], ['level', '=', $level]])->findOrEmpty()->toArray(); + return $info['id']; + } + + /** + * 获取地址名称 + */ + public function getAreaName($id){ + $info = $this->model->field("name")->where([['id', '=', $id ]])->findOrEmpty()->toArray(); + return $info['name']; + } + +} diff --git a/niucloud/app/service/admin/sys/AttachmentService.php b/niucloud/app/service/admin/sys/AttachmentService.php new file mode 100644 index 0000000..ac71b7b --- /dev/null +++ b/niucloud/app/service/admin/sys/AttachmentService.php @@ -0,0 +1,325 @@ +model = new SysAttachment(); + $this->core_attachment_service = new CoreAttachmentService(); + } + + /** + * 新增素材 + * @param array $data + */ + public function add(array $data) + { + $data[ 'site_id' ] = $this->site_id; + return $this->core_attachment_service->add($data); + } + + /** + * + * /** + * 编辑素材 + * @param int $att_id + * @param array $data + * @return SysAttachment + */ + public function edit(int $att_id, array $data) + { + return $this->core_attachment_service->edit($this->site_id, $att_id, $data); + } + + /** + * 修改附件分组 + * @param $att_id + * @param $cate_id + * @return bool + */ + public function modifyCategory($att_id, $cate_id) + { + $where = array ( + [ 'att_id', '=', $att_id ], + [ 'site_id', '=', $this->site_id ], + ); + $this->model->where($where)->update([ 'cate_id' => $cate_id, 'update_time' => time() ]); + return true; + } + + /** + * 批量更新附件分组 + * @param $att_ids + * @param $cate_id + * @return bool + */ + public function batchModifyCategory($att_ids, $cate_id) + { + + $where = array ( + [ 'att_id', 'in', is_string($att_ids) ? explode($att_ids) : $att_ids ], + [ 'site_id', '=', $this->site_id ], + ); + $this->model->where($where)->update([ 'cate_id' => $cate_id, 'update_time' => time() ]); + return true; + } + + /** + * 删除素材 + * @param int $att_id + * @return mixed + */ + public function del(int $att_id) + { + return $this->core_attachment_service->del($this->site_id, $att_id); + } + + /** + * 批量删除 + * @param $data + * @return true|null + */ + public function delAll($data) + { + return $this->core_attachment_service->delAll($this->site_id, $data); + } + + /** + * 管理端获取附件列表 + * @param array $data + * @return array + */ + public function getPage(array $data) + { + $where = array ( + [ 'site_id', '=', $this->site_id ] + ); + if (!empty($data[ 'att_type' ])) { + $where[] = [ 'att_type', '=', $data[ 'att_type' ] ]; + } + if (!empty($data[ 'cate_id' ])) { + $where[] = [ 'cate_id', '=', $data[ 'cate_id' ] ]; + } + if (!empty($data[ 'real_name' ])) { + $where[] = [ 'real_name', 'like', '%' . $data[ 'real_name' ] . '%' ]; + } + return $this->getPageList($this->model, $where, 'att_id,path,real_name,att_type,url', 'att_id desc', each:function($item, $key) + { + $item[ 'thumb' ] = get_thumb_images($this->site_id, $item[ 'url' ], FileDict::SMALL); + }); + } + + /** + * 新增素材组 + * @param array $data + * @return mixed + */ + public function addCategory(array $data) + { + $data[ 'site_id' ] = $this->site_id; + $category_model = new SysAttachmentCategory(); + $attachment = $category_model->create($data); + if (!$attachment->id) + throw new AdminException('ADD_FAIL');//创建失败 + return $attachment->att_id; + } + + /** + * 素材组模型对象 + * @param int $site_id + * @param int $id + * @return mixed + */ + public function findCategory(int $site_id, int $id) + { + $where = array ( + [ 'site_id', '=', $site_id ], + [ 'id', '=', $id ] + ); + $category_model = new SysAttachmentCategory(); + $category = $category_model->where($where)->findOrEmpty(); + if ($category->isEmpty()) + throw new AdminException('ATTACHMENT_GROUP_NOT_EXIST'); + return $category; + } + + /** + * 编辑素材组 + * @param int $id + * @param array $data + * @return SysAttachmentCategory + */ + public function editCategory(int $id, array $data) + { + $where = array ( + [ 'site_id', '=', $this->site_id ], + [ 'id', '=', $id ] + ); + $category_model = new SysAttachmentCategory(); + return $category_model->where($where)->update($data); + } + + /** + * 删除素材组 + * @param int $id + * @return mixed + * @throws DbException + */ + public function delCategory(int $id) + { + //查询是否有下级菜单或按钮 + $category = $this->findCategory($this->site_id, $id); + if ($this->model->where([ [ 'cate_id', '=', $id ] ])->count() > 0) + throw new AdminException('ATTACHMENT_GROUP_HAS_IMAGE'); + + //下级存在图片不能删除 + return $category->delete(); + + } + + /** + * 管理端获取附件组列表 + * @param array $data + * @return array + * @throws DbException + */ + public function getCategoryPage(array $data) + { + $where = array ( + [ 'site_id', '=', $this->site_id ] + ); + if (!empty($data[ 'type' ])) { + $where[] = [ 'type', '=', $data[ 'type' ] ]; + } + if (!empty($data[ 'name' ])) { + $where[] = [ 'name', 'like', '%' . $data[ 'name' ] . '%' ]; + } + return $this->getPageList(( new SysAttachmentCategory() ), $where, 'id,name', 'id desc'); + } + + /** + * 获取分组列表 + * @param array $data + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getCategoryList(array $data) + { + $where = array ( + [ 'site_id', '=', $this->site_id ] + ); + if (!empty($data[ 'type' ])) { + $where[] = [ 'type', '=', $data[ 'type' ] ]; + } + if (!empty($data[ 'name' ])) { + $where[] = [ 'name', 'like', '%' . $data[ 'name' ] . '%' ]; + } + return SysAttachmentCategory::where($where)->field('id,name,type')->order('id desc')->select()->toArray(); + } + + /** + * 获取图标库分类列表 + * @param array $data + * @return array|null + */ + public function getIconCategoryList(array $data) + { + $icon_list = IconDict::getIcon(); + foreach ($icon_list as $k => $v) { + unset($icon_list[ $k ][ 'glyphs' ]); + if (!empty($data[ 'name' ]) && !str_contains($v['name'], $data['name'])) { + unset($icon_list[ $k ]); + } + } + return array_values($icon_list); + } + + /** + * 获取图标库列表 + * @param array $data + * @return array|null + */ + public function getIconList(array $data) + { + $icon_list = IconDict::getIcon(); + + $res = [ + 'current_page' => intval($data[ 'page' ]), + 'per_page' => intval($data[ 'limit' ]), + 'data' => [], + 'total' => 0 + ]; + + $temp_data = []; + + foreach ($icon_list as $v) { + + $icon = $v[ 'glyphs' ]; // 图标列表 + + foreach ($icon as $ck => $cv) { + // 素材表中数据保持要一致 + $icon[ $ck ][ 'att_id' ] = $cv[ 'icon_id' ]; + $icon[ $ck ][ 'url' ] = $v[ 'font_family' ] . '-' . $v[ 'css_prefix_text' ] . $cv[ 'font_class' ]; + $icon[ $ck ][ 'real_name' ] = $cv[ 'name' ]; + + // 查询名称 + if (!empty($data[ 'real_name' ]) && !str_contains($cv['name'], $data['real_name'])) { + unset($icon[ $ck ]); + } + } + + $icon = array_values($icon); + + if (!empty($data[ 'cate_id' ]) && $data[ 'cate_id' ] == $v[ 'id' ]) { + // 查询指定分类下的图标 + $temp_data = $icon; + break; + } else { + // 查询全部图标 + $temp_data = array_merge($temp_data, $icon); + } + } + + // 手动分页 + $res[ 'total' ] = count($temp_data); // 总数量 + $start = ( $res[ 'current_page' ] - 1 ) * $res[ 'per_page' ]; // 数组下标从0 开始 + $icon_list = array_slice($temp_data, $start, $res[ 'per_page' ]); + + $res[ 'data' ] = $icon_list; + + return $res; + } + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/sys/ConfigService.php b/niucloud/app/service/admin/sys/ConfigService.php new file mode 100644 index 0000000..662ca26 --- /dev/null +++ b/niucloud/app/service/admin/sys/ConfigService.php @@ -0,0 +1,390 @@ +core_config_service = new CoreConfigService(); + } + + /** + * 获取版权信息(网站整体,不按照站点设置) + * @return array|mixed + */ + public function getCopyright() + { + return (new CoreSysConfigService())->getCopyright($this->site_id); + } + + /** + * 设置版权信息(整体设置,不按照站点) + * @param array $value + * @return bool + */ + public function setCopyright(array $value) + { + $data = [ + 'icp' => $value['icp'], + 'gov_record' => $value['gov_record'], + 'gov_url' => $value['gov_url'], + 'market_supervision_url' => $value['market_supervision_url'], + 'logo' => $value['logo'], + 'company_name' => $value['company_name'], + 'copyright_link' => $value['copyright_link'], + 'copyright_desc' => $value['copyright_desc'] + ]; + return $this->core_config_service->setConfig($this->site_id,'COPYRIGHT', $data); + } + + /** + * 获取网站信息 + * @return array + */ + public function getWebSite() + { + return (new SiteService())->getInfo($this->site_id); + + } + /** + * 设置网站信息 + * @return bool + */ + public function setWebSite($data) + { + + return (new SiteService())->edit($this->site_id, $data); + + } + /** + * 获取前端域名 + * @return array|string[] + */ + public function getSceneDomain(){ + return (new CoreSysConfigService())->getSceneDomain($this->site_id); + } + + /** + * 获取服务信息 + * @return array|mixed + */ + public function getService() + { + $info = (new CoreConfigService())->getConfig(0, 'SERVICE_INFO'); + if(empty($info)) + { + $info = []; + $info['value'] = [ + 'wechat_code' => '', + 'enterprise_wechat' => '', + 'tel' => '', + ]; + } + return $info['value']; + } + + /** + * 设置服务信息 + * @param array $value + * @return bool + */ + public function setService (array $value) + { + $data = [ + "wechat_code" => $value['wechat_code'], + "enterprise_wechat" => $value['enterprise_wechat'], + "tel" => $value['tel'] + ]; + return $this->core_config_service->setConfig(0,'SERVICE_INFO', $data); + } + + /** + * 设置地图key + * @param array $value + * @return bool + */ + public function setMap(array $value) + { + $data = [ + 'key' => $value['key'], + ]; + return $this->core_config_service->setConfig($this->site_id,'MAPKEY', $data); + } + + /** + * 获取地图key + */ + public function getMap() + { + $info = (new CoreConfigService())->getConfig($this->site_id, 'MAPKEY'); + if(empty($info)) + { + $info = []; + $info['value'] = [ + 'key' => 'IZQBZ-3UHEU-WTCVD-2464U-I5N4V-ZFFU3', + ]; + } + return $info['value']; + } + + /** + * 获取站点主页配置 + * @return mixed|string[] + */ + public function getSiteIndexConfig() + { + $config = (new CoreConfigService())->getConfig($this->site_id, "site_index"); + if(empty($config)) + { + $config['value'] = [ + 'view_path' => 'index/site_index' + ]; + }else{ + $result = event("SiteIndex"); + $index_list = []; + foreach ($result as $v) + { + $index_list = empty($index_list) ? $v: array_merge($index_list, $v); + } + $tag = 0; + $view_path = $config['value']['view_path']; + foreach ($index_list as $v) + { + $v_view_path = $v['view_path'] ?? ''; + if($view_path == $v_view_path) + { + $tag = 1; + break; + } + } + if($tag == 0) + { + $config['value'] = [ + 'view_path' => 'index/site_index' + ]; + } + + } + return $config['value']['view_path']; + } + + /** + * 站点主页配置 + * @param $data + * @return true + */ + public function setSiteIndexConfig($data) + { + $config = [ + 'view_path' => $data['view_path'] , + ]; + //检测是否路劲一个异常 + $index_list = $this->getSiteIndexList(); + $check_tag = 0; + foreach($index_list as $v) + { + if($v['view_path'] == $data['view_path']) + { + $check_tag = 1; + } + } + if($check_tag == 0) throw new AdminException('SITE_INDEX_VIEW_PATH_NOT_EXIST'); + (new CoreConfigService())->setConfig($this->site_id, "site_index", $config); + return true; + } + + /** + * 获取站点配置的首页列表 + * @return array + */ + public function getSiteIndexList() + { + $result = event("SiteIndex"); + $index_list = []; + foreach ($result as $v) + { + $index_list = empty($index_list) ? $v: array_merge($index_list, $v); + } + $view_path = $this->getSiteIndexConfig(); + foreach ($index_list as $k => $v) + { + $v_view_path = $v['view_path'] ?? ''; + $index_list[$k]['is_use'] = ($v_view_path == $view_path) ? 1: 0; + } + return $index_list; + } + + /** + * 设置站点快捷菜单 + * @param $data + * @return bool + */ + public function setShortcutMenu($data) + { + (new CoreConfigService())->setConfig($this->site_id, 'shortcut_menu', $data); + return true; + } + + /** + * 获取站点快捷菜单 + * @return array|mixed + */ + public function getShortcutMenu() + { + $config = (new CoreConfigService())->getConfig($this->site_id, 'shortcut_menu'); + $menu = $config['value'] ?? []; + if(!empty($menu)){ + $menu_service = new MenuService(); + foreach($menu as $k => &$v){ + $menu_key = $v['menu_key'] ?? ''; + if($menu_key != ''){ + $item_router_path = $menu_service->getFullRouterPath($menu_key); + if(empty($item_router_path)){ + unset($v[$k]); + }else{ + $v['router_path'] = $item_router_path; + } + } + } + } + return $menu; + } + /** + * 获取平台主页配置 + * @return mixed|string[] + */ + public function getAdminIndexConfig() + { + $config = (new CoreConfigService())->getConfig($this->site_id, "admin_index"); + if(empty($config)) + { + $config['value'] = [ + 'view_path' => 'index/index' + ]; + }else{ + $result = event("AdminIndex"); + $index_list = []; + foreach ($result as $v) + { + $index_list = empty($index_list) ? $v: array_merge($index_list, $v); + } + $tag = 0; + $view_path = $config['value']['view_path']; + foreach ($index_list as $v) + { + $v_view_path = $v['view_path'] ?? ''; + if($view_path == $v_view_path) + { + $tag = 1; + break; + } + } + if($tag == 0) + { + $config['value'] = [ + 'view_path' => 'index/index' + ]; + } + + } + return $config['value']['view_path']; + } + + /** + * 站点主页配置 + * @param $data + * @return true + */ + public function setAdminIndexConfig($data) + { + $config = [ + 'view_path' => $data['view_path'] , + ]; + //检测是否路劲一个异常 + $index_list = $this->getAdminIndexList(); + $check_tag = 0; + foreach($index_list as $v) + { + if($v['view_path'] == $data['view_path']) + { + $check_tag = 1; + } + } + if($check_tag == 0) throw new AdminException('ADMIN_INDEX_VIEW_PATH_NOT_EXIST'); + (new CoreConfigService())->setConfig($this->site_id, "admin_index", $config); + return true; + } + + /** + * 获取站点配置的首页列表 + * @return array + */ + public function getAdminIndexList() + { + $result = event("AdminIndex"); + $index_list = []; + foreach ($result as $v) + { + $index_list = empty($index_list) ? $v: array_merge($index_list, $v); + } + $view_path = $this->getAdminIndexConfig(); + foreach ($index_list as $k => $v) + { + $v_view_path = $v['view_path'] ?? ''; + $index_list[$k]['is_use'] = ($v_view_path == $view_path) ? 1: 0; + } + return $index_list; + } + + /** + * 获取手机端首页列表 + * @param $data + * @return array + */ + public function getWapIndexList($data) + { + return ( new CoreSysConfigService() )->getWapIndexList($data); + } + + /** + * 获取开发者key + * @return array + */ + public function getDeveloperToken() { + return (new CoreConfigService())->getConfigValue(0, "DEVELOPER_TOKEN"); + } + + /** + * 设置开发者key + * @param array $data + * @return array + */ + public function setDeveloperToken(array $data) { + return (new CoreConfigService())->setConfig(0, "DEVELOPER_TOKEN", $data); + } +} diff --git a/niucloud/app/service/admin/sys/MenuService.php b/niucloud/app/service/admin/sys/MenuService.php new file mode 100644 index 0000000..3bc19ff --- /dev/null +++ b/niucloud/app/service/admin/sys/MenuService.php @@ -0,0 +1,665 @@ +model = new SysMenu(); + } + + /** + * 新增菜单接口 + * @param array $data + * @return SysMenu|Model + */ + public function add(array $data) + { + $menu = $this->find($data['menu_key'], $data['app_type']); + if(!$menu->isEmpty()) throw new AdminException('validate_menu.exit_menu_key');//创建失败 + + $data['source'] = MenuDict::CREATE; + $res = $this->model->create($data); + if(!$res) throw new AdminException('ADD_FAIL');//创建失败 + + Cache::tag(self::$cache_tag_name)->clear(); + return $res; + } + + + /** + * 更新菜单 + * @param string $menu_key + * @param array $data + * @return SysMenu + */ + public function edit(string $app_type, string $menu_key, array $data) + { + $where = array( + ['app_type', '=', $app_type], + ['menu_key', '=', $menu_key] + ); + $res = $this->model->update($data, $where); + Cache::tag(self::$cache_tag_name)->clear(); + return $res; + } + + /** + * 获取信息 + * @param string $menu_key + * @return array + */ + public function get(string $app_type, string $menu_key){ + return $this->model->where([['app_type', '=', $app_type],['menu_key', '=', $menu_key]])->findOrEmpty()->toArray(); + } + + /** + * @param string $menu_key + * @param string $app_type + * @return SysMenu|array|mixed|Model + */ + public function find(string $menu_key, string $app_type = ''){ + $where = array( + ['menu_key', '=', $menu_key] + ); + if(!empty($app_type)){ + $where[] = ['app_type', '=', $app_type]; + } + $menu = $this->model->where($where)->findOrEmpty(); + return $menu; + } + + /** + * 菜单删除 + * @param string $menu_key + * @return bool + * @throws DbException + */ + public function del(string $app_type, string $menu_key){ + //查询是否有下级菜单或按钮 + $menu = $this->find($menu_key, $app_type); + if($this->model->where([['parent_key', '=', $menu_key], ['app_type', '=', $app_type]])->count() > 0) + throw new AdminException('MENU_NOT_ALLOW_DELETE'); + + $res = $menu->delete(); + Cache::tag(self::$cache_tag_name)->clear(); + return $res; + } + + /** + * 通过菜单menu_key获取 + * @param int $site_id + * @param array $menu_keys + * @param string $app_type + * @param int $is_tree + * @param $addon 用于检测插件筛选 + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getMenuListByMenuKeys(int $site_id, array $menu_keys, string $app_type, int $is_tree = 0, $addon = 'all') + { + sort($menu_keys); + $cache_name = 'menu' . md5(implode("_", $menu_keys)) . $is_tree.$addon.$site_id; + $menu_list = cache_remember( + $cache_name, + function () use ($site_id, $menu_keys, $app_type, $is_tree, $addon) { + $where = [ + ['menu_key', 'in', $menu_keys], + ]; + $addons = ( new AddonService() )->getAddonKeysBySiteId($site_id); + $addons[] = ''; + + $delete_menu_addon = []; + $addon_loader = new DictLoader("Menu"); + + if($addon != 'all'){ + $where[] = ['addon', '=', $addon]; + + $delete_menu = $addon_loader->load(["addon" => $addon, "app_type" => $app_type])['delete'] ?? []; + if (!empty($delete_menu) && is_array($delete_menu)) $delete_menu_addon[] = $delete_menu; + } else { + $where[] = ['addon', 'in', $addons]; + + foreach ($addons as $addon) { + $delete_menu = $addon_loader->load(["addon" => $addon, "app_type" => $app_type])['delete'] ?? []; + if (!empty($delete_menu) && is_array($delete_menu)) $delete_menu_addon[] = $delete_menu; + } + } + + // 排除插件中delete的菜单 + if (!empty($delete_menu_addon)) { + $delete_intersect = array_intersect(...$delete_menu_addon); + if (!empty($delete_intersect)) { + $where[] = ['menu_key', 'not in', $delete_intersect]; + } + } + if(!empty($app_type)){ + $where[] = ['app_type', '=', $app_type]; + } + return $this->model->where($where)->order('sort', 'desc')->select()->toArray(); + }, + self::$cache_tag_name + ); + foreach ($menu_list as &$v) + { + $lang_menu_key = "dict_menu_". $v['app_type']. '.'. $v['menu_key']; + $lang_menu_name = get_lang("dict_menu_". $v['app_type']. '.'. $v['menu_key']); + //语言已定义 + if($lang_menu_key != $lang_menu_name) + { + $v['menu_name'] = $lang_menu_name; + } + //首页加载 + if($v['menu_key'] == 'overview' && $v['app_type'] == 'site') + { + $view_path = (new ConfigService())->getSiteIndexConfig(); + $v['view_path'] = $view_path; + } + + if($v['menu_key'] == 'overview' && $v['app_type'] == 'admin') + { + $view_path = (new ConfigService())->getAdminIndexConfig(); + $v['view_path'] = $view_path; + } + + } + + return $is_tree ? $this->menuToTree($menu_list, 'menu_key', 'parent_key', 'children', 'auth', '', 1) : $menu_list; + + } + + /** + * 获取所有接口菜单 + */ + public function getAllMenuList($app_type = '', $status = 'all', $is_tree = 0, $is_button = 0) + { + $cache_name = 'menu_api_' .$app_type.'_'. $status . '_' . $is_tree . '_' . $is_button; + $menu_list = cache_remember( + $cache_name, + function () use ($status, $is_tree, $is_button, $app_type) { + $where = [ +// ['menu_type', 'in', [0,1]] + ['app_type', '=', $app_type], + ]; + if ($status != 'all') { + $where[] = ['status', '=', $status]; + } + return $this->model->where($where)->order('sort desc')->select()->toArray(); + }, + self::$cache_tag_name + ); + foreach ($menu_list as &$v) + { + $lang_menu_key = "dict_menu_". $v['app_type']. '.'. $v['menu_key']; + $lang_menu_name = get_lang("dict_menu_". $v['app_type']. '.'. $v['menu_key']); + //语言已定义 + if($lang_menu_key != $lang_menu_name) + { + $v['menu_name'] = $lang_menu_name; + } + //首页加载 + if($v['menu_key'] == 'overview' && $v['app_type'] == 'site') + { + $view_path = (new ConfigService())->getSiteIndexConfig(); + $v['view_path'] = $view_path; + } + + if($v['menu_key'] == 'overview' && $v['app_type'] == 'admin') + { + $view_path = (new ConfigService())->getAdminIndexConfig(); + $v['view_path'] = $view_path; + } + + } + + return $is_tree ? $this->menuToTree($menu_list, 'menu_key', 'parent_key', 'children', 'auth', '', $is_button) : $menu_list; + + } + + + /** + * 通过菜单menu_key组获取接口数组 + * @param array $menu_keys + * @param string $app_type + * @return mixed|string + */ + public function getApiListByMenuKeys(array $menu_keys, string $app_type = '') + { + sort($menu_keys); + $cache_name = 'api' . md5(implode("_", $menu_keys)); + return cache_remember( + $cache_name, + function () use ($menu_keys, $app_type) { + $where = [ + ['menu_key', 'in', $menu_keys] + ]; + if(!empty($app_type)){ + $where[] = ['app_type', '=', $app_type]; + } + $menu_list = (new SysMenu())->where($where)->order('sort', 'desc')->column('api_url,methods'); + foreach ($menu_list as $v) { + $auth_menu_list[$v['methods']][] = $v['api_url']; + } + return $auth_menu_list ?? []; + }, + self::$cache_tag_name + ); + } + + + /** + * 通过菜单menu_key组获取按钮数组 + * @param array $menu_keys + * @param string $app_type + * @return mixed + */ + public function getButtonListBuMenuKeys(array $menu_keys, string $app_type = '') + { + sort($menu_keys); + $cache_name = 'button' . md5(implode("_", $menu_keys)); + return cache_remember( + $cache_name, + function () use ($menu_keys, $app_type) { + $where = [ + ['menu_key', 'in', $menu_keys], + ['menu_type', '=', MenuTypeDict::BUTTON] + ]; + if(!empty($app_type)){ + $where[] = ['app_type', '=', $app_type]; + } + return $this->model->where($where)->order('sort', 'desc')->column('menu_key'); + }, + self::$cache_tag_name + ); + } + + /** + * 获取所有接口菜单权限 + * @param $app_type + * @param $status + * @return mixed + */ + public function getAllApiList($app_type = '', $status = 'all') + { + $cache_name = 'all_api' .$app_type.'_'. $status; + return cache_remember( + $cache_name, + function () use ($status, $app_type) { + $where = [ + ['api_url', '<>', ''], + ['app_type', '=', $app_type], + ]; + if ($status != 'all') { + $where[] = ['status', '=', $status]; + } + $menu_list = $this->model->where($where)->order('sort', 'desc')->column('methods, api_url'); + $auth_menu_list = []; + foreach ($menu_list as $v) { + $auth_menu_list[$v['methods']][] = $v['api_url']; + } + return $auth_menu_list; + }, + self::$cache_tag_name + ); + } + + /** + * 通过站点端口获取菜单id + * @param string $app_type + * @param $status + * @return mixed|string + */ + public function getAllMenuIdsByAppType(string $app_type, $status = 'all'){ + $cache_name = 'menu_id_by_app_type_' .$app_type; + return cache_remember( + $cache_name, + function () use ($app_type, $status) { + $where = [ +// + ['app_type', '=', $app_type], + ]; + if ($status != 'all') { + $where[] = ['status', '=', $status]; + } + return $this->model->where($where)->order('sort desc')->column('menu_key'); + }, + self::$cache_tag_name + ); + } + + + + /** + * 获取所有按钮菜单 + */ + public function getAllButtonList($app_type = '', $status = 'all', $is_tree = 0) + { + $cache_name = 'menu_api_' .$app_type.'_' . $status . '_' . $is_tree; + return cache_remember( + $cache_name, + function () use ($status, $is_tree, $app_type) { + $where = [ + ['menu_type', '=', MenuTypeDict::BUTTON], + ['app_type', '=', $app_type], + ]; + if ($status != 'all') { + $where[] = ['status', '=', $status]; + } + return $this->model->where($where)->order('sort', 'desc')->column('menu_key'); + }, + self::$cache_tag_name + ); + } + + /** + * 把返回的数据集转换成Tree(专属于) + * @param $list 要转换的数据集 + * @param string $pk + * @param string $pid + * @param string $child + * @param int $root + * @return array + */ + public function menuToTree($list, $pk = 'id', $pid = 'pid', $child = 'child', $button_name = 'auth', $root = '', $is_button = 0) + { + // 创建Tree + $tree = array(); + if (is_array($list)) { + // 创建基于主键的数组引用 + $refer = array(); + foreach ($list as $key => $data) { + $refer[$data[$pk]] =& $list[$key]; + } + foreach ($list as $key => $data) { + // 判断是否存在parent + $parent_id = $data[$pid]; + if ($root == $parent_id) { + $tree[] =& $list[$key]; + } else { + if (isset($refer[$parent_id])) { + $parent =& $refer[$parent_id]; + if ($list[$key]['menu_type'] == 2 && $is_button == 1) { + $parent[$button_name][] =& $list[$key]['menu_key']; + } else { + $parent[$child][] =& $list[$key]; + } + + } + } + } + } + return $tree; + + } + + /** + * 获取完整的路由地址 + * @param $menu_key + * @return string + */ + public function getFullRouterPath($menu_key){ + $menu = $this->model->where([['menu_key', '=', $menu_key]])->findOrEmpty($menu_key); + if($menu->isEmpty()) return ''; + $parents = []; + $this->getParentDirectory($menu, $parents); + $parents = array_reverse($parents); + $router_path = implode('/', $parents); + if(!empty($router_path)){ + $router_path .= '/'.$menu['router_path']; + }else{ + $router_path = $menu['router_path']; + } + return $router_path; + } + + /** + * 递归查询模板集合 + * @param SysMenu $menu + * @param $parents + * @return void + */ + public function getParentDirectory(SysMenu $menu, &$parents){ + if(!$menu->isEmpty() && !empty($menu['parent_key'])){ + $parent_menu = $this->model->where([['menu_key', '=', $menu['parent_key']]])->findOrEmpty(); + if(!empty($parent_menu)){ + if(!empty($parent_menu['router_path'])) $parents[] = $parent_menu['router_path']; + $this->getParentDirectory($parent_menu, $parents); + } + } + + } + + /** + * 获取系统菜单(站点权限api极限) + * @param string $app_type + * @param string $addons + * @return mixed|string + */ + public function getApiListBySystem(string $app_type = '', array $addons = []) + { + sort($addons); + $cache_name = 'system_menu_api_' . $app_type.implode("_", $addons); + return cache_remember( + $cache_name, + function () use ($app_type, $addons) { + $addons[] = ''; + $where = [ + ['addon', 'in', $addons] + ]; + if(!empty($app_type)){ + $where[] = ['app_type', '=', $app_type]; + } + $menu_list = (new SysMenu())->where($where)->order('sort', 'desc')->column('api_url,methods'); + foreach ($menu_list as $v) { + $auth_menu_list[$v['methods']][] = $v['api_url']; + } + return $auth_menu_list ?? []; + }, + self::$cache_tag_name + ); + } + + /** + * 站点所拥有的菜单极限 + * @param string $app_type + * @param array $addons + * @param int $is_tree + * @return array|mixed|string + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getMenuListBySystem(string $app_type, array $addons, int $is_tree = 0, int $is_button = 1) + { + sort($addons); + $cache_name = 'menu' . md5(implode("_", $addons)) . $is_tree; + $menu_list = cache_remember( + $cache_name, + function () use ($addons, $app_type, $is_tree) { + $where = [ + ['addon', 'in', $addons] + ]; + if(!empty($app_type)){ + $where[] = ['app_type', '=', $app_type]; + } + // 排除插件中delete的菜单 + $delete_menu_addon = []; + $addon_loader = new DictLoader("Menu"); + foreach ($addons as $addon) { + $delete_menu = $addon_loader->load(["addon" => $addon, "app_type" => $app_type])['delete'] ?? []; + if (!empty($delete_menu) && is_array($delete_menu)) $delete_menu_addon[] = $delete_menu; + } + if (!empty($delete_menu_addon)) { + $delete_intersect = array_intersect(...$delete_menu_addon); + if (!empty($delete_intersect)) { + $where[] = ['menu_key', 'not in', $delete_intersect]; + } + } + return $this->model->where($where)->order('sort', 'desc')->select()->toArray(); + }, + self::$cache_tag_name + ); + + foreach ($menu_list as &$v) + { + $lang_menu_key = "dict_menu_". $v['app_type']. '.'. $v['menu_key']; + $lang_menu_name = get_lang("dict_menu_". $v['app_type']. '.'. $v['menu_key']); + //语言已定义 + if($lang_menu_key != $lang_menu_name) + { + $v['menu_name'] = $lang_menu_name; + } + //首页加载 + if($v['menu_key'] == 'overview' && $v['app_type'] == 'site') + { + $view_path = (new ConfigService())->getSiteIndexConfig(); + $v['view_path'] = $view_path; + } + + if($v['menu_key'] == 'overview' && $v['app_type'] == 'admin') + { + $view_path = (new ConfigService())->getAdminIndexConfig(); + $v['view_path'] = $view_path; + } + } + return $is_tree ? $this->menuToTree($menu_list, 'menu_key', 'parent_key', 'children', 'auth', '', $is_button) : $menu_list; + + } + + /** + * 通过站点的应用配置获取所有的keys + * @param string $app_type + * @param array $addons + * @return mixed|string + */ + public function getMenuKeysBySystem(string $app_type, array $addons){ + sort($addons); + $cache_name = 'menu_keys_' . $app_type.implode("_", $addons); + return cache_remember( + $cache_name, + function () use ($app_type, $addons) { + $addons[] = ''; + $where = [ + ['addon', 'in', $addons] + ]; + if(!empty($app_type)){ + $where[] = ['app_type', '=', $app_type]; + } + return (new SysMenu())->where($where)->order('sort', 'desc')->column('menu_key'); + }, + self::$cache_tag_name + ); + } + + public function getSystemMenu($status = 'all', $is_tree = 0, $is_button = 0) + { + + if($is_button == 0) + { + $where = [ + ['menu_type', 'in', [0,1]] + ]; + } + + if ($status != 'all') { + $where[] = ['status', '=', $status]; + } + $where[] = [ 'addon', '=','']; + $menu_list = (new SysMenu())->where($where)->order('sort desc')->select()->toArray(); + foreach ($menu_list as &$v) + { + $lang_menu_key = 'dict_menu_admin' . '.'. $v['menu_key']; + $lang_menu_name = get_lang($lang_menu_key); + //语言已定义 + if($lang_menu_key != $lang_menu_name) + { + $v['menu_name'] = $lang_menu_name; + } + } + return $is_tree ? $this->menuToTree($menu_list, 'menu_key', 'parent_key', 'children', 'auth', '', $is_button) : $menu_list; + } + + public function getAddonMenu($app_key,$status = 'all', $is_tree = 0, $is_button = 0) + { + + if($is_button == 0) + { + $where = [ + ['menu_type', 'in', [0,1]] + ]; + } + + if ($status != 'all') { + $where[] = ['status', '=', $status]; + } + $where[] = [ 'addon', '=',$app_key]; + $menu_list = (new SysMenu())->where($where)->select()->toArray(); + return $is_tree ? $this->menuToTree($menu_list, 'menu_key', 'parent_key', 'children', 'auth', '', $is_button) : $menu_list; + } + + /** + * 查询菜单类型为目录的菜单 + * @param string $addon + */ + public function getMenuByTypeDir(string $addon = 'system') { + $cache_name = 'menu_api_by_type_dir' . $addon; + $menu_list = cache_remember( + $cache_name, + function () use ($addon) { + $where = [ + ['menu_type', '=', 0 ], + ['app_type', '=', 'site'] + ]; + //查询应用 + $where[] = ['addon', '=', $addon == 'system' ? '' : $addon ]; + return (new SysMenu())->where($where)->order('sort desc')->select()->toArray(); + }, + self::$cache_tag_name + ); + foreach ($menu_list as &$v) + { + $lang_menu_key = 'dict_menu_admin' . '.'. $v['menu_key']; + $lang_menu_name = get_lang($lang_menu_key); + //语言已定义 + if($lang_menu_key != $lang_menu_name) + { + $v['menu_name'] = $lang_menu_name; + } + } + + return $this->menuToTree($menu_list, 'menu_key', 'parent_key', 'children', 'auth', '', 0); + } +} diff --git a/niucloud/app/service/admin/sys/RoleService.php b/niucloud/app/service/admin/sys/RoleService.php new file mode 100644 index 0000000..5be42cc --- /dev/null +++ b/niucloud/app/service/admin/sys/RoleService.php @@ -0,0 +1,197 @@ +model = new SysRole(); + } + + /** + * 管理端获取角色列表 + * @param array $data + * @return array + */ + public function getPage(array $data) + { + $where = [['site_id', '=', $this->site_id]]; + if(!empty($data['role_name'])) { + $where[] = ['role_name', 'like', "%".$data['role_name']."%"]; + } + $field = 'role_id,role_name,status,create_time'; + $search_model = $this->model->where($where)->field($field)->order('create_time desc')->append(['status_name']); + return $this->pageQuery($search_model); + } + /** + * 获取权限信息 + * @param int $role_id + * @return array + */ + public function getInfo(int $role_id){ + return $this->model->append(['status_name'])->findOrEmpty($role_id)->toArray(); + } + + /** + * 获取站点下的所有权限 + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getAll() + { + $where = array( + ['site_id', '=', $this->site_id], + ['status', '=', 1] + ); + return $this->model->where($where)->field('role_id,role_name,status,create_time')->select()->toArray(); + } + + /** + * 新增权限 + * @param array $data + * @return true + */ + public function add(array $data){ + $data['create_time'] = time(); + $data['app_type'] = $this->app_type; + $data['site_id'] = $this->site_id; + $this->model->save($data); + Cache::tag(self::$cache_tag_name.$this->site_id)->clear(); + return true; + } + + /** + * 更新权限 + * @param int $role_id + * @param array $data + * @return true + */ + public function edit(int $role_id, array $data){ + $where = array( + ['role_id', '=', $role_id], + ['site_id', '=', $this->site_id], + ); + $data['update_time'] = time(); + $this->model->update($data, $where); + Cache::tag(self::$cache_tag_name.$this->site_id)->clear(); + return true; + + } + + /** + * 获取模型对象 + * @param int $site_id + * @param int $role_id + * @return mixed + */ + public function find(int $site_id, int $role_id){ + $where = array( + ['role_id', '=', $role_id], + ['site_id', '=', $site_id], + ); + $role = $this->model->where($where)->findOrEmpty(); + if ($role->isEmpty()) + throw new AdminException('USER_ROLE_NOT_EXIST'); + return $role; + } + + /** + * 删除权限(saas应该不允许删除) + * @param int $role_id + * @return mixed + * @throws DbException + */ + public function del(int $role_id){ + $role = $this->find($this->site_id, $role_id); + if(SysUserRole::where([['role_ids', 'like',['%"'.$role_id.'"%']]])->count() > 0) + throw new AdminException('USER_ROLE_NOT_ALLOW_DELETE'); + $res = $role->delete(); + Cache::tag(self::$cache_tag_name.$this->site_id)->clear(); + return $res; + + } + + /** + * 获取角色id为健名,角色名为键值的数据 + * @param int $site_id + * @return mixed|string + */ + public function getColumn(int $site_id){ + $cache_name = 'role_column_'.$site_id; + return cache_remember( + $cache_name, + function() use($site_id) { + $where = [ + ['site_id', '=', $site_id] + ]; + return $this->model->where($where)->column('role_name', 'role_id'); + }, + [MenuService::$cache_tag_name, self::$cache_tag_name.$this->site_id] + ); + } + + /** + * 通过权限组id获取菜单id + * @param int $site_id + * @param array $role_ids + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getMenuIdsByRoleIds(int $site_id, array $role_ids){ + $menu_keys = (new SiteService())->getMenuIdsBySiteId($site_id, 1); + $allow_role_ids = array_merge($role_ids, $menu_keys); + sort($allow_role_ids); + $cache_name = 'user_role_'.$site_id.'_'.md5(implode('_', $allow_role_ids)); + return cache_remember( + $cache_name, + function() use($role_ids, $menu_keys) { + $rules = $this->model->where([['role_id', 'IN', $role_ids], ['status', '=', RoleStatusDict::ON]])->field('rules')->select()->toArray(); + if(!empty($rules)){ + $temp = []; + foreach($rules as $k => $v){ + $temp = array_merge($temp, $v['rules']); + } + $temp = array_unique($temp); + if(empty($menu_keys)) return []; + if(empty($temp)) return []; + return array_intersect($temp, $menu_keys); + } + return []; + }, + [MenuService::$cache_tag_name, self::$cache_tag_name.$site_id] + ); + + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/sys/SystemService.php b/niucloud/app/service/admin/sys/SystemService.php new file mode 100644 index 0000000..8446bf6 --- /dev/null +++ b/niucloud/app/service/admin/sys/SystemService.php @@ -0,0 +1,191 @@ + PHP_OS, + 'environment' => $_SERVER[ 'SERVER_SOFTWARE' ], + 'php_v' => PHP_VERSION, + 'version' => config('version') + ]; + } + + /** + * 获取域名配置 + */ + public function getUrl() + { + $wap_domain = !empty(env("system.wap_domain")) ? preg_replace('#/$#', '', env("system.wap_domain")) : request()->domain(); + $web_domain = !empty(env("system.web_domain")) ? preg_replace('#/$#', '', env("system.web_domain")) : request()->domain(); + + return [ + 'wap_domain' => env("system.wap_domain"), + 'wap_url' => $wap_domain . "/wap/" . $this->site_id, + 'web_url' => $web_domain . "/web/" . $this->site_id, + ]; + } + + /** + * 获取系统信息 + * @return array + */ + public function getSystemInfo() + { + $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]; + + //环境权限 + $system_variables = []; + //pdo + $pdo = extension_loaded('pdo') && extension_loaded('pdo_mysql'); + $system_variables[] = [ "name" => "pdo", "need" => get_lang('dict_setting.php_authority_ask'), "status" => $pdo ]; + //curl + $curl = extension_loaded('curl') && function_exists('curl_init'); + $system_variables[] = [ "name" => "curl", "need" => get_lang('dict_setting.php_authority_ask'), "status" => $curl ]; + //openssl + $openssl = extension_loaded('openssl'); + $system_variables[] = [ "name" => "openssl", "need" => get_lang('dict_setting.php_authority_ask'), "status" => $openssl ]; + //gd + $gd = extension_loaded('gd'); + $system_variables[] = [ "name" => "GD库", "need" => get_lang('dict_setting.php_authority_ask'), "status" => $gd ]; + //fileinfo + $fileinfo = extension_loaded('fileinfo'); + $system_variables[] = [ "name" => "fileinfo", "need" => get_lang('dict_setting.php_authority_ask'), "status" => $fileinfo ]; + //目录权限 + $root_path = str_replace("\\", DIRECTORY_SEPARATOR, dirname(__FILE__, 5)); + $root_path = str_replace("../", DIRECTORY_SEPARATOR, $root_path); + + + $dirs_list = [ + [ "path" => $root_path . DIRECTORY_SEPARATOR . 'runtime' . DIRECTORY_SEPARATOR, "need" => get_lang('dict_setting.file_authority_ask'), "path_name" => "/runtime", "name" => "runtime" ], + [ "path" => $root_path . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'upload' . DIRECTORY_SEPARATOR, "need" => get_lang('dict_setting.file_authority_ask'), "path_name" => "/public/upload", "name" => "upload" ], + ]; + //目录 可读 可写检测 + foreach ($dirs_list as $k => $v) { + $is_readable = is_readable($v[ "path" ]); + $is_write = is_write($v[ "path" ]); + if ($is_readable && $is_write) { + $dirs_list[ $k ][ "status" ] = true; + } else { + $dirs_list[ $k ][ "status" ] = false; + } + } + $system_variables = array_merge($system_variables, $dirs_list); + + //获取环境版本 + $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.mysql_version'), "demand" => get_lang('dict_setting.mysql_ask'), "server" => $row[ 0 ][ 'verson' ] ]; + + // 进程 + $process[] = [ "name" => "php think queue:listen", "need" => get_lang('dict_setting.php_authority_ask'), "status" => ( new SystemService() )->checkJob() ]; + + return [ "server" => $server, "dirs_list" => $dirs_list, 'system_variables' => $system_variables, 'server_version' => $server_version, 'process' => $process ]; + } + + /** + * 清理缓存 + */ + public function schemaCache() + { + + if (is_dir(dirname($_SERVER[ 'DOCUMENT_ROOT' ]) . '/runtime/schema')) { + rmdirs(dirname($_SERVER[ 'DOCUMENT_ROOT' ]) . '/runtime/schema'); + } + return 'CLEAR_MYSQL_CACHE_SUCCESS'; + } + + /** + *校验消息队列是否正常运行 + * @return bool + */ + public function checkJob() + { + $secret = uniqid('', true); + $file = root_path('runtime') . $secret . '.job'; + try { + CheckJob::dispatch([ 'file' => $file ]); + } catch ( Throwable $e) { + return false; + } +// $timeout = 0; +// while($timeout < 5){ +// if (file_exists($file)) { +// @unlink($file); +// return true; +// } +// $timeout++; +// sleep(1); +// } + sleep(3); + if (file_exists($file)) { + @unlink($file); + return true; + } + return false; + } + + /** + * 校验计划任务是否正常运行 + * @return bool + */ + public function checkSchedule() + { + $file = root_path('runtime') . '.schedule'; + if (file_exists($file)) { + $time = file_get_contents($file); + if (!empty($time) && abs($time - time()) < 90) { + return true; + } + } + return false; + } + + /** + * 设置布局 + * @param string $key + */ + public function setLayout(string $key) { + $layouts = array_column(event('SiteLayout'), 'key'); + if (!in_array($key, $layouts)) throw new CommonException('LAYOUT_NOT_EXIST'); + (new CoreConfigService())->setConfig($this->site_id, 'SITE_LAYOUT', [ 'key' => $key ]); + return true; + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/upgrade/BackupService.php b/niucloud/app/service/admin/upgrade/BackupService.php new file mode 100644 index 0000000..cd1f2fe --- /dev/null +++ b/niucloud/app/service/admin/upgrade/BackupService.php @@ -0,0 +1,103 @@ +upgrade_dir .$this->upgrade_task['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']); + + // 备份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; + } + + /** + * 备份数据库 + * @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最高 + ]); + + $prefix = config('database.connections.'.config('database.default'))['prefix']; + if ($this->upgrade_task['upgrade']['app_key'] == AddonDict::FRAMEWORK_KEY) { + // 不需要备份的表 + $noot_need_backup = ["{$prefix}sys_user_log", "{$prefix}jobs", "{$prefix}jobs_failed"]; + $tables = array_diff(array_column($db->dataList(), 'name'), $noot_need_backup); + } else { + $tables = []; + $table_prefix = "{$prefix}{$this->upgrade_task['upgrade']['app_key']}"; + foreach ($db->dataList() as $table) { + if (strpos($table['name'], $table_prefix) === 0) { + $tables[] = $table['name']; + } + } + } + + foreach ($tables as $table) { + $db->setFile()->backup($table); + } + return true; + } +} diff --git a/niucloud/app/service/admin/upgrade/ExecuteSqlTrait.php b/niucloud/app/service/admin/upgrade/ExecuteSqlTrait.php new file mode 100644 index 0000000..4301c6b --- /dev/null +++ b/niucloud/app/service/admin/upgrade/ExecuteSqlTrait.php @@ -0,0 +1,68 @@ + 0) { + $table_name = $match_data[ 1 ]; + $new_table_name = $prefix . $table_name; + $sql = implode($new_table_name, explode($table_name, $sql, 2)); + } + return $sql; + } +} diff --git a/niucloud/app/service/admin/upgrade/RestoreService.php b/niucloud/app/service/admin/upgrade/RestoreService.php new file mode 100644 index 0000000..1900ef4 --- /dev/null +++ b/niucloud/app/service/admin/upgrade/RestoreService.php @@ -0,0 +1,59 @@ +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)) { + foreach ($file_list as $file) { + $db->setFile($file)->import(0, $file['time']); + } + } + } + return true; + } +} diff --git a/niucloud/app/service/admin/upgrade/UpgradeService.php b/niucloud/app/service/admin/upgrade/UpgradeService.php new file mode 100644 index 0000000..1b14d19 --- /dev/null +++ b/niucloud/app/service/admin/upgrade/UpgradeService.php @@ -0,0 +1,532 @@ + ['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' => '升级完成'] + ]; + + public function __construct() + { + parent::__construct(); + + $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); + } + + /** + * 升级前环境检测 + * @param string $addon + * @return void + */ + 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; + $wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR; + + try { + 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'); + } catch (\Exception $e) { + if (strpos($e->getMessage(), 'open basedir') !== false) { + throw new CommonException('OPEN_BASEDIR_ERROR'); + } + throw new CommonException($e->getMessage()); + } + + $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) ]; + + $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 $addon + * @return array + */ + public function upgrade(string $addon = '') { + if ($this->upgrade_task) throw new CommonException('UPGRADE_TASK_EXIST'); + + $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'); + } + + $response = (new CoreAddonCloudService())->upgradeAddon($upgrade); + if (isset($response['code']) && $response['code'] == 0) throw new CommonException($response['msg']); + + try { + $key = uniqid(); + $upgrade_dir = $this->upgrade_dir . $key . DIRECTORY_SEPARATOR; + + if (!is_dir($upgrade_dir)) { + dir_mkdir($upgrade_dir); + } + + $upgrade_tsak = [ + 'key' => $key, + 'upgrade' => $upgrade, + 'step' => 'requestUpgrade', + 'executed' => ['requestUpgrade'], + 'log' => [ $this->steps['requestUpgrade']['title'] ], + 'params' => ['token' => $response['token'] ], + 'upgrade_content' => $this->getUpgradeContent($addon) + ]; + + Cache::set($this->cache_key, $upgrade_tsak); + return $upgrade_tsak; + } catch (\Exception $e) { + if (strpos($e->getMessage(), 'open_basedir') !== false) { + throw new CommonException('OPEN_BASEDIR_ERROR'); + } + throw new CommonException($e->getMessage()); + } + } + + /** + * 执行升级 + * @return true + */ + public function execute() { + if (!$this->upgrade_task) return true; + + $steps = array_keys($this->steps); + $index = array_search($this->upgrade_task['step'], $steps); + $step = $steps[ $index + 1 ] ?? ''; + $params = $this->upgrade_task['params'] ?? []; + + if ($step) { + try { + $res = $this->$step(...$params); + + if (is_array($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']; + } + Cache::set($this->cache_key, $this->upgrade_task); + } catch (\Exception $e) { + $this->upgrade_task['step'] = $step; + $this->upgrade_task['error'] = $e->getMessage(); + $this->upgradeErrorHandle(); + } + return true; + } else { + return true; + } + } + + /** + * 下载升级文件 + * @param string $token + * @param string $dir + * @param int $index + * @param $step + * @return true|null + */ + public function downloadFile(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_mkdir($dir); + } + $res = (new CoreAddonCloudService())->downloadUpgradeFile($token, $dir, $index, $step, $length); + return $res; + } + + /** + * 备份源码 + * @return true + */ + public function backupCode() { + (new BackupService())->backupCode(); + return true; + } + + /** + * 备份数据库 + * @return true + */ + public function backupSql() { + (new BackupService())->backupSql(); + return true; + } + + /** + * 覆盖更新升级的代码 + * @return void + */ + public function coverCode($index = 0) { + $this->upgrade_task['is_cover'] = 1; + $addon = $this->upgrade_task['upgrade']['app_key']; + + $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; + + $version_item = $version_list[$index]; + $version_no = $version_item['version_no']; + + $to_dir = $addon == AddonDict::FRAMEWORK_KEY ? $this->root_path : $this->root_path . 'niucloud' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $addon; + + // 获取文件变更记录 + if (file_exists($code_dir . $version_no . '.txt')) { + $change = array_filter(explode("\n", file_get_contents($code_dir . $version_no . '.txt'))); + foreach ($change as &$item) { + list($operation, $md5, $file) = $item = explode(' ', $item); + if ($operation == '-') { + @unlink($to_dir . $file); + } + } + // 合并依赖 + $this->installDepend($code_dir . $version_no, array_column($change, 2)); + } + + // 覆盖文件 + if (is_dir($code_dir . $version_no)) { + dir_copy($code_dir . $version_no, $to_dir); + if ($addon != AddonDict::FRAMEWORK_KEY) { + (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'; + } 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 + if (file_exists($sql_file)) { + $this->executeSql($sql_file); + } + + // 执行升级方法 + if (class_exists($class_path)) { + (new $class_path())->handle(); + } + + $index ++; + if ($index < count($version_list)) { + return compact('index'); + } else { + return true; + } + } + + /** + * 合并依赖 + * @param string $version_no + * @return void + */ + public function installDepend(string $dir, array $change_files) { + $addon = $this->upgrade_task['upgrade']['app_key']; + $depend_service = new CoreDependService(); + + if ($addon == AddonDict::FRAMEWORK_KEY) { + $composer = '/niucloud/composer.json'; + $admin_package = '/admin/package.json'; + $web_package = '/web/package.json'; + $uniapp_package = '/uni-app/package.json'; + } else { + $composer = "/niucloud/addon/{$addon}/package/composer.json"; + $admin_package = "/niucloud/addon/{$addon}/package/admin-package.json"; + $web_package = "/niucloud/addon/{$addon}/package/web-package.json"; + $uniapp_package = "/niucloud/addon/{$addon}/package/uni-app-package.json"; + } + + if (in_array($composer, $change_files)) { + $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]; + } + $depend_service->writeArrayToJsonFile($original, $dir . $composer); + } + if (in_array($admin_package, $change_files)) { + $original = $depend_service->getNpmContent('admin'); + $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]; + } + $depend_service->writeArrayToJsonFile($original, $dir . $admin_package); + } + if (in_array($web_package, $change_files)) { + $original = $depend_service->getNpmContent('web'); + $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]; + } + $depend_service->writeArrayToJsonFile($original, $dir . $web_package); + } + if (in_array($uniapp_package, $change_files)) { + $original = $depend_service->getNpmContent('uni-app'); + $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]; + } + $depend_service->writeArrayToJsonFile($original, $dir . $uniapp_package); + } + } + + /** + * 处理手机端 + * @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; + dir_copy($code_dir . 'uni-app', $this->root_path . 'uni-app'); + + $addon_list = (new CoreAddonService())->getInstallAddonList(); + if (!empty($addon_list)) { + + foreach ($addon_list as $addon => $item) { + $this->addon = $addon; + + // 编译 diy-group 自定义组件代码文件 + $this->compileDiyComponentsCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $addon); + + // 编译 fixed-group 固定模板组件代码文件 + $this->compileFixedComponentsCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $addon); + + // 编译 pages.json 页面路由代码文件 + $this->installPageCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR); + + // 编译 加载插件标题语言包 + $this->compileLocale($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $addon); + } + } + return true; + } + + /** + * 执行升级sql + * @param string $sql_file + * @return true + */ + private function executeSql(string $sql_file) { + $sql_content = file_get_contents($sql_file); + + if (!empty($sql_content)) { + $prefix = config('database.connections.mysql.prefix'); + $sql_data = array_filter($this->getSqlQuery($sql_content)); + + if (!empty($sql_data)) { + foreach ($sql_data as $sql) { + $sql = $prefix ? $this->handleSqlPrefix($sql, $prefix) : $sql; + Db::query($sql); + } + } + } + return true; + } + + /** + * 刷新菜单 + * @return void + */ + public function refreshMenu() { + if ($this->upgrade_task['upgrade']['app_key'] == AddonDict::FRAMEWORK_KEY) { + (new InstallSystemService())->installMenu(); + } else { + (new CoreMenuService())->refreshAddonMenu($this->upgrade_task['upgrade']['app_key']); + } + return true; + } + + /** + * 安装计划任务 + * @return true + */ + public function installSchedule() { + if ($this->upgrade_task['upgrade']['app_key'] == AddonDict::FRAMEWORK_KEY) { + (new CoreScheduleInstallService())->installSystemSchedule(); + } else { + (new CoreScheduleInstallService())->installAddonSchedule($this->upgrade_task['upgrade']['app_key']); + } + return true; + } + + /** + * 更新完成 + * @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); + } + $this->clearUpgradeTask(5); + return true; + } + + /** + * 升级出错之后的处理 + * @return true|void + */ + public function upgradeErrorHandle() { + try { + if (isset($this->upgrade_task['is_cover'])) { + $restore_service = (new RestoreService()); + $restore_service->restoreCode(); + $restore_service->restoreSql(); + } + $this->clearUpgradeTask(5); + return true; + } catch (\Exception $e) { + $this->clearUpgradeTask(5); + return true; + } + } + + /** + * 获取升级内容 + * @param string $addon + * @return array|\core\util\niucloud\Response|object|\Psr\Http\Message\ResponseInterface + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function getUpgradeContent(string $addon = '') { + $upgrade = [ + 'product_key' => BaseNiucloudClient::PRODUCT + ]; + 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'); + } + + return (new CoreModuleService())->getUpgradeContent($upgrade)['data'] ?? []; + } + + /** + * 获取正在进行的升级任务 + * @return mixed|null + */ + public function getUpgradeTask() { + return $this->upgrade_task; + } + + /** + * 清除升级任务 + * @return true + */ + public function clearUpgradeTask(int $delayed = 0) { + if ($delayed) { + Cache::set($this->cache_key, $this->upgrade_task, $delayed); + } else { + Cache::set($this->cache_key, null); + } + return true; + } + + /** + * 获取插件定义的package目录 + * @param string $addon + * @return string + */ + public function geAddonPackagePath(string $addon) + { + return root_path() . 'addon' .DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR . 'package' . DIRECTORY_SEPARATOR; + } +} diff --git a/niucloud/app/service/admin/upload/StorageConfigService.php b/niucloud/app/service/admin/upload/StorageConfigService.php new file mode 100644 index 0000000..9117f3b --- /dev/null +++ b/niucloud/app/service/admin/upload/StorageConfigService.php @@ -0,0 +1,116 @@ +getStorageList($this->site_id); + } + + /** + * 获取存储配置 + * @param string $storage_type + * @return array + */ + public function getStorageConfig(string $storage_type) + { + $storage_type_list = StorageDict::getType(); + if(!array_key_exists($storage_type, $storage_type_list)) throw new AdminException('OSS_TYPE_NOT_EXIST'); + $info = (new CoreConfigService())->getConfig($this->site_id, 'STORAGE'); + if(empty($info)) + { + $config_type = ['default' => StorageDict::LOCAL];//初始化 + }else + $config_type = $info['value']; + + $data = [ + 'storage_type' => $storage_type, + 'is_use' => $storage_type == $config_type['default'] ? StorageDict::ON : StorageDict::OFF, + 'name' => $storage_type_list[$storage_type]['name'], + ]; + foreach ($storage_type_list[$storage_type]['params'] as $k_param => $v_param) + { + $data['params'][$k_param] = [ + 'name' => $v_param, + 'value' => $config_type[$storage_type][$k_param] ?? '' + ]; + } + return $data; + + } + + /** + * 云存储配置 + * @param string $storage_type + * @param array $data + * @return bool + */ + public function setStorageConfig(string $storage_type, array $data) + { + $storage_type_list = StorageDict::getType(); + if(!array_key_exists($storage_type, $storage_type_list)) throw new AdminException('OSS_TYPE_NOT_EXIST'); + if($storage_type != FileDict::LOCAL){ + $domain = $data['domain']; + if (!str_contains($domain, 'http://') && !str_contains($domain, 'https://')){ + throw new AdminException('STORAGE_NOT_HAS_HTTP_OR_HTTPS'); + } + } + $info = (new CoreConfigService())->getConfig($this->site_id, 'STORAGE'); + if(empty($info)) + { + $config['default'] = ''; + + }else{ + $config = $info['value']; + } + //初始化数据 + if($data['is_use']) + { + $config['default'] = $storage_type; + }else{ + $config['default'] = ''; + } + foreach ($storage_type_list[$storage_type]['params'] as $k_param => $v_param) + { + $config[$storage_type][$k_param] = $data[$k_param] ?? ''; + } + + return (new CoreConfigService())->setConfig($this->site_id, 'STORAGE', $config); + } + + + +} diff --git a/niucloud/app/service/admin/upload/UploadConfigService.php b/niucloud/app/service/admin/upload/UploadConfigService.php new file mode 100644 index 0000000..5af2842 --- /dev/null +++ b/niucloud/app/service/admin/upload/UploadConfigService.php @@ -0,0 +1,57 @@ +core_upload_config_service = new CoreUploadConfigService(); + } + + /** + * 获取上传配置 + * @return array|Response + */ + public function getUploadConfig() + { + return $this->core_upload_config_service->getUploadConfig($this->site_id); + + } + + /** + * 上传设置 + * @param array $data + * @return SysConfig|bool|Model + */ + public function setUploadConfig(array $data) + { + return $this->core_upload_config_service->setUploadConfig($this->site_id, $data); + } + + + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/upload/UploadService.php b/niucloud/app/service/admin/upload/UploadService.php new file mode 100644 index 0000000..2eddf29 --- /dev/null +++ b/niucloud/app/service/admin/upload/UploadService.php @@ -0,0 +1,70 @@ +root_path.'/'.'image'.'/'.$this->site_id.'/'.date('Ym').'/'.date('d'); + $core_upload_service = new CoreUploadService($is_attachment); + //如果没有选择相册分组的话,就选择第一个相册分组 + return $core_upload_service->image($file, $this->site_id, $dir, $cate_id); + } + + /** + * 附件库上传视频 + * @param $file + * @param int $cate_id + * @return array + */ + public function video($file, int $cate_id = 0){ + $dir = $this->root_path.'/'.'video'.'/'.$this->site_id.'/'.date('Ym').'/'.date('d'); + $core_upload_service = new CoreUploadService(true); + return $core_upload_service->video($file, $this->site_id, $dir, $cate_id); + } + + /** + * 文件上传 + * @param $file + * @param string $type + * @return array + * @throws Exception + */ + public function document($file, string $type){ + if(!in_array($type, FileDict::getSceneType())) + throw new UploadFileException('UPLOAD_TYPE_ERROR'); + $dir = $this->root_path.'/document/'.$type.'/'.$this->site_id.'/'.date('Ym').'/'.date('d'); + $core_upload_service = new CoreUploadService(); + return $core_upload_service->document($file, $this->site_id, $type, $dir, StorageDict::LOCAL); + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/user/UserRoleService.php b/niucloud/app/service/admin/user/UserRoleService.php new file mode 100644 index 0000000..9360596 --- /dev/null +++ b/niucloud/app/service/admin/user/UserRoleService.php @@ -0,0 +1,146 @@ +model = new SysUserRole(); + } + + /** + * 添加用户权限(添加站点用户) + * @param int $uid + * @param array $data + * @param int $site_id + * @return true + */ + public function add(int $uid, array $data, int $site_id = 0){ + $user_role_model = new SysUserRole(); + $is_exist = $user_role_model->where([ ['uid', '=', $uid], ['site_id', '=', $site_id] ])->count(); + if ($is_exist) throw new CommonException('SITE_USER_EXIST'); + + $is_admin = $data['is_admin'] ?? 0; + $role_data = array( + 'uid' => $uid, + 'is_admin' => $is_admin, + 'site_id' => $site_id == 0 ? $this->site_id : $site_id + ); + if(!$is_admin){ + //校验权限越界 + $role_data['role_ids'] = $data['role_ids'] ?? []; + } + $user_role_model->save($role_data); + return true; + } + + /** + * 更新用户权限(编辑站点用户) + * @param int $site_id + * @param int $uid + * @param array $role_ids + * @return bool + */ + public function edit(int $site_id, int $uid, array $role_ids){ + $user_role = $this->model->where([['uid', '=', $uid], ['site_id', '=', $site_id]])->findOrEmpty(); + if ($user_role->isEmpty()) + throw new AdminException('NO_SITE_USER_ROLE'); + + $is_admin = $user_role->is_admin; + if($is_admin)//超级管理员不允许改动权限 + throw new AdminException('ADMIN_NOT_ALLOW_EDIT_ROLE'); + if (!empty(array_diff_assoc($role_ids, $user_role->role_ids))) { + //校验权限越界 + $user_role->save(['role_ids' => $role_ids]); + $cache_name = 'user_role_'.$uid.'_'.$site_id; + Cache::delete($cache_name); + return true; + } + return false; + } + + /** + * 用户权限信息(获取用户对应站点权限) + * @param int $site_id + * @param int $uid + * @return mixed + */ + public function getUserRole(int $site_id, int $uid){ + $cache_name = 'user_role_'.$uid.'_'.$site_id; + return cache_remember( + $cache_name, + function() use($uid, $site_id) { + $user_role_model = new SysUserRole(); + $where = array( + ['uid', '=', $uid], + ['site_id', '=', $site_id] + ); + return $user_role_model->where($where)->findOrEmpty()->toArray(); + }, + [self::$role_cache_name, RoleService::$cache_tag_name.$this->site_id] + ); + } + + /** + * 获取用户默认站点(切勿用于平台管理端) + * @param int $uid + * @return SysUserRole|array|mixed|Model + */ + public function getUserDefaultSiteId(int $uid){ + $user_role_model = new SysUserRole(); + $default_site_id = $this->request->defaultSiteId(); + return $user_role_model->where([['uid', '=', $uid], ['site_id', '<>', $default_site_id]])->findOrEmpty()?->site_id; + } + + /** + * 通过角色id组获取角色 + * @param array $role_ids + * @param int $site_id + * @return mixed + */ + public function getRoleByUserRoleIds(array $role_ids, int $site_id){ + sort($role_ids); + $cache_name = 'role_by_ids_'.md5(implode(',', $role_ids)).'_'.$site_id; + return cache_remember( + $cache_name, + function() use($role_ids, $site_id) { + $where = array( + ['role_id', 'in', $role_ids], + ['site_id', '=', $site_id] + ); + return SysRole::where($where)->column('role_name'); + }, + [self::$role_cache_name, RoleService::$cache_tag_name.$this->site_id] + ); + } + + +} diff --git a/niucloud/app/service/admin/user/UserService.php b/niucloud/app/service/admin/user/UserService.php new file mode 100644 index 0000000..cb169c6 --- /dev/null +++ b/niucloud/app/service/admin/user/UserService.php @@ -0,0 +1,318 @@ +model = new SysUser(); + } + + /** + * 用户列表 + * @param array $where + * @return array + */ + public function getPage(array $where) + { + return $this->getPageList($this->model, $where, 'uid,username,head_img,real_name,last_ip,last_time,login_count,status', 'uid desc',['status_name']); + } + + + /** + * 用户详情 + * @param int $uid + * @return array + */ + public function getInfo(int $uid){ + $where = array( + ['uid', '=', $uid], + ); + $field = 'uid, username, head_img, real_name, last_ip, last_time, create_time, login_count, status, delete_time, update_time'; + $user = $this->model->where($where)->field($field)->append(['status_name'])->findOrEmpty(); + return $user->toArray(); + } + + /** + * 获取用户列表 + * @param array $where + * @return array + */ + public function getUserAdminPage(array $where) + { + $site_id = $this->site_id; + $field = 'id,SysUserRole.uid,site_id,role_ids,SysUserRole.create_time,is_admin,SysUserRole.status'; + $order = 'SysUserRole.create_time desc'; + $search_model = (new SysUserRole()) + ->field($field) + ->order($order) + ->with('userinfo') + ->hasWhere('userinfo', function ($query) use ($where, $site_id) { + $condition = [ + ['SysUserRole.site_id', '=', $site_id ] + ]; + if (!empty($where['username'])) $condition[] = ['username', 'like', "%{$where['username']}%"]; + if (!empty($where['realname'])) $condition[] = ['realname', 'like', "%{$where['realname']}%"]; + $query->where($condition); + }) + ->append(['status_name']); + + return $this->pageQuery($search_model, function ($item, $key) { + if (!empty($item->role_ids)) { + $item->role_array = (new UserRoleService())->getRoleByUserRoleIds($item->role_ids, $this->site_id); + } else { + $item->role_array = []; + } + }); + } + + /** + * 获取用户信息 + * @param int $uid + * @return array + */ + public function getUserAdminInfo(int $uid) + { + $field = 'id,uid,site_id,role_ids,create_time,is_admin,status'; + $info = (new SysUserRole())->where([ ['uid', '=', $uid], ['site_id', '=', $this->site_id ] ]) + ->field($field) + ->with('userinfo') + ->findOrEmpty() + ->toArray(); + + if (!empty($info)) { + if (!empty($info['role_ids'])) { + $info['role_array'] = (new UserRoleService())->getRoleByUserRoleIds($info['role_ids'], $this->site_id); + } else { + $info['role_array'] = []; + } + } + return $info; + } + + /** + * 添加用户(添加用户,不添加站点) + * @param array $data + * @return bool + * @throws Exception + */ + public function add(array $data){ + $user_data = [ + 'username' => $data['username'], + 'head_img' => $data['head_img'], + 'status' => $data['status'], + 'real_name' => $data['real_name'], + 'password' => create_password($data['password']) + ]; + $user = $this->model->create($user_data); + return $user?->uid; + } + + /** + * 添加对应站点用户(添加站点,同时添加站点用户,用于添加站点以及站点添加站点用户) + * @param $data + * @param $site_id + * @return bool + */ + public function addSiteUser($data, $site_id) + { + Db::startTrans(); + try { + if (isset($data['uid']) && !empty($data['uid'])) { + $uid = $data['uid']; + $user = $this->model->where([ ['uid', '=', $uid] ])->field('uid')->findOrEmpty(); + if ($user->isEmpty()) { + Db::commit(); + throw new AdminException('USER_NOT_EXIST'); + } + } else { + //添加用户 + $uid = $this->add($data); + } + $role_ids = $data['role_ids'] ?? []; + $is_admin = $data['is_admin'] ?? 0; + //创建用户站点管理权限 + (new UserRoleService())->add($uid, ['role_ids' => $role_ids, 'is_admin' => $is_admin], $site_id); + Db::commit(); + return $uid; + } catch ( Exception $e) { + Db::rollback(); + throw new AdminException($e->getMessage()); + } + } + + /** + * 更新对应站点用户 + * @param $uid + * @param $data + * @param $site_id + * @return true + */ + public function editSiteUser($uid, $data, $site_id) + { + Db::startTrans(); + try { + //添加用户 + $this->edit($uid, $data); + $role_ids = $data['role_ids'] ?? []; + $is_admin = $data['is_admin'] ?? 0; + //创建用户站点管理权限 + (new UserRoleService())->edit($site_id, $uid, $role_ids); + Db::commit(); + return true; + } catch ( Exception $e) { + Db::rollback(); + throw new AdminException($e->getMessage()); + } + } + + /** + * 检测用户名是否重复 + * @param $username + * @return bool + * @throws DbException + */ + public function checkUsername($username) + { + $count = $this->model->where([['username', '=', $username]])->count(); + if($count > 0) + { + return true; + } + else return false; + } + + /** + * 用户模型对象 + * @param int $uid + * @return SysUser|array|mixed|Model + */ + public function find(int $uid){ + + $user = $this->model->findOrEmpty($uid); + if ($user->isEmpty()) + throw new AdminException('USER_NOT_EXIST'); + return $user; + } + + /** + * 编辑用户 + * @param int $uid + * @param array $data + * @return true + */ + public function edit(int $uid, array $data){ + $user = $this->find($uid); + $user_data = [ + ]; + $is_off_status = false; + if(isset($data['status'])){ + $this->statusChange($uid, $data['status']); + if($data['status'] == UserDict::OFF) + $is_off_status = true; + } + if(isset($data['head_img'])){ + $user_data['head_img'] = $data['head_img']; + } + if(isset($data['real_name'])){ + $user_data['real_name'] = $data['real_name']; + } + + $password = $data['password'] ?? ''; + $is_change_password = false; + if(!empty($password) && !check_password($password, $user->password)){ + $user_data['password'] = create_password($password); + $is_change_password = true; + } + if(empty($user_data)) + return true; + //更新用户信息 + $user->save($user_data); + //更新权限 禁用用户 修改密码 都会清理token + if($is_off_status || $is_change_password){ + LoginService::clearToken($uid); + } + return true; + } + + /** + * 改变用户状态 + * @param $uid + * @param $status + * @return true + */ + public function statusChange($uid, $status) { + (new SysUserRole())->where([ ['uid', '=', $uid], ['site_id', '=', $this->uid] ])->update(['status' => $status]); + LoginService::clearToken($uid); + return true; + } + + /** + * 删除 + * @param int $uid + * @return true + */ + public function del(int $uid){ + $where = [ + ['uid', '=', $uid], + ['site_id', '=', $this->site_id] + ]; + (new SysUserRole())->where($where)->delete(); + return true; + + } + + /** + * 通过账号获取管理员信息 + * @param string $username + * @return SysUser|array|mixed|Model + */ + public function getUserInfoByUsername(string $username){ + return $this->model->where([['username', '=',$username]])->findOrEmpty(); + } + + /** + * 获取全部用户列表(用于平台整体用户管理) + * @param array $where + * @return array + */ + public function getUserAllPage(array $where) + { + $field = 'uid, username, head_img'; + return $this->model->withSearch(['username', 'realname', 'create_time'], $where) + ->field($field) + ->order('uid desc') + ->select() + ->toArray(); + } +} diff --git a/niucloud/app/service/admin/weapp/WeappConfigService.php b/niucloud/app/service/admin/weapp/WeappConfigService.php new file mode 100644 index 0000000..f4b2552 --- /dev/null +++ b/niucloud/app/service/admin/weapp/WeappConfigService.php @@ -0,0 +1,61 @@ +getWeappConfig($this->site_id); + return array_merge($config_info, $this->getWeappStaticInfo()); + + } + + /** + * 设置配置 + * @param array $data + * @return SysConfig|bool|Model + */ + public function setWeappConfig(array $data){ + return (new CoreWeappConfigService())->setWeappConfig($this->site_id, $data); + } + + /** + *查询微信小程序需要的静态信息 + * @return array + */ + public function getWeappStaticInfo(){ + $domain = request()->domain(); + return [ + 'serve_url' => (string)url('/api/weapp/serve/'.$this->site_id, [],'',true), + 'request_url' => $domain, + 'socket_url' => "wss://".request()->host(), + 'upload_url' => $domain, + 'download_url' => $domain, + 'upload_ip' => '8.140.96.55' + ]; + } +} diff --git a/niucloud/app/service/admin/weapp/WeappPackageService.php b/niucloud/app/service/admin/weapp/WeappPackageService.php new file mode 100644 index 0000000..fb12c5e --- /dev/null +++ b/niucloud/app/service/admin/weapp/WeappPackageService.php @@ -0,0 +1,33 @@ +model = new Applet(); + } + + public function add(array $data) + { + $data['version_num'] = version_to_int($data['version']);//版本号数字 + $data['u'] = $this->uid;//发布者 + $data['status'] = ''; + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/weapp/WeappTemplateService.php b/niucloud/app/service/admin/weapp/WeappTemplateService.php new file mode 100644 index 0000000..67c09b0 --- /dev/null +++ b/niucloud/app/service/admin/weapp/WeappTemplateService.php @@ -0,0 +1,99 @@ +site_id; + $core_notice_service = new CoreNoticeService(); + $list = $core_notice_service->getList($site_id); + $template = []; + foreach ($list as $k => $v){ + if(in_array(NoticeTypeDict::WEAPP, $v['support_type'])) $template[] = $v; + } + return $template; + } + + /** + * 同步微信公众号消息模板 + * @param array $keys + * @return true + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function syncAll(array $keys = []){ + $site_id = $this->site_id; + $core_notice_service = new CoreNoticeService(); + $list = $core_notice_service->getList($site_id, $keys); + if(empty($list)) throw new NoticeException('NOTICE_TEMPLATE_NOT_EXIST'); + + foreach($list as $v){ + $this->syncItem($v); + } + return true; + } + + /** + * @param $item + * @return true + */ + public function syncItem($item){ + $key = $item['key'] ?? ''; + $weapp = $item['weapp'] ?? []; + $tid = $weapp['tid'] ?? ''; + if(empty($tid)) $error = 'WECHAT_TEMPLATE_NEED_NO'; + $weapp_template_id = $item['weapp_template_id']; + //删除原来的消息模板 + $template_loader = (new TemplateLoader(NoticeTypeDict::WEAPP, ['site_id' => $this->site_id])); + $template_loader->delete(['template_id' => $weapp_template_id ]); +// (new CoreWeappTemplateService())->deleteTemplate($this->site_id, $weapp_template_id); + //新的消息模板 + + $kid_list = $weapp['kid_list'] ?? []; + $scene_desc = $weapp['scene_desc'] ?? ''; +// $res = (new CoreWeappTemplateService())->addTemplate($this->site_id, $tid, $kid_list, $scene_desc); + $res = $template_loader->addTemplate(['tid' => $tid, 'kid_list' => $kid_list, 'scene_desc' => $scene_desc ]); + $notice_service = new NoticeService(); + if (isset($res[ 'errcode' ]) && $res[ 'errcode' ] == 0) { + //修改 + $notice_service->modify($key, 'weapp_template_id', $res[ 'priTmplId' ]); + } else { + throw new NoticeException($res[ 'errmsg' ]); + } + return true; + } + +} \ No newline at end of file diff --git a/niucloud/app/service/admin/weapp/WeappVersionService.php b/niucloud/app/service/admin/weapp/WeappVersionService.php new file mode 100644 index 0000000..9ec9351 --- /dev/null +++ b/niucloud/app/service/admin/weapp/WeappVersionService.php @@ -0,0 +1,117 @@ +model = new WeappVersion(); + } + + /** + * 添加小程序版本 + * @param array $data + */ + public function add(array $data) + { + $uploading = $this->model->where([ ['site_id', '=', $this->site_id], ['status', '=', 0] ])->field('id')->findOrEmpty(); + if (!$uploading->isEmpty()) throw new CommonException('WEAPP_UPLOADING'); + + $version_no = $this->model->where([ ['site_id', '=', $this->site_id] ])->order('version_no desc')->field('version_no')->findOrEmpty()->toArray()['version_no'] ?? 0; + $version_no += 1; + $version = "1.0.{$version_no}"; + + $upload_res = (new CoreWeappCloudService())->uploadWeapp([ + 'site_id' => $this->site_id, + 'version' => $version, + 'desc' => $data['desc'] ?? '' + ]); + + $res = $this->model->create([ + 'site_id' => $this->site_id, + 'version' => $version, + 'version_no' => $version_no, + 'desc' => $data['desc'] ?? '', + 'create_time' => time(), + 'task_key' => $upload_res['key'] + ]); + return $res->id; + } + + public function getPreviewImage() { + try { + return (new CoreWeappCloudService())->getWeappPreviewImage(); + } catch (\Exception $e) { + return ''; + } + } + + /** + * 获取小程序版本列表 + * @param array $where + * @return array + */ + public function getPage(array $where = []) + { + $field = 'id, version, version_no, desc, create_time, status, fail_reason, task_key'; + $order = 'version_no desc'; + $where[] = ['site_id', '=', $this->site_id]; + $search_model = $this->model->where($where)->field($field)->order($order)->append(['status_name']); + return $this->pageQuery($search_model); + } + + /** + * 编辑 + * @param int $id + * @param array $data + * @return true + */ + public function edit(int $id, array $data) + { + $data['status'] = 0; + $data['update_time'] = time(); + $this->model->where([['id', '=', $id], ['site_id', '=', $this->site_id] ])->create($data); + return true; + } + + /** + * 删除 + * @param int $id + * @return true + */ + public function del(int $id){ + $this->model->where([['id', '=', $id], ['site_id', '=', $this->site_id]])->delete(); + return true; + } + + /** + * 获取小程序上传日志 + * @param string $key + * @return null + */ + public function getUploadLog(string $key) { + return (new CoreWeappCloudService())->getWeappCompileLog($key); + } +} diff --git a/niucloud/app/service/admin/wechat/WechatConfigService.php b/niucloud/app/service/admin/wechat/WechatConfigService.php new file mode 100644 index 0000000..5cdf30d --- /dev/null +++ b/niucloud/app/service/admin/wechat/WechatConfigService.php @@ -0,0 +1,51 @@ +getWechatConfig($this->site_id); + } + + /** + * 设置配置 + * @param array $data + * @return SysConfig|bool|Model + */ + public function setWechatConfig(array $data){ + return (new CoreWechatConfigService())->setWechatConfig($this->site_id, $data); + } + + /** + *查询微信需要的静态信息 + * @return array + */ + public function getWechatStaticInfo(){ + return (new CoreWechatConfigService())->getWechatStaticInfo($this->site_id); + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/wechat/WechatEventService.php b/niucloud/app/service/admin/wechat/WechatEventService.php new file mode 100644 index 0000000..2e495eb --- /dev/null +++ b/niucloud/app/service/admin/wechat/WechatEventService.php @@ -0,0 +1,36 @@ +MsgType){ + case WechatDict::EVENT_SUBSCRIBE : + $message->FromUserName; + break; + } + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/wechat/WechatFansService.php b/niucloud/app/service/admin/wechat/WechatFansService.php new file mode 100644 index 0000000..ef735f8 --- /dev/null +++ b/niucloud/app/service/admin/wechat/WechatFansService.php @@ -0,0 +1,42 @@ +getConfig($this->site_id, 'WECHAT_MENU')['value'] ?? []; + } + + + /** + * 更新微信菜单 + * @param array $data + * @return SysConfig|bool|Model + * @throws GuzzleException + * @throws InvalidConfigException + */ + public function edit(array $data){ + $core_wechat_api_service = new CoreWechatApiService(); + $menu_result = $core_wechat_api_service->menuCreate($this->site_id, $data); + if(!empty($menu_result['errcode']) && $menu_result['errcode'] != 0) + throw new WechatException($menu_result['errmsg']); + + //先尝试改变微信接口菜单 + $core_config_service = new CoreConfigService(); + return $core_config_service->setConfig($this->site_id, 'WECHAT_MENU', $data); + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/wechat/WechatReplyService.php b/niucloud/app/service/admin/wechat/WechatReplyService.php new file mode 100644 index 0000000..af89257 --- /dev/null +++ b/niucloud/app/service/admin/wechat/WechatReplyService.php @@ -0,0 +1,113 @@ +core_wechat_reply_service = new CoreWechatReplyService(); + } + + /** + *关键字回复列表 + * @return array + */ + public function getKeywordPage(array $data = []){ + + return $this->core_wechat_reply_service->getKeywordPage($this->site_id, $data); + } + + /** + * 获取关键词回复信息 + * @param int $id + * @return array + */ + public function getKeywordInfo(int $id){ + return $this->core_wechat_reply_service->getKeywordInfo($this->site_id, $id); + } + + /** + * 新增关键词回复 + * @param array $data + * @return true + */ + public function addKeyword(array $data){ + return $this->core_wechat_reply_service->addKeyword($this->site_id, $data); + } + + /** + * 更新关键词回复 + * @param int $id + * @param array $data + * @return WechatReply + */ + public function editKeyword(int $id, array $data){ + return $this->core_wechat_reply_service->editKeyword($this->site_id, $id, $data); + } + + /** + * 删除关键词回复 + * @return void|null + */ + public function delKeyword(int $id){ + return $this->core_wechat_reply_service->delKeyword($this->site_id, $id); + } + + /** + * 获取默认回复 + * @return void|null + */ + public function getDefault(){ + return $this->core_wechat_reply_service->delKeyword($this->site_id); + } + + /** + * 更新默认回复 + * @param array $data + * @return void|null + */ + public function editDefault(array $data){ + return $this->core_wechat_reply_service->editDefault($this->site_id, $data); + } + + + /** + * 获取关注回复 + * @return array + */ + public function getSubscribe(){ + return $this->core_wechat_reply_service->getSubscribe($this->site_id); + + } + + /** + * 更新关注回复 + * @param array $data + * @return void|null + */ + public function editSubscribe(array $data){ + return $this->core_wechat_reply_service->editSubscribe($this->site_id, $data); + } +} \ No newline at end of file diff --git a/niucloud/app/service/admin/wechat/WechatTemplateService.php b/niucloud/app/service/admin/wechat/WechatTemplateService.php new file mode 100644 index 0000000..1a4bfee --- /dev/null +++ b/niucloud/app/service/admin/wechat/WechatTemplateService.php @@ -0,0 +1,99 @@ +site_id; + $core_notice_service = new CoreNoticeService(); + $list = $core_notice_service->getList($site_id, $keys); + if (empty($list)) throw new NoticeException('NOTICE_TEMPLATE_NOT_EXIST'); + foreach ($list as $v) { + $this->syncItem($v); + } + return true; + } + + /** + * @param $item + * @return true + */ + public function syncItem($item) + { + $key = $item[ 'key' ] ?? ''; + $wechat = $item[ 'wechat' ] ?? ''; + $temp_key = $wechat[ 'temp_key' ] ?? ''; + $keyword_name_list = $wechat[ 'keyword_name_list' ] ?? ''; + + if (empty($temp_key)) $error = 'WECHAT_TEMPLATE_NEED_NO'; + $wechat_template_id = $item[ 'wechat_template_id' ]; + //删除原来的消息模板 +// (new CoreWechatTemplateService())->deletePrivateTemplate($this->site_id, $wechat_template_id); + $template_loader = new TemplateLoader('wechat', [ 'site_id' => $this->site_id ]); + $template_loader->delete([ 'templateId' => $wechat_template_id ]); + //新的消息模板 +// $res = (new CoreWechatTemplateService())->addTemplate($this->site_id, $temp_key, $keyword_name_list); + $res = $template_loader->addTemplate([ 'shortId' => $temp_key, 'keyword_name_list' => $keyword_name_list ]); + $notice_service = new NoticeService(); + if (isset($res[ 'errcode' ]) && $res[ 'errcode' ] == 0) { + //修改 + $notice_service->modify($key, 'wechat_template_id', $res[ 'template_id' ]); + } else { + throw new NoticeException($res[ 'errmsg' ]); + } + return true; + } + + /** + * 获取模板消息 + * @return array + */ + public function getList() + { + $site_id = $this->site_id; + $core_notice_service = new CoreNoticeService(); + $list = $core_notice_service->getList($site_id); + $template = []; + foreach ($list as $k => $v) { + if (in_array(NoticeTypeDict::WECHAT, $v[ 'support_type' ])) $template[] = $v; + } + return $template; + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/agreement/AgreementService.php b/niucloud/app/service/api/agreement/AgreementService.php new file mode 100644 index 0000000..c04c121 --- /dev/null +++ b/niucloud/app/service/api/agreement/AgreementService.php @@ -0,0 +1,35 @@ +getAgreement($this->site_id, $key); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/captcha/CaptchaService.php b/niucloud/app/service/api/captcha/CaptchaService.php new file mode 100644 index 0000000..8c21184 --- /dev/null +++ b/niucloud/app/service/api/captcha/CaptchaService.php @@ -0,0 +1,46 @@ +create(); + } + + /** + * 核验验证码 + * @return true + */ + public function check(){ + return (new CoreCaptchaService())->check(); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/diy/DiyConfigService.php b/niucloud/app/service/api/diy/DiyConfigService.php new file mode 100644 index 0000000..a9013c5 --- /dev/null +++ b/niucloud/app/service/api/diy/DiyConfigService.php @@ -0,0 +1,52 @@ +getSiteCache($this->site_id); + if (count($site_addon[ 'apps' ]) == 1) { + $key = $site_addon[ 'apps' ][ 0 ][ 'key' ]; + } + } + return (new CoreDiyConfigService())->getBottomConfig($this->site_id, $key); + } + + /** + * 获取启动页配置 + * @return array + */ + public function getStartUpPageConfig($type) + { + return (new CoreDiyConfigService())->getStartUpPageConfig($this->site_id, $type); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/diy/DiyRouteService.php b/niucloud/app/service/api/diy/DiyRouteService.php new file mode 100644 index 0000000..e60a7ed --- /dev/null +++ b/niucloud/app/service/api/diy/DiyRouteService.php @@ -0,0 +1,68 @@ +model = new DiyRoute(); + } + + /** + * 获取页面分享信息 + * @param array $data + * @return array|void + */ + public function getShare(array $data = []) + { + $field = 'id,title,name,page,share,is_share'; + $info = $this->model->field($field)->where([ [ 'page', '=', $data[ 'route' ] ], [ 'site_id', '=', $this->site_id ] ])->findOrEmpty()->toArray(); + $share = []; + if (!empty($info[ 'share' ])) { + $share = json_decode($info[ 'share' ], true); + $share[ 'route' ] = $info[ 'page' ]; + $share[ 'query' ] = ''; + $query = []; + + if (!empty($data[ 'params' ])) { + $query = json_decode($data[ 'params' ], true); + } + + if ($this->member_id > 0) { + $query[ 'mid' ] = $this->member_id; + } + + if (!empty($query)) { + $str = []; + foreach ($query as $k => $v) { + $str[] = $k . '=' . $v; + } + $share[ 'query' ] = implode('&', $str); + } + + $share[ 'url' ] = $share[ 'route' ] . ( $share[ 'query' ] ? '?' . $share[ 'query' ] : '' ); + } + return $share; + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/diy/DiyService.php b/niucloud/app/service/api/diy/DiyService.php new file mode 100644 index 0000000..d5f9635 --- /dev/null +++ b/niucloud/app/service/api/diy/DiyService.php @@ -0,0 +1,114 @@ +model = new Diy(); + } + + /** + * 获取自定义页面信息 + * @param array $params + * @return array + */ + public function getInfo(array $params = []) + { + $start_up_page = []; + $page_template = []; + + if (!empty($params[ 'name' ])) { + + // 查询启动页 + $diy_config_service = new DiyConfigService(); + $start_up_page = $diy_config_service->getStartUpPageConfig($params[ 'name' ]); + + $page_template = TemplateDict::getTemplate([ 'key' => [ $params[ 'name' ] ] ]); + if (!empty($page_template)) { + $page_template = $page_template [ $params[ 'name' ] ]; + } + } + + if (!empty($start_up_page) && !empty($page_template) && !empty($start_up_page[ 'page' ]) && $start_up_page[ 'page' ] != $page_template[ 'page' ]) { + $info = $start_up_page; + return $info; + } else { + $condition = [ + [ 'site_id', '=', $this->site_id ] + ]; + if (!empty($params[ 'id' ])) { + $condition[] = [ 'id', '=', $params[ 'id' ] ]; + } elseif (!empty($params[ 'name' ])) { + $condition[] = [ 'name', '=', $params[ 'name' ] ]; + $condition[] = [ 'is_default', '=', 1 ]; + } + + $field = 'id,site_id,title,name,type,template, mode,value,is_default,share,visit_count'; + + $info = $this->model->field($field)->where($condition)->findOrEmpty()->toArray(); + if (empty($info)) { + // 查询默认页面数据 + if (!empty($params[ 'name' ])) { + $page_data = $this->getFirstPageData($params[ 'name' ]); + if (!empty($page_data)) { + $info = [ + 'site_id' => $this->site_id, + 'title' => $page_data[ 'title' ], + 'name' => $page_data[ 'type' ], + 'type' => $page_data[ 'type' ], + 'template' => $page_data[ 'template' ], + 'mode' => $page_data[ 'mode' ], + 'value' => json_encode($page_data[ 'data' ], JSON_UNESCAPED_UNICODE), + 'is_default' => 1, + 'share' => '', + 'visit_count' => 0 + ]; + } + } + } + return $info; + } + } + + /** + * 获取默认页面数据 + * @param $type + * @return array|mixed + */ + public function getFirstPageData($type) + { + $pages = PagesDict::getPages([ 'type' => $type ]); + if (!empty($pages)) { + $template = array_key_first($pages); + $page = array_shift($pages); + $page[ 'template' ] = $template; + $page[ 'type' ] = $type; + return $page; + } + return []; + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/login/AuthService.php b/niucloud/app/service/api/login/AuthService.php new file mode 100644 index 0000000..2cac888 --- /dev/null +++ b/niucloud/app/service/api/login/AuthService.php @@ -0,0 +1,102 @@ +model = new Member(); + } + + public function checkSiteAuth(Request $request){ + //如果登录信息非法就报错 + if($this->member_id > 0){ + $member_service = new MemberService(); + $member_info = $member_service->findMemberInfo(['member_id' => $this->member_id, 'site_id' => $this->site_id]); + if($member_info->isEmpty()) + throw new AuthException('MEMBER_NOT_EXIST'); + } + return true; + } + + /** + * 检测站点的合法性 + * @param Request $request + * @return true + */ + public function checkSite(Request $request){ + $site_id = $request->apiSiteId();//todo 可以是依赖传值,也可以通过domain域名来获取site_id + $site_info = (new CoreSiteService())->getSiteCache($site_id); + if(empty($site_info)) throw new AuthException('SITE_NOT_EXIST'); + $rule = strtolower(trim($request->rule()->getRule())); + if($rule != 'site'){ + if ($site_info['status'] == SiteDict::CLOSE || $site_info['expire_time'] < time()) throw new AuthException('SITE_CLOSE_NOT_ALLOW'); + } + $request->siteId($site_id); + return true; + } + + /** + * 绑定手机号 + * @param string $mobile + * @param string $mobile_code + * @return true + */ + public function bindMobile(string $mobile, string $mobile_code){ + + if(empty($mobile)){ + $result = (new CoreWeappAuthService())->getUserPhoneNumber($this->site_id, $mobile_code); + if(empty($result)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST'); + $phone_info = $result['phone_info']; + $mobile = $phone_info['purePhoneNumber']; + if(empty($mobile)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST'); + }else{ + //todo 校验手机号验证码 + (new LoginService())->checkMobileCode($mobile); + } + $member_service = new MemberService(); + $member = $member_service->findMemberInfo(['member_id' => $this->member_id, 'site_id' => $this->site_id]); + if($member->isEmpty()) throw new AuthException('MEMBER_NOT_EXIST'); + + $o_mobile = $member['mobile'];//原始手机号 + if(!empty($o_mobile)) throw new AuthException('MOBILE_IS_BIND_MEMBER'); + + $mobile_member = $member_service->findMemberInfo(['mobile' => $mobile, 'site_id' => $this->site_id]); + if(!$mobile_member->isEmpty()) throw new AuthException('MOBILE_IS_EXIST'); + +// if(empty($mobile)) throw new AuthException('MOBILE_NEEDED');//必须填写 + $member->save([ + 'mobile' => $mobile + ]); + return true; + } + + +} diff --git a/niucloud/app/service/api/login/LoginService.php b/niucloud/app/service/api/login/LoginService.php new file mode 100644 index 0000000..dc9d44c --- /dev/null +++ b/niucloud/app/service/api/login/LoginService.php @@ -0,0 +1,303 @@ +model = new Member(); + } + + /** + * 会员注册 + * @param $data + */ + public function register($data) + { + //检测设置是否自动注册 + //自动注册检测授权信息 + //注册登录 + } + + /** + * 登录操作 + * @param Member $member_info + * @param string $login_type + * @return array + */ + public function login(Member $member_info, string $login_type) + { + //绑定第三方授权 + $this->bingOpenid($member_info); + if (!$member_info->status) throw new ApiException('MEMBER_LOCK'); + $member_info->login_time = time(); + $member_info->login_ip = $this->request->ip(); + $member_info->login_channel = $this->channel; + $member_info->login_type = $login_type; + $member_info->login_count++; + $member_info->last_visit_time = time(); + $member_info->save(); + $token_info = $this->createToken($member_info); + event("MemberLogin", $member_info); + return [ + 'token' => $token_info['token'], + 'expires_time' => $token_info['params']['exp'], + ]; + } + + + /** + * 账号登录 + * @param string $username + * @param string $password + * @return array|false + */ + public function account(string $username, string $password) + { + $member_service = new MemberService(); + $member_info = $member_service->findMemberInfo(['username|mobile' => $username, 'site_id' => $this->site_id]); + if ($member_info->isEmpty()) throw new AuthException('MEMBER_NOT_EXIST');//账号不存在 + if (!check_password($password, $member_info->password)) return false;//密码与账号不匹配 + return $this->login($member_info, MemberLoginTypeDict::USERNAME); + } + + + /** + * 手机号登录 + * @param string $mobile + * @return array + */ + public function mobile(string $mobile){ + //校验手机验证码 + $this->checkMobileCode($mobile); + //登录注册配置 + $config = (new MemberConfigService())->getLoginConfig(); + $is_mobile = $config['is_mobile']; + if($is_mobile != 1) throw new AuthException('MOBILE_LOGIN_UNOPENED'); + $member_service = new MemberService(); + $member_info = $member_service->findMemberInfo(['mobile' => $mobile, 'site_id' => $this->site_id]); + if ($member_info->isEmpty()) throw new AuthException('MEMBER_NOT_EXIST');//账号不存在 + + return $this->login($member_info, MemberLoginTypeDict::MOBILE); + } + + /** + * 生成token + * @param $member_info + * @return array|null + */ + public function createToken($member_info): ?array + { + $expire_time = env('system.api_token_expire_time') ?? 3600;//todo 不一定和管理端合用这个token时限 + return TokenAuth::createToken($member_info->member_id, AppTypeDict::API, ['member_id' => $member_info->member_id, 'username' => $member_info->username, 'site_id' => $member_info->site_id], $expire_time); + } + + /** + * 登陆退出(当前账户) + */ + public function logout(): ?bool + { + self::clearToken($this->member_id, $this->request->apiToken()); + return true; + } + + /** + * 清理token + * @param int $member_id + * @param string|null $token + * @return bool|null + */ + public static function clearToken(int $member_id, ?string $token = ''): ?bool + { + TokenAuth::clearToken($member_id, AppTypeDict::API, $token); + return true; + } + + + /** + * 解析token + * @param string|null $token + * @return array + */ + public function parseToken(?string $token){ + if(empty($token)) + { + //定义专属于授权认证机制的错误响应, 定义专属语言包 + throw new AuthException('MUST_LOGIN', 401); + } + + try { + $token_info = TokenAuth::parseToken($token, AppTypeDict::API); + } catch ( Throwable $e ) { +// if(env('app_debug', false)){ +// throw new AuthException($e->getMessage(), 401); +// }else{ + throw new AuthException('LOGIN_EXPIRE', 401); +// } + } + if(!$token_info) + { + throw new AuthException('MUST_LOGIN', 401); + } + //验证有效次数或过期时间 + return $token_info; + } + + /** + * 手机发送验证码 + * @param $mobile + * @param string $type 发送短信的业务场景 + * @return array + * @throws Exception + */ + public function sendMobileCode($mobile, string $type = ''){ + (new CaptchaService())->check(); + if(empty($mobile)) throw new AuthException('MOBILE_NEEDED'); + //发送 + if(!in_array($type, SmsDict::SCENE_TYPE)) throw new AuthException('MEMBER_MOBILE_CAPTCHA_ERROR'); + $code = str_pad(random_int(1, 9999), 4, 0, STR_PAD_LEFT);// 生成4位随机数,左侧补0 + (new NoticeService())->send('member_verify_code', ['code' => $code, 'mobile' => $mobile]); + //将验证码存入缓存 + $key = md5(uniqid(null, true)); + $cache_tag_name = "mobile_key".$mobile.$type; + $this->clearMobileCode($mobile, $type); + Cache::tag($cache_tag_name)->set($key, [ 'mobile' => $mobile, 'code' => $code, 'type' => $type], 600); + return ['key' => $key]; + } + + public function getMobileCodeCacheName(){ + + } + + public function clearMobileCode($mobile, $type){ + $cache_tag_name = "mobile_key".$mobile.$type; + Cache::tag($cache_tag_name)->clear(); + } + + /** + * 校验手机验证码 + * @param string $mobile + * @return true + */ + public function checkMobileCode(string $mobile){ + if(empty($mobile)) throw new AuthException('MOBILE_NEEDED'); + $mobile_key = request()->param('mobile_key', ''); + $mobile_code = request()->param('mobile_code', ''); + if(empty($mobile_key) || empty($mobile_code)) throw new AuthException('MOBILE_CAPTCHA_ERROR'); + $cache = Cache::get($mobile_key); + if(empty($cache)) throw new AuthException('MOBILE_CAPTCHA_ERROR'); + $temp_mobile = $cache['mobile']; + $temp_code = $cache['code']; + $temp_type = $cache['type']; + if($temp_mobile != $mobile || $temp_code != $mobile_code) throw new AuthException('MOBILE_CAPTCHA_ERROR'); + $this->clearMobileCode($temp_mobile, $temp_type); + return true; + + } + + /** + * 绑定openid + * @param $member + * @return true + */ + public function bingOpenid($member){ + $config = (new MemberConfigService())->getLoginConfig(); + $is_auth_register = $config['is_auth_register']; + $open_id = $this->request->param('openid'); + if(!empty($open_id)){ + Log::write('channel_1'.$this->channel); + if(!empty($this->channel)){ + $openid_field = match($this->channel){ + 'wechat' => 'wx_openid', + 'weapp' => 'weapp_openid', + default => '' + }; + if(!empty($openid_field)){ + if(!$member->isEmpty()){ + if(empty($member->$openid_field)){ + //todo 定义当前第三方授权方没有退出登录功能,故这儿不做openid是否存在账号验证 +// $member_service = new MemberService(); +// $open_member = $member_service->findMemberInfo([$openid_field => $open_id, 'site_id' => $this->site_id]); + + $member->$openid_field = $open_id; + $member->save(); + }else{ + if( $member->$openid_field != $open_id){ + throw new AuthException('MEMBER_IS_BIND_AUTH'); + } + } + } + } + } + } + return true; + } + + /** + * 重置密码 + * @param string $mobile + * @param string $password + */ + public function resetPassword(string $mobile, string $password){ + $member_service = new MemberService(); + //校验手机验证码 + $this->checkMobileCode($mobile); + $member_info = $member_service->findMemberInfo(['mobile' => $mobile, 'site_id' => $this->site_id]); + if ($member_info->isEmpty()) throw new AuthException('MOBILE_NOT_EXIST_MEMBER');//账号不存在 + //todo 需要考虑一下,新的密码和原密码一样能否通过验证 + $password_hash = create_password($password); + $data = array( + 'password' => $password_hash, + ); + $member_service->editByFind($member_info, $data); + self::clearToken($member_info['member_id'], $this->request->apiToken()); + return true; + } + + public function loginScanCode(){ + + } + + public function loginByScanCode(){ + + } + + public function checkScanCode(){ + + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/login/RegisterService.php b/niucloud/app/service/api/login/RegisterService.php new file mode 100644 index 0000000..9a2a73d --- /dev/null +++ b/niucloud/app/service/api/login/RegisterService.php @@ -0,0 +1,216 @@ +model = new Member(); + } + + /** + * 会员公共注册 + * @param string $mobile + * @param $data + * @param string $type + * @param bool $is_verify_mobile + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function register(string $mobile, $data, string $type, bool $is_verify_mobile = true) + { + //校验注册方式 + if (empty(MemberRegisterTypeDict::getType()[ $type ])) + throw new AuthException('REG_CHANNEL_NOT_EXIST'); + $data = $this->bindByMobile($mobile, $data, $type, $is_verify_mobile); + $member_service = new MemberService(); + if (!is_array($data)) { + $member_id = $data; + } else { + if (empty($data[ 'nickname' ])) { + if (!empty($data[ 'username' ])) { + $data[ 'nickname' ] = $data[ 'username' ]; + } elseif (!empty($mobile)) { + $data[ 'nickname' ] = substr_replace($mobile, '****', 3, 4); + } else { + $data[ 'nickname' ] = $this->createName(); + } + } + $data[ 'register_channel' ] = $this->channel; + $data[ 'register_type' ] = $type; + $data[ 'site_id' ] = $this->site_id; + $pid = $this->request->get('pid'); + if ($pid > 0) { + $p_member_info = $member_service->findMemberInfo([ 'member_id' => $pid, 'site_id' => $this->site_id ]); + if (!$p_member_info->isEmpty()) $data[ 'pid' ] = $pid;//设置上级推荐人 + } + $member_id = ( new MemberService() )->add($data); + $data[ 'member_id' ] = $member_id; + event('MemberRegister', $data); + CoreMemberService::setMemberNo($this->site_id, $member_id); + } + $member_info = $member_service->findMemberInfo([ 'member_id' => $member_id, 'site_id' => $this->site_id ]); + if ($member_info->isEmpty()) throw new AuthException('MEMBER_NOT_EXIST');//账号已存在 + return ( new LoginService() )->login($member_info, $type); + } + + /** + * 随机创建一个昵称 + * @return string + */ + public function createName() + { + $microtime = substr(microtime(true), strpos(microtime(true), '.') + 1); + $chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $username = ''; + for ($i = 0; $i < 6; $i++) { + $username .= $chars[ random_int(0, (strlen($chars) - 1)) ]; + } + + return $microtime . strtoupper(base_convert(time() - 1420070400, 10, 36)) . $username; + + } + + /** + * 账号注册 + * @param string $username + * @param string $password + * @param $mobile + * @return array + */ + public function account(string $username, string $password, $mobile) + { + //todo 校验验证码 可以加try catch 后续 + ( new CaptchaService() )->check(); + + //登录注册配置 + $config = ( new MemberConfigService() )->getLoginConfig(); + $is_username = $config[ 'is_username' ]; + //未开启账号密码登录注册 + if ($is_username != 1) throw new AuthException('MEMBER_USERNAME_LOGIN_NOT_OPEN'); + $member_service = new MemberService(); + $member_info = $member_service->findMemberInfo([ 'username' => $username, 'site_id' => $this->site_id ]); + if (!$member_info->isEmpty()) throw new AuthException('MEMBER_IS_EXIST');//账号已存在 + + $password_hash = create_password($password); + $data = array ( + 'username' => $username, + 'password' => $password_hash, + ); + return $this->register($mobile, $data, MemberRegisterTypeDict::USERNAME); + } + + /** + * 手机号注册 + * @param $mobile + * @return array + */ + public function mobile($mobile) + { + //登录注册配置 + $config = ( new MemberConfigService() )->getLoginConfig(); + $is_mobile = $config[ 'is_mobile' ]; + //未开启账号密码登录注册 + if ($is_mobile != 1) throw new AuthException('MEMBER_USERNAME_LOGIN_NOT_OPEN'); + $member_service = new MemberService(); + $member_info = $member_service->findMemberInfo([ 'mobile' => $mobile, 'site_id' => $this->site_id ]); + if (!$member_info->isEmpty()) throw new AuthException('MEMBER_IS_EXIST');//账号已存在 + + $data = array ( + 'mobile' => $mobile, + ); + return $this->register($mobile, $data, MemberRegisterTypeDict::MOBILE); + } + + /** + * 校验是否启用第三方登录注册 + * @return true + */ + public function checkAuth() + { + $config = ( new MemberConfigService() )->getLoginConfig(); + $is_auth_register = $config[ 'is_auth_register' ]; + if ($is_auth_register != 1) throw new AuthException('AUTH_LOGIN_NOT_OPEN');//手机号已存在 + return true; + } + + /** + * 通过手机号尝试绑定已存在会员,没有就绑定数据(todo 仅限注册使用) + * @param string $mobile + * @param array $data + * @param string $type + * @param bool $is_verify + * @return array|mixed + */ + public function bindByMobile($mobile, array $data, string $type, bool $is_verify = true) + { + $config = ( new MemberConfigService() )->getLoginConfig(); + $is_bind_mobile = $config[ 'is_bind_mobile' ]; + + $with_field = match($type){ + MemberLoginTypeDict::USERNAME => 'username', + MemberLoginTypeDict::MOBILE => 'mobile', + MemberLoginTypeDict::WECHAT => 'wx_openid', + MemberLoginTypeDict::WEAPP => 'weapp_openid', + }; + if ($type == MemberLoginTypeDict::MOBILE || $is_bind_mobile == 1) { + if (empty($mobile)) throw new AuthException('MOBILE_NEEDED');//必须填写 + //todo 校验手机号验证码 + if ($is_verify) { + ( new LoginService() )->checkMobileCode($mobile); + } + if ($is_bind_mobile == 1) { + $member_service = new MemberService(); + $member = $member_service->findMemberInfo([ 'mobile' => $mobile, 'site_id' => $this->site_id ]); + if (!$member->isEmpty()) { + if ($type == MemberLoginTypeDict::MOBILE) { + throw new AuthException('MOBILE_IS_EXIST');//手机号注册时发现手机号已存在账号 + } else { + if ($member->$with_field != '') throw new AuthException('MOBILE_IS_EXIST');//手机号已存在 + foreach ($data as $k => $v) { + $member->$k = $v; + } + $member->save(); + return $member->member_id; + } + } + } + $data[ 'mobile' ] = $mobile; + } + return $data; + } + + +} diff --git a/niucloud/app/service/api/member/AddressService.php b/niucloud/app/service/api/member/AddressService.php new file mode 100644 index 0000000..8bbc132 --- /dev/null +++ b/niucloud/app/service/api/member/AddressService.php @@ -0,0 +1,101 @@ +model = new MemberAddress(); + } + + /** + * 获取会员收货地址列表 + * @param array $where + * @return array + */ + public function getList(array $where = []) + { + $field = 'id,member_id,name,mobile,address,address_name,full_address,is_default,type'; + $order = 'is_default desc, id desc'; + + $list = $this->model->where([ ['site_id', '=', $this->site_id],['member_id', '=', $this->member_id ] ])->withSearch(["type"], $where)->field($field)->order($order)->select()->toArray(); + return $list; + } + + /** + * 获取会员收货地址信息 + * @param int $id + * @return array + */ + public function getInfo(int $id) + { + $field = 'id,member_id,name,mobile,province_id,city_id,district_id,address,address_name,full_address,lng,lat,is_default,type'; + + $info = $this->model->field($field)->where([ ['id', '=', $id], ['site_id', '=', $this->site_id], ['member_id', '=', $this->member_id ] ])->findOrEmpty()->toArray(); + return $info; + } + + /** + * 添加会员收货地址 + * @param array $data + * @return mixed + */ + public function add(array $data) + { + if ($data['is_default']) { + $this->model->where([ ['member_id', '=', $this->member_id ], ['type', '=', $data['type']] ])->update(['is_default' => 0]); + } + $data['member_id'] = $this->member_id; + $data['site_id'] = $this->site_id; + $res = $this->model->create($data); + return $res->id; + } + + /** + * 会员收货地址编辑 + * @param int $id + * @param array $data + * @return bool + */ + public function edit(int $id, array $data) + { + if ($data['is_default']) { + $this->model->where([ ['member_id', '=', $this->member_id ], ['type', '=', $data['type']] ])->update(['is_default' => 0]); + } + $this->model->where([ ['id', '=', $id], ['site_id', '=', $this->site_id], ['member_id', '=', $this->member_id ] ])->update($data); + return true; + } + + /** + * 删除会员收货地址 + * @param int $id + * @return bool + */ + public function del(int $id) + { + $model = $this->model->where([ ['id', '=', $id], ['site_id', '=', $this->site_id], ['member_id', '=', $this->member_id ] ])->find(); + $res = $model->delete(); + return $res; + } + +} diff --git a/niucloud/app/service/api/member/MemberAccountService.php b/niucloud/app/service/api/member/MemberAccountService.php new file mode 100644 index 0000000..9c01ad3 --- /dev/null +++ b/niucloud/app/service/api/member/MemberAccountService.php @@ -0,0 +1,67 @@ +model = new MemberAccountLog(); + } + + /** + * 会员账户流水列表 + * @param array $where + * @return array + */ + public function getPage(array $where = []) + { + $where['member_id'] = $this->member_id; + $field = 'id, member_id, site_id, account_type, account_data, from_type, related_id, create_time, memo'; + $search_model = $this->model->where([['site_id', '=', $this->site_id]])->withSearch(['member_id','account_type', 'from_type', 'create_time'],$where)->field($field)->order('create_time desc')->append(['from_type_name', 'account_type_name']); + return $this->pageQuery($search_model); + } + /** + * 账户流水详情 + * @param int $id + * @return array + */ + public function getInfo(int $id) + { + $field = 'id, member_id, site_id, account_type, account_data, from_type, related_id, create_time, memo'; + return $this->model->where([['id', '=', $id], ['site_id', '=', $this->site_id], ['member_id', '=', $this->member_id]])->field($field)->append(['from_type_name', 'account_type_name'])->findOrEmpty()->toArray(); + } + + /** + * 会员账户统计数量 + * @param array $where + * @return int + * @throws DbException + */ + public function getCount(array $where = []){ + $where['member_id'] = $this->member_id; + + return $this->model->where([['site_id', '=', $this->site_id]])->withSearch(['member_id','account_type', 'from_type', 'create_time'],$where)->count(); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/member/MemberCashOutAccountService.php b/niucloud/app/service/api/member/MemberCashOutAccountService.php new file mode 100644 index 0000000..36ec0f2 --- /dev/null +++ b/niucloud/app/service/api/member/MemberCashOutAccountService.php @@ -0,0 +1,110 @@ +model = new MemberCashOutAccount(); + } + + /** + * 会员提现账户列表 + * @param array $where + * @return array + */ + public function getPage(array $where = []) + { + $where['member_id'] = $this->member_id; + $where['site_id'] = $this->site_id; + $field = 'account_id,site_id,member_id,account_type,bank_name,realname,account_no'; + $search_model = $this->model->where($where)->field($field)->order('create_time desc'); + + return $this->pageQuery($search_model); + } + + /** + * 提现账户详情 + * @param int $account_id + * @return array + */ + public function getInfo(int $account_id) + { + $field = 'account_id,site_id,member_id,account_type,bank_name,realname,account_no'; + return $this->model->where([['account_id', '=', $account_id], ['site_id', '=', $this->site_id], ['member_id', '=', $this->member_id]])->field($field)->findOrEmpty()->toArray(); + } + + /** + * 获取首条信息 + * @param array $where + * @param string $order_field + * @param string $order + * @return array + */ + public function getFirstInfo(array $where, $order_field = 'create_time', string $order = 'desc'){ + $where[] = ['site_id', '=', $this->site_id]; + $where[] = ['member_id', '=', $this->member_id]; + $field = 'account_id,site_id,member_id,account_type,bank_name,realname,account_no'; + return $this->model->where($where)->order($order_field, $order)->field($field)->findOrEmpty()->toArray(); + } + + /** + * 添加提现账号 + * @param array $data + * @return int + */ + public function add(array $data) + { + $data['site_id'] = $this->site_id; + $data['member_id'] = $this->member_id; + $data['create_time'] = time(); + $res = $this->model->create($data); + return $res->account_id; + } + + /** + * 修改提现账户 + * @param int $account_id + * @param array $data + * @return true + */ + public function edit(int $account_id, array $data) + { + $data['update_time'] = time(); + $this->model->update($data, [ [ 'site_id', '=', $this->site_id ], [ 'member_id', '=', $this->member_id ], ['account_id', '=', $account_id] ]); + return true; + } + + /** + * 删除 + * @param int $account_id + * @return true + */ + public function del(int $account_id) + { + $where = [ + ['member_id', '=', $this->member_id], + ['site_id', '=', $this->site_id], + ['account_id', '=', $account_id] + ]; + $this->model->where($where)->delete(); + return true; + } +} \ No newline at end of file diff --git a/niucloud/app/service/api/member/MemberCashOutService.php b/niucloud/app/service/api/member/MemberCashOutService.php new file mode 100644 index 0000000..f7cf0ee --- /dev/null +++ b/niucloud/app/service/api/member/MemberCashOutService.php @@ -0,0 +1,104 @@ +model = new MemberCashOut(); + } + + /** + * 会员提现列表 + * @param array $where + * @return array + */ + public function getPage(array $where = []) + { + $where['member_id'] = $this->member_id; + $where['site_id'] = $this->site_id; + $field = 'id,site_id,cash_out_no,member_id,account_type,transfer_type,transfer_realname,transfer_mobile,transfer_bank,transfer_account,transfer_status,transfer_time,apply_money,rate,service_money,money,audit_time,status,remark,create_time,refuse_reason'; + $search_model = $this->model->where($where)->withSearch(['member_id','status', 'create_time'],$where)->with(['memberInfo', 'transfer'])->field($field)->append(['account_type_name', 'transfer_type_name', 'status_name', 'transfer_status_name'])->order('create_time desc'); + + return $this->pageQuery($search_model); + } + + /** + * 提现详情 + * @param int $id + * @return array + */ + public function getInfo(int $id) + { + $field = 'id,site_id,cash_out_no,member_id,transfer_type,transfer_realname,transfer_mobile,transfer_bank,transfer_account,transfer_fail_reason,transfer_time,apply_money,rate,service_money,money,audit_time,status,remark,create_time,refuse_reason'; + return $this->model->where([['id', '=', $id], ['site_id', '=', $this->site_id], ['member_id', '=', $this->member_id]])->with(['memberInfo', 'transfer'])->field($field)->append(['account_type_name', 'transfer_type_name', 'status_name', 'transfer_status_name'])->findOrEmpty()->toArray(); + } + + + /** + * 申请提现 + * @param array $data + * @return true + */ + public function apply(array $data){ + + return (new CoreMemberCashOutService())->apply($this->site_id, $this->member_id, $data); + } + + + /** + * 撤销提现申请 + * @param int $id + * @return true + */ + public function cancel(int $id){ + $cash_out = $this->model->where([ + ['site_id', '=', $this->site_id], + ['id', '=', $id], + ['member_id', '=', $this->member_id], + ])->findOrEmpty(); + + if($cash_out->isEmpty()) throw new ApiException('RECHARGE_LOG_NOT_EXIST'); + if($cash_out['status'] != MemberCashOutDict::WAIT_AUDIT) throw new CommonException('CASHOUT_STATUS_NOT_IN_WAIT_AUDIT'); + $cash_out->save( + + [ + 'cancel_time' => time(), + 'status' => MemberCashOutDict::CANCEL + ] + ); + (new CoreMemberCashOutService())->giveback($this->site_id, $cash_out); + return true; + } + + /** + * 获取提现配置 + * @return array + */ + public function getCashOutConfig(){ + return (new CoreMemberConfigService())->getCashOutConfig($this->site_id); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/member/MemberConfigService.php b/niucloud/app/service/api/member/MemberConfigService.php new file mode 100644 index 0000000..24026a0 --- /dev/null +++ b/niucloud/app/service/api/member/MemberConfigService.php @@ -0,0 +1,32 @@ +getLoginConfig($this->site_id); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/member/MemberLogService.php b/niucloud/app/service/api/member/MemberLogService.php new file mode 100644 index 0000000..87b3fed --- /dev/null +++ b/niucloud/app/service/api/member/MemberLogService.php @@ -0,0 +1,40 @@ +edit(['last_visit_time' => time()]); + return true; + } + + +} \ No newline at end of file diff --git a/niucloud/app/service/api/member/MemberService.php b/niucloud/app/service/api/member/MemberService.php new file mode 100644 index 0000000..f45dfea --- /dev/null +++ b/niucloud/app/service/api/member/MemberService.php @@ -0,0 +1,146 @@ +model = new Member(); + } + + /** + * 新增会员 + */ + public function add(array $data){ + $data['site_id'] = $this->site_id; + return $this->model->create($data)?->member_id ?? 0; + } + + /** + * 更新会员 + * @param array $data + * @return true + */ + public function edit(array $data) + { + $member = $this->findMemberInfo(['member_id' => $this->member_id, 'site_id' => $this->site_id]); + + if($member->isEmpty()) throw new ApiException('MEMBER_NOT_EXIST'); + $member->allowField(['nickname', 'headimg', 'birthday', 'sex', 'last_visit_time'])->save($data); + return true; + } + + /** + * 获取会员信息 + * @return array + */ + public function getInfo() + { + $field = 'member_id, site_id, username, member_no, mobile, register_channel, nickname, headimg, member_level, member_label, login_ip, login_type, login_time, create_time, last_visit_time, last_consum_time, sex, status, birthday, point, balance, growth, is_member, member_time, is_del, province_id, city_id, district_id, address, location, money, money_get, wx_openid, weapp_openid, commission, commission_get, commission_cash_outing'; + return $this->model->where([['member_id', '=', $this->member_id]])->field($field)->append(['sex_name'])->findOrEmpty()->toArray(); + } + + /** + * 会员中心信息 + */ + public function center() + { + $field = 'member_id, site_id, username, member_no, mobile, register_channel, nickname, headimg, member_level, member_label, login_ip, login_type, login_time, create_time, last_visit_time, last_consum_time, sex, status, birthday, point, balance, growth, is_member, member_time, is_del, province_id, city_id, district_id, address, location, money, money_get, commission, commission_get, commission_cash_outing'; + return $this->model->where([['member_id', '=', $this->member_id]])->field($field)->append(['sex_name'])->findOrEmpty()->toArray(); + } + + /** + * 获取会员的模型对象(todo 慎用!!! 现主要用于登录) + * @param array $data + * @return Member|array|mixed|Model !!! 仔细看,返回值是模型对象 如果想要判断是否为空 请用 $member->isEmpty() + */ + public function findMemberInfo(array $data){ + //会员账号 + if(!empty($data['username'])) + $where[] = ['username', '=', $data['username']]; + //会员手机号 + if(!empty($data['mobile'])) + $where[] = ['mobile', '=', $data['mobile']]; + //会员id + if(!empty($data['member_id'])) + $where[] = ['member_id', '=', $data['member_id']]; + //微信公众号openid + if(!empty($data['wx_openid'])) + $where[] = ['wx_openid', '=', $data['wx_openid']]; + //微信小程序openid + if(!empty($data['weapp_openid'])) + $where[] = ['weapp_openid', '=', $data['weapp_openid']]; + + if(!empty($data['username|mobile'])) + $where[] = ['username|mobile', '=', $data['username|mobile']]; + if(empty($where)){ + $where[] = ['member_id', '=', -1]; + } + if(isset($data['site_id']) ) + $where[] = ['site_id', '=', $data['site_id']]; + return $this->model->where($where)->findOrEmpty(); + } + + /** + * 通过对象修改会员信息 + * @param $member + * @param $data + * @return void + */ + public function editByFind($member, $data){ + return $member->save($data); + } + + /** + * 修改字段 + * @param string $field + * @param $data + * @return null + */ + public function modify(string $field, $data) + { + return (new CoreMemberService())->modify($this->site_id, $this->member_id, $field, $data); + } + + public function getQrcode(){ + // 生成会员二维码 + $qrcode_dir = 'upload/member/temp'; + if (!is_dir($qrcode_dir)) mkdir($qrcode_dir, intval('0755', 8), true); + $id = "member-".$this->member_id; + $qrcode_path = "{$qrcode_dir}/order_qrcode_{$this->member_id}.png"; + \core\util\QRcode::png($id, $qrcode_path, 'L', 16, 1); + + // 生成会员条形码 + $barcode_path = (new Barcode(14, $id))->generateBarcode($qrcode_dir, 2); + $detail = []; + $detail['verify_code_qrcode'] = image_to_base64($qrcode_path, true); + $detail['verify_code_barcode'] = image_to_base64($barcode_path); + return $detail; + } +} \ No newline at end of file diff --git a/niucloud/app/service/api/notice/NoticeService.php b/niucloud/app/service/api/notice/NoticeService.php new file mode 100644 index 0000000..153d38a --- /dev/null +++ b/niucloud/app/service/api/notice/NoticeService.php @@ -0,0 +1,49 @@ +send($this->site_id, $key, $data); + } + + /** + * 获取微信小程序订阅消息模板id + * @param string $keys + * @return array + */ + public function getWeappNoticeTemplateId(string $keys) { + return (new SysNotice())->where([ ['site_id', '=', $this->site_id], ['key', 'in', explode(',', $keys) ], ['weapp_template_id', '<>', ''], ['is_weapp', '=', 1] ])->column('weapp_template_id'); + } +} \ No newline at end of file diff --git a/niucloud/app/service/api/order/RechargeOrderService.php b/niucloud/app/service/api/order/RechargeOrderService.php new file mode 100644 index 0000000..d8126af --- /dev/null +++ b/niucloud/app/service/api/order/RechargeOrderService.php @@ -0,0 +1,95 @@ +model = new RechargeOrder(); + } + + /** + * 会员充值 + * @param $data //['order_from' => 'h5', 'ip' => '127.0.0.1', 'member_message' => '','recharge_money' => 12.00] + */ + public function recharge(array $data) + { + $data['order_from'] = $this->channel; + $data['site_id'] = $this->site_id; + $data['member_id'] = $this->member_id; + return (new CoreRechargeOrderService())->create($data); + } + + + /** + * 充值订单分页列表 + * @param array $where + * @return array + */ + public function getPage(array $where) + { + $field = 'order_id, site_id, order_no, order_from, order_type, out_trade_no, order_status, refund_status, member_id, ip, member_message, order_item_money, order_discount_money, order_money, create_time, pay_time, close_time, is_delete, is_enable_refund, remark, invoice_id, close_reason'; + $order = 'create_time desc'; + $where['order_type'] = 'recharge'; + $search_model = $this->model->where([ ['site_id', '=', $this->site_id], ['member_id', '=', $this->member_id] ])->withSearch(['order_status'], $where)->field($field)->with(['item' => function($query) { + $query->field('order_item_id, order_id, member_id, item_id, item_type, item_name, item_image, price, num, item_money, is_refund, refund_no, refund_status, create_time'); + }])->order($order)->append(['order_from_name']); + $list = $this->pageQuery($search_model); + $order_status = RechargeOrderDict::getStatus(); + //$refund_status = RechargeOrderDict::getRefundStatus(); + foreach ($list['data'] as $k => $v) + { + $list['data'][$k]['order_status_info'] = $order_status[$v['order_status']] ?? []; + // $list['data'][$k]['refund_status_name'] = $refund_status[$v['refund_status']]['name'] ?? ''; + } + return $list; + } + + /** + * 充值订单详情 + * @param int $order_id + * @return array + */ + public function getDetail(int $order_id) + { + $field = 'order_id, site_id, order_no, order_from, order_type, out_trade_no, order_status, refund_status, member_id, ip, member_message, order_item_money, order_discount_money, order_money, create_time, pay_time, close_time, is_delete, is_enable_refund, remark, invoice_id, close_reason'; + $detail = $this->model->where([['order_type', '=', 'recharge'], ['site_id', '=', $this->site_id], ['member_id', '=', $this->member_id], ['order_id', '=', $order_id]])->field($field)->with(['item' => function($query) { + $query->field('order_item_id, order_id, member_id, item_id, item_type, item_name, item_image, price, num, item_money, is_refund, refund_no, refund_status, create_time'); + }])->append(['order_from_name'])->findOrEmpty()->toArray(); + if(!empty($detail)) + { + $detail['order_status_info'] = RechargeOrderDict::getStatus($detail['order_status']) ?? []; + } + return $detail; + } + + /** + * 充值订单状态 + * @return array|array[]|string + */ + public function getStatus() + { + return RechargeOrderDict::getStatus(); + } +} \ No newline at end of file diff --git a/niucloud/app/service/api/pay/PayService.php b/niucloud/app/service/api/pay/PayService.php new file mode 100644 index 0000000..1a1bee3 --- /dev/null +++ b/niucloud/app/service/api/pay/PayService.php @@ -0,0 +1,108 @@ +core_pay_service = new CorePayService(); + } + + /** + * 去支付 + * @param string $type + * @param string $trade_type + * @param int $trade_id + * @param string $return_url + * @param string $quit_url + * @param string $buyer_id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function pay(string $type, string $trade_type, int $trade_id, string $return_url = '', string $quit_url = '', string $buyer_id = '', string $voucher = ''){ + + $member = (new CoreMemberService())->getInfoByMemberId($this->site_id, $this->member_id); + switch ($this->channel) { + case ChannelDict::WECHAT://公众号 + $openid = $member['wx_openid'] ?? ''; + break; + case ChannelDict::WEAPP://微信小程序 + $openid = $member['weapp_openid'] ?? ''; + break; + } + + return $this->core_pay_service->pay($this->site_id, $trade_type, $trade_id, $type, $this->channel, $openid ?? '', $return_url, $quit_url, $buyer_id, $voucher); + } + + /** + * 关闭支付 + * @param string $type + * @param string $out_trade_no + * @return null + */ + public function close(string $type, string $out_trade_no){ + return $this->core_pay_service->close($this->site_id, $type); + } + + /** + * 支付异步通知 + * @param string $channel + * @param string $type + * @param string $action + * @return void|null + */ + public function notify(string $channel, string $type, string $action){ + return $this->core_pay_service->notify($this->site_id, $channel, $type, $action); + } + + /** + * 通过交易流水号查询支付信息以及支付方式 + * @param $out_trade_no + * @return array + */ + public function getInfoByOutTradeNo($out_trade_no){ + return $this->core_pay_service->getInfoByOutTradeNo($this->site_id, $out_trade_no, $this->channel); + } + + public function getInfoByTrade(string $trade_type, int $trade_id){ + return $this->core_pay_service->getInfoByTrade($this->site_id, $trade_type, $trade_id, $this->channel); + } + + /** + * 获取支付方法 + * @param string $trade_type + * @return array|array[] + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getPayTypeByTrade(string $trade_type){ + return $this->core_pay_service->getPayTypeByTrade($this->site_id, $trade_type, $this->channel); + } +} \ No newline at end of file diff --git a/niucloud/app/service/api/scan/ScanService.php b/niucloud/app/service/api/scan/ScanService.php new file mode 100644 index 0000000..93dfdbc --- /dev/null +++ b/niucloud/app/service/api/scan/ScanService.php @@ -0,0 +1,44 @@ +core_scan_service = new CoreScanService(); + } + + + /** + * 校验扫码信息 + * @param string $key + * @return mixed + */ + public function checkScan(string $key) + { + return $this->core_scan_service->checkScan($this->site_id, $key); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/site/SiteService.php b/niucloud/app/service/api/site/SiteService.php new file mode 100644 index 0000000..c1af9c8 --- /dev/null +++ b/niucloud/app/service/api/site/SiteService.php @@ -0,0 +1,43 @@ +model = new Site(); + } + + + + /** + * 获取授权当前站点信息(用做缓存) + * @return mixed + */ + public function getSiteCache(){ + + return (new CoreSiteService())->getSiteCache($this->site_id); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/sys/AreaService.php b/niucloud/app/service/api/sys/AreaService.php new file mode 100644 index 0000000..70444e4 --- /dev/null +++ b/niucloud/app/service/api/sys/AreaService.php @@ -0,0 +1,100 @@ +model = new SysArea(); + } + + /** + * 获取地区信息 + * @param int $pid //上级pid + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getListByPid(int $pid = 0) + { + + $cache_name = self::$cache_tag_name.'_api_pid_'.$pid; + return cache_remember( + $cache_name, + function() use($pid) { + return $this->model->where([['pid', '=', $pid]])->field('id, name')->select()->toArray(); + }, + [self::$cache_tag_name] + ); + } + + /** + * 查询地区树列表 + * @param int $level //层级1,2,3 + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getAreaTree(int $level = 3) + { + $cache_name = self::$cache_tag_name.'_api_tree_'.$level; + return cache_remember( + $cache_name, + function() use($level) { + $list = $this->model->where([['level', '<=', $level]])->field('id, pid, name')->select()->toArray(); + return list_to_tree($list); + }, + [self::$cache_tag_name] + ); + } + + public function getAreaByAreaCode($id) { + $cache_name = self::$cache_tag_name.'_api_area_'. $id; + return cache_remember( + $cache_name, + function() use($id) { + $level = [1 => 'province', 2 => 'city', 3 => 'district']; + $tree = []; + $area = $this->model->where([ ['id', '=', $id] ])->field('id,level,pid,name')->findOrEmpty(); + + if (!$area->isEmpty()) { + $tree[ $level[ $area['level'] ] ] = $area->toArray(); + + while ($area['level'] > 1) { + $area = $this->model->where([ ['id', '=', $area['pid'] ] ])->field('id,level,pid,name')->findOrEmpty(); + $tree[ $level[ $area['level'] ] ] = $area->toArray(); + } + } + return $tree; + }, + [self::$cache_tag_name] + ); + } + +} diff --git a/niucloud/app/service/api/sys/ConfigService.php b/niucloud/app/service/api/sys/ConfigService.php new file mode 100644 index 0000000..2cf716e --- /dev/null +++ b/niucloud/app/service/api/sys/ConfigService.php @@ -0,0 +1,59 @@ +getCopyright($this->site_id); + } + + /** + * 获取前端域名 + * @return array|string[] + */ + public function getSceneDomain(){ + return (new CoreSysConfigService())->getSceneDomain($this->site_id); + } + + /** + * 获取手机端首页列表 + * @param $data + * @return array + */ + public function getWapIndexList($data) + { + return ( new CoreSysConfigService() )->getWapIndexList($data); + } +} diff --git a/niucloud/app/service/api/upload/Base64Service.php b/niucloud/app/service/api/upload/Base64Service.php new file mode 100644 index 0000000..6f9582f --- /dev/null +++ b/niucloud/app/service/api/upload/Base64Service.php @@ -0,0 +1,42 @@ +root_path.'/'.'image'.'/'.$this->site_id.'/'.date('Ym').'/'.date('d'); + $core_base64_service = new CoreBase64Service(); + return $core_base64_service->image($content, $this->site_id, $dir); + } + + +} \ No newline at end of file diff --git a/niucloud/app/service/api/upload/FetchService.php b/niucloud/app/service/api/upload/FetchService.php new file mode 100644 index 0000000..96dab57 --- /dev/null +++ b/niucloud/app/service/api/upload/FetchService.php @@ -0,0 +1,42 @@ +root_path.'/'.'image'.'/'.$this->site_id.'/'.date('Ym').'/'.date('d'); + $core_upload_service = new CoreFetchService(); + return $core_upload_service->image($url, $this->site_id, $dir); + } + + +} \ No newline at end of file diff --git a/niucloud/app/service/api/upload/UploadService.php b/niucloud/app/service/api/upload/UploadService.php new file mode 100644 index 0000000..6c1e23b --- /dev/null +++ b/niucloud/app/service/api/upload/UploadService.php @@ -0,0 +1,72 @@ +root_path . '/' . 'image' . '/' . $this->site_id . '/' . date('Ym') . '/' . date('d'); + $core_upload_service = new CoreUploadService(); + return $core_upload_service->image($file, $this->site_id, $dir, $this->cate_id); + } + + /** + * 附件库上传视频 + * @param $file + * @return array + * @throws Exception + */ + public function video($file) + { + $dir = $this->root_path . '/' . 'video' . '/' . $this->site_id . '/' . date('Ym') . '/' . date('d'); + $core_upload_service = new CoreUploadService(); + return $core_upload_service->video($file, $this->site_id, $dir, $this->cate_id); + } + + /** + * 文件上传 + * @param $file + * @param string $type + * @return array + * @throws Exception + */ + public function document($file, string $type = '') + { + if(!in_array($type, FileDict::getSceneType())) + throw new UploadFileException('UPLOAD_TYPE_ERROR'); + $dir = $this->root_path.'/document/'.$type.'/'.$this->site_id.'/'.date('Ym').'/'.date('d'); + $core_upload_service = new CoreUploadService(); + return $core_upload_service->document($file, $this->site_id, $type, $dir, StorageDict::LOCAL); + } +} \ No newline at end of file diff --git a/niucloud/app/service/api/weapp/WeappAuthService.php b/niucloud/app/service/api/weapp/WeappAuthService.php new file mode 100644 index 0000000..134357d --- /dev/null +++ b/niucloud/app/service/api/weapp/WeappAuthService.php @@ -0,0 +1,158 @@ +core_weapp_serve_service = new CoreWeappAuthService(); + } + + /** + * 通过code获取微信小程序用户信息 + * @param string $code + * @return array + * @throws InvalidConfigException + */ + public function getUserInfoByCode(string $code){ +// $iv = $this->request->param('iv', ''); +// $encrypted_data = $this->request->param('encrypted_data', ''); + $result = $this->core_weapp_serve_service->session($this->site_id, $code); +// if(empty($result)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST'); +// $userinfo = $this->core_weapp_serve_service->decryptData($result['session_key'], $iv, $encrypted_data); + $openid = $result['openid'] ?? '';//对应微信的 openid + $unionid = $result['unionid'] ?? '' ;//对应微信的 unionid + if(empty($openid)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST'); + //todo 这儿还可能会获取用户昵称 头像 性别 ....用以更新会员信息 +// $nickname = $userinfo['nickName'] ?? '';//对应微信的 nickname +// $avatar = $userinfo['avatarUrl'] ?? '';//对应微信的 头像地址 +// $sex = $userinfo['gender'];//性别 + return [ + $openid, + $unionid, +// $avatar, +// $nickname, +// $sex + ]; + } + + /** + * 登录 + * @param string $code + * @return array + */ + public function login(string $code) + { + + [ + $openid, + $unionid, +// $avatar, +// $nickname, +// $sex + ] = $this->getUserInfoByCode($code); + + $member_service = new MemberService(); + $member_info = $member_service->findMemberInfo(['weapp_openid' => $openid, 'site_id' => $this->site_id]); + if($member_info->isEmpty()){ + $config = (new MemberConfigService())->getLoginConfig(); + $is_bind_mobile = $config['is_bind_mobile']; + $is_auth_register = $config['is_auth_register']; + if($is_bind_mobile == 0 && $is_auth_register == 1){ + return $this->register($openid); + }else{ + return ['openid' => $openid]; + } + }else{ + //可能会更新用户和粉丝表 + $login_service = new LoginService(); + return $login_service->login($member_info, MemberLoginTypeDict::WEAPP); + } + //todo 业务落地 + + } + + /** + * 注册 + * @param string $openid + * @param string $mobile + * @param string $mobile_code + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws GuzzleException + * @throws InvalidConfigException + * @throws ModelNotFoundException + */ + public function register(string $openid, string $mobile = '', string $mobile_code = ''){ + + if(empty($openid)) throw new AuthException('AUTH_LOGIN_TAG_NOT_EXIST'); + //todo openid可能还需要合法性验证 + $config = (new MemberConfigService())->getLoginConfig(); + $is_bind_mobile = $config['is_bind_mobile']; + if($is_bind_mobile == 1){ + if(empty($mobile)){ + $result = $this->core_weapp_serve_service->getUserPhoneNumber($this->site_id, $mobile_code); + if(empty($result)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST'); + $phone_info = $result['phone_info']; + $mobile = $phone_info['purePhoneNumber']; + if(empty($mobile)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST'); + $is_verify_mobile = false; + }else{ + $is_verify_mobile = true; + } + } + $member_service = new MemberService(); + $member_info = $member_service->findMemberInfo(['weapp_openid' => $openid, 'site_id' => $this->site_id]); + + if(!$member_info->isEmpty()) throw new AuthException('MEMBER_IS_EXIST');//账号已存在, 不能在注册 + $register_service = new RegisterService(); + return $register_service->register($mobile ?? '', + [ + 'weapp_openid' => $openid + ], + MemberRegisterTypeDict::WEAPP, + $is_verify_mobile ?? false + ); + + } + +} \ No newline at end of file diff --git a/niucloud/app/service/api/wechat/WechatAuthService.php b/niucloud/app/service/api/wechat/WechatAuthService.php new file mode 100644 index 0000000..fc6d92f --- /dev/null +++ b/niucloud/app/service/api/wechat/WechatAuthService.php @@ -0,0 +1,206 @@ +core_wechat_serve_service = new CoreWechatServeService(); + } + + /** + * 网页授权 + * @param string $url + * @param string $scopes + * @return array + */ + public function authorization(string $url = '', string $scopes = 'snsapi_base') + { + //todo 业务落地 + return ['url' => $this->core_wechat_serve_service->authorization($this->site_id, $url, $scopes)]; + } + + /** + * 处理授权回调 + * @param string $code + * @return array + */ + public function userFromCode(string $code) + { + $userinfo = $this->core_wechat_serve_service->userFromCode($this->site_id, $code); + if (empty($userinfo)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST'); + $token_response = $userinfo->getTokenResponse(); + if (empty($token_response)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST'); + $scope = $token_response['scope']; + if ($scope == 'snsapi_base') {//静默授权 + $openid = $token_response['openid'] ?? ''; + } else { + $openid = $userinfo->getId();//对应微信的 openid + $nickname = $userinfo->getNickname();//对应微信的 nickname + $avatar = $userinfo->getAvatar();//对应微信的 头像地址 + } + if (empty($openid)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST'); + //todo 这儿还可能会获取用户昵称 头像 性别 ....用以更新会员信息 + return [$avatar ?? '', $nickname ?? '', $openid]; + //todo 业务落地 + } + + /** + * 登录通过code + * @param string $code + * @return array|string[]|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function loginByCode(string $code){ + [$avatar, $nickname, $openid] = $this->userFromCode($code); + return $this->login($openid, $nickname, $avatar); + } + + /** + * 公众号登录 + * @param string $openid + * @param string $nickname + * @param string $avatar + * @return array|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function login(string $openid, string $nickname = '', string $avatar = '') + { + + $member_service = new MemberService(); + $member_info = $member_service->findMemberInfo(['wx_openid' => $openid, 'site_id' => $this->site_id]); + if ($member_info->isEmpty()) { + $config = (new MemberConfigService())->getLoginConfig(); + $is_bind_mobile = $config['is_bind_mobile']; + $is_auth_register = $config['is_auth_register']; + if ($is_bind_mobile == 0 && $is_auth_register == 1) { + return $this->register($openid, '', $nickname, $avatar); + } else { + return ['avatar' => $avatar, 'nickname' => $nickname, 'openid' => $openid]; + } + } else { + //可能会更新用户和粉丝表 + $login_service = new LoginService(); + return $login_service->login($member_info, MemberLoginTypeDict::WECHAT); + } + } + + /** + * 同步数据 + * @param string $code + * @return true + */ + public function sync(string $code) + { + [$avatar, $nickname, $openid] = $this->userFromCode($code); + //更新粉丝 + $core_wechat_fans_service = new CoreWechatFansService(); + //这儿或许可以异步 + $core_wechat_fans_service->edit($this->site_id, $openid, ['avatar' => $avatar, 'nickname' => $nickname]); + $member_service = new MemberService(); + $member_info = $member_service->findMemberInfo(['wx_openid' => $openid, 'site_id' => $this->site_id]); + if ($member_info->isEmpty()) throw new AuthException('MEMBER_NOT_EXIST');//账号不存在 + $member_service->editByFind($member_info, ['headimg' => $avatar, 'nickname' => $nickname]); + return true; + } + + /** + * 注册 + * @param string $openid + * @param string $mobile + * @param string $nickname + * @param string $avatar + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function register(string $openid, string $mobile = '', string $nickname = '', string $avatar = '') + { + $member_service = new MemberService(); + $member_info = $member_service->findMemberInfo(['wx_openid' => $openid, 'site_id' => $this->site_id]); + if (!$member_info->isEmpty()) throw new AuthException('MEMBER_IS_EXIST');//账号已存在, 不能在注册 + $register_service = new RegisterService(); + return $register_service->register($mobile, + [ + 'wx_openid' => $openid, + 'nickname' => $nickname, + 'headimg' => $avatar + ], + MemberRegisterTypeDict::WECHAT + ); + + } + + /** + * 获取jssdkconfig + * @param string $url + * @return array|string + */ + public function jssdkConfig(string $url = '') + { + return $this->core_wechat_serve_service->jssdkConfig($this->site_id, $url); + } + + + /** + * 扫码登录 + * @return array + */ + public function scanLogin() + { + $data = array( + 'channel' => $this->channel, + ); + + $key = (new CoreScanService())->scan($this->site_id, ScanDict::WECHAT_LOGIN, $data, 300); + $url = $this->core_wechat_serve_service->scan($this->site_id, $key, 300); + return [ + 'url' => $url, + 'key' => $key + ]; + } +} \ No newline at end of file diff --git a/niucloud/app/service/api/wechat/WechatServeService.php b/niucloud/app/service/api/wechat/WechatServeService.php new file mode 100644 index 0000000..b953794 --- /dev/null +++ b/niucloud/app/service/api/wechat/WechatServeService.php @@ -0,0 +1,51 @@ +core_wechat_serve_service = new CoreWechatServeService(); + } + + /** + * 消息与时间推送 + * @return Response + * @throws BadRequestException + * @throws InvalidArgumentException + * @throws ReflectionException + * @throws Throwable + */ + public function serve(){ + return $this->core_wechat_serve_service->serve($this->site_id); + } + +} \ No newline at end of file diff --git a/niucloud/app/service/core/addon/CoreAddonBaseService.php b/niucloud/app/service/core/addon/CoreAddonBaseService.php new file mode 100644 index 0000000..41bcbe4 --- /dev/null +++ b/niucloud/app/service/core/addon/CoreAddonBaseService.php @@ -0,0 +1,107 @@ +root_path = dirname(root_path()) . DIRECTORY_SEPARATOR; + $this->addon_path = root_path() . 'addon' . DIRECTORY_SEPARATOR; + } + + /** + * 获取插件基础配置信息 + * @param string $addon + * @return array|mixed + */ + public function getAddonConfig(string $addon) + { + $path = $this->addon_path . $addon . DIRECTORY_SEPARATOR . 'info.json'; + $resource_path = $this->addon_path . $addon . DIRECTORY_SEPARATOR . 'resource' . DIRECTORY_SEPARATOR; + if (is_file($path)) { + $json_string = file_get_contents($path); + // 用参数true把JSON字符串强制转成PHP数组 + $info = json_decode($json_string, true); + $info['icon'] = $resource_path . 'icon.png'; + $info['cover'] = $resource_path . 'cover.png'; + } + return $info ?? []; + } + + /** + * 获取插件配置文件目录 + * @param string $addon + * @return string + */ + public function getAddonConfigPath(string $addon) + { + return $this->addon_path . $addon . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR; + } + + /** + * 获取插件定义的package目录 + * @param string $addon + * @return string + */ + public function geAddonPackagePath(string $addon) + { + return $this->addon_path . $addon . DIRECTORY_SEPARATOR . 'package' . DIRECTORY_SEPARATOR; + } + + /** + * 读取json文件转化成数组返回 + * @param $json_file_path //json文件目录 + */ + public function jsonFileToArray(string $json_file_path) + { + if (file_exists($json_file_path)) { + $content_json = @file_get_contents($json_file_path); + return json_decode($content_json, true); + } else + return []; + } + + /** + * 读取json文件转化成数组返回 + * @param array $content + * @param string $file_path + * @return true + */ + public function writeArrayToJsonFile(array $content, string $file_path) + { + $content_json = json_encode($content, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + $content_json = preg_replace('/\[\]/', '{}', $content_json); + $result = @file_put_contents($file_path, $content_json); + if (!$result) { + throw new CommonException($file_path . '文件不存在或者权限不足'); + } + return true; + } + +} diff --git a/niucloud/app/service/core/addon/CoreAddonCloudService.php b/niucloud/app/service/core/addon/CoreAddonCloudService.php new file mode 100644 index 0000000..81036dd --- /dev/null +++ b/niucloud/app/service/core/addon/CoreAddonCloudService.php @@ -0,0 +1,336 @@ +getAddonConfig($addon)['compile'] ?? []; + + $need_build = false; + // 拷贝composer文件 + $composer_file = $this->addonPath($addon) . 'package' . DIRECTORY_SEPARATOR . 'composer.json'; + if (file_exists($composer_file)) { + file_put_contents($package_dir . 'composer.json', file_get_contents(root_path() . 'composer.json')); + $need_build = true; + } + // 拷贝手机端文件 + if (!in_array('wap', $compile)) { + dir_copy($this->root_path . 'uni-app', $package_dir . 'uni-app', exclude_dirs:['node_modules', 'unpackage', 'dist']); + $need_build = true; + } + // 拷贝admin端文件 + if (!in_array('admin', $compile)) { + dir_copy($this->root_path . 'admin', $package_dir . 'admin', exclude_dirs:['node_modules', 'dist', '.vscode', '.idea']); + $need_build = true; + } + // 拷贝web端文件 + if (!in_array('web', $compile)) { + dir_copy($this->root_path . 'web', $package_dir . 'web', exclude_dirs:['node_modules', '.output', '.nuxt']); + $need_build = true; + } + + if ($need_build) { + // 将临时目录下文件生成压缩包 + $zip_file = $temp_dir . DIRECTORY_SEPARATOR . 'build.zip'; + (new CoreAddonDevelopDownloadService(''))->compressToZip($package_dir, $zip_file); + + $install_task = Cache::get('install_task'); + $query = [ + 'authorize_code' => $this->auth_code, + 'timestamp' => $install_task['timestamp'] + ]; + $response = (new CloudService())->httpPost('cloud/build?' . http_build_query($query), [ + 'multipart' => [ + [ + 'name' => 'file', + 'contents' => fopen($zip_file, 'r'), + 'filename' => 'build.zip' + ] + ], + 'timeout' => 50.0 + ]); + if (isset($response['code']) && $response['code'] == 0) throw new CommonException($response['msg']); + + // 删除临时文件 + del_target_dir($temp_dir, true); + + Cache::set('build_success_' . $addon, null); + } else { + (new CoreAddonInstallService($addon))->handleAddonInstall(); + } + return true; + } + + /** + * 获取编译结果 + * @param string $addon + * @return void + */ + public function getBuildLog(string $addon) { + try { + $install_task = Cache::get('install_task'); + if (empty($install_task) || !isset($install_task['timestamp'])) return true; + + $query = [ + 'authorize_code' => $this->auth_code, + 'timestamp' => $install_task['timestamp'] + ]; + $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'] == 0) { + (new CoreAddonInstallService($addon))->installExceptionHandle(); + $install_task['error'] = 'ADDON_INSTALL_FAIL'; + Cache::set('install_task', $install_task, 10); + return $build_log; + } + if ($last['percent'] == 100) { + $build_log['data'][0] = $this->buildSuccess($addon, $build_log['data'][0], $install_task['timestamp']); + } + } + return $build_log; + } catch (\Exception $e) { + $install_task = Cache::get('install_task'); + $install_task['error'] = $e->getMessage(); + Cache::set('install_task', $install_task, 10); + throw new CommonException($e->getMessage()); + } + } + + /** + * 云编译成功 + * @param string $addon + * @return void + */ + public function buildSuccess(string $addon, array $log, $timestamp) { + $query = [ + 'authorize_code' => $this->auth_code, + 'timestamp' => $timestamp + ]; + $chunk_size = 1 * 1024 * 1024; + + $cache = Cache::get('build_success_' . $addon); + + if (is_null($cache)) { + $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); + + // 下载任务key + $task_key = uniqid(); + // 此次下载任务临时目录 + $temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $task_key . DIRECTORY_SEPARATOR; + dir_mkdir($temp_dir); + + Cache::set('build_success_' . $addon, ['step' => $step, 'index' => 0, 'length' => $length, 'task_key' => $task_key]); + } else { + $temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'cloud_build' . DIRECTORY_SEPARATOR . $cache['task_key'] . DIRECTORY_SEPARATOR; + $zip_file = $temp_dir . 'build.zip'; + $zip_resource = fopen($zip_file, 'a'); + + if (($cache['index'] + 1) <= $cache['step']) { + $start = $cache['index'] * $chunk_size; + $end = ($cache['index'] + 1) * $chunk_size; + $end = min($end, $cache['length']); + + $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); + + $cache['index'] += 1; + Cache::set('build_success_' . $addon, $cache); + + $log[] = ['action' => '编译包下载中,已下载' . round($cache['index'] / $cache['step'] * 100) . '%', 'percent' => '100' ]; + } else { + // 解压文件 + $zip = new \ZipArchive(); + if ($zip->open($zip_file) === true) { + dir_mkdir($temp_dir . 'build'); + $zip->extractTo($temp_dir . 'build'); + $zip->close(); + + if (is_dir($temp_dir . 'build' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'admin')) { + del_target_dir(public_path() .'admin', true); + } + if (is_dir($temp_dir . 'build' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'web')) { + del_target_dir(public_path() .'web', true); + } + if (is_dir($temp_dir . 'build' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'wap')) { + del_target_dir(public_path() .'wap', true); + } + + dir_copy($temp_dir . 'build', root_path()); + + // 安装插件 + (new CoreAddonInstallService($addon))->handleAddonInstall(); + + // 删除临时文件 + @del_target_dir($temp_dir, true); + + Cache::set('build_success_' . $addon, null); + } else { + Cache::set('build_success_' . $addon, null); + // 调用插件安装异常处理 + (new CoreAddonInstallService($addon))->installExceptionHandle(); + throw new CommonException('Zip decompression failed'); + } + } + } + return $log; + } + + /** + * 下载插件 + * @param string $addon + * @param string $version + * @return void + */ + public function downloadAddon(string $addon, string $version) { + $action_token = (new CoreModuleService())->getActionToken('download', ['data' => ['app_key' => $addon, 'version' => $version]]); + 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]]); + if ($action_token['code'] != 1) throw new CommonException($action_token['msg']); + } + + $query = [ + 'authorize_code' => $this->auth_code, + 'addon_name' => $addon, + 'addon_version' => $version, + 'token' => $action_token['data']['token'] ?? '' + ]; + // 获取文件大小 + $response = (new CloudService())->request('HEAD','cloud/download?' . http_build_query($query), [ + 'headers' => ['Range' => 'bytes=0-'] + ]); + $length = $response->getHeader('Content-range'); + $length = (int)explode("/", $length[0])[1]; + + $temp_dir = runtime_path() . 'backup' . DIRECTORY_SEPARATOR . 'addon_download' . DIRECTORY_SEPARATOR . uniqid() . DIRECTORY_SEPARATOR; + dir_mkdir($temp_dir); + + $zip_file = $temp_dir . $addon . '.zip'; + $zip_resource = fopen($zip_file, 'w'); + + $response = (new CloudService())->request('GET','cloud/download?' . http_build_query($query), [ + 'headers' => ['Range' => "bytes=0-{$length}"] + ]); + fwrite($zip_resource, $response->getBody()); + fclose($zip_resource); + + return $zip_file; + } + + /** + * 插件升级 + * @param $data + * @return void + * @throws \GuzzleHttp\Exception\GuzzleException + */ + 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, + 'token' => $action_token['data']['token'] ?? '' + ]; + // 获取文件大小 + $response = (new CloudService())->httpGet('cloud/upgrade?' . http_build_query($query)); + $response['token'] = $query['token']; + return $response; + } + + /** + * 下载升级文件 + * @param string $dir + * @param string $token + * @return void + */ + public function downloadUpgradeFile(string $token, string $dir = '', int $index = -1, $step = 0, $length = 0) { + $query = [ + 'authorize_code' => $this->auth_code, + 'token' => $token + ]; + $chunk_size = 1 * 1024 * 1024; + + if ($index == -1) { + $response = (new CloudService())->request('HEAD','cloud/upgrade/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); + + $index++; + return compact('token', 'dir', 'index', 'step', 'length'); + } else { + $zip_file = $dir . 'upgrade.zip'; + $zip_resource = fopen($zip_file, 'a'); + + if ($index < $step) { + $start = $index * $chunk_size; + $end = ($index + 1) * $chunk_size; + $end = min($end, $length); + + $response = (new CloudService())->request('GET','cloud/upgrade/download?' . http_build_query($query), [ + 'headers' => ['Range' => "bytes={$start}-{$end}"] + ]); + fwrite($zip_resource, $response->getBody()); + fclose($zip_resource); + + $index++; + return compact('token', 'dir', 'index', 'step', 'length'); + } else { + $zip = new \ZipArchive(); + if ($zip->open($zip_file) === true) { + dir_mkdir($dir . 'code'); + $zip->extractTo($dir . 'code'); + $zip->close(); + } + return true; + } + } + } +} diff --git a/niucloud/app/service/core/addon/CoreAddonDevelopBuildService.php b/niucloud/app/service/core/addon/CoreAddonDevelopBuildService.php new file mode 100644 index 0000000..3569ac9 --- /dev/null +++ b/niucloud/app/service/core/addon/CoreAddonDevelopBuildService.php @@ -0,0 +1,228 @@ +root_path = project_path(); + } + + /** + * 插件打包 + * @param string $addon + * @return void + */ + public function build(string $addon) + { + $this->addon = $addon; + $this->addon_path = root_path() . 'addon' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR; + + if (!is_dir($this->addon_path)) throw new AddonException('ADDON_IS_NOT_EXIST');//当前目录中不存在此项插件 + + $this->admin(); + $this->uniapp(); + $this->buildUniappPagesJson(); + $this->web(); + $this->resource(); + $this->menu('admin'); + $this->menu('site'); + + $zip_file = runtime_path() . $addon . '.zip'; + if (file_exists($zip_file)) unlink($zip_file); + (new CoreAddonDevelopDownloadService(''))->compressToZip($this->addon_path, $zip_file); + + return true; + } + + /** + * 下载 + * @param string $addon + * @return \think\response\File + */ + public function download(string $addon) { + $zip_file = runtime_path() . $addon . '.zip'; + if (!file_exists($zip_file)) throw new AddonException('ADDON_ZIP_ERROR');//下载失败 + return str_replace(project_path(), '', $zip_file); + } + + /** + * 同步菜单 + * @param string $app_type + * @return true + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function menu(string $app_type) { + $where = [ ['app_type', '=', $app_type], ['addon', '=', $this->addon] ]; + $field = 'menu_name,menu_key,menu_short_name,parent_key,menu_type,icon,api_url,router_path,view_path,methods,sort,status,is_show'; + $menu = (new SysMenu())->where($where)->field($field)->order('sort', 'desc')->select()->toArray(); + if (!empty($menu)) { + $menu = (new MenuService())->menuToTree($menu, 'menu_key', 'parent_key', 'children'); + (new SysMenu())->where($where)->update(['source' => MenuDict::SYSTEM]); + } + + $addon_dict = $this->addon_path . 'app' . DIRECTORY_SEPARATOR . 'dict' . DIRECTORY_SEPARATOR . 'menu' . DIRECTORY_SEPARATOR . $app_type . '.php'; + + $content = 'arrayFormat($menu); + $content .= '];'; + file_put_contents($addon_dict, $content); + + return true; + } + + private function arrayFormat($array, $level = 1) { + $tab = ''; + for ($i = 0; $i < $level; $i++) { + $tab .= ' '; + } + $content = ''; + foreach ($array as $k => $v) { + if (in_array($k, ['status_name', 'menu_type_name']) || ($level > 2 && $k == 'parent_key')) continue; + if (is_array($v)) { + $content .= $tab; + if (is_string($k)) { + $content .= "'{$k}' => "; + } + $content .= '[' . PHP_EOL . $this->arrayFormat($v, $level + 1); + $content .= $tab . '],' . PHP_EOL; + } else { + $content .= $tab ."'{$k}' => '{$v}'," . PHP_EOL; + } + } + return $content; + } + + /** + * admin打包 + * @return void + */ + public function admin() + { + $admin_path = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR; + if (!is_dir($admin_path)) return true; + + $addon_admin_path = $this->addon_path . 'admin' . DIRECTORY_SEPARATOR; + if (is_dir($addon_admin_path)) del_target_dir($addon_admin_path, true); + dir_copy($admin_path, $addon_admin_path); + + // 打包admin icon文件 + $icon_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'styles' . DIRECTORY_SEPARATOR . 'icon' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon; + if (is_dir($icon_dir)) dir_copy($icon_dir, $addon_admin_path . 'icon'); + + return true; + } + + /** + * wap打包 + * @return void + */ + public function uniapp() + { + $uniapp_path = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR; + if (!is_dir($uniapp_path)) return true; + + $addon_uniapp_path = $this->addon_path . 'uni-app' . DIRECTORY_SEPARATOR; + if (is_dir($addon_uniapp_path)) del_target_dir($addon_uniapp_path, true); + dir_copy($uniapp_path, $addon_uniapp_path); + + return true; + } + + public function buildUniappPagesJson() { + $pages_json = file_get_contents($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'pages.json'); + $code_begin = strtoupper($this->addon) . '_PAGE_BEGIN' . PHP_EOL; + $code_end = strtoupper($this->addon) . '_PAGE_END' . PHP_EOL; + + if(strpos($pages_json, $code_begin) !== false && strpos($pages_json, $code_end) !== false) + { + $pattern = "/\/\/\s+{$code_begin}([\S\s]+)\/\/\s+{$code_end}?/"; + preg_match($pattern, $pages_json, $match); + + if (!empty($match)) { + $addon_pages = $match[1]; + + $content = ' <<| BENCHMARK | |
| till '.$markerId.': | '.number_format($thisTime-$lastTime, 6).'s |
|---|---|
| TOTAL: | '.number_format($lastTime-$startTime, 6).'s |
l)e.partial=!0,e.time.push({startPTS:Math.max(a,d.start(i)),endPTS:Math.min(t,d.end(i))});else if(t<=l)break}return e},m.getPartialFragment=function(f){var S,T,d,e=null,a=0,t=this.bufferPadding,o=this.fragments;return Object.keys(o).forEach(function(u){var i=o[u];i&&_(i)&&(T=i.body.start-t,d=i.body.end+t,f>=T&&f<=d&&(S=Math.min(f-T,d-f),a<=S&&(e=i.body,a=S)))}),e},m.getState=function(f){var S=s(f),T=this.fragments[S];return T?T.buffered?_(T)?R.PARTIAL:R.OK:T.backtrack?R.BACKTRACKED:R.APPENDING:R.NOT_LOADED},m.backtrack=function(f,S){var T=s(f),d=this.fragments[T];if(!d||d.backtrack)return null;var e=d.backtrack=S||d.loaded;return d.loaded=null,e},m.getBacktrackData=function(f){var S=s(f),T=this.fragments[S];if(T){var d,e=T.backtrack;if(e!=null&&(d=e.payload)!==null&&d!==void 0&&d.byteLength)return e;this.removeFragment(f)}return null},m.isTimeBuffered=function(f,S,T){for(var d,e,a=0;a -1&&(this.subtitleTrack=this.queuedDefaultTrack,this.queuedDefaultTrack=-1),this.useTextTrackPolling=!(this.media.textTracks&&"onchange"in this.media.textTracks),this.useTextTrackPolling?this.pollTrackChange(500):this.media.textTracks.addEventListener("change",this.asyncPollTrackChange))},a.pollTrackChange=function(t){self.clearInterval(this.subtitlePollingInterval),this.subtitlePollingInterval=self.setInterval(this.trackChangeListener,t)},a.onMediaDetaching=function(){this.media&&(self.clearInterval(this.subtitlePollingInterval),this.useTextTrackPolling||this.media.textTracks.removeEventListener("change",this.asyncPollTrackChange),this.trackId>-1&&(this.queuedDefaultTrack=this.trackId),L(this.media.textTracks).forEach(function(t){Object(b.clearCurrentCues)(t)}),this.subtitleTrack=-1,this.media=null)},a.onManifestLoading=function(){this.tracks=[],this.groupId=null,this.tracksInGroup=[],this.trackId=-1,this.selectDefaultTrack=!0},a.onManifestParsed=function(t,o){this.tracks=o.subtitleTracks},a.onSubtitleTrackLoaded=function(t,o){var u=o.id,i=o.details,l=this.trackId,p=this.tracksInGroup[l];if(p){var g=p.details;p.details=o.details,this.log("subtitle track "+u+" loaded ["+i.startSN+"-"+i.endSN+"]"),u===this.trackId&&(this.retryCount=0,this.playlistLoaded(u,o,g))}else this.warn("Invalid subtitle track id "+u)},a.onLevelLoading=function(t,o){this.switchLevel(o.level)},a.onLevelSwitching=function(t,o){this.switchLevel(o.level)},a.switchLevel=function(t){var o=this.hls.levels[t];if(o!=null&&o.textGroupIds){var u=o.textGroupIds[o.urlId];if(this.groupId!==u){var i=this.tracksInGroup?this.tracksInGroup[this.trackId]:void 0,l=this.tracks.filter(function(v){return!u||v.groupId===u});this.tracksInGroup=l;var p=this.findTrackId(i==null?void 0:i.name)||this.findTrackId();this.groupId=u;var g={subtitleTracks:l};this.log("Updating subtitle tracks, "+l.length+' track(s) found in "'+u+'" group-id'),this.hls.trigger(R.Events.SUBTITLE_TRACKS_UPDATED,g),p!==-1&&this.setSubtitleTrack(p,i)}}},a.findTrackId=function(t){for(var o=this.tracksInGroup,u=0;u0&&(E=n?"["+c.join(" | ")+"]":c.join(`
+`)),E},r.getTextAndFormat=function(){return this.rows},v}(),i=function(){function v(n,c,E){this.chNr=void 0,this.outputFilter=void 0,this.mode=void 0,this.verbose=void 0,this.displayedMemory=void 0,this.nonDisplayedMemory=void 0,this.lastOutputScreen=void 0,this.currRollUpRow=void 0,this.writeScreen=void 0,this.cueStartTime=void 0,this.logger=void 0,this.chNr=n,this.outputFilter=c,this.mode=null,this.verbose=0,this.displayedMemory=new u(E),this.nonDisplayedMemory=new u(E),this.lastOutputScreen=new u(E),this.currRollUpRow=this.displayedMemory.rows[14],this.writeScreen=this.displayedMemory,this.mode=null,this.cueStartTime=null,this.logger=E}var r=v.prototype;return r.reset=function(){this.mode=null,this.displayedMemory.reset(),this.nonDisplayedMemory.reset(),this.lastOutputScreen.reset(),this.outputFilter.reset(),this.currRollUpRow=this.displayedMemory.rows[14],this.writeScreen=this.displayedMemory,this.mode=null,this.cueStartTime=null},r.getHandler=function(){return this.outputFilter},r.setHandler=function(n){this.outputFilter=n},r.setPAC=function(n){this.writeScreen.setPAC(n)},r.setBkgData=function(n){this.writeScreen.setBkgData(n)},r.setMode=function(n){n!==this.mode&&(this.mode=n,this.logger.log(R.INFO,"MODE="+n),this.mode==="MODE_POP-ON"?this.writeScreen=this.nonDisplayedMemory:(this.writeScreen=this.displayedMemory,this.writeScreen.reset()),this.mode!=="MODE_ROLL-UP"&&(this.displayedMemory.nrRollUpRows=null,this.nonDisplayedMemory.nrRollUpRows=null),this.mode=n)},r.insertChars=function(n){for(var c=0;c
/gi,`
+`)}var f=function(){function S(){this.state="INITIAL",this.buffer="",this.decoder=new b,this.regionList=[],this.cue=null,this.oncue=void 0,this.onparsingerror=void 0,this.onflush=void 0}var T=S.prototype;return T.parse=function(d){var e=this;function a(){var l=e.buffer,p=0;for(l=m(l);p=0;){const s=n[0];for(let u=0;u`)}).catch()},N=n=>{xe(n).then(l=>{const d=l.data.data??[];if(d[0]&&d[0].length){const f=d[0][d[0].length-1];if(f.code==0){m();return}if(f.code==1&&f.percent==100){m(),T();return}setTimeout(()=>{N(n)},2e3)}})},M=()=>{k.confirm(e("authTips"),e("warning"),{distinguishCancelAndClose:!0,confirmButtonText:e("toBind"),cancelButtonText:e("toNiucloud")}).then(()=>{x.push({path:"/app/authorize"})}).catch(n=>{n==="cancel"&&window.open("https://www.niucloud.com/app")})},$=()=>{k.confirm(e("weappTips"),e("warning"),{confirmButtonText:e("toSetting"),cancelButtonText:e("cancel")}).then(()=>{x.push({path:"/channel/weapp/config"})}).catch(n=>{})};return(n,l)=>{const d=le,f=oe,g=ne,b=se,j=ie,S=pe,O=ce,X=de,R=re,E=ue,Y=ge,q=me,G=_e,H=fe;return w(),B("div",ye,[u("div",Te,[u("span",Ee,p(o(I)),1)]),a(f,{modelValue:y.value,"onUpdate:modelValue":l[0]||(l[0]=s=>y.value=s),class:"demo-tabs",onTabChange:P},{default:i(()=>[a(d,{label:o(e)("weappAccessFlow"),name:"/channel/weapp"},null,8,["label"]),a(d,{label:o(e)("subscribeMessage"),name:"/channel/weapp/message"},null,8,["label"]),a(d,{label:o(e)("weappRelease"),name:"/channel/weapp/code"},null,8,["label"])]),_:1},8,["modelValue"]),a(X,{class:"box-card !border-none",shadow:"never"},{default:i(()=>[u("div",Be,[a(g,{type:"primary",onClick:z,loading:_.value,disabled:t.loading},{default:i(()=>[h(p(o(e)("cloudRelease")),1)]),_:1},8,["loading","disabled"]),a(g,{onClick:A,disabled:t.loading},{default:i(()=>[h(p(o(e)("localRelease")),1)]),_:1},8,["disabled"])]),ae((w(),te(S,{class:"mt-[15px]",data:t.data,size:"default"},{empty:i(()=>[u("span",null,p(o(e)("emptyData")),1)]),default:i(()=>[a(b,{prop:"version",label:o(e)("code"),align:"left"},null,8,["label"]),a(b,{prop:"status_name",label:o(e)("status"),align:"left"},{default:i(({row:s})=>[u("div",null,p(s.status_name),1),s.status==-1?(w(),B("div",ke,p(o(e)("failReason"))+p(s.fail_reason),1)):D("",!0)]),_:1},8,["label"]),a(b,{prop:"create_time",label:o(e)("createTime"),align:"center"},null,8,["label"]),a(b,{label:o(e)("operation"),fixed:"right",align:"right","min-width":"120"},{default:i(({row:s,$index:J})=>[v.value&&J==0&&s.status==1&&t.page==1?(w(),B("div",Ue,[a(j,{content:v.value,"raw-content":"",effect:"light"},{default:i(()=>[a(g,{type:"primary",link:""},{default:i(()=>[h(p(o(e)("preview")),1)]),_:1})]),_:1},8,["content"])])):D("",!0)]),_:1},8,["label"])]),_:1},8,["data"])),[[H,t.loading]]),u("div",We,[a(O,{"current-page":t.page,"onUpdate:current-page":l[1]||(l[1]=s=>t.page=s),"page-size":t.limit,"onUpdate:page-size":l[2]||(l[2]=s=>t.limit=s),layout:"total, sizes, prev, pager, next, jumper",total:t.total,onSizeChange:m,onCurrentChange:m},null,8,["current-page","page-size","total"])])]),_:1}),a(G,{modelValue:V.value,"onUpdate:modelValue":l[7]||(l[7]=s=>V.value=s),title:o(e)("codeDownTwoDesc"),width:"30%","before-close":L},{footer:i(()=>[u("span",ze,[a(g,{onClick:l[6]||(l[6]=s=>V.value=!1)},{default:i(()=>[h(p(o(e)("cancel")),1)]),_:1}),a(g,{type:"primary",onClick:z},{default:i(()=>[h(p(o(e)("confirm")),1)]),_:1})])]),default:i(()=>[a(q,{ref_key:"ruleFormRef",ref:W,model:c.value,"label-width":"120px"},{default:i(()=>[a(E,{prop:"code",label:o(e)("code")},{default:i(()=>[a(R,{modelValue:c.value.code,"onUpdate:modelValue":l[3]||(l[3]=s=>c.value.code=s),placeholder:o(e)("codePlaceholder"),onkeyup:"this.value = this.value.replace(/[^\\d\\.]/g,'');"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),a(E,{prop:"path",label:o(e)("path")},{default:i(()=>[a(Y,{modelValue:c.value.path,"onUpdate:modelValue":l[4]||(l[4]=s=>c.value.path=s),api:"weapp/upload",accept:".zip"},null,8,["modelValue","accept"])]),_:1},8,["label"]),a(E,{label:o(e)("content")},{default:i(()=>[a(R,{type:"textarea",modelValue:c.value.content,"onUpdate:modelValue":l[5]||(l[5]=s=>c.value.content=s),placeholder:o(e)("contentPlaceholder")},null,8,["modelValue","placeholder"])]),_:1},8,["label"])]),_:1},8,["model"])]),_:1},8,["modelValue","title"])])}}});const la=Ce(Ne,[["__scopeId","data-v-8bfc122b"]]);export{la as default};
diff --git a/niucloud/public/admin/assets/code-cea24823.png b/niucloud/public/admin/assets/code-cea24823.png
new file mode 100644
index 0000000..498bd67
Binary files /dev/null and b/niucloud/public/admin/assets/code-cea24823.png differ
diff --git a/niucloud/public/admin/assets/commission-0ddaecaf.js b/niucloud/public/admin/assets/commission-0ddaecaf.js
new file mode 100644
index 0000000..d396416
--- /dev/null
+++ b/niucloud/public/admin/assets/commission-0ddaecaf.js
@@ -0,0 +1 @@
+import{d as H,O,n as q,r as g,f as A,h as p,c as u,e,w as l,a as s,t as r,u as a,N as i,F as G,G as W,I as T,i as f,y as X,R as J,cH as K,al as Q,am as Z,_ as ee,W as te,X as ae,aq as oe,aC as le,cI as se,E as ie,Y as ne,af as re,ah as me,a3 as ce,$ as de}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css */import{_ as pe}from"./default_headimg-a897263d.js";import{f as _e,n as ue,o as fe}from"./member-ff972216.js";import{_ as he}from"./member-commission-info.vue_vue_type_script_setup_true_lang-8dd3413e.js";/* empty css */const be={class:"main-container"},ve={class:"flex justify-between items-center mb-[5px]"},ge={class:"text-[20px]"},xe={class:"statistic-card"},we={class:"statistic-footer"},ye={class:"footer-item text-[14px] text-[#666]"},ke={class:"statistic-card"},Ce={class:"statistic-footer"},Fe={class:"footer-item text-[14px] text-[#666]"},Ee={class:"statistic-card"},De={class:"statistic-footer"},Pe={class:"footer-item text-[14px] text-[#666]"},Te={class:"statistic-card"},Ve={class:"statistic-footer"},Ie={class:"footer-item text-[14px] text-[#666]"},Le={class:"mt-[10px]"},Ne=["onClick"],$e=["src"],Se={key:1,class:"w-[50px] h-[50px] mr-[10px]",src:pe,alt:""},ze={class:"flex flex flex-col"},Re={class:""},Be={key:0},Ue={key:1},Ye={class:"mt-[16px] flex justify-end"},_t=H({__name:"commission",setup(Me){const C=O(),F=parseInt(C.query.id||0),V=C.meta.title,o=q({page:1,limit:10,total:0,loading:!0,data:[],searchParam:{keywords:"",from_type:"",create_time:"",mobile:"",member_id:F}}),E=g([]);(async()=>{E.value=await(await _e("commission")).data})();const c=g([]);(()=>{ue({member_id:F}).then(m=>{c.value=m.data})})();const D=g(),I=m=>{m&&(m.resetFields(),_())},_=(m=1)=>{o.loading=!0,o.page=m,fe({page:o.page,limit:o.limit,...o.searchParam}).then(n=>{o.loading=!1,o.data=n.data.data,o.total=n.data.total}).catch(()=>{o.loading=!1})};_();const x=g(null),L=m=>{x.value.setFormData(m),x.value.showDialog=!0},N=A(),$=m=>{N.push(`/member/detail?id=${m}`)};return(m,n)=>{const h=K,b=Q,S=Z,w=ee,z=te,v=ae,P=oe,R=le,B=se,y=ie,U=ne,d=re,Y=me,M=ce,j=de;return p(),u("div",be,[e(w,{class:"box-card !border-none",shadow:"never"},{default:l(()=>[s("div",ve,[s("span",ge,r(a(V)),1)]),e(w,{class:"box-card !border-none base-bg !px-[35px]",shadow:"never"},{default:l(()=>[e(S,{class:"flex"},{default:l(()=>[e(b,{span:6,class:"min-w-[100px]"},{default:l(()=>[s("div",xe,[e(h,{value:c.value.total_commission?Number.parseFloat(c.value.total_commission).toFixed(2):"0.00"},null,8,["value"]),s("div",we,[s("div",ye,[s("span",null,r(a(i)("totalCommission")),1)])])])]),_:1}),e(b,{span:6,class:"min-w-[100px]"},{default:l(()=>[s("div",ke,[e(h,{value:c.value.commission?Number.parseFloat(c.value.commission).toFixed(2):"0.00"},null,8,["value"]),s("div",Ce,[s("div",Fe,[s("span",null,r(a(i)("commission")),1)])])])]),_:1}),e(b,{span:6,class:"min-w-[100px]"},{default:l(()=>[s("div",Ee,[e(h,{value:c.value.withdrawn_commission?Number.parseFloat(c.value.withdrawn_commission).toFixed(2):"0.00"},null,8,["value"]),s("div",De,[s("div",Pe,[s("span",null,r(a(i)("withdrawnCommission")),1)])])])]),_:1}),e(b,{span:6,class:"min-w-[100px]"},{default:l(()=>[s("div",Te,[e(h,{value:c.value.commission_cash_outing?Number.parseFloat(c.value.commission_cash_outing).toFixed(2):"0.00"},null,8,["value"]),s("div",Ve,[s("div",Ie,[s("span",null,r(a(i)("cashOutingCommission")),1)])])])]),_:1})]),_:1})]),_:1}),e(w,{class:"box-card !border-none mb-[10px] table-search-wrap",shadow:"never"},{default:l(()=>[e(U,{inline:!0,model:o.searchParam,ref_key:"searchFormRef",ref:D},{default:l(()=>[e(v,{label:a(i)("memberInfo"),prop:"keywords"},{default:l(()=>[e(z,{modelValue:o.searchParam.keywords,"onUpdate:modelValue":n[0]||(n[0]=t=>o.searchParam.keywords=t),class:"w-[240px]",placeholder:a(i)("memberInfoPlaceholder")},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),e(v,{label:a(i)("fromType"),prop:"from_type"},{default:l(()=>[e(R,{modelValue:o.searchParam.from_type,"onUpdate:modelValue":n[1]||(n[1]=t=>o.searchParam.from_type=t),clearable:"",placeholder:a(i)("fromTypePlaceholder"),class:"input-width"},{default:l(()=>[e(P,{label:a(i)("selectPlaceholder"),value:""},null,8,["label"]),(p(!0),u(G,null,W(E.value,(t,k)=>(p(),T(P,{label:t.name,value:k},null,8,["label","value"]))),256))]),_:1},8,["modelValue","placeholder"])]),_:1},8,["label"]),e(v,{label:a(i)("createTime"),prop:"create_time"},{default:l(()=>[e(B,{modelValue:o.searchParam.create_time,"onUpdate:modelValue":n[2]||(n[2]=t=>o.searchParam.create_time=t),type:"datetimerange","value-format":"YYYY-MM-DD HH:mm:ss","start-placeholder":a(i)("startDate"),"end-placeholder":a(i)("endDate")},null,8,["modelValue","start-placeholder","end-placeholder"])]),_:1},8,["label"]),e(v,null,{default:l(()=>[e(y,{type:"primary",onClick:n[3]||(n[3]=t=>_())},{default:l(()=>[f(r(a(i)("search")),1)]),_:1}),e(y,{onClick:n[4]||(n[4]=t=>I(D.value))},{default:l(()=>[f(r(a(i)("reset")),1)]),_:1})]),_:1})]),_:1},8,["model"])]),_:1}),s("div",Le,[X((p(),T(Y,{data:o.data,size:"large"},{empty:l(()=>[s("span",null,r(o.loading?"":a(i)("emptyData")),1)]),default:l(()=>[e(d,{prop:"member_id",label:a(i)("memberId"),"min-width":"80","show-overflow-tooltip":!0},{default:l(({row:t})=>[f(r(t.member.member_no),1)]),_:1},8,["label"]),e(d,{label:a(i)("memberInfo"),"min-width":"150","show-overflow-tooltip":!0},{default:l(({row:t})=>[s("div",{class:"flex items-center cursor-pointer",onClick:k=>$(t.member_id)},[t.member.headimg?(p(),u("img",{key:0,class:"w-[50px] h-[50px] mr-[10px]",src:a(J)(t.member.headimg),alt:""},null,8,$e)):(p(),u("img",Se)),s("div",ze,[s("span",Re,r(t.member.nickname||""),1)])],8,Ne)]),_:1},8,["label"]),e(d,{prop:"mobile",label:a(i)("mobile"),"min-width":"100"},{default:l(({row:t})=>[f(r(t.member.mobile||""),1)]),_:1},8,["label"]),e(d,{prop:"account_data",label:a(i)("accountData"),"min-width":"80",align:"right"},{default:l(({row:t})=>[t.account_data>=0?(p(),u("span",Be,"+"+r(t.account_data),1)):(p(),u("span",Ue,r(t.account_data),1))]),_:1},8,["label"]),e(d,{prop:"account_sum",label:a(i)("accountSum"),"min-width":"120",align:"right"},null,8,["label"]),e(d,{prop:"from_type_name",label:a(i)("fromType"),"min-width":"180",align:"center"},null,8,["label"]),e(d,{prop:"create_time","show-overflow-tooltip":!0,label:a(i)("createTime"),"min-width":"150"},null,8,["label"]),e(d,{label:a(i)("operation"),align:"right",fixed:"right",width:"100"},{default:l(({row:t})=>[e(y,{type:"primary",link:"",onClick:k=>L(t)},{default:l(()=>[f(r(a(i)("info")),1)]),_:2},1032,["onClick"])]),_:1},8,["label"])]),_:1},8,["data"])),[[j,o.loading]]),s("div",Ye,[e(M,{"current-page":o.page,"onUpdate:current-page":n[5]||(n[5]=t=>o.page=t),"page-size":o.limit,"onUpdate:page-size":n[6]||(n[6]=t=>o.limit=t),layout:"total, sizes, prev, pager, next, jumper",total:o.total,onSizeChange:n[7]||(n[7]=t=>_()),onCurrentChange:_},null,8,["current-page","page-size","total"])])])]),_:1}),e(he,{ref_key:"moneyDialog",ref:x,onComplete:_},null,512)])}}});export{_t as default};
diff --git a/niucloud/public/admin/assets/common-adf8ca96.js b/niucloud/public/admin/assets/common-adf8ca96.js
new file mode 100644
index 0000000..138940e
--- /dev/null
+++ b/niucloud/public/admin/assets/common-adf8ca96.js
@@ -0,0 +1 @@
+import{aJ as e}from"./index-6010b07e.js";function r(t){let o={headers:{"Content-Type":"multipart/form-data"}};return e.post("hygl/uploadFile",t,o)}function u(t){return e.get("hygl/getCouponsList",{params:t})}export{u as g,r as u};
diff --git a/niucloud/public/admin/assets/config-4c993e14.js b/niucloud/public/admin/assets/config-4c993e14.js
new file mode 100644
index 0000000..05bc056
--- /dev/null
+++ b/niucloud/public/admin/assets/config-4c993e14.js
@@ -0,0 +1 @@
+import{d as M,O as $,f as j,r as y,n as b,N as e,aI as I,s as O,a2 as x,h as V,c as B,a as s,u as a,t as n,y as K,I as W,w as l,e as t,i as f,W as F,X as L,_ as Q,aw as z,ax as G,Y as X,E as Y,$ as H}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import{_ as J}from"./index-4718d422.js";import"./el-form-item-4ed993c7.js";/* empty css */import{g as Z,a as ee,e as ae}from"./wechat-688fa021.js";/* empty css */import"./index.vue_vue_type_style_index_0_lang-cc99af21.js";/* empty css */import"./attachment-bc20fd95.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-6f0143c4.js";/* empty css */import"./sys-0f76aff3.js";import"./_plugin-vue_export-helper-c27b6911.js";const te={class:"main-container"},oe={class:"detail-head"},le=s("span",{class:"iconfont iconxiangzuojiantou !text-xs"},null,-1),se={class:"ml-[1px]"},ne=s("span",{class:"adorn"},"|",-1),ie={class:"right"},re={class:"panel-title !text-sm"},de={class:"form-tip"},pe={class:"panel-title !text-sm"},ce={class:"form-tip"},ue={class:"form-tip"},me={class:"panel-title !text-sm"},_e={class:"form-tip"},he={class:"form-tip"},fe={class:"form-tip"},ge={class:"form-tip"},be={class:"form-tip"},ve={class:"flex"},we={class:"panel-title !text-sm"},ye={class:"form-tip"},xe={class:"fixed-footer-wrap"},Ve={class:"fixed-footer"},oa=M({__name:"config",setup(ke){const k=$(),P=j(),S=k.meta.title,m=y(!0),r=b({wechat_name:"",wechat_original:"",app_id:"",app_secret:"",qr_code:"",token:"",encoding_aes_key:"",encryption_type:"not_encrypt"}),v=y(),C=b({wechat_name:[{required:!0,message:e("wechatNamePlaceholder"),trigger:"blur"}],wechat_original:[{required:!0,message:e("wechatOriginalPlaceholder"),trigger:"blur"}],app_id:[{required:!0,message:e("appidPlaceholder"),trigger:"blur"}],app_secret:[{required:!0,message:e("appSecretPlaceholder"),trigger:"blur"}],token:[{required:!0,message:e("tokenPlaceholder"),trigger:"blur"}],encoding_aes_key:[{required:!0,message:e("encodingAesKeyPlaceholder"),trigger:"blur"}]});Z().then(u=>{Object.assign(r,u.data),m.value=!1});const c=b({business_domain:"",js_secure_domain:"",serve_url:"",web_auth_domain:""});ee().then(u=>{Object.assign(c,u.data),m.value=!1});const{copy:E,isSupported:T,copied:w}=I(),_=u=>{if(!T.value){x({message:e("notSupportCopy"),type:"warning"});return}E(u)};O(w,()=>{w.value&&x({message:e("copySuccess"),type:"success"})});const q=async u=>{m.value||!u||await u.validate(async o=>{o&&(m.value=!0,ae(r).then(()=>{m.value=!1}).catch(()=>{m.value=!1}))})};return(u,o)=>{const p=F,d=L,A=J,h=Q,g=z,U=G,N=X,R=Y,D=H;return V(),B("div",te,[s("div",oe,[s("div",{class:"left",onClick:o[0]||(o[0]=i=>a(P).push({path:"/channel/wechat"}))},[le,s("span",se,n(a(e)("returnToPreviousPage")),1)]),ne,s("span",ie,n(a(S)),1)]),K((V(),W(N,{model:r,"label-width":"150px",ref_key:"formRef",ref:v,rules:C,class:"page-form"},{default:l(()=>[t(h,{class:"box-card !border-none",shadow:"never"},{default:l(()=>[s("h3",re,n(a(e)("wechatInfo")),1),t(d,{label:a(e)("wechatName"),prop:"wechat_name"},{default:l(()=>[t(p,{modelValue:r.wechat_name,"onUpdate:modelValue":o[1]||(o[1]=i=>r.wechat_name=i),placeholder:a(e)("wechatNamePlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),t(d,{label:a(e)("wechatOriginal"),prop:"wechat_original"},{default:l(()=>[t(p,{modelValue:r.wechat_original,"onUpdate:modelValue":o[2]||(o[2]=i=>r.wechat_original=i),placeholder:a(e)("wechatOriginalPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),t(d,{label:a(e)("wechatQrcode"),prop:"qr_code"},{default:l(()=>[t(A,{modelValue:r.qr_code,"onUpdate:modelValue":o[3]||(o[3]=i=>r.qr_code=i)},null,8,["modelValue"]),s("div",de,n(a(e)("wechatQrcodeTips")),1)]),_:1},8,["label"])]),_:1}),t(h,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:l(()=>[s("h3",pe,n(a(e)("wechatDevelopInfo")),1),t(d,{label:a(e)("wechatAppid"),prop:"app_id"},{default:l(()=>[t(p,{modelValue:r.app_id,"onUpdate:modelValue":o[4]||(o[4]=i=>r.app_id=i),placeholder:a(e)("appidPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"]),s("div",ce,n(a(e)("wechatAppidTips")),1)]),_:1},8,["label"]),t(d,{label:a(e)("wechatAppsecret"),prop:"app_secret"},{default:l(()=>[t(p,{modelValue:r.app_secret,"onUpdate:modelValue":o[5]||(o[5]=i=>r.app_secret=i),placeholder:a(e)("appSecretPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"]),s("div",ue,n(a(e)("wechatAppsecretTips")),1)]),_:1},8,["label"])]),_:1}),t(h,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:l(()=>[s("h3",me,n(a(e)("theServerSetting")),1),t(d,{label:"URL"},{default:l(()=>[t(p,{"model-value":c.serve_url,placeholder:"Please input",class:"input-width",readonly:!0},{append:l(()=>[s("div",{class:"cursor-pointer",onClick:o[6]||(o[6]=i=>_(c.serve_url))},n(a(e)("copy")),1)]),_:1},8,["model-value"])]),_:1}),t(d,{label:"Token",prop:"token"},{default:l(()=>[t(p,{modelValue:r.token,"onUpdate:modelValue":o[7]||(o[7]=i=>r.token=i),placeholder:a(e)("tokenPlaceholder"),class:"input-width",maxlength:"32","show-word-limit":"",clearable:""},null,8,["modelValue","placeholder"]),s("div",_e,n(a(e)("tokenTips")),1)]),_:1}),t(d,{label:"EncodingAESKey",prop:"encoding_aes_key"},{default:l(()=>[t(p,{modelValue:r.encoding_aes_key,"onUpdate:modelValue":o[8]||(o[8]=i=>r.encoding_aes_key=i),placeholder:a(e)("encodingAesKeyPlaceholder"),class:"input-width",maxlength:"43","show-word-limit":"",clearable:""},null,8,["modelValue","placeholder"]),s("div",he,n(a(e)("encodingAESKeyTips")),1)]),_:1}),t(d,{label:a(e)("encryptionType"),prop:"encryption_type"},{default:l(()=>[t(U,{modelValue:r.encryption_type,"onUpdate:modelValue":o[9]||(o[9]=i=>r.encryption_type=i)},{default:l(()=>[t(g,{label:"not_encrypt"},{default:l(()=>[f(n(a(e)("cleartextMode")),1)]),_:1}),t(g,{label:"compatible"},{default:l(()=>[f(n(a(e)("compatibleMode")),1)]),_:1}),t(g,{label:"safe"},{default:l(()=>[f(n(a(e)("safeMode")),1)]),_:1})]),_:1},8,["modelValue"]),s("div",fe,n(a(e)("cleartextModeTips")),1),s("div",ge,n(a(e)("compatibleModeTips")),1),s("div",be,n(a(e)("safeModeTips")),1)]),_:1},8,["label"])]),_:1}),t(h,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:l(()=>[s("div",ve,[s("h3",we,n(a(e)("functionSetting")),1)]),t(d,{label:""},{default:l(()=>[s("div",ye,n(a(e)("functionSettingTips")),1)]),_:1}),t(d,{label:a(e)("businessDomain")},{default:l(()=>[t(p,{"model-value":c.business_domain,placeholder:"Please input",class:"input-width",readonly:!0},{append:l(()=>[s("div",{class:"cursor-pointer",onClick:o[10]||(o[10]=i=>_(c.business_domain))},n(a(e)("copy")),1)]),_:1},8,["model-value"])]),_:1},8,["label"]),t(d,{label:a(e)("jsSecureDomain")},{default:l(()=>[t(p,{"model-value":c.js_secure_domain,placeholder:"Please input",class:"input-width",readonly:!0},{append:l(()=>[s("div",{class:"cursor-pointer",onClick:o[11]||(o[11]=i=>_(c.business_domain))},n(a(e)("copy")),1)]),_:1},8,["model-value"])]),_:1},8,["label"]),t(d,{label:a(e)("webAuthDomain")},{default:l(()=>[t(p,{"model-value":c.web_auth_domain,placeholder:"Please input",class:"input-width",readonly:!0},{append:l(()=>[s("div",{class:"cursor-pointer",onClick:o[12]||(o[12]=i=>_(c.business_domain))},n(a(e)("copy")),1)]),_:1},8,["model-value"])]),_:1},8,["label"])]),_:1})]),_:1},8,["model","rules"])),[[D,m.value]]),s("div",xe,[s("div",Ve,[t(R,{type:"primary",loading:m.value,onClick:o[13]||(o[13]=i=>q(v.value))},{default:l(()=>[f(n(a(e)("save")),1)]),_:1},8,["loading"])])])])}}});export{oa as default};
diff --git a/niucloud/public/admin/assets/config-4d791795.js b/niucloud/public/admin/assets/config-4d791795.js
new file mode 100644
index 0000000..40e26b2
--- /dev/null
+++ b/niucloud/public/admin/assets/config-4d791795.js
@@ -0,0 +1 @@
+import{aJ as y,d as I,O as D,r as v,n as F,aI as O,s as R,a2 as g,N as a,h,c as $,a as n,t as u,u as l,y as j,I as H,w as i,e as r,i as M,aK as U,X as J,W as K,_ as L,Y as T,E as W,$ as X}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import{q as Y}from"./sys-0f76aff3.js";import{_ as z}from"./_plugin-vue_export-helper-c27b6911.js";function A(){return y.get("channel/h5/config")}function G(_){return y.put("channel/h5/config",_,{showSuccessMessage:!0})}const P={class:"main-container"},Q={class:"flex ml-[18px] justify-between items-center mt-[20px]"},Z={class:"text-[20px]"},ee={class:"fixed-footer-wrap"},te={class:"fixed-footer"},oe=I({__name:"config",setup(_){const w=D().meta.title,s=v(!0),e=F({is_open:!0,request_url:""}),d=v();A().then(t=>{Object.assign(e,t.data),e.is_open=Boolean(Number(e.is_open)),s.value=!1}),Y().then(t=>{e.request_url=t.data.wap_url+"/"});const{copy:x,isSupported:b,copied:m}=O(),C=t=>{if(!b.value){g({message:a("notSupportCopy"),type:"warning"});return}x(t)};R(m,()=>{m.value&&g({message:a("copySuccess"),type:"success"})});const E=()=>{window.open(e.request_url)},k=async t=>{s.value||!t||await t.validate(async o=>{if(o){s.value=!0;const c={...e};c.is_open=Number(c.is_open),G(c).then(()=>{s.value=!1}).catch(()=>{s.value=!1})}})};return(t,o)=>{const c=U,f=J,N=K,q=L,V=T,B=W,S=X;return h(),$("div",P,[n("div",Q,[n("span",Z,u(l(w)),1)]),j((h(),H(V,{model:e,"label-width":"150px",ref_key:"formRef",ref:d,class:"page-form"},{default:i(()=>[r(q,{class:"box-card !border-none",shadow:"never"},{default:i(()=>[r(f,{label:l(a)("isOpen")},{default:i(()=>[r(c,{modelValue:e.is_open,"onUpdate:modelValue":o[0]||(o[0]=p=>e.is_open=p)},null,8,["modelValue"])]),_:1},8,["label"]),r(f,{label:l(a)("h5DomainName")},{default:i(()=>[r(N,{"model-value":e.request_url,class:"input-width",readonly:!0},{append:i(()=>[n("div",{class:"cursor-pointer",onClick:o[1]||(o[1]=p=>C(e.request_url))},u(l(a)("copy")),1)]),_:1},8,["model-value"]),n("span",{class:"ml-2 cursor-pointer visit-btn",onClick:E},u(l(a)("clickVisit")),1)]),_:1},8,["label"])]),_:1})]),_:1},8,["model"])),[[S,s.value]]),n("div",ee,[n("div",te,[r(B,{type:"primary",loading:s.value,onClick:o[2]||(o[2]=p=>k(d.value))},{default:i(()=>[M(u(l(a)("save")),1)]),_:1},8,["loading"])])])])}}});const me=z(oe,[["__scopeId","data-v-a4af058c"]]);export{me as default};
diff --git a/niucloud/public/admin/assets/config-715ad915.js b/niucloud/public/admin/assets/config-715ad915.js
new file mode 100644
index 0000000..b235767
--- /dev/null
+++ b/niucloud/public/admin/assets/config-715ad915.js
@@ -0,0 +1 @@
+import{d as T,O as A,f as K,r as h,n as B,aI as I,s as $,a2 as v,N as e,h as b,c as D,a as s,u as a,t as n,y as O,I as R,w as p,e as t,i as g,W,X as j,_ as F,Y as L,E as Q,$ as z}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css */import{_ as M}from"./index.vue_vue_type_style_index_0_lang-eec94bc0.js";/* empty css */import{_ as X}from"./index-4718d422.js";import"./el-form-item-4ed993c7.js";/* empty css */import{g as Y,a as G,s as H}from"./aliapp-2e18109a.js";/* empty css *//* empty css */import"./index.vue_vue_type_style_index_0_lang-cc99af21.js";/* empty css */import"./attachment-bc20fd95.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-6f0143c4.js";/* empty css */import"./sys-0f76aff3.js";import"./_plugin-vue_export-helper-c27b6911.js";const J={class:"main-container"},Z={class:"detail-head"},ee=s("span",{class:"iconfont iconxiangzuojiantou !text-xs"},null,-1),ae={class:"ml-[1px]"},le=s("span",{class:"adorn"},"|",-1),te={class:"right"},oe={class:"panel-title !text-sm"},se={class:"form-tip"},ie={class:"panel-title !text-sm"},pe={class:"input-width"},ne={class:"form-tip"},re={class:"input-width"},de={class:"form-tip"},ue={class:"input-width"},ce={class:"form-tip"},me={class:"panel-title !text-sm"},_e={class:"flex"},fe={class:"panel-title !text-sm"},ye={class:"fixed-footer-wrap"},he={class:"fixed-footer"},He=T({__name:"config",setup(ve){const V=A(),w=K(),x=V.meta.title,u=h(!0),o=B({name:"",qrcode:"",private_key:"",app_id:"",aes_key:"",public_key_crt:"",alipay_public_key_crt:"",alipay_with_crt:"",request_url:""}),f=h();Y().then(d=>{Object.assign(o,d.data),u.value=!1}),G().then(d=>{o.request_url=d.data.domain});const{copy:k,isSupported:C,copied:y}=I(),S=d=>{if(!C.value){v({message:e("notSupportCopy"),type:"warning"});return}k(d)};$(y,()=>{y.value&&v({message:e("copySuccess"),type:"success"})});const E=async d=>{u.value||!d||await d.validate(async l=>{l&&(u.value=!0,H(o).then(()=>{u.value=!1}).catch(()=>{u.value=!1}))})};return(d,l)=>{const c=W,r=j,P=X,m=F,_=M,U=L,q=Q,N=z;return b(),D("div",J,[s("div",Z,[s("div",{class:"left",onClick:l[0]||(l[0]=i=>a(w).push({path:"/channel/aliapp"}))},[ee,s("span",ae,n(a(e)("returnToPreviousPage")),1)]),le,s("span",te,n(a(x)),1)]),O((b(),R(U,{model:o,"label-width":"150px",ref_key:"formRef",ref:f,class:"page-form"},{default:p(()=>[t(m,{class:"box-card !border-none",shadow:"never"},{default:p(()=>[s("h3",oe,n(a(e)("aliappSet")),1),t(r,{label:a(e)("aliappName")},{default:p(()=>[t(c,{modelValue:o.name,"onUpdate:modelValue":l[1]||(l[1]=i=>o.name=i),placeholder:a(e)("aliappNamePlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),t(r,{label:a(e)("aliappQrcode")},{default:p(()=>[t(P,{modelValue:o.qrcode,"onUpdate:modelValue":l[2]||(l[2]=i=>o.qrcode=i)},null,8,["modelValue"]),s("div",se,n(a(e)("aliappQrcodeTips")),1)]),_:1},8,["label"])]),_:1}),t(m,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:p(()=>[s("h3",ie,n(a(e)("aliappDevelopInfo")),1),t(r,{label:a(e)("aliappOriginal")},{default:p(()=>[t(c,{modelValue:o.private_key,"onUpdate:modelValue":l[3]||(l[3]=i=>o.private_key=i),placeholder:a(e)("aliappOriginalPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),t(r,{label:a(e)("aliappAppid")},{default:p(()=>[t(c,{modelValue:o.app_id,"onUpdate:modelValue":l[4]||(l[4]=i=>o.app_id=i),placeholder:a(e)("appidPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),t(r,{label:a(e)("countersignType")},{default:p(()=>[g(n(a(e)("certificate")),1)]),_:1},8,["label"]),t(r,{label:a(e)("publicKey")},{default:p(()=>[s("div",pe,[t(_,{modelValue:o.public_key_crt,"onUpdate:modelValue":l[5]||(l[5]=i=>o.public_key_crt=i),api:"sys/document/aliyun"},null,8,["modelValue"])]),s("div",ne,n(a(e)("publicKeyTips")),1)]),_:1},8,["label"]),t(r,{label:a(e)("alipayPublicKey")},{default:p(()=>[s("div",re,[t(_,{modelValue:o.alipay_public_key_crt,"onUpdate:modelValue":l[6]||(l[6]=i=>o.alipay_public_key_crt=i),api:"sys/document/aliyun"},null,8,["modelValue"])]),s("div",de,n(a(e)("alipayPublicKeyTips")),1)]),_:1},8,["label"]),t(r,{label:a(e)("alipayWithCrt")},{default:p(()=>[s("div",ue,[t(_,{modelValue:o.alipay_with_crt,"onUpdate:modelValue":l[7]||(l[7]=i=>o.alipay_with_crt=i),api:"sys/document/aliyun"},null,8,["modelValue"])]),s("div",ce,n(a(e)("alipayWithCrtTips")),1)]),_:1},8,["label"])]),_:1}),t(m,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:p(()=>[s("h3",me,n(a(e)("theServerSetting")),1),t(r,{label:"AESKey"},{default:p(()=>[t(c,{modelValue:o.aes_key,"onUpdate:modelValue":l[8]||(l[8]=i=>o.aes_key=i),placeholder:a(e)("AESKeyPlaceholder"),class:"input-width","show-word-limit":"",clearable:""},null,8,["modelValue","placeholder"])]),_:1})]),_:1}),t(m,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:p(()=>[s("div",_e,[s("h3",fe,n(a(e)("functionSetting")),1)]),t(r,{label:a(e)("serveWhiteList")},{default:p(()=>[t(c,{"model-value":o.request_url,class:"input-width",readonly:!0},{append:p(()=>[s("div",{class:"cursor-pointer",onClick:l[9]||(l[9]=i=>S(o.request_url))},n(a(e)("copy")),1)]),_:1},8,["model-value"])]),_:1},8,["label"])]),_:1})]),_:1},8,["model"])),[[N,u.value]]),s("div",ye,[s("div",he,[t(q,{type:"primary",loading:u.value,onClick:l[10]||(l[10]=i=>E(f.value))},{default:p(()=>[g(n(a(e)("save")),1)]),_:1},8,["loading"])])])])}}});export{He as default};
diff --git a/niucloud/public/admin/assets/config-8cc9fc39.js b/niucloud/public/admin/assets/config-8cc9fc39.js
new file mode 100644
index 0000000..9df65fe
--- /dev/null
+++ b/niucloud/public/admin/assets/config-8cc9fc39.js
@@ -0,0 +1 @@
+import{aJ as t}from"./index-6010b07e.js";function r(e){return t.get(`hygl/config/${e}`)}function s(e){return t.post("hygl/config",e,{showErrorMessage:!0,showSuccessMessage:!0})}function n(e){return t.put(`hygl/config/${e.id}`,e,{showErrorMessage:!0,showSuccessMessage:!0})}function g(e){return t.get(`hygl/config/resetH5SiteQRCode/${e}`)}export{s as a,n as e,r as g,g as r};
diff --git a/niucloud/public/admin/assets/config-978d7f3b.js b/niucloud/public/admin/assets/config-978d7f3b.js
new file mode 100644
index 0000000..245d87d
--- /dev/null
+++ b/niucloud/public/admin/assets/config-978d7f3b.js
@@ -0,0 +1 @@
+import{d as M,O as K,f as O,r as w,n as b,N as e,aI as B,s as D,a2 as y,h as k,c as j,a as s,u as l,t as r,y as W,I as F,w as p,e as o,i as f,W as L,X as Q,_ as z,aw as G,ax as X,Y,E as H,$ as J}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css */import{_ as Z}from"./index.vue_vue_type_style_index_0_lang-eec94bc0.js";/* empty css */import{_ as ee}from"./index-4718d422.js";import"./el-form-item-4ed993c7.js";/* empty css */import{g as x,d as le}from"./weapp-7423630d.js";/* empty css *//* empty css */import"./index.vue_vue_type_style_index_0_lang-cc99af21.js";/* empty css */import"./attachment-bc20fd95.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-6f0143c4.js";/* empty css */import"./sys-0f76aff3.js";import"./_plugin-vue_export-helper-c27b6911.js";const oe={class:"main-container"},ae={class:"detail-head"},te=s("span",{class:"iconfont iconxiangzuojiantou !text-xs"},null,-1),pe={class:"ml-[1px]"},se=s("span",{class:"adorn"},"|",-1),re={class:"right"},de={class:"panel-title !text-sm"},ne={class:"form-tip"},ie={class:"panel-title !text-sm"},ue={class:"form-tip"},ce={class:"form-tip"},_e={class:"panel-title !text-sm"},me={class:"input-width"},fe={class:"form-tip"},ve={class:"form-tip"},he={class:"panel-title !text-sm"},ge={class:"form-tip"},we={class:"form-tip"},be={class:"form-tip"},ye={class:"form-tip"},ke={class:"form-tip"},xe={class:"flex"},Ve={class:"panel-title !text-sm"},Pe={class:"fixed-footer-wrap"},Ue={class:"fixed-footer"},rl=M({__name:"config",setup(qe){const V=K(),P=O(),U=V.meta.title,c=w(!0),t=b({weapp_name:"",weapp_original:"",app_id:"",app_secret:"",qr_code:"",token:"",encoding_aes_key:"",encryption_type:"not_encrypt",serve_url:"",request_url:"",socket_url:"",upload_url:"",download_url:"",upload_private_key:""}),h=w(),q=b({weapp_name:[{required:!0,message:e("weappNamePlaceholder"),trigger:"blur"}],weapp_original:[{required:!0,message:e("weappOriginalPlaceholder"),trigger:"blur"}],app_id:[{required:!0,message:e("appidPlaceholder"),trigger:"blur"}],app_secret:[{required:!0,message:e("appSecretPlaceholder"),trigger:"blur"}],token:[{required:!0,message:e("tokenPlaceholder"),trigger:"blur"}],encoding_aes_key:[{required:!0,message:e("encodingAesKeyPlaceholder"),trigger:"blur"}]});x().then(u=>{Object.assign(t,u.data),c.value=!1}),x().then(u=>{Object.assign(u.data)});const{copy:C,isSupported:T,copied:g}=B(),_=u=>{if(!T.value){y({message:e("notSupportCopy"),type:"warning"});return}C(u)};D(g,()=>{g.value&&y({message:e("copySuccess"),type:"success"})});const E=async u=>{c.value||!u||await u.validate(async a=>{a&&(c.value=!0,le(t).then(()=>{c.value=!1}).catch(()=>{c.value=!1}))})};return(u,a)=>{const i=L,n=Q,S=ee,m=z,$=Z,v=G,A=X,N=Y,R=H,I=J;return k(),j("div",oe,[s("div",ae,[s("div",{class:"left",onClick:a[0]||(a[0]=d=>l(P).push({path:"/channel/weapp"}))},[te,s("span",pe,r(l(e)("returnToPreviousPage")),1)]),se,s("span",re,r(l(U)),1)]),W((k(),F(N,{model:t,"label-width":"170px",ref_key:"formRef",ref:h,rules:q,class:"page-form"},{default:p(()=>[o(m,{class:"box-card !border-none",shadow:"never"},{default:p(()=>[s("h3",de,r(l(e)("weappInfo")),1),o(n,{label:l(e)("weappName"),prop:"weapp_name"},{default:p(()=>[o(i,{modelValue:t.weapp_name,"onUpdate:modelValue":a[1]||(a[1]=d=>t.weapp_name=d),placeholder:l(e)("weappNamePlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),o(n,{label:l(e)("weappOriginal"),prop:"weapp_original"},{default:p(()=>[o(i,{modelValue:t.weapp_original,"onUpdate:modelValue":a[2]||(a[2]=d=>t.weapp_original=d),placeholder:l(e)("weappOriginalPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),o(n,{label:l(e)("weappQrcode"),prop:"qr_code"},{default:p(()=>[o(S,{modelValue:t.qr_code,"onUpdate:modelValue":a[3]||(a[3]=d=>t.qr_code=d)},null,8,["modelValue"]),s("div",ne,r(l(e)("weappQrcodeTips")),1)]),_:1},8,["label"])]),_:1}),o(m,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:p(()=>[s("h3",ie,r(l(e)("weappDevelopInfo")),1),o(n,{label:l(e)("weappAppid"),prop:"app_id"},{default:p(()=>[o(i,{modelValue:t.app_id,"onUpdate:modelValue":a[4]||(a[4]=d=>t.app_id=d),placeholder:l(e)("appidPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"]),s("div",ue,r(l(e)("weappAppidTips")),1)]),_:1},8,["label"]),o(n,{label:l(e)("weappAppsecret"),prop:"app_secret"},{default:p(()=>[o(i,{modelValue:t.app_secret,"onUpdate:modelValue":a[5]||(a[5]=d=>t.app_secret=d),placeholder:l(e)("appSecretPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"]),s("div",ce,r(l(e)("weappAppsecretTips")),1)]),_:1},8,["label"])]),_:1}),o(m,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:p(()=>[s("h3",_e,r(l(e)("weappUpload")),1),o(n,{label:l(e)("uploadKey"),prop:"upload_private_key"},{default:p(()=>[s("div",me,[o($,{modelValue:t.upload_private_key,"onUpdate:modelValue":a[6]||(a[6]=d=>t.upload_private_key=d),api:"sys/document/wechat"},null,8,["modelValue"])]),s("div",fe,r(l(e)("uploadKeyTips")),1),s("div",ve,r(l(e)("uploadIpTips"))+r(t.upload_ip),1)]),_:1},8,["label"])]),_:1}),o(m,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:p(()=>[s("h3",he,r(l(e)("theServerSetting")),1),o(n,{label:"URL"},{default:p(()=>[o(i,{"model-value":t.serve_url,placeholder:"Please input",class:"input-width",readonly:!0},{append:p(()=>[s("div",{class:"cursor-pointer",onClick:a[7]||(a[7]=d=>_(t.serve_url))},r(l(e)("copy")),1)]),_:1},8,["model-value"])]),_:1}),o(n,{label:"Token",prop:"token"},{default:p(()=>[o(i,{modelValue:t.token,"onUpdate:modelValue":a[8]||(a[8]=d=>t.token=d),placeholder:l(e)("tokenPlaceholder"),class:"input-width",maxlength:"32","show-word-limit":"",clearable:""},null,8,["modelValue","placeholder"]),s("div",ge,r(l(e)("tokenTips")),1)]),_:1}),o(n,{label:"EncodingAESKey",prop:"encoding_aes_key"},{default:p(()=>[o(i,{modelValue:t.encoding_aes_key,"onUpdate:modelValue":a[9]||(a[9]=d=>t.encoding_aes_key=d),placeholder:l(e)("encodingAesKeyPlaceholder"),class:"input-width",maxlength:"43","show-word-limit":"",clearable:""},null,8,["modelValue","placeholder"]),s("div",we,r(l(e)("encodingAESKeyTips")),1)]),_:1}),o(n,{label:l(e)("encryptionType"),prop:"encryption_type"},{default:p(()=>[o(A,{modelValue:t.encryption_type,"onUpdate:modelValue":a[10]||(a[10]=d=>t.encryption_type=d)},{default:p(()=>[o(v,{label:"not_encrypt"},{default:p(()=>[f(r(l(e)("cleartextMode")),1)]),_:1}),o(v,{label:"compatible"},{default:p(()=>[f(r(l(e)("compatibleMode")),1)]),_:1}),o(v,{label:"safe"},{default:p(()=>[f(r(l(e)("safeMode")),1)]),_:1})]),_:1},8,["modelValue"]),s("div",be,r(l(e)("cleartextModeTips")),1),s("div",ye,r(l(e)("compatibleModeTips")),1),s("div",ke,r(l(e)("safeModeTips")),1)]),_:1},8,["label"])]),_:1}),o(m,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:p(()=>[s("div",xe,[s("h3",Ve,r(l(e)("functionSetting")),1)]),o(n,{label:l(e)("requestUrl")},{default:p(()=>[o(i,{"model-value":t.request_url,placeholder:"Please input",class:"input-width",readonly:!0},{append:p(()=>[s("div",{class:"cursor-pointer",onClick:a[11]||(a[11]=d=>_(t.request_url))},r(l(e)("copy")),1)]),_:1},8,["model-value"])]),_:1},8,["label"]),o(n,{label:l(e)("socketUrl")},{default:p(()=>[o(i,{"model-value":t.socket_url,placeholder:"Please input",class:"input-width",readonly:!0},{append:p(()=>[s("div",{class:"cursor-pointer",onClick:a[12]||(a[12]=d=>_(t.socket_url))},r(l(e)("copy")),1)]),_:1},8,["model-value"])]),_:1},8,["label"]),o(n,{label:l(e)("uploadUrl")},{default:p(()=>[o(i,{"model-value":t.upload_url,placeholder:"Please input",class:"input-width",readonly:!0},{append:p(()=>[s("div",{class:"cursor-pointer",onClick:a[13]||(a[13]=d=>_(t.upload_url))},r(l(e)("copy")),1)]),_:1},8,["model-value"])]),_:1},8,["label"]),o(n,{label:l(e)("downloadUrl")},{default:p(()=>[o(i,{"model-value":t.download_url,placeholder:"Please input",class:"input-width",readonly:!0},{append:p(()=>[s("div",{class:"cursor-pointer",onClick:a[14]||(a[14]=d=>_(t.download_url))},r(l(e)("copy")),1)]),_:1},8,["model-value"])]),_:1},8,["label"])]),_:1})]),_:1},8,["model","rules"])),[[I,c.value]]),s("div",Pe,[s("div",Ue,[o(R,{type:"primary",loading:c.value,onClick:a[15]||(a[15]=d=>E(h.value))},{default:p(()=>[f(r(l(e)("save")),1)]),_:1},8,["loading"])])])])}}});export{rl as default};
diff --git a/niucloud/public/admin/assets/config-c9a3921b.js b/niucloud/public/admin/assets/config-c9a3921b.js
new file mode 100644
index 0000000..cdd24b1
--- /dev/null
+++ b/niucloud/public/admin/assets/config-c9a3921b.js
@@ -0,0 +1 @@
+import{d as I,O as S,r as u,n as k,aI as q,s as N,a2 as m,N as e,y as D,h as R,c as B,a as n,t as l,u as s,e as o,w as a,X as F,W as V,_ as L,Y as U,$,p as j,g as M}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";import{q as O}from"./sys-0f76aff3.js";import{_ as P}from"./_plugin-vue_export-helper-c27b6911.js";const W=""+new URL("preview-52aad803.png",import.meta.url).href,X=r=>(j("data-v-d65a39d5"),r=r(),M(),r),Y={class:"main-container"},z={class:"flex ml-[18px] justify-between items-center mt-[20px]"},A={class:"text-[20px]"},G=X(()=>n("img",{class:"w-[500px]",src:W,alt:""},null,-1)),H=I({__name:"config",setup(r){const f=S().meta.title,p=u(!0),t=k({is_open:!1,request_url:""}),v=u();O().then(c=>{t.request_url=c.data.web_url+"/",p.value=!1});const{copy:g,isSupported:w,copied:i}=q(),h=c=>{if(!w.value){m({message:e("notSupportCopy"),type:"warning"});return}g(c)};N(i,()=>{i.value&&m({message:e("copySuccess"),type:"success"})});const y=()=>{window.open(t.request_url)};return(c,_)=>{const d=F,x=V,b=L,C=U,E=$;return D((R(),B("div",Y,[n("div",z,[n("span",A,l(s(f)),1)]),o(C,{model:t,"label-width":"150px",ref_key:"formRef",ref:v,class:"page-form"},{default:a(()=>[o(b,{class:"box-card !border-none",shadow:"never"},{default:a(()=>[o(d,{label:s(e)("preview"),prop:"weapp_name"},{default:a(()=>[G]),_:1},8,["label"]),o(d,{label:s(e)("PCDomainName")},{default:a(()=>[o(x,{"model-value":t.request_url,class:"input-width",readonly:!0},{append:a(()=>[n("div",{class:"cursor-pointer",onClick:_[0]||(_[0]=K=>h(t.request_url))},l(s(e)("copy")),1)]),_:1},8,["model-value"]),n("span",{class:"ml-2 cursor-pointer visit-btn",onClick:y},l(s(e)("clickVisit")),1)]),_:1},8,["label"])]),_:1})]),_:1},8,["model"])])),[[E,p.value]])}}});const ne=P(H,[["__scopeId","data-v-d65a39d5"]]);export{ne as default};
diff --git a/niucloud/public/admin/assets/config-eaf1c3f2.css b/niucloud/public/admin/assets/config-eaf1c3f2.css
new file mode 100644
index 0000000..8e8d4a5
--- /dev/null
+++ b/niucloud/public/admin/assets/config-eaf1c3f2.css
@@ -0,0 +1 @@
+.visit-btn[data-v-d65a39d5]{color:var(--el-color-primary)}
diff --git a/niucloud/public/admin/assets/config-edit-4300ae81.js b/niucloud/public/admin/assets/config-edit-4300ae81.js
new file mode 100644
index 0000000..bd13b5c
--- /dev/null
+++ b/niucloud/public/admin/assets/config-edit-4300ae81.js
@@ -0,0 +1 @@
+import{d as q,r as y,n as N,q as A,N as e,h as f,I as w,w as o,a as K,e as p,aQ as g,i as b,t as P,u as t,y as M,W as D,X as E,Y as R,E as x,a7 as F,$ as B}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import{e as S,a as j,g as O}from"./config-8cc9fc39.js";const $={class:"dialog-footer"},Z=q({__name:"config-edit",emits:["complete"],setup(L,{expose:V,emit:C}){let _=y(!1);const u=y(!1),c={id:"",we_chat_pay_appid:"",we_chat_pay_app_id:"",we_chat_pay_miniapp_id:"",we_chat_pay_mch_id:"",we_chat_pay_key:"",we_chat_pay_miniapp_secret:"",we_chat_pay_notify_url:"",alipay_appId:"",alipay_rsa_private_key:"",alipay_public_key:"",alipay_notify_url:""},l=N({...c}),m=y(),v=A(()=>({we_chat_pay_appid:[{required:!0,message:e("weChatPayAppidPlaceholder"),trigger:"blur"}],we_chat_pay_app_id:[{required:!0,message:e("weChatPayAppIdPlaceholder"),trigger:"blur"}],we_chat_pay_miniapp_id:[{required:!0,message:e("weChatPayMiniappIdPlaceholder"),trigger:"blur"}],we_chat_pay_mch_id:[{required:!0,message:e("weChatPayMchIdPlaceholder"),trigger:"blur"}],we_chat_pay_key:[{required:!0,message:e("weChatPayKeyPlaceholder"),trigger:"blur"}],we_chat_pay_miniapp_secret:[{required:!0,message:e("weChatPayMiniappSecretPlaceholder"),trigger:"blur"}],we_chat_pay_notify_url:[{required:!0,message:e("weChatPayNotifyUrlPlaceholder"),trigger:"blur"}],alipay_appId:[{required:!0,message:e("alipayAppIdPlaceholder"),trigger:"blur"}],alipay_rsa_private_key:[{required:!0,message:e("alipayRsaPrivateKeyPlaceholder"),trigger:"blur"}],alipay_public_key:[{required:!0,message:e("alipayPublicKeyPlaceholder"),trigger:"blur"}],alipay_notify_url:[{required:!0,message:e("alipayNotifyUrlPlaceholder"),trigger:"blur"}]})),I=async s=>{if(u.value||!s)return;let a=l.id?S:j;await s.validate(async r=>{r&&(u.value=!0,a(l).then(n=>{u.value=!1,_.value=!1,C("complete")}).catch(n=>{u.value=!1}))})};return V({showDialog:_,setFormData:async(s=null)=>{if(Object.assign(l,c),u.value=!0,s){const a=await(await O(s.id)).data;a&&Object.keys(l).forEach(r=>{a[r]!=null&&(l[r]=a[r])})}u.value=!1}}),(s,a)=>{const r=D,d=E,n=R,h=x,U=F,k=B;return f(),w(U,{modelValue:t(_),"onUpdate:modelValue":a[13]||(a[13]=i=>g(_)?_.value=i:_=i),title:l.id?t(e)("updateConfig"):t(e)("addConfig"),width:"50%",class:"diy-dialog-wrap","destroy-on-close":!0},{footer:o(()=>[K("span",$,[p(h,{onClick:a[11]||(a[11]=i=>g(_)?_.value=!1:_=!1)},{default:o(()=>[b(P(t(e)("cancel")),1)]),_:1}),p(h,{type:"primary",loading:u.value,onClick:a[12]||(a[12]=i=>I(m.value))},{default:o(()=>[b(P(t(e)("confirm")),1)]),_:1},8,["loading"])])]),default:o(()=>[M((f(),w(n,{model:l,"label-width":"120px",ref_key:"formRef",ref:m,rules:t(v),class:"page-form"},{default:o(()=>[p(d,{label:t(e)("weChatPayAppid")},{default:o(()=>[p(r,{modelValue:l.we_chat_pay_appid,"onUpdate:modelValue":a[0]||(a[0]=i=>l.we_chat_pay_appid=i),clearable:"",placeholder:t(e)("weChatPayAppidPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),p(d,{label:t(e)("weChatPayAppId")},{default:o(()=>[p(r,{modelValue:l.we_chat_pay_app_id,"onUpdate:modelValue":a[1]||(a[1]=i=>l.we_chat_pay_app_id=i),clearable:"",placeholder:t(e)("weChatPayAppIdPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),p(d,{label:t(e)("weChatPayMiniappId")},{default:o(()=>[p(r,{modelValue:l.we_chat_pay_miniapp_id,"onUpdate:modelValue":a[2]||(a[2]=i=>l.we_chat_pay_miniapp_id=i),clearable:"",placeholder:t(e)("weChatPayMiniappIdPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),p(d,{label:t(e)("weChatPayMchId")},{default:o(()=>[p(r,{modelValue:l.we_chat_pay_mch_id,"onUpdate:modelValue":a[3]||(a[3]=i=>l.we_chat_pay_mch_id=i),clearable:"",placeholder:t(e)("weChatPayMchIdPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),p(d,{label:t(e)("weChatPayKey")},{default:o(()=>[p(r,{modelValue:l.we_chat_pay_key,"onUpdate:modelValue":a[4]||(a[4]=i=>l.we_chat_pay_key=i),clearable:"",placeholder:t(e)("weChatPayKeyPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),p(d,{label:t(e)("weChatPayMiniappSecret")},{default:o(()=>[p(r,{modelValue:l.we_chat_pay_miniapp_secret,"onUpdate:modelValue":a[5]||(a[5]=i=>l.we_chat_pay_miniapp_secret=i),clearable:"",placeholder:t(e)("weChatPayMiniappSecretPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),p(d,{label:t(e)("weChatPayNotifyUrl"),prop:"we_chat_pay_notify_url"},{default:o(()=>[p(r,{modelValue:l.we_chat_pay_notify_url,"onUpdate:modelValue":a[6]||(a[6]=i=>l.we_chat_pay_notify_url=i),clearable:"",placeholder:t(e)("weChatPayNotifyUrlPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),p(d,{label:t(e)("alipayAppId")},{default:o(()=>[p(r,{modelValue:l.alipay_appId,"onUpdate:modelValue":a[7]||(a[7]=i=>l.alipay_appId=i),clearable:"",placeholder:t(e)("alipayAppIdPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),p(d,{label:t(e)("alipayRsaPrivateKey")},{default:o(()=>[p(r,{modelValue:l.alipay_rsa_private_key,"onUpdate:modelValue":a[8]||(a[8]=i=>l.alipay_rsa_private_key=i),clearable:"",placeholder:t(e)("alipayRsaPrivateKeyPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),p(d,{label:t(e)("alipayPublicKey")},{default:o(()=>[p(r,{modelValue:l.alipay_public_key,"onUpdate:modelValue":a[9]||(a[9]=i=>l.alipay_public_key=i),clearable:"",placeholder:t(e)("alipayPublicKeyPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),p(d,{label:t(e)("alipayNotifyUrl"),prop:"alipay_notify_url"},{default:o(()=>[p(r,{modelValue:l.alipay_notify_url,"onUpdate:modelValue":a[10]||(a[10]=i=>l.alipay_notify_url=i),clearable:"",placeholder:t(e)("alipayNotifyUrlPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"])]),_:1},8,["model","rules"])),[[k,u.value]])]),_:1},8,["modelValue","title"])}}});export{Z as default};
diff --git a/niucloud/public/admin/assets/config-f3b067d2.css b/niucloud/public/admin/assets/config-f3b067d2.css
new file mode 100644
index 0000000..4561794
--- /dev/null
+++ b/niucloud/public/admin/assets/config-f3b067d2.css
@@ -0,0 +1 @@
+.visit-btn[data-v-a4af058c]{color:var(--el-color-primary)}
diff --git a/niucloud/public/admin/assets/config-fa8d1c5f.js b/niucloud/public/admin/assets/config-fa8d1c5f.js
new file mode 100644
index 0000000..a2f37db
--- /dev/null
+++ b/niucloud/public/admin/assets/config-fa8d1c5f.js
@@ -0,0 +1 @@
+import{d as U,O as N,r as y,n as x,q as E,N as a,h as C,c as F,a as d,t as m,u as r,e as _,w as i,i as f,I as B,B as H,a2 as M,W as R,X as A,E as D,Y as K,_ as S}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import{g as O,r as j,e as Q}from"./config-8cc9fc39.js";import{u as $}from"./common-adf8ca96.js";const T={class:"main-container"},W={class:"detail-head"},X={class:"right"},Y=d("p",{style:{color:"red"}},'重新生成二维码后->点击"保存"将替换此二维码',-1),z=["src"],G=["href"],J={class:"fixed-footer-wrap"},L={class:"fixed-footer"},ie=U({__name:"config",setup(Z){const w=N();parseInt(w.query.id);const h=y(!1),q=w.meta.title,g={id:0,we_chat_pay_appid:"",we_chat_pay_app_id:"",we_chat_pay_miniapp_id:"",we_chat_pay_mch_id:"",we_chat_pay_key:"",we_chat_pay_miniapp_secret:"",we_chat_pay_notify_url:"",alipay_appId:"",alipay_rsa_private_key:"",alipay_public_key:"",alipay_notify_url:"",we_chat_pay_mch_secret_cert:"",we_chat_pay_mch_public_cert_path:"",h5_site_url:"",h5_qrcode_url:"",ol_h5_qrcode_url:""},l=x({...g}),b=async(c=0)=>{Object.assign(l,g);const e=await(await O(c)).data;Object.keys(l).forEach(o=>{e[o]!=null&&(l[o]=e[o])})};b();const P=y();y([]);const v=E(()=>({we_chat_pay_appid:[{required:!0,message:a("weChatPayAppidPlaceholder"),trigger:"blur"}],we_chat_pay_app_id:[{required:!0,message:a("weChatPayAppIdPlaceholder"),trigger:"blur"}],we_chat_pay_miniapp_id:[{required:!0,message:a("weChatPayMiniappIdPlaceholder"),trigger:"blur"}],we_chat_pay_mch_id:[{required:!0,message:a("weChatPayMchIdPlaceholder"),trigger:"blur"}],we_chat_pay_key:[{required:!0,message:a("weChatPayKeyPlaceholder"),trigger:"blur"}],we_chat_pay_miniapp_secret:[{required:!0,message:a("weChatPayMiniappSecretPlaceholder"),trigger:"blur"}],we_chat_pay_notify_url:[{required:!0,message:a("weChatPayNotifyUrlPlaceholder"),trigger:"blur"}],we_chat_pay_mch_secret_cert:[{required:!0,message:a("商户私钥必传"),trigger:"blur"}],we_chat_pay_mch_public_cert_path:[{required:!0,message:a("商户公钥必传"),trigger:"blur"}],alipay_appId:[{required:!0,message:a("alipayAppIdPlaceholder"),trigger:"blur"}],alipay_rsa_private_key:[{required:!0,message:a("alipayRsaPrivateKeyPlaceholder"),trigger:"blur"}],alipay_public_key:[{required:!0,message:a("alipayPublicKeyPlaceholder"),trigger:"blur"}],alipay_notify_url:[{required:!0,message:a("alipayNotifyUrlPlaceholder"),trigger:"blur"}]})),k=async c=>{h.value||!c||await c.validate(async e=>{e&&(h.value=!0,Q(l).then(s=>{h.value=!1,b()}).catch(s=>{h.value=!1}))})},I=async()=>{let c=l;if(!c.id){M({message:"请先填写必要信息并点击保存后再试",type:"warning"});return}j(c.id).then(e=>{e.code&&(l.h5_qrcode_url=e.data.url)}).catch(e=>{console.log(e)})},V=(c,e,o)=>{const p=c.target;if(!p.files||p.files.length===0)return;const s=p.files[0];let n=new FormData;n.append("file",s),n.append("path",o),$(n).then(u=>{console.log(222,u),u.code&&(l[e]=u.data.file_path)}).catch(u=>{})};return(c,e)=>{const o=R,p=A,s=D,n=K,u=S;return C(),F("div",T,[d("div",W,[d("span",X,m(r(q)),1)]),_(u,{class:"box-card !border-none",shadow:"never"},{default:i(()=>[_(n,{model:l,"label-width":"270px",ref_key:"formRef",ref:P,rules:r(v),class:"page-form"},{default:i(()=>[_(p,{label:r(a)("weChatPayAppId"),prop:"we_chat_pay_app_id"},{default:i(()=>[_(o,{modelValue:l.we_chat_pay_app_id,"onUpdate:modelValue":e[0]||(e[0]=t=>l.we_chat_pay_app_id=t),clearable:"",placeholder:r(a)("weChatPayAppIdPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),_(p,{label:r(a)("weChatPayMchId"),prop:"we_chat_pay_mch_id"},{default:i(()=>[_(o,{modelValue:l.we_chat_pay_mch_id,"onUpdate:modelValue":e[1]||(e[1]=t=>l.we_chat_pay_mch_id=t),clearable:"",placeholder:r(a)("weChatPayMchIdPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),_(p,{label:r(a)("weChatPayKey"),prop:"we_chat_pay_key"},{default:i(()=>[_(o,{modelValue:l.we_chat_pay_key,"onUpdate:modelValue":e[2]||(e[2]=t=>l.we_chat_pay_key=t),clearable:"",placeholder:r(a)("weChatPayKeyPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),_(p,{label:r(a)("weChatPayNotifyUrl"),prop:"we_chat_pay_notify_url"},{default:i(()=>[_(o,{disabled:"true",modelValue:l.we_chat_pay_notify_url,"onUpdate:modelValue":e[3]||(e[3]=t=>l.we_chat_pay_notify_url=t),clearable:"",placeholder:r(a)("weChatPayNotifyUrlPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),_(p,{label:r(a)("上传微信商户私钥(apiclient_key.pem)"),prop:"we_chat_pay_mch_secret_cert"},{default:i(()=>[_(o,{modelValue:l.we_chat_pay_mch_secret_cert,"onUpdate:modelValue":e[4]||(e[4]=t=>l.we_chat_pay_mch_secret_cert=t),clearable:"",placeholder:r(a)("请上传商户私钥"),class:"input-width"},null,8,["modelValue","placeholder"]),d("div",null,[d("input",{type:"file",onChange:e[5]||(e[5]=t=>V(t,"we_chat_pay_mch_secret_cert","config_we_chat_pay_mch_secret_cert"))},null,32)])]),_:1},8,["label"]),_(p,{label:r(a)("上传微信商户公钥(apiclient_cert.pem)"),prop:"we_chat_pay_mch_public_cert_path"},{default:i(()=>[_(o,{modelValue:l.we_chat_pay_mch_public_cert_path,"onUpdate:modelValue":e[6]||(e[6]=t=>l.we_chat_pay_mch_public_cert_path=t),clearable:"",placeholder:r(a)("请上传商户公钥"),class:"input-width"},null,8,["modelValue","placeholder"]),d("input",{type:"file",onChange:e[7]||(e[7]=t=>V(t,"we_chat_pay_mch_public_cert_path","config_we_chat_pay_mch_public_cert_path"))},null,32)]),_:1},8,["label"]),_(p,{label:r(a)("H5站点地址"),prop:"h5_site_url"},{default:i(()=>[_(o,{disabled:"true",modelValue:l.h5_site_url,"onUpdate:modelValue":e[8]||(e[8]=t=>l.h5_site_url=t),clearable:"",placeholder:r(a)("H5站点地址"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),_(p,{label:r(a)("H5站点二维码"),prop:"h5_qrcode_url"},{default:i(()=>[_(o,{disabled:"true",modelValue:l.h5_qrcode_url,"onUpdate:modelValue":e[9]||(e[9]=t=>l.h5_qrcode_url=t),clearable:"",placeholder:r(a)("H5站点二维码"),class:"input-width"},null,8,["modelValue","placeholder"]),_(s,{style:{"margin-left":"15px"},type:"primary",onClick:e[10]||(e[10]=t=>I())},{default:i(()=>[f(m(r(a)("重新生成二维码")),1)]),_:1})]),_:1},8,["label"]),l.ol_h5_qrcode_url?(C(),B(p,{key:0,label:r(a)("原始H5站点二维码"),prop:"h5_qrcode_url"},{default:i(()=>[d("div",null,[Y,d("img",{src:l.ol_h5_qrcode_url,alt:""},null,8,z),d("a",{href:l.ol_h5_qrcode_url,target:"downloadFile",download:"h5_qrcode.png"},[_(s,{type:"primary"},{default:i(()=>[f("打开二维码")]),_:1})],8,G)])]),_:1},8,["label"])):H("",!0)]),_:1},8,["model","rules"])]),_:1}),d("div",J,[d("div",L,[_(s,{type:"primary",onClick:e[11]||(e[11]=t=>k(P.value))},{default:i(()=>[f(m(r(a)("save")),1)]),_:1})])])])}}});export{ie as default};
diff --git a/niucloud/public/admin/assets/config.config-8e11454c.js b/niucloud/public/admin/assets/config.config-8e11454c.js
new file mode 100644
index 0000000..816a595
--- /dev/null
+++ b/niucloud/public/admin/assets/config.config-8e11454c.js
@@ -0,0 +1 @@
+const a="id",e="站点id",t="请输入站点id",l="微信支付-APP的id",i="请输入微信支付-APP的id",c="微信支付-公众号APPID",o="请输入微信支付-公众号APPID",P="微信支付-小程序APPID",d="请输入微信支付-小程序APPID",p="微信支付-商户号",y="请输入微信支付-商户号",h="微信支付-商户号秘钥",n="请输入微信支付-商户号秘钥",r="微信支付-小程序secret",s="请输入微信支付-小程序secret",C="微信支付-异步回调地址",w="请输入微信支付-异步回调地址",I="支付宝-appid",A="请输入支付宝-appid",f="支付宝-开发者私钥",K="请输入支付宝-开发者私钥",M="支付宝-支付宝公钥",D="请输入支付宝-支付宝公钥",g="支付宝-异步回调地址",N="请输入支付宝-异步回调地址",U="创建时间",u="添加配置项",b="编辑配置项",v="确定要删除该数据吗?",R="请选择开始时间",S="请选择结束时间",T={id:a,siteId:e,siteIdPlaceholder:t,weChatPayAppid:l,weChatPayAppidPlaceholder:i,weChatPayAppId:c,weChatPayAppIdPlaceholder:o,weChatPayMiniappId:P,weChatPayMiniappIdPlaceholder:d,weChatPayMchId:p,weChatPayMchIdPlaceholder:y,weChatPayKey:h,weChatPayKeyPlaceholder:n,weChatPayMiniappSecret:r,weChatPayMiniappSecretPlaceholder:s,weChatPayNotifyUrl:C,weChatPayNotifyUrlPlaceholder:w,alipayAppId:I,alipayAppIdPlaceholder:A,alipayRsaPrivateKey:f,alipayRsaPrivateKeyPlaceholder:K,alipayPublicKey:M,alipayPublicKeyPlaceholder:D,alipayNotifyUrl:g,alipayNotifyUrlPlaceholder:N,createTime:U,addConfig:u,updateConfig:b,configDeleteTips:v,startDate:R,endDate:S};export{u as addConfig,I as alipayAppId,A as alipayAppIdPlaceholder,g as alipayNotifyUrl,N as alipayNotifyUrlPlaceholder,M as alipayPublicKey,D as alipayPublicKeyPlaceholder,f as alipayRsaPrivateKey,K as alipayRsaPrivateKeyPlaceholder,v as configDeleteTips,U as createTime,T as default,S as endDate,a as id,e as siteId,t as siteIdPlaceholder,R as startDate,b as updateConfig,c as weChatPayAppId,o as weChatPayAppIdPlaceholder,l as weChatPayAppid,i as weChatPayAppidPlaceholder,h as weChatPayKey,n as weChatPayKeyPlaceholder,p as weChatPayMchId,y as weChatPayMchIdPlaceholder,P as weChatPayMiniappId,d as weChatPayMiniappIdPlaceholder,r as weChatPayMiniappSecret,s as weChatPayMiniappSecretPlaceholder,C as weChatPayNotifyUrl,w as weChatPayNotifyUrlPlaceholder};
diff --git a/niucloud/public/admin/assets/copyright-7ea83f49.js b/niucloud/public/admin/assets/copyright-7ea83f49.js
new file mode 100644
index 0000000..3649fd7
--- /dev/null
+++ b/niucloud/public/admin/assets/copyright-7ea83f49.js
@@ -0,0 +1 @@
+import{d as k,r as g,n as f,N as o,h as v,c as U,y as E,I as P,w as i,e as a,a as c,t as u,u as t,i as D,X as N,W as R,_ as C,Y as B,E as F,$ as I}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";import{_ as L}from"./index-4718d422.js";import{Q as S,R as O}from"./sys-0f76aff3.js";/* empty css */import"./index.vue_vue_type_style_index_0_lang-cc99af21.js";/* empty css */import"./attachment-bc20fd95.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-6f0143c4.js";/* empty css */import"./_plugin-vue_export-helper-c27b6911.js";const $={class:"main-container"},j={class:"panel-title !text-sm"},q={class:"panel-title !text-sm"},Q={class:"fixed-footer-wrap"},T={class:"fixed-footer"},Ve=k({__name:"copyright",setup(W){const n=g(!0),l=f({icp:"",gov_record:"",gov_url:"",market_supervision_url:"",logo:"",company_name:"",copyright_link:"",copyright_desc:""});(async(m=0)=>{const e=await(await S()).data;Object.keys(l).forEach(p=>{e[p]!=null&&(l[p]=e[p])}),n.value=!1})();const _=g(),b=f({site_name:[{required:!0,message:o("siteNamePlaceholder"),trigger:"blur"}]}),y=async m=>{n.value||!m||await m.validate(async e=>{e&&(n.value=!0,O(l).then(()=>{n.value=!1}).catch(()=>{n.value=!1}))})};return(m,e)=>{const p=L,d=N,s=R,h=C,V=B,w=F,x=I;return v(),U("div",$,[E((v(),P(V,{model:l,"label-width":"150px",ref_key:"formRef",ref:_,rules:b,class:"page-form"},{default:i(()=>[a(h,{class:"box-card !border-none",shadow:"never"},{default:i(()=>[c("h3",j,u(t(o)("copyrightEdit")),1),a(d,{label:t(o)("logo")},{default:i(()=>[a(p,{modelValue:l.logo,"onUpdate:modelValue":e[0]||(e[0]=r=>l.logo=r)},null,8,["modelValue"])]),_:1},8,["label"]),a(d,{label:t(o)("companyName"),prop:"company_name"},{default:i(()=>[a(s,{modelValue:l.company_name,"onUpdate:modelValue":e[1]||(e[1]=r=>l.company_name=r),placeholder:t(o)("companyNamePlaceholder"),class:"input-width",clearable:"",maxlength:"30"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),a(d,{label:t(o)("copyrightLink")},{default:i(()=>[a(s,{modelValue:l.copyright_link,"onUpdate:modelValue":e[2]||(e[2]=r=>l.copyright_link=r),placeholder:t(o)("copyrightLinkPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),a(d,{label:t(o)("copyrightDesc")},{default:i(()=>[a(s,{modelValue:l.copyright_desc,"onUpdate:modelValue":e[3]||(e[3]=r=>l.copyright_desc=r),type:"textarea",rows:"4",clearable:"",placeholder:t(o)("copyrightDescPlaceholder"),class:"input-width",maxlength:"150"},null,8,["modelValue","placeholder"])]),_:1},8,["label"])]),_:1}),a(h,{class:"box-card !border-none mt-[16px]",shadow:"never"},{default:i(()=>[c("h3",q,u(t(o)("putOnRecordEdit")),1),a(d,{label:t(o)("icp"),prop:"icp"},{default:i(()=>[a(s,{modelValue:l.icp,"onUpdate:modelValue":e[4]||(e[4]=r=>l.icp=r),placeholder:t(o)("icpPlaceholder"),class:"input-width",clearable:"",maxlength:"20"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),a(d,{label:t(o)("govRecord")},{default:i(()=>[a(s,{modelValue:l.gov_record,"onUpdate:modelValue":e[5]||(e[5]=r=>l.gov_record=r),placeholder:t(o)("govRecordPlaceholder"),class:"input-width",clearable:"",maxlength:"50"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),a(d,{label:t(o)("govUrl")},{default:i(()=>[a(s,{modelValue:l.gov_url,"onUpdate:modelValue":e[6]||(e[6]=r=>l.gov_url=r),placeholder:t(o)("govUrlPlaceholder"),class:"input-width",clearable:""},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),a(d,{label:t(o)("marketSupervisionUrl")},{default:i(()=>[a(s,{modelValue:l.market_supervision_url,"onUpdate:modelValue":e[7]||(e[7]=r=>l.market_supervision_url=r),rows:"4",clearable:"",placeholder:t(o)("marketSupervisionUrlPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"])]),_:1})]),_:1},8,["model","rules"])),[[x,n.value]]),c("div",Q,[c("div",T,[a(w,{type:"primary",loading:n.value,onClick:e[8]||(e[8]=r=>y(_.value))},{default:i(()=>[D(u(t(o)("save")),1)]),_:1},8,["loading"])])])])}}});export{Ve as default};
diff --git a/niucloud/public/admin/assets/coupons-edit-247f87bb.js b/niucloud/public/admin/assets/coupons-edit-247f87bb.js
new file mode 100644
index 0000000..77aea3c
--- /dev/null
+++ b/niucloud/public/admin/assets/coupons-edit-247f87bb.js
@@ -0,0 +1 @@
+import{_ as o}from"./coupons-edit.vue_vue_type_style_index_0_lang-2b39ed54.js";import"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";import"./dict-3e5bfbe1.js";export{o as default};
diff --git a/niucloud/public/admin/assets/coupons-edit.vue_vue_type_style_index_0_lang-2b39ed54.js b/niucloud/public/admin/assets/coupons-edit.vue_vue_type_style_index_0_lang-2b39ed54.js
new file mode 100644
index 0000000..f5c554c
--- /dev/null
+++ b/niucloud/public/admin/assets/coupons-edit.vue_vue_type_style_index_0_lang-2b39ed54.js
@@ -0,0 +1 @@
+import{aJ as f,d as B,r as v,n as I,q as R,N as l,s as T,h as w,I as V,w as s,a as Y,e as r,aQ as P,i as c,t as y,u as o,y as C,c as O,F as j,G,z,W as J,X as Q,aE as W,aw as X,ax as A,cI as H,Y as K,E as Z,a7 as ee,$ as le}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";import{u as ae}from"./dict-3e5bfbe1.js";function ye(d){return f.get("hygl/coupons",{params:d})}function oe(d){return f.get(`hygl/coupons/${d}`)}function te(d){return f.post("hygl/coupons",d,{showErrorMessage:!0,showSuccessMessage:!0})}function se(d){return f.put(`hygl/coupons/${d.id}`,d,{showErrorMessage:!0,showSuccessMessage:!0})}function Ee(d){return f.delete(`hygl/coupons/${d}`,{showErrorMessage:!0,showSuccessMessage:!0})}const re={class:"dialog-footer"},De=B({__name:"coupons-edit",emits:["complete"],setup(d,{expose:L,emit:F}){let u=v(!1);const m=v(!1),E={id:"",name:"",nominal_value:"",stock:"100",is_show:"1",is_long_term_valid:"1",is_obsolete:"0",valid_time:[]},a=I({...E}),D=v(),M=R(()=>({name:[{required:!0,message:l("namePlaceholder"),trigger:"blur"}],nominal_value:[{required:!0,message:l("nominalValuePlaceholder"),trigger:"blur"},{validator:(p,e,n)=>{const i=parseFloat(e);isNaN(i)||i<=0||i>99999||!/^\d+(\.\d{1,2})?$/.test(e)?n(new Error(l("请输入0.1-99999"))):n()}}],stock:[{required:!0,message:l("stockPlaceholder"),trigger:"blur"},{validator:(p,e,n)=>{e&&!/^\d{0,99999}$/.test(e)?n(new Error(l("generateBetween"))):n()}}],is_show:[{required:!0,message:l("isShowPlaceholder"),trigger:"blur"}],is_long_term_valid:[{required:!0,message:l("isLongTermValidPlaceholder"),trigger:"blur"}]})),S=async p=>{if(m.value||!p)return;let e=a.id?se:te;await p.validate(async n=>{n&&(m.value=!0,e(a).then(h=>{m.value=!1,u.value=!1,F("complete")}).catch(h=>{m.value=!1}))})};let g=v([]);return(async()=>{g.value=await(await ae("is_show_radio")).data.dictionary})(),T(()=>g.value,()=>{a.is_show=g.value[0].value}),L({showDialog:u,setFormData:async(p=null)=>{if(Object.assign(a,E),m.value=!0,p){const e=await(await oe(p.id)).data;e&&Object.keys(a).forEach(n=>{e[n]!=null&&(a[n]=e[n])})}m.value=!1}}),(p,e)=>{const n=J,i=Q,h=W,_=X,b=A,U=H,q=K,k=Z,x=ee,N=le;return w(),V(x,{modelValue:o(u),"onUpdate:modelValue":e[9]||(e[9]=t=>P(u)?u.value=t:u=t),title:a.id?o(l)("updateCoupons"):o(l)("addCoupons"),width:"50%",class:"diy-dialog-wrap","destroy-on-close":!0},{footer:s(()=>[Y("span",re,[r(k,{onClick:e[7]||(e[7]=t=>P(u)?u.value=!1:u=!1)},{default:s(()=>[c(y(o(l)("cancel")),1)]),_:1}),r(k,{type:"primary",loading:m.value,onClick:e[8]||(e[8]=t=>S(D.value))},{default:s(()=>[c(y(o(l)("confirm")),1)]),_:1},8,["loading"])])]),default:s(()=>[C((w(),V(q,{model:a,"label-width":"120px",ref_key:"formRef",ref:D,rules:o(M),class:"page-form"},{default:s(()=>[r(i,{label:o(l)("name"),prop:"name"},{default:s(()=>[r(n,{modelValue:a.name,"onUpdate:modelValue":e[0]||(e[0]=t=>a.name=t),clearable:"",placeholder:o(l)("namePlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),r(i,{label:o(l)("nominalValue"),prop:"nominal_value"},{default:s(()=>[r(h,{modelValue:a.nominal_value,"onUpdate:modelValue":e[1]||(e[1]=t=>a.nominal_value=t),clearable:"",placeholder:o(l)("nominalValuePlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),r(i,{label:o(l)("stock"),prop:"stock"},{default:s(()=>[r(h,{modelValue:a.stock,"onUpdate:modelValue":e[2]||(e[2]=t=>a.stock=t),clearable:"",placeholder:o(l)("stockPlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),r(i,{label:o(l)("isShow"),prop:"is_show"},{default:s(()=>[r(b,{modelValue:a.is_show,"onUpdate:modelValue":e[3]||(e[3]=t=>a.is_show=t),placeholder:o(l)("isShowPlaceholder")},{default:s(()=>[(w(!0),O(j,null,G(o(g),(t,$)=>(w(),V(_,{key:$,label:t.value},{default:s(()=>[c(y(t.name),1)]),_:2},1032,["label"]))),128))]),_:1},8,["modelValue","placeholder"])]),_:1},8,["label"]),r(i,{label:o(l)("isObsolete"),prop:"is_obsolete"},{default:s(()=>[r(b,{modelValue:a.is_obsolete,"onUpdate:modelValue":e[4]||(e[4]=t=>a.is_obsolete=t),placeholder:o(l)("isObsoletePlaceholder")},{default:s(()=>[r(_,{label:"1"},{default:s(()=>[c("是")]),_:1}),r(_,{label:"0"},{default:s(()=>[c("否")]),_:1})]),_:1},8,["modelValue","placeholder"])]),_:1},8,["label"]),r(i,{label:o(l)("isLongTermValid"),prop:"is_long_term_valid"},{default:s(()=>[r(b,{modelValue:a.is_long_term_valid,"onUpdate:modelValue":e[5]||(e[5]=t=>a.is_long_term_valid=t),placeholder:o(l)("isLongTermValidPlaceholder")},{default:s(()=>[r(_,{label:"1"},{default:s(()=>[c("是")]),_:1}),r(_,{label:"0"},{default:s(()=>[c("否")]),_:1})]),_:1},8,["modelValue","placeholder"])]),_:1},8,["label"]),C(r(i,{label:o(l)("validTime"),prop:"valid_time"},{default:s(()=>[r(U,{modelValue:a.valid_time,"onUpdate:modelValue":e[6]||(e[6]=t=>a.valid_time=t),type:"daterange","value-format":"YYYY-MM-DD","start-placeholder":o(l)("startDate"),"end-placeholder":o(l)("endDate")},null,8,["modelValue","start-placeholder","end-placeholder"])]),_:1},8,["label"]),[[z,a.is_long_term_valid!=="1"]])]),_:1},8,["model","rules"])),[[N,m.value]])]),_:1},8,["modelValue","title"])}}});export{De as _,Ee as d,ye as g};
diff --git a/niucloud/public/admin/assets/coupons-f2705205.css b/niucloud/public/admin/assets/coupons-f2705205.css
new file mode 100644
index 0000000..b4aa26d
--- /dev/null
+++ b/niucloud/public/admin/assets/coupons-f2705205.css
@@ -0,0 +1 @@
+@charset "UTF-8";.multi-hidden[data-v-abf34589]{word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
diff --git a/niucloud/public/admin/assets/coupons-fa4cee9b.js b/niucloud/public/admin/assets/coupons-fa4cee9b.js
new file mode 100644
index 0000000..a4e2aec
--- /dev/null
+++ b/niucloud/public/admin/assets/coupons-fa4cee9b.js
@@ -0,0 +1 @@
+import{d as R,O as q,n as G,r as b,h as s,c as d,e as a,w as n,a as w,t as u,u as e,i as _,N as l,F as y,G as x,I as P,y as M,B as C,a5 as W,E as X,W as Y,X as A,aq as H,aC as J,Y as K,_ as Q,af as Z,ah as ee,a3 as te,$ as ae}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css */import{_ as le}from"./index.vue_vue_type_script_setup_true_lang-edbadcfb.js";import"./el-form-item-4ed993c7.js";/* empty css */import{u as oe}from"./dict-3e5bfbe1.js";import{_ as ne,g as ie,d as se}from"./coupons-edit.vue_vue_type_style_index_0_lang-2b39ed54.js";import{_ as re}from"./_plugin-vue_export-helper-c27b6911.js";/* empty css *//* empty css *//* empty css *//* empty css */const ue={class:"main-container"},de={class:"flex justify-between items-center"},me={class:"text-lg"},pe={class:"mt-[10px]"},ce={key:0},_e={key:0},fe={key:0},ve={class:"mt-[16px] flex justify-end"},he=R({__name:"coupons",setup(we){const F=q().meta.title;let o=G({page:1,limit:10,total:0,loading:!0,data:[],searchParam:{name:"",nominal_value:[],is_show:""}});const k=b();b([]);const f=b([]);(async()=>{f.value=await(await oe("is_show_radio")).data.dictionary})();const c=(p=1)=>{o.loading=!0,o.page=p,ie({page:o.page,limit:o.limit,...o.searchParam}).then(i=>{o.loading=!1,o.data=i.data.data,o.total=i.data.total}).catch(()=>{o.loading=!1})};c();const v=b(null),T=()=>{v.value.setFormData(),v.value.showDialog=!0},B=p=>{v.value.setFormData(p),v.value.showDialog=!0},L=p=>{W.confirm(l("couponsDeleteTips"),l("warning"),{confirmButtonText:l("confirm"),cancelButtonText:l("cancel"),type:"warning"}).then(()=>{se(p).then(()=>{c()}).catch(()=>{})})},$=p=>{p&&(p.resetFields(),c())};return(p,i)=>{const h=X,z=Y,g=A,N=le,V=H,S=J,U=K,E=Q,m=Z,I=ee,j=te,O=ae;return s(),d("div",ue,[a(E,{class:"box-card !border-none",shadow:"never"},{default:n(()=>[w("div",de,[w("span",me,u(e(F)),1),a(h,{type:"primary",onClick:T},{default:n(()=>[_(u(e(l)("addCoupons")),1)]),_:1})]),a(E,{class:"box-card !border-none my-[10px] table-search-wrap",shadow:"never"},{default:n(()=>[a(U,{inline:!0,model:e(o).searchParam,ref_key:"searchFormRef",ref:k},{default:n(()=>[a(g,{label:e(l)("name"),prop:"name"},{default:n(()=>[a(z,{modelValue:e(o).searchParam.name,"onUpdate:modelValue":i[0]||(i[0]=t=>e(o).searchParam.name=t),placeholder:e(l)("namePlaceholder")},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),a(g,{label:e(l)("nominalValue"),prop:"nominal_value"},{default:n(()=>[a(N,{modelValue:e(o).searchParam.nominal_value,"onUpdate:modelValue":i[1]||(i[1]=t=>e(o).searchParam.nominal_value=t)},null,8,["modelValue"])]),_:1},8,["label"]),a(g,{label:e(l)("isShow"),prop:"is_show"},{default:n(()=>[a(S,{class:"w-[280px]",modelValue:e(o).searchParam.is_show,"onUpdate:modelValue":i[2]||(i[2]=t=>e(o).searchParam.is_show=t),clearable:"",placeholder:e(l)("isShowPlaceholder")},{default:n(()=>[a(V,{label:"全部",value:""}),(s(!0),d(y,null,x(f.value,(t,r)=>(s(),P(V,{key:r,label:t.name,value:t.value},null,8,["label","value"]))),128))]),_:1},8,["modelValue","placeholder"])]),_:1},8,["label"]),a(g,null,{default:n(()=>[a(h,{type:"primary",onClick:i[3]||(i[3]=t=>c())},{default:n(()=>[_(u(e(l)("search")),1)]),_:1}),a(h,{onClick:i[4]||(i[4]=t=>$(k.value))},{default:n(()=>[_(u(e(l)("reset")),1)]),_:1})]),_:1})]),_:1},8,["model"])]),_:1}),w("div",pe,[M((s(),P(I,{data:e(o).data,size:"large"},{empty:n(()=>[w("span",null,u(e(o).loading?"":e(l)("emptyData")),1)]),default:n(()=>[a(m,{prop:"id",label:e(l)("id"),"min-width":"120","show-overflow-tooltip":!0},null,8,["label"]),a(m,{prop:"name",label:e(l)("name"),"min-width":"120","show-overflow-tooltip":!0},null,8,["label"]),a(m,{prop:"nominal_value",label:e(l)("nominalValue"),"min-width":"120","show-overflow-tooltip":!0},null,8,["label"]),a(m,{prop:"stock",label:e(l)("stock"),"min-width":"120","show-overflow-tooltip":!0},null,8,["label"]),a(m,{label:e(l)("isShow"),"min-width":"180",align:"center","show-overflow-tooltip":!0},{default:n(({row:t})=>[(s(!0),d(y,null,x(f.value,(r,D)=>(s(),d("div",null,[r.value==t.is_show?(s(),d("div",ce,u(r.name),1)):C("",!0)]))),256))]),_:1},8,["label"]),a(m,{label:e(l)("isObsolete"),"min-width":"180",align:"center","show-overflow-tooltip":!0},{default:n(({row:t})=>[(s(!0),d(y,null,x(f.value,(r,D)=>(s(),d("div",null,[r.value==t.is_obsolete?(s(),d("div",_e,u(r.name),1)):C("",!0)]))),256))]),_:1},8,["label"]),a(m,{label:e(l)("isLongTermValid"),"min-width":"180",align:"center","show-overflow-tooltip":!0},{default:n(({row:t})=>[(s(!0),d(y,null,x(f.value,(r,D)=>(s(),d("div",null,[r.value==t.is_long_term_valid?(s(),d("div",fe,u(r.name),1)):C("",!0)]))),256))]),_:1},8,["label"]),a(m,{label:e(l)("validTime"),"min-width":"180",align:"center","show-overflow-tooltip":!0},{default:n(({row:t})=>[_(u(t.valid_time||""),1)]),_:1},8,["label"]),a(m,{label:e(l)("createTime"),"min-width":"180",align:"center","show-overflow-tooltip":!0},{default:n(({row:t})=>[_(u(t.create_time||""),1)]),_:1},8,["label"]),a(m,{label:e(l)("operation"),fixed:"right","min-width":"120"},{default:n(({row:t})=>[a(h,{type:"primary",link:"",onClick:r=>B(t)},{default:n(()=>[_(u(e(l)("edit")),1)]),_:2},1032,["onClick"]),a(h,{type:"primary",link:"",onClick:r=>L(t.id)},{default:n(()=>[_(u(e(l)("delete")),1)]),_:2},1032,["onClick"])]),_:1},8,["label"])]),_:1},8,["data"])),[[O,e(o).loading]]),w("div",ve,[a(j,{"current-page":e(o).page,"onUpdate:current-page":i[5]||(i[5]=t=>e(o).page=t),"page-size":e(o).limit,"onUpdate:page-size":i[6]||(i[6]=t=>e(o).limit=t),layout:"total, sizes, prev, pager, next, jumper",total:e(o).total,onSizeChange:i[7]||(i[7]=t=>c()),onCurrentChange:c},null,8,["current-page","page-size","total"])])]),a(ne,{ref_key:"editCouponsDialog",ref:v,onComplete:c},null,512)]),_:1})])}}});const We=re(he,[["__scopeId","data-v-abf34589"]]);export{We as default};
diff --git a/niucloud/public/admin/assets/coupons.coupons-b9f57d59.js b/niucloud/public/admin/assets/coupons.coupons-b9f57d59.js
new file mode 100644
index 0000000..3a868df
--- /dev/null
+++ b/niucloud/public/admin/assets/coupons.coupons-b9f57d59.js
@@ -0,0 +1 @@
+const o="id",e="站点id",s="请输入站点id",l="卡券名字",t="请输入卡券名字",n="卡券面值",a="请输入卡券面值",c="卡券库存",i="请输入卡券库存",d="是否展示",r="请输入是否展示",h="是否长期有效",m="请输入是否长期有效",u="创建时间",P="添加优惠券",p="编辑优惠券",T="确定要删除该数据吗?",V="请选择开始时间",v="请选择结束时间",D="有效期开始时间",b="有效期截止时间",g="有效期",k="是否作废",w="请输入是否作废",C={id:o,siteId:e,siteIdPlaceholder:s,name:l,namePlaceholder:t,nominalValue:n,nominalValuePlaceholder:a,stock:c,stockPlaceholder:i,isShow:d,isShowPlaceholder:r,isLongTermValid:h,isLongTermValidPlaceholder:m,createTime:u,addCoupons:P,updateCoupons:p,couponsDeleteTips:T,startDate:V,endDate:v,validFrom:D,validUntil:b,validTime:g,isObsolete:k,isObsoletePlaceholder:w};export{P as addCoupons,T as couponsDeleteTips,u as createTime,C as default,v as endDate,o as id,h as isLongTermValid,m as isLongTermValidPlaceholder,k as isObsolete,w as isObsoletePlaceholder,d as isShow,r as isShowPlaceholder,l as name,t as namePlaceholder,n as nominalValue,a as nominalValuePlaceholder,e as siteId,s as siteIdPlaceholder,V as startDate,c as stock,i as stockPlaceholder,p as updateCoupons,D as validFrom,g as validTime,b as validUntil};
diff --git a/niucloud/public/admin/assets/course-036fa26c.js b/niucloud/public/admin/assets/course-036fa26c.js
new file mode 100644
index 0000000..ed6ec2c
--- /dev/null
+++ b/niucloud/public/admin/assets/course-036fa26c.js
@@ -0,0 +1 @@
+import{d as w,O as u,f,r as g,n as v,h as y,c as b,a as t,u as s,t as e,N as n,e as c,w as r,i as o,E as T,_ as k}from"./index-6010b07e.js";/* empty css *//* empty css */import{g as E}from"./wechat-688fa021.js";const O=""+new URL("wechat_1-0a26d3a6.png",import.meta.url).href,R=""+new URL("wechat_4-94a271d5.png",import.meta.url).href,C=""+new URL("wechat_2-0513f476.png",import.meta.url).href,j=""+new URL("wechat_3-0a96f3fe.png",import.meta.url).href,L={class:"main-container"},N={class:"detail-head"},U=t("span",{class:"iconfont iconxiangzuojiantou !text-xs"},null,-1),B={class:"ml-[1px]"},q=t("span",{class:"adorn"},"|",-1),V={class:"right"},D={class:"mt-[20px]"},P={class:"flex"},S=t("div",{class:"min-w-[60px]"},[t("span",{class:"flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary"},"1")],-1),z={class:"flex items-center text-[14px]"},A=t("span",{class:"text-primary"},"URL / Token / EncondingAESKey",-1),K=t("div",{class:"w-[100%] mt-[10px]"},[t("img",{class:"w-[100%]",src:O})],-1),W={class:"flex items-center text-[14px] mt-[20px]"},$=t("div",{class:"w-[100%] mt-[10px]"},[t("img",{class:"w-[100%]",src:R})],-1),F={class:"flex mt-[40px]"},G=t("div",{class:"min-w-[60px]"},[t("span",{class:"flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary"},"2")],-1),H={class:"flex items-center text-[14px]"},I=t("div",{class:"w-[100%] mt-[10px]"},[t("img",{class:"w-[100%]",src:C})],-1),J={class:"flex mt-[40px]"},M=t("div",{class:"min-w-[60px]"},[t("span",{class:"flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary"},"3")],-1),Q={class:"flex items-center text-[14px]"},X={class:"text-primary"},Y=t("div",{class:"w-[100%] mt-[10px]"},[t("img",{class:"w-[100%]",src:j})],-1),at=w({__name:"course",setup(Z){const p=u().meta.title,_=f(),l=g(!0),d=v({wechat_name:"",wechat_original:"",app_id:"",app_secret:"",qr_code:"",token:"",encoding_aes_key:"",encryption_type:"not_encrypt"});E().then(i=>{Object.assign(d,i.data),l.value=!1});const m=()=>{window.open("https://mp.weixin.qq.com/","_blank")};return(i,a)=>{const x=T,h=k;return y(),b("div",L,[t("div",N,[t("div",{class:"left",onClick:a[0]||(a[0]=st=>s(_).push({path:"/channel/wechat"}))},[U,t("span",B,e(s(n)("returnToPreviousPage")),1)]),q,t("span",V,e(s(p)),1)]),c(h,{class:"box-card !border-none",shadow:"never"},{default:r(()=>[t("div",D,[t("div",P,[S,t("div",null,[t("p",z,[o(e(s(n)("writingTipsOne1"))+"--",1),c(x,{link:"",type:"primary",onClick:m},{default:r(()=>[o(e(s(n)("writingTipsOne2")),1)]),_:1}),o(", "+e(s(n)("writingTipsOne3")),1),A,o(e(s(n)("writingTipsOne4")),1)]),K,t("p",W,e(s(n)("writingTipsOne5")),1),$])]),t("div",F,[G,t("div",null,[t("p",H,e(s(n)("writingTipsTwo1")),1),I])]),t("div",J,[M,t("div",null,[t("p",Q,[o(e(s(n)("writingTipsThree1")),1),t("span",X,e(s(n)("writingTipsThree2")),1)]),Y])])])]),_:1})])}}});export{at as default};
diff --git a/niucloud/public/admin/assets/course-17d84e13.js b/niucloud/public/admin/assets/course-17d84e13.js
new file mode 100644
index 0000000..8ba5e3d
--- /dev/null
+++ b/niucloud/public/admin/assets/course-17d84e13.js
@@ -0,0 +1 @@
+import{d as m,O as h,f as u,h as w,c as f,a as s,u as t,t as e,N as n,e as r,w as a,i,E as v,_ as g}from"./index-6010b07e.js";/* empty css *//* empty css */const y=""+new URL("weapp_1-7017a047.png",import.meta.url).href,b=""+new URL("weapp_2-8fac7fa5.png",import.meta.url).href,T=""+new URL("weapp_3-07a2249e.png",import.meta.url).href,k=""+new URL("weapp_4-d837a9b1.png",import.meta.url).href,E={class:"main-container"},R={class:"detail-head"},j=s("span",{class:"iconfont iconxiangzuojiantou !text-xs"},null,-1),C={class:"ml-[1px]"},L=s("span",{class:"adorn"},"|",-1),N={class:"right"},U={class:"mt-[20px]"},B={class:"flex"},O=s("div",{class:"min-w-[60px]"},[s("span",{class:"flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary"},"1")],-1),V={class:"flex items-center text-[14px]"},q=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:y})],-1),F={class:"flex mt-[40px]"},P=s("div",{class:"min-w-[60px]"},[s("span",{class:"flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary"},"2")],-1),S={class:"flex items-center text-[14px]"},z=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:b})],-1),A={class:"flex mt-[40px]"},D=s("div",{class:"min-w-[60px]"},[s("span",{class:"flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary"},"3")],-1),K={class:"flex items-center text-[14px]"},$={class:"text-primary"},G=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:T})],-1),H={class:"flex mt-[40px]"},I=s("div",{class:"min-w-[60px]"},[s("span",{class:"flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary"},"4")],-1),J={class:"flex items-center text-[14px]"},M=s("span",{class:"text-primary"},"URL / Token / EncondingAESKey",-1),Q=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:k})],-1),es=m({__name:"course",setup(W){const c=h(),p=u(),l=c.meta.title,d=()=>{window.open("https://mp.weixin.qq.com/","_blank")};return(X,o)=>{const _=v,x=g;return w(),f("div",E,[s("div",R,[s("div",{class:"left",onClick:o[0]||(o[0]=Y=>t(p).push({path:"/channel/weapp"}))},[j,s("span",C,e(t(n)("returnToPreviousPage")),1)]),L,s("span",N,e(t(l)),1)]),r(x,{class:"box-card !border-none",shadow:"never"},{default:a(()=>[s("div",U,[s("div",B,[O,s("div",null,[s("p",V,[i(e(t(n)("writingTipsOne1")),1),r(_,{link:"",type:"primary",onClick:d},{default:a(()=>[i(e(t(n)("writingTipsOne2")),1)]),_:1}),i(","+e(t(n)("writingTipsOne3")),1)]),q])]),s("div",F,[P,s("div",null,[s("p",S,e(t(n)("writingTipsTwo1")),1),z])]),s("div",A,[D,s("div",null,[s("p",K,[i(e(t(n)("writingTipsThree1")),1),s("span",$,e(t(n)("writingTipsThree2")),1)]),G])]),s("div",H,[I,s("div",null,[s("p",J,[i(e(t(n)("writingTipsFour1")),1),M,i(e(t(n)("writingTipsFour2")),1)]),Q])])])]),_:1})])}}});export{es as default};
diff --git a/niucloud/public/admin/assets/course-a965b567.js b/niucloud/public/admin/assets/course-a965b567.js
new file mode 100644
index 0000000..158b63b
--- /dev/null
+++ b/niucloud/public/admin/assets/course-a965b567.js
@@ -0,0 +1 @@
+import{d as g,O as y,f as v,r as b,n as C,h as R,c as T,a as s,u as t,t as e,N as a,e as o,w as i,i as c,E as k,al as L,am as U,_ as j}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css */import{g as E}from"./wechat-688fa021.js";const N=""+new URL("alipay1-029c00a2.png",import.meta.url).href,O=""+new URL("alipay2-f74219b9.png",import.meta.url).href,B=""+new URL("alipay3-0895ce6e.png",import.meta.url).href,V=""+new URL("alipay4-92fef352.png",import.meta.url).href,D=""+new URL("alipay4_1-ad9b08e3.jpg",import.meta.url).href,P=""+new URL("alipay4_2-cbaa820b.jpg",import.meta.url).href,q=""+new URL("alipay4_3-4a213289.jpg",import.meta.url).href,z=""+new URL("alipay4_4-7924cbdd.jpg",import.meta.url).href,S=""+new URL("alipay5-6dba1989.png",import.meta.url).href,W=""+new URL("alipay6-f1e18995.png",import.meta.url).href,$=""+new URL("alipay7-c805d7c0.png",import.meta.url).href,A=""+new URL("alipay8-3097d150.png",import.meta.url).href,F={class:"main-container"},G={class:"detail-head"},H=s("span",{class:"iconfont iconxiangzuojiantou !text-xs"},null,-1),I={class:"ml-[1px]"},J=s("span",{class:"adorn"},"|",-1),K={class:"right"},M={class:"mt-[20px]"},Q={class:"flex"},X=s("div",{class:"min-w-[60px]"},[s("span",{class:"flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary"},"1")],-1),Y={class:"flex items-center text-[14px]"},Z=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:N})],-1),ss={class:"flex items-center text-[14px] mt-[20px]"},ts=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:O})],-1),es=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:B})],-1),as={class:"flex mt-[40px]"},os=s("div",{class:"min-w-[60px]"},[s("span",{class:"flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary"},"2")],-1),is={class:"flex items-center text-[14px]"},ns={class:"w-[100%] mt-[10px] flex flex-wrap"},cs=s("div",{class:"w-[100%]"},[s("img",{class:"w-[100%]",src:V})],-1),rs=s("div",{class:"w-[100%]"},[s("img",{class:"w-[100%]",src:D})],-1),ps=s("div",{class:"w-[100%]"},[s("img",{class:"w-[100%]",src:P})],-1),ls=s("div",{class:"w-[100%]"},[s("img",{class:"w-[100%]",src:q})],-1),_s=s("div",{class:"w-[100%]"},[s("img",{class:"w-[100%]",src:z})],-1),ds={class:"flex mt-[40px]"},ms=s("div",{class:"min-w-[60px]"},[s("span",{class:"flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary"},"3")],-1),xs={class:"flex items-center text-[14px]"},hs=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:S})],-1),us=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:W})],-1),ws={class:"flex items-center text-[14px] mt-[20px]"},fs=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:$})],-1),gs={class:"flex items-center text-[14px] mt-[20px]"},ys=s("div",{class:"w-[100%] mt-[10px]"},[s("img",{class:"w-[100%]",src:A})],-1),Us=g({__name:"course",setup(vs){const l=y(),_=v(),d=l.meta.title,m=b(!0),x=C({wechat_name:"",wechat_original:"",app_id:"",app_secret:"",qr_code:"",token:"",encoding_aes_key:"",encryption_type:"not_encrypt"});E().then(r=>{Object.assign(x,r.data),m.value=!1});const h=()=>{window.open("https://open.alipay.com/develop/manage","_blank")};return(r,p)=>{const u=k,n=L,w=U,f=j;return R(),T("div",F,[s("div",G,[s("div",{class:"left",onClick:p[0]||(p[0]=bs=>t(_).push({path:"/channel/aliapp"}))},[H,s("span",I,e(t(a)("returnToPreviousPage")),1)]),J,s("span",K,e(t(d)),1)]),o(f,{class:"box-card !border-none",shadow:"never"},{default:i(()=>[s("div",M,[s("div",Q,[X,s("div",null,[s("p",Y,[c(e(t(a)("alipayCourseTipsOne1"))+"--",1),o(u,{link:"",type:"primary",onClick:h},{default:i(()=>[c(e(t(a)("alipayCourseTipsOne2")),1)]),_:1}),c(", "+e(t(a)("alipayCourseTipsOne3")),1)]),Z,s("p",ss,e(t(a)("alipayCourseTipsTwo1")),1),ts,es])]),s("div",as,[os,s("div",null,[s("p",is,e(t(a)("alipayCourseTipsTwo2")),1),s("div",ns,[cs,s("div",null,[o(w,{gutter:20},{default:i(()=>[o(n,{span:6},{default:i(()=>[rs]),_:1}),o(n,{span:6},{default:i(()=>[ps]),_:1}),o(n,{span:6},{default:i(()=>[ls]),_:1}),o(n,{span:6},{default:i(()=>[_s]),_:1})]),_:1})])])])]),s("div",ds,[ms,s("div",null,[s("p",xs,e(t(a)("alipayCourseTipsThree1")),1),hs,us,s("p",ws,e(t(a)("alipayCourseTipsThree2")),1),fs,s("p",gs,e(t(a)("alipayCourseTipsThree3")),1),ys])])])]),_:1})])}}});export{Us as default};
diff --git a/niucloud/public/admin/assets/cron-56794c65.js b/niucloud/public/admin/assets/cron-56794c65.js
new file mode 100644
index 0000000..3c24748
--- /dev/null
+++ b/niucloud/public/admin/assets/cron-56794c65.js
@@ -0,0 +1 @@
+import{d as T,n as z,r as k,h as c,c as h,e as a,w as r,u as o,N as n,i as p,t as i,a as b,y as F,I as $,W as B,X as N,cI as Y,E as I,Y as U,_ as L,af as S,ah as j,a3 as H,$ as M}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";import{S as R}from"./sys-0f76aff3.js";import{_ as W}from"./cron-info.vue_vue_type_script_setup_true_lang-4ef60fee.js";/* empty css */const X={class:"main-container"},q={class:"mt-[16px]"},A={key:0},G={key:1},J={class:"mt-[16px] flex justify-end"},he=T({__name:"cron",setup(K){const e=z({page:1,limit:10,total:0,loading:!0,data:[],searchParam:{title:"",type:"",last_time:""}}),y=k(),m=(d=1)=>{e.loading=!0,e.page=d,R({page:e.page,limit:e.limit,...e.searchParam}).then(l=>{e.loading=!1,e.data=l.data.data,e.total=l.data.total}).catch(()=>{e.loading=!1})};m();const _=k(null),w=d=>{_.value.setFormData(d),_.value.showDialog=!0};return(d,l)=>{const x=B,u=N,C=Y,f=I,D=U,v=L,s=S,E=j,P=H,V=M;return c(),h("div",X,[a(v,{class:"box-card !border-none",shadow:"never"},{default:r(()=>[a(v,{class:"box-card !border-none my-[16px] table-search-wrap",shadow:"never"},{default:r(()=>[a(D,{inline:!0,model:e.searchParam,ref_key:"searchFormRef",ref:y},{default:r(()=>[a(u,{label:o(n)("title"),prop:"title"},{default:r(()=>[a(x,{modelValue:e.searchParam.title,"onUpdate:modelValue":l[0]||(l[0]=t=>e.searchParam.title=t),placeholder:o(n)("titlePlaceholder")},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),a(u,{label:o(n)("lastTime"),prop:"last_time"},{default:r(()=>[a(C,{modelValue:e.searchParam.last_time,"onUpdate:modelValue":l[1]||(l[1]=t=>e.searchParam.last_time=t),type:"datetimerange","value-format":"YYYY-MM-DD HH:mm:ss","start-placeholder":o(n)("startDate"),"end-placeholder":o(n)("endDate")},null,8,["modelValue","start-placeholder","end-placeholder"])]),_:1},8,["label"]),a(u,null,{default:r(()=>[a(f,{type:"primary",onClick:l[2]||(l[2]=t=>m())},{default:r(()=>[p(i(o(n)("search")),1)]),_:1}),a(f,{onClick:l[3]||(l[3]=t=>{var g;return(g=y.value)==null?void 0:g.resetFields()})},{default:r(()=>[p(i(o(n)("reset")),1)]),_:1})]),_:1})]),_:1},8,["model"])]),_:1}),b("div",q,[F((c(),$(E,{data:e.data,size:"large"},{empty:r(()=>[b("span",null,i(e.loading?"":o(n)("emptyData")),1)]),default:r(()=>[a(s,{prop:"title","show-overflow-tooltip":!0,label:o(n)("title"),"min-width":"150"},null,8,["label"]),a(s,{prop:"type_name",label:o(n)("typeName"),"min-width":"120"},null,8,["label"]),a(s,{label:o(n)("crondType"),"min-width":"180",align:"center"},{default:r(({row:t})=>[t.type=="crond"?(c(),h("span",A,i(t.crond_length)+i(t.crond_type_name),1)):(c(),h("span",G,i(o(n)("cron")),1))]),_:1},8,["label"]),a(s,{prop:"count",label:o(n)("count"),"min-width":"120"},null,8,["label"]),a(s,{label:o(n)("lastTime"),"min-width":"180",align:"center"},{default:r(({row:t})=>[p(i(t.last_time||""),1)]),_:1},8,["label"]),a(s,{label:o(n)("nextTime"),"min-width":"180",align:"center"},{default:r(({row:t})=>[p(i(t.next_time||""),1)]),_:1},8,["label"]),a(s,{label:o(n)("operation"),align:"right",fixed:"right",width:"100"},{default:r(({row:t})=>[a(f,{type:"primary",link:"",onClick:g=>w(t)},{default:r(()=>[p(i(o(n)("info")),1)]),_:2},1032,["onClick"])]),_:1},8,["label"])]),_:1},8,["data"])),[[V,e.loading]]),b("div",J,[a(P,{"current-page":e.page,"onUpdate:current-page":l[4]||(l[4]=t=>e.page=t),"page-size":e.limit,"onUpdate:page-size":l[5]||(l[5]=t=>e.limit=t),layout:"total, sizes, prev, pager, next, jumper",total:e.total,onSizeChange:l[6]||(l[6]=t=>m()),onCurrentChange:m},null,8,["current-page","page-size","total"])])])]),_:1}),a(W,{ref_key:"cronDialog",ref:_,onComplete:m},null,512)])}}});export{he as default};
diff --git a/niucloud/public/admin/assets/cron-info-0c412e6c.js b/niucloud/public/admin/assets/cron-info-0c412e6c.js
new file mode 100644
index 0000000..a891567
--- /dev/null
+++ b/niucloud/public/admin/assets/cron-info-0c412e6c.js
@@ -0,0 +1 @@
+import{_ as o}from"./cron-info.vue_vue_type_script_setup_true_lang-4ef60fee.js";import"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";export{o as default};
diff --git a/niucloud/public/admin/assets/cron-info.vue_vue_type_script_setup_true_lang-4ef60fee.js b/niucloud/public/admin/assets/cron-info.vue_vue_type_script_setup_true_lang-4ef60fee.js
new file mode 100644
index 0000000..96a1f70
--- /dev/null
+++ b/niucloud/public/admin/assets/cron-info.vue_vue_type_script_setup_true_lang-4ef60fee.js
@@ -0,0 +1 @@
+import{d as E,r as m,n as N,q as V,h as r,I as h,w as e,a as n,e as o,i as B,t as l,u as a,N as s,y as F,c as b,X as T,Y as C,E as I,a7 as O,$ as R}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";const j={class:"input-width"},S={class:"input-width"},$={key:0,class:"input-width"},q={key:1,class:"input-width"},J={class:"input-width"},L={class:"input-width"},U={class:"input-width"},X={class:"input-width"},Y={class:"input-width"},z={class:"input-width"},A={class:"input-width"},G={class:"dialog-footer"},et=E({__name:"cron-info",setup(H,{expose:v}){const c=m(!1),u=m(!0),p={count:0,create_time:"",crond_length:"",crond_type:"",crond_type_name:"",data:"",delete_time:"",last_time:"",next_time:"",status_desc:"",title:"",type:"",type_name:"",update_time:""},t=N({...p}),y=m(),w=V(()=>({}));return v({showDialog:c,setFormData:async(_=null)=>{u.value=!0,Object.assign(t,p),_&&Object.keys(t).forEach(d=>{_[d]!=null&&(t[d]=_[d])}),u.value=!1}}),(_,d)=>{const i=T,g=C,x=I,D=O,k=R;return r(),h(D,{modelValue:c.value,"onUpdate:modelValue":d[1]||(d[1]=f=>c.value=f),title:a(s)("cronInfo"),width:"550px","destroy-on-close":!0},{footer:e(()=>[n("span",G,[o(x,{type:"primary",onClick:d[0]||(d[0]=f=>c.value=!1)},{default:e(()=>[B(l(a(s)("confirm")),1)]),_:1})])]),default:e(()=>[F((r(),h(g,{model:t,"label-width":"110px",ref_key:"formRef",ref:y,rules:a(w),class:"page-form"},{default:e(()=>[o(i,{label:a(s)("title")},{default:e(()=>[n("div",j,l(t.title),1)]),_:1},8,["label"]),o(i,{label:a(s)("typeName")},{default:e(()=>[n("div",S,l(t.type_name),1)]),_:1},8,["label"]),o(i,{label:a(s)("crondType")},{default:e(()=>[t.type=="crond"?(r(),b("div",$,l(t.crond_length)+" "+l(t.crond_type_name),1)):(r(),b("div",q,l(a(s)("cron")),1))]),_:1},8,["label"]),o(i,{label:a(s)("count")},{default:e(()=>[n("div",J,l(t.count),1)]),_:1},8,["label"]),o(i,{label:a(s)("task")},{default:e(()=>[n("div",L,l(t.task),1)]),_:1},8,["label"]),o(i,{label:a(s)("data")},{default:e(()=>[n("div",U,l(JSON.stringify(t.data)),1)]),_:1},8,["label"]),o(i,{label:a(s)("statusDesc")},{default:e(()=>[n("div",X,l(t.status_desc),1)]),_:1},8,["label"]),o(i,{label:a(s)("lastTime")},{default:e(()=>[n("div",Y,l(t.last_time),1)]),_:1},8,["label"]),o(i,{label:a(s)("nextTime")},{default:e(()=>[n("div",z,l(t.next_time),1)]),_:1},8,["label"]),o(i,{label:a(s)("createTime")},{default:e(()=>[n("div",A,l(t.create_time),1)]),_:1},8,["label"])]),_:1},8,["model","rules"])),[[k,u.value]])]),_:1},8,["modelValue","title"])}}});export{et as _};
diff --git a/niucloud/public/admin/assets/decorate.edit-e6b85004.js b/niucloud/public/admin/assets/decorate.edit-e6b85004.js
new file mode 100644
index 0000000..1195bae
--- /dev/null
+++ b/niucloud/public/admin/assets/decorate.edit-e6b85004.js
@@ -0,0 +1 @@
+const t="开发环境配置",e="wap域名(WAP_DOMAIN)",o="请输入wap域名",a="页面设置",n="内容",c="样式",i="页面样式",l="页面内容",s="页面名称",r="请输入页面名称",g="页面颜色",p="背景图片",m="边距设置",d="组件样式",h="底部背景",S="底部背景包含边距和圆角",N="组件背景",C="上边距",v="下边距",T="左右边距",u="上圆角",y="下圆角",b="温馨提示",A="确定离开此页面?",P="系统可能不会保存您所做的更改。",x="正在装修",M="上移",w="下移",H="复制",B="删除",I="重置",f="底部导航",k="此处控制当前页面底部导航菜单是否显示",R="链接地址",D="确定要删除吗?",U="无法复制",W="组件只能添加",z="个",F="确认要重置组件默认数据吗?",G="图片上传",L="图片上传",E="图片设置",O="建议上传尺寸相同的图片,推荐尺寸750*350",V="添加图片",_="请上传图片",j="图片高度",q="请输入图片高度",J="图片高度格式错误,请输入数字",K="文章数据",Q="文章样式",X="文章背景",Y="数据来源",Z="默认",$="手动选择",tt="文章数量",et="请选择",ot="文章选择",at="标题",nt="封面",ct="栏目",it="摘要",lt="已选",st="请选择文章",rt="导航模式",gt="排版模式",pt="横排",mt="竖排",dt="选择模式",ht="图文导航",St="图片导航",Nt="文字导航",Ct="图片设置",vt="图片大小",Tt="图片圆角",ut="展示风格",yt="固定显示",bt="单行滑动",At="分页滑动",Pt="每行数量",xt="每行数量",Mt="导航设置",wt="行",Ht="建议上传尺寸相同的图片,推荐尺寸60*60",Bt="标题",It="请输入标题",ft="添加导航",kt="高度设置",Rt="空白高度",Dt="风格设置",Ut="标题样式",Wt="风格选择",zt="标题内容",Ft="标题名称",Gt="请输入标题",Lt="对齐方式",Et="居左",Ot="居中",Vt="文字设置",_t="文字大小",jt="文字粗细",qt="加粗",Jt="常规",Kt="文字颜色",Qt="标题内容",Xt="副标题",Yt="请输入副标题",Zt="“更多”按钮内容",$t="文字",te="请输入文字",ee="是否显示",oe="会员样式",ae="模板",ne="图片间隙",ce="魔方样式",ie="热区",le="热区设置",se="添加热区",re="个热区",ge="热区管理",pe="请选择热区",me="的链接地址",de={developTitle:t,wapDomain:e,wapDomainPlaceholder:o,pageSet:a,tabEditContent:n,tabEditStyle:c,pageStyle:i,pageContent:l,pageName:s,pageNamePlaceholder:r,pageBgColor:g,bgUrl:p,marginSet:m,componentStyleTitle:d,bottomBgColor:h,bottomBgTips:S,componentBgColor:N,marginTop:C,marginBottom:v,marginBoth:T,topRounded:u,bottomRounded:y,warmPrompt:b,leavePageTitleTips:A,leavePageContentTips:P,decorating:x,moveUpComponent:M,moveDownComponent:w,copyComponent:H,delComponent:B,resetComponent:I,tabbar:f,tabbarSwitchTips:k,link:R,delComponentTips:D,notCopy:U,componentCanOnlyAdd:W,piece:z,resetComponentTips:F,image:G,imageUpload:L,imageSet:E,imageAdsTips:O,addImageAd:V,imageUrlTip:_,imageHeight:j,imageHeightPlaceholder:q,imageHeightRegNum:J,articleData:K,articleStyle:Q,articleBgColor:X,dataSources:Y,defaultSources:Z,manualSelectionSources:$,articleNum:tt,selectPlaceholder:et,selectArticleTips:ot,articleTitle:at,articleImage:nt,articleCategoryName:ct,articleSummary:it,selected:lt,selectArticleTip:st,graphicNavModeTitle:rt,layoutMode:gt,layoutModeHorizontal:pt,layoutModeVertical:mt,graphicNavSelectMode:dt,graphicNavModeGraphic:ht,graphicNavModeImg:St,graphicNavModeText:Nt,graphicNavImageSet:Ct,graphicNavImageSize:vt,graphicNavAroundRadius:Tt,graphicNavShowStyle:ut,graphicNavStyleFixed:yt,graphicNavStyleSingleSlide:bt,graphicNavStylePageSlide:At,graphicNavRowCount:Pt,graphicNavPageCount:xt,graphicNavSetLabel:Mt,line:wt,graphicNavTips:Ht,graphicNavTitle:Bt,graphicNavTitlePlaceholder:It,addGraphicNav:ft,blankHeightSet:kt,blankHeight:Rt,styleSet:Dt,titleStyle:Ut,selectStyle:Wt,titleContent:zt,title:Ft,titlePlaceholder:Gt,textAlign:Lt,textAlignLeft:Et,textAlignCenter:Ot,textSet:Vt,textFontSize:_t,textFontWeight:jt,fontWeightBold:qt,fontWeightNormal:Jt,textColor:Kt,subTitleContent:Qt,subTitle:Xt,subTitlePlaceholder:Yt,moreContent:Zt,more:$t,morePlaceholder:te,moreIsShow:ee,memberStyle:oe,template:ae,imageGap:ne,rubikCubeStyle:ce,hotArea:ie,hotAreaSet:le,addHotArea:se,selectedAfterHotArea:re,hotAreaManage:ge,selectedHotArea:pe,hotAreaLink:me};export{ft as addGraphicNav,se as addHotArea,V as addImageAd,X as articleBgColor,ct as articleCategoryName,K as articleData,nt as articleImage,tt as articleNum,Q as articleStyle,it as articleSummary,at as articleTitle,p as bgUrl,Rt as blankHeight,kt as blankHeightSet,h as bottomBgColor,S as bottomBgTips,y as bottomRounded,N as componentBgColor,W as componentCanOnlyAdd,d as componentStyleTitle,H as copyComponent,Y as dataSources,x as decorating,de as default,Z as defaultSources,B as delComponent,D as delComponentTips,t as developTitle,qt as fontWeightBold,Jt as fontWeightNormal,Tt as graphicNavAroundRadius,Ct as graphicNavImageSet,vt as graphicNavImageSize,ht as graphicNavModeGraphic,St as graphicNavModeImg,Nt as graphicNavModeText,rt as graphicNavModeTitle,xt as graphicNavPageCount,Pt as graphicNavRowCount,dt as graphicNavSelectMode,Mt as graphicNavSetLabel,ut as graphicNavShowStyle,yt as graphicNavStyleFixed,At as graphicNavStylePageSlide,bt as graphicNavStyleSingleSlide,Ht as graphicNavTips,Bt as graphicNavTitle,It as graphicNavTitlePlaceholder,ie as hotArea,me as hotAreaLink,ge as hotAreaManage,le as hotAreaSet,G as image,O as imageAdsTips,ne as imageGap,j as imageHeight,q as imageHeightPlaceholder,J as imageHeightRegNum,E as imageSet,L as imageUpload,_ as imageUrlTip,gt as layoutMode,pt as layoutModeHorizontal,mt as layoutModeVertical,P as leavePageContentTips,A as leavePageTitleTips,wt as line,R as link,$ as manualSelectionSources,T as marginBoth,v as marginBottom,m as marginSet,C as marginTop,oe as memberStyle,$t as more,Zt as moreContent,ee as moreIsShow,te as morePlaceholder,w as moveDownComponent,M as moveUpComponent,U as notCopy,g as pageBgColor,l as pageContent,s as pageName,r as pageNamePlaceholder,a as pageSet,i as pageStyle,z as piece,I as resetComponent,F as resetComponentTips,ce as rubikCubeStyle,st as selectArticleTip,ot as selectArticleTips,et as selectPlaceholder,Wt as selectStyle,lt as selected,re as selectedAfterHotArea,pe as selectedHotArea,Dt as styleSet,Xt as subTitle,Qt as subTitleContent,Yt as subTitlePlaceholder,n as tabEditContent,c as tabEditStyle,f as tabbar,k as tabbarSwitchTips,ae as template,Lt as textAlign,Ot as textAlignCenter,Et as textAlignLeft,Kt as textColor,_t as textFontSize,jt as textFontWeight,Vt as textSet,Ft as title,zt as titleContent,Gt as titlePlaceholder,Ut as titleStyle,u as topRounded,e as wapDomain,o as wapDomainPlaceholder,b as warmPrompt};
diff --git a/niucloud/public/admin/assets/decorate.preview-902d21f3.js b/niucloud/public/admin/assets/decorate.preview-902d21f3.js
new file mode 100644
index 0000000..4968d14
--- /dev/null
+++ b/niucloud/public/admin/assets/decorate.preview-902d21f3.js
@@ -0,0 +1 @@
+const e="预览",o="微信小程序",c="微信公众号",p="链接",t="复制",a="复制成功",n="小程序未配置",s="开发环境配置",w="wap域名(WAP_DOMAIN)",i="请输入wap域名",l={preview:e,weapp:o,wechat:c,link:p,copy:t,copySuccess:a,weappNotSet:n,developTitle:s,wapDomain:w,wapDomainPlaceholder:i};export{t as copy,a as copySuccess,l as default,s as developTitle,p as link,e as preview,w as wapDomain,i as wapDomainPlaceholder,o as weapp,n as weappNotSet,c as wechat};
diff --git a/niucloud/public/admin/assets/default_headimg-a897263d.js b/niucloud/public/admin/assets/default_headimg-a897263d.js
new file mode 100644
index 0000000..6671ce5
--- /dev/null
+++ b/niucloud/public/admin/assets/default_headimg-a897263d.js
@@ -0,0 +1 @@
+const e=""+new URL("member_head-1e927329.png",import.meta.url).href;export{e as _};
diff --git a/niucloud/public/admin/assets/detail-4ddc2d10.js b/niucloud/public/admin/assets/detail-4ddc2d10.js
new file mode 100644
index 0000000..762a5b6
--- /dev/null
+++ b/niucloud/public/admin/assets/detail-4ddc2d10.js
@@ -0,0 +1 @@
+import{d as k,cM as x,O as N,f as D,r as c,h as u,c as I,y as B,I as p,w as t,a,t as l,u as s,N as o,e as i,B as C,X as F,_ as M,Y as R,$ as E}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";import{g as T}from"./order-35500d85.js";const S={class:"main-container"},V={class:"panel-title"},$={class:"input-width"},O={class:"input-width"},q={class:"input-width"},L={class:"input-width"},X={class:""},Y={class:""},j={class:"input-width"},z={class:"input-width"},A={class:"input-width"},G={class:"input-width"},H={class:"input-width"},J={class:"input-width"},K={class:"input-width"},P={class:"input-width"},oe=k({__name:"detail",setup(Q){x();const f=N(),v=D(),m=parseInt(f.query.order_id),d=c(!0),e=c(null);m?(async(n=0)=>{d.value=!0,e.value=null,await T(n).then(({data:_})=>{e.value=_}).catch(()=>{}),d.value=!1})(m):d.value=!1;const b=c(),h=n=>{v.push(`/member/detail?id=${n}`)};return(n,_)=>{const r=F,w=M,y=R,g=E;return u(),I("div",S,[B((u(),p(y,{model:e.value,"label-width":"150px",ref_key:"formRef",ref:b,class:"page-form"},{default:t(()=>[e.value?(u(),p(w,{key:0,class:"box-card !border-none relative",shadow:"never"},{default:t(()=>[a("h3",V,l(s(o)("orderInfo")),1),i(r,{label:s(o)("orderNo")},{default:t(()=>[a("div",$,l(e.value.order_no),1)]),_:1},8,["label"]),i(r,{label:s(o)("orderMoney")},{default:t(()=>[a("div",O,l(e.value.order_money),1)]),_:1},8,["label"]),i(r,{label:s(o)("orderDiscountMoney")},{default:t(()=>[a("div",q,l(e.value.order_discount_money),1)]),_:1},8,["label"]),i(r,{label:s(o)("member")},{default:t(()=>[a("div",L,[a("div",{class:"flex flex flex-col cursor-pointer",onClick:_[0]||(_[0]=W=>h(e.value.member_id))},[a("span",X,l(e.value.member.nickname||""),1),a("span",Y,l(e.value.member.mobile||""),1)])])]),_:1},8,["label"]),i(r,{label:s(o)("ip")},{default:t(()=>[a("div",j,l(e.value.ip),1)]),_:1},8,["label"]),i(r,{label:s(o)("orderFromName")},{default:t(()=>[a("div",z,l(e.value.order_from_name),1)]),_:1},8,["label"]),i(r,{label:s(o)("orderStatus")},{default:t(()=>[a("div",A,l(e.value.order_status_info.name),1)]),_:1},8,["label"]),i(r,{label:s(o)("payTypeName")},{default:t(()=>[a("div",G,l(e.value.pay_type_name),1)]),_:1},8,["label"]),i(r,{label:s(o)("createTime")},{default:t(()=>[a("div",H,l(e.value.create_time||""),1)]),_:1},8,["label"]),i(r,{label:s(o)("payTime")},{default:t(()=>[a("div",J,l(e.value.pay_time||""),1)]),_:1},8,["label"]),i(r,{label:s(o)("remark")},{default:t(()=>[a("div",K,l(e.value.remark||""),1)]),_:1},8,["label"]),i(r,{label:s(o)("memberMessage")},{default:t(()=>[a("div",P,l(e.value.member_message||""),1)]),_:1},8,["label"])]),_:1})):C("",!0)]),_:1},8,["model"])),[[g,d.value]])])}}});export{oe as default};
diff --git a/niucloud/public/admin/assets/detection-1cfbea40.js b/niucloud/public/admin/assets/detection-1cfbea40.js
new file mode 100644
index 0000000..84e7234
--- /dev/null
+++ b/niucloud/public/admin/assets/detection-1cfbea40.js
@@ -0,0 +1 @@
+import{d as w,O as S,r as h,a0 as v,y as k,u as t,h as i,c as d,I as C,w as n,a as s,t as c,N as a,e,B,af as E,ah as N,a1 as z,_ as D,$ as I}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css */import{v as V}from"./tools-8d764897.js";const j={class:"main-container attachment-container min-h-[80vh]"},O={class:"flex justify-between items-center"},T={class:"text-[20px]"},L={class:"bg-[#fff] pb-[20px] mb-3"},R={class:"pt-[20px] pb-[10px] text-sm"},$={class:"text-[14px]"},q={class:"bg-[#fff] pb-[20px] mb-3"},A={class:"py-[20px] text-sm"},F={class:"text-[14px]"},G={class:"bg-[#fff] pb-[20px] mb-3"},H={class:"py-[20px] text-sm"},J={class:"text-[14px]"},K={key:0},M={key:1},P={class:"bg-[#fff] pb-[20px] mb-3"},Q={class:"py-[20px] text-sm"},U={class:"text-[14px]"},W={key:0},X={key:1},me=w({__name:"detection",setup(Y){const g=S().meta.title,o=h({});let m=h(!0);return(()=>{V().then(u=>{o.value=u.data,m.value=!1})})(),(u,te)=>{const l=E,r=N,f=v("Select"),_=z,b=v("CloseBold"),x=D,y=I;return k((i(),d("div",j,[Object.keys(o.value).length?(i(),C(x,{key:0,class:"box-card !border-none",shadow:"never"},{default:n(()=>[s("div",O,[s("span",T,c(t(g)),1)]),s("div",L,[s("p",R,c(t(a)("serverInformation")),1),s("div",$,[e(r,{data:o.value.server,size:"large"},{default:n(()=>[e(l,{prop:"name",label:t(a)("environment"),align:"left","min-width":"200"},null,8,["label"]),e(l,{prop:"server",label:t(a)("version"),align:"left","min-width":"140"},null,8,["label"])]),_:1},8,["data"])])]),s("div",q,[s("p",A,c(t(a)("systemDemand")),1),s("div",F,[e(r,{data:o.value.server_version,size:"large"},{default:n(()=>[e(l,{prop:"name",label:t(a)("environment"),align:"left","min-width":"200"},null,8,["label"]),e(l,{prop:"demand",label:t(a)("demand"),align:"left","min-width":"140"},null,8,["label"]),e(l,{prop:"server",label:t(a)("version"),align:"left","min-width":"140"},null,8,["label"])]),_:1},8,["data"])])]),s("div",G,[s("p",H,c(t(a)("authorityStatus")),1),s("div",J,[e(r,{data:o.value.system_variables,size:"large"},{default:n(()=>[e(l,{prop:"name",label:t(a)("name"),align:"left","min-width":"200"},null,8,["label"]),e(l,{prop:"need",label:t(a)("demand"),align:"left","min-width":"140"},null,8,["label"]),e(l,{label:t(a)("status"),align:"left","min-width":"140"},{default:n(({row:p})=>[p.status?(i(),d("span",K,[e(_,{color:"green"},{default:n(()=>[e(f)]),_:1})])):(i(),d("span",M,[e(_,{color:"red"},{default:n(()=>[e(b)]),_:1})]))]),_:1},8,["label"])]),_:1},8,["data"])])]),s("div",P,[s("p",Q,c(t(a)("process")),1),s("div",U,[e(r,{data:o.value.process,size:"large"},{default:n(()=>[e(l,{prop:"name",label:t(a)("name"),align:"left","min-width":"200"},null,8,["label"]),e(l,{prop:"need",label:t(a)("demand"),align:"left","min-width":"140"},null,8,["label"]),e(l,{label:t(a)("status"),align:"left","min-width":"140"},{default:n(({row:p})=>[p.status?(i(),d("span",W,[e(_,{color:"green"},{default:n(()=>[e(f)]),_:1})])):(i(),d("span",X,[e(_,{color:"red"},{default:n(()=>[e(b)]),_:1})]))]),_:1},8,["label"])]),_:1},8,["data"])])])]),_:1})):B("",!0)])),[[y,t(m)]])}}});export{me as default};
diff --git a/niucloud/public/admin/assets/detection-21d58aad.css b/niucloud/public/admin/assets/detection-21d58aad.css
new file mode 100644
index 0000000..dd512e0
--- /dev/null
+++ b/niucloud/public/admin/assets/detection-21d58aad.css
@@ -0,0 +1 @@
+.items{border-bottom:1px solid #eee}
diff --git a/niucloud/public/admin/assets/developer-25adcf57.png b/niucloud/public/admin/assets/developer-25adcf57.png
new file mode 100644
index 0000000..8ffd37b
Binary files /dev/null and b/niucloud/public/admin/assets/developer-25adcf57.png differ
diff --git a/niucloud/public/admin/assets/developer_token-12d21183.js b/niucloud/public/admin/assets/developer_token-12d21183.js
new file mode 100644
index 0000000..85554e7
--- /dev/null
+++ b/niucloud/public/admin/assets/developer_token-12d21183.js
@@ -0,0 +1 @@
+import{d as w,r as i,n as y,N as l,h as _,c as E,y as T,I as V,w as n,e as s,a as c,t as d,u as r,i as B,W as D,X as C,E as N,_ as I,Y as R,$ as F}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css */import{T as P,U}from"./sys-0f76aff3.js";const $={class:"main-container"},q={class:"panel-title !text-sm"},L={class:"text-[14px] text-[#a9a9a9] leading-tight mt-[10px]"},J=w({__name:"developer_token",setup(S){const e=i(!0),o=i({token:""});P().then(({data:t})=>{e.value=!1,t.token&&(o.value=t)}).catch();const u=i(),v=y({token:[{required:!0,message:l("tokenPlaceholder"),trigger:"blur"}]}),f=async t=>{e.value||!t||await t.validate(async a=>{a&&(e.value=!0,U(o.value).then(()=>{e.value=!1}).catch(()=>{e.value=!1}))})};return(t,a)=>{const k=D,m=C,h=N,g=I,x=R,b=F;return _(),E("div",$,[T((_(),V(x,{model:o.value,"label-width":"0",ref_key:"formRef",ref:u,rules:v,class:"page-form"},{default:n(()=>[s(g,{class:"box-card !border-none",shadow:"never"},{default:n(()=>[c("h3",q,d(r(l)("developerTokenEdit")),1),s(m,{label:"",prop:"token"},{default:n(()=>[c("div",null,[s(k,{modelValue:o.value.token,"onUpdate:modelValue":a[0]||(a[0]=p=>o.value.token=p),placeholder:r(l)("tokenPlaceholder"),class:"input-width",clearable:"",maxlength:"30"},null,8,["modelValue","placeholder"])]),c("div",L,d(r(l)("tokenTips")),1)]),_:1}),s(m,{label:""},{default:n(()=>[s(h,{type:"primary",loading:e.value,onClick:a[1]||(a[1]=p=>f(u.value))},{default:n(()=>[B(d(r(l)("save")),1)]),_:1},8,["loading"])]),_:1})]),_:1})]),_:1},8,["model","rules"])),[[b,e.value]])])}}});export{J as default};
diff --git a/niucloud/public/admin/assets/dict-3e5bfbe1.js b/niucloud/public/admin/assets/dict-3e5bfbe1.js
new file mode 100644
index 0000000..8939bcd
--- /dev/null
+++ b/niucloud/public/admin/assets/dict-3e5bfbe1.js
@@ -0,0 +1 @@
+import{aJ as e}from"./index-6010b07e.js";function c(t){return e.get("dict/dict",{params:t})}function i(t){return e.get(`dict/dict/${t}`)}function u(t){return e.post("dict/dict",t,{showErrorMessage:!0,showSuccessMessage:!0})}function n(t){return e.put(`dict/dict/${t.id}`,t,{showErrorMessage:!0,showSuccessMessage:!0})}function o(t){return e.delete(`dict/dict/${t}`,{showErrorMessage:!0,showSuccessMessage:!0})}function a(t,s){return e.put(`dict/dictionary/${t}`,s,{showErrorMessage:!0,showSuccessMessage:!0})}function d(){return e.get("dict/all")}function g(t){return e.get(`dict/dictionary/type/${t}`)}export{u as a,c as b,d as c,o as d,n as e,i as g,a as s,g as u};
diff --git a/niucloud/public/admin/assets/dict-5908cbf4.js b/niucloud/public/admin/assets/dict-5908cbf4.js
new file mode 100644
index 0000000..0a36953
--- /dev/null
+++ b/niucloud/public/admin/assets/dict-5908cbf4.js
@@ -0,0 +1 @@
+import{_ as o}from"./dict.vue_vue_type_style_index_0_lang-8df6262f.js";import"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css */import"./dict-3e5bfbe1.js";export{o as default};
diff --git a/niucloud/public/admin/assets/dict.list-7d009441.js b/niucloud/public/admin/assets/dict.list-7d009441.js
new file mode 100644
index 0000000..855d5c9
--- /dev/null
+++ b/niucloud/public/admin/assets/dict.list-7d009441.js
@@ -0,0 +1 @@
+const a="字典名称",e="请输入字典名称",t="字典关键词",c="请输入字典关键词",o="字典数据",d="请输入字典数据",l="备注",s="请输入备注",n="添加数据字典",m="编辑数据字典",r="确定要删除该数据吗?",i="数据管理",h="添加数据",D="编辑数据",P="数据名称",u="请输入数据名称",p="数据值",k="请输入数据值",y="数值越大越排前",N="请输入备注",T="创建时间",V={name:a,namePlaceholder:e,key:t,keyPlaceholder:c,data:o,dataPlaceholder:d,memo:l,memoPlaceholder:s,addDict:n,updateDict:m,dictDeleteTips:r,dictData:i,addDictData:h,editDictData:D,dataName:P,dataNamePlaceholder:u,dataValue:p,dataValuePlaceholder:k,sortPlaceholder:y,momePlaceholder:N,createTime:T};export{n as addDict,h as addDictData,T as createTime,o as data,P as dataName,u as dataNamePlaceholder,d as dataPlaceholder,p as dataValue,k as dataValuePlaceholder,V as default,i as dictData,r as dictDeleteTips,D as editDictData,t as key,c as keyPlaceholder,l as memo,s as memoPlaceholder,N as momePlaceholder,a as name,e as namePlaceholder,y as sortPlaceholder,m as updateDict};
diff --git a/niucloud/public/admin/assets/dict.vue_vue_type_style_index_0_lang-8df6262f.js b/niucloud/public/admin/assets/dict.vue_vue_type_style_index_0_lang-8df6262f.js
new file mode 100644
index 0000000..f56f711
--- /dev/null
+++ b/niucloud/public/admin/assets/dict.vue_vue_type_style_index_0_lang-8df6262f.js
@@ -0,0 +1 @@
+import{d as W,r as i,q as X,N as l,h as U,I,w as n,a as g,e as t,i as c,t as r,u as a,y as Y,cx as y,E as A,af as G,ah as H,W as K,X as M,aE as Q,Y as Z,a7 as ee,$ as le}from"./index-6010b07e.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css */import{s as ae,g as te}from"./dict-3e5bfbe1.js";const oe={class:"mb-[10px]"},ne={class:"dialog-footer"},ue={class:"text-[12px] text-[#a9a9a9] leading-normal mt-[5px]"},se={class:"dialog-footer"},ke=W({__name:"dict",emits:["complete"],setup(ie,{expose:P,emit:$}){const v=i(!1),f=i(!1),_=i(!1),m=i([]),x=i(),V=i("add"),k=i(),w=i(""),h={name:"",value:"",sort:0,memo:""},u=i({...h}),F=X(()=>({name:[{required:!0,message:l("dataNamePlaceholder"),trigger:"blur"}],value:[{required:!0,message:l("dataValuePlaceholder"),trigger:"blur"}]})),B=()=>{V.value="add",u.value=y(h),_.value=!0},C=i(0),q=(s,e)=>{V.value="edit",C.value=e,u.value=y(h),u.value=Object.assign(u.value,y(s)),_.value=!0},R=async s=>{s&&await s.validate(async e=>{e&&(V.value!="edit"?m.value.push(y(u.value)):m.value.splice(C.value,1,y(u.value)),m.value.sort(function(d,p){return p.sort-d.sort}),_.value=!1)})},T=s=>{m.value.splice(s,1)},O=async()=>{f.value=!0,ae(x.value,{dictionary:JSON.stringify(m.value)}).then(s=>{f.value=!1,v.value=!1,$("complete")}).catch(()=>{f.value=!1})};return P({showDialog:v,setFormData:async(s=null)=>{v.value=!0,f.value=!0,x.value=s.id,w.value=s.name;const e=await(await te(s.id)).data;m.value=e.dictionary,f.value=!1}}),(s,e)=>{const d=A,p=G,S=H,D=K,b=M,j=Q,z=Z,E=ee,J=le;return U(),I(E,{modelValue:v.value,"onUpdate:modelValue":e[10]||(e[10]=o=>v.value=o),title:a(l)("dictData"),width:"60%",class:"diy-dialog-wrap","destroy-on-close":!0},{footer:n(()=>[g("span",ne,[t(d,{onClick:e[0]||(e[0]=o=>v.value=!1)},{default:n(()=>[c(r(a(l)("cancel")),1)]),_:1}),t(d,{type:"primary",onClick:e[1]||(e[1]=o=>O())},{default:n(()=>[c(r(a(l)("confirm")),1)]),_:1})])]),default:n(()=>[g("div",oe,[t(d,{type:"primary",onClick:B},{default:n(()=>[c(r(a(l)("addDictData")),1)]),_:1})]),Y((U(),I(S,{data:m.value,size:"large"},{default:n(()=>[t(p,{label:a(l)("dataName"),prop:"name"},null,8,["label"]),t(p,{label:a(l)("dataValue"),prop:"value"},null,8,["label"]),t(p,{label:a(l)("sort"),align:"center","min-width":"100px",prop:"sort"},null,8,["label"]),t(p,{label:a(l)("memo"),prop:"memo"},null,8,["label"]),t(p,{label:a(l)("operation"),align:"right",fixed:"right",width:"120"},{default:n(({row:o,$index:N})=>[t(d,{type:"primary",link:"",onClick:L=>q(o,N)},{default:n(()=>[c(r(a(l)("edit")),1)]),_:2},1032,["onClick"]),t(d,{type:"primary",link:"",onClick:L=>T(N)},{default:n(()=>[c(r(a(l)("delete")),1)]),_:2},1032,["onClick"])]),_:1},8,["label"])]),_:1},8,["data"])),[[J,f.value]]),t(E,{modelValue:_.value,"onUpdate:modelValue":e[9]||(e[9]=o=>_.value=o),title:V.value!="edit"?a(l)("addDictData"):a(l)("editDictData"),width:"480",class:"diy-dialog-wrap","destroy-on-close":!0},{footer:n(()=>[g("span",se,[t(d,{onClick:e[7]||(e[7]=o=>_.value=!1)},{default:n(()=>[c(r(a(l)("cancel")),1)]),_:1}),t(d,{type:"primary",onClick:e[8]||(e[8]=o=>R(k.value))},{default:n(()=>[c(r(a(l)("confirm")),1)]),_:1})])]),default:n(()=>[t(z,{model:u.value,"label-width":"120px",ref_key:"formRef",ref:k,rules:a(F),class:"page-form"},{default:n(()=>[t(b,{label:a(l)("name")},{default:n(()=>[t(D,{modelValue:w.value,"onUpdate:modelValue":e[2]||(e[2]=o=>w.value=o),disabled:"",class:"input-width"},null,8,["modelValue"])]),_:1},8,["label"]),t(b,{label:a(l)("dataName"),prop:"name"},{default:n(()=>[t(D,{modelValue:u.value.name,"onUpdate:modelValue":e[3]||(e[3]=o=>u.value.name=o),clearable:"",placeholder:a(l)("dataNamePlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),t(b,{label:a(l)("dataValue"),prop:"value"},{default:n(()=>[t(D,{modelValue:u.value.value,"onUpdate:modelValue":e[4]||(e[4]=o=>u.value.value=o),clearable:"",placeholder:a(l)("dataValuePlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"]),t(b,{label:a(l)("sort"),prop:"sort"},{default:n(()=>[g("div",null,[t(j,{modelValue:u.value.sort,"onUpdate:modelValue":e[5]||(e[5]=o=>u.value.sort=o),":step":1,"step-strictly":"","value-on-clear":0,min:0,class:"input-width"},null,8,["modelValue"]),g("p",ue,r(a(l)("sortPlaceholder")),1)])]),_:1},8,["label"]),t(b,{label:a(l)("memo")},{default:n(()=>[t(D,{modelValue:u.value.memo,"onUpdate:modelValue":e[6]||(e[6]=o=>u.value.memo=o),type:"textarea",clearable:"",placeholder:a(l)("momePlaceholder"),class:"input-width"},null,8,["modelValue","placeholder"])]),_:1},8,["label"])]),_:1},8,["model","rules"])]),_:1},8,["modelValue","title"])]),_:1},8,["modelValue","title"])}}});export{ke as _};
diff --git a/niucloud/public/admin/assets/diy-5ff717bd.js b/niucloud/public/admin/assets/diy-5ff717bd.js
new file mode 100644
index 0000000..1fcfbab
--- /dev/null
+++ b/niucloud/public/admin/assets/diy-5ff717bd.js
@@ -0,0 +1 @@
+import{aJ as t}from"./index-6010b07e.js";function s(e){return t.get("diy/diy",{params:e})}function n(e){return t.post("diy/diy",e,{showSuccessMessage:!0})}function u(e){return t.put(`diy/diy/${e.id}`,e,{showSuccessMessage:!0})}function r(e){return t.put("diy/use",e,{showSuccessMessage:!0})}function o(e){return t.put("diy/diy/share",e,{showSuccessMessage:!0})}function a(e){return t.delete(`diy/diy/${e}`,{showSuccessMessage:!0})}function g(e){return t.get("diy/init",{params:e})}function c(e){return t.get("diy/link",{params:e})}function y(e){return t.get("diy/bottom",{params:e})}function d(e){return t.get("diy/bottom/config",{params:e})}function f(e){return t.post("diy/bottom",e,{showSuccessMessage:!0})}function p(e){return t.get("diy/template",{params:e})}function D(e){return t.get("diy/template/pages",{params:e})}function h(e){return t.get("diy/route",{params:e})}function m(){return t.get("diy/route/apps")}function S(e){return t.get("diy/route/info",{params:e})}function l(e){return t.put("diy/route/share",e,{showSuccessMessage:!0})}function P(e){return t.get("diy/decorate",{params:e})}function w(e){return t.put("diy/change",e,{showSuccessMessage:!0})}function M(e){return t.get("diy/apps")}export{D as a,n as b,P as c,w as d,u as e,M as f,c as g,p as h,g as i,s as j,a as k,o as l,m,h as n,S as o,l as p,y as q,d as r,r as s,f as t};
diff --git a/niucloud/public/admin/assets/diy-8d93d096.js b/niucloud/public/admin/assets/diy-8d93d096.js
new file mode 100644
index 0000000..2839995
--- /dev/null
+++ b/niucloud/public/admin/assets/diy-8d93d096.js
@@ -0,0 +1 @@
+import{cy as u,cx as o,au as a,a5 as s,N as r,a2 as i}from"./index-6010b07e.js";const h=u("diy",{state:()=>({id:0,load:!1,currentIndex:-99,currentComponent:"edit-page",pageMode:"diy",editTab:"content",name:"",type:"",typeName:"",templateName:"",isDefault:0,predefineColors:["#F4391c","#ff4500","#ff8c00","#FFD009","#ffd700","#19C650","#90ee90","#00ced1","#1e90ff","#c71585","#FF407E","#CFAF70","#A253FF","rgba(255, 69, 0, 0.68)","rgb(255, 120, 0)","hsl(181, 100%, 37%)","hsla(209, 100%, 56%, 0.73)","#c7158577"],components:[],global:{title:"页面",pageBgColor:"",bgUrl:"",imgWidth:"",imgHeight:"",topStatusBar:{bgColor:"#ffffff",isTransparent:!1,isShow:!0,style:"style-1",textColor:"#333333",textAlign:"center"},bottomTabBarSwitch:!0,popWindow:{imgUrl:"",imgWidth:"",imgHeight:"",count:-1,show:0,link:{name:""}},template:{textColor:"#303133",pageBgColor:"",componentBgColor:"",topRounded:0,bottomRounded:0,elementBgColor:"",topElementRounded:0,bottomElementRounded:0,margin:{top:0,bottom:0,both:0}}},value:[]}),getters:{editComponent:e=>e.currentIndex==-99?e.global:e.value[e.currentIndex]},actions:{init(){this.global={title:"页面",pageBgColor:"",bgUrl:"",imgWidth:"",imgHeight:"",topStatusBar:{bgColor:"#ffffff",isTransparent:!1,isShow:!0,style:"style-1",textColor:"#333333",textAlign:"center"},bottomTabBarSwitch:!0,popWindow:{imgUrl:"",imgWidth:"",imgHeight:"",count:-1,show:0,link:{name:""}},template:{textColor:"#303133",pageBgColor:"",componentBgColor:"",topRounded:0,bottomRounded:0,elementBgColor:"",topElementRounded:0,bottomElementRounded:0,margin:{top:0,bottom:0,both:0}}},this.value=[]},addComponent(e,n){if(!this.load)return;let t=o(n);if(t.id=this.generateRandom(),t.componentName=e,t.componentTitle=t.title,t.ignore=[],Object.assign(t,t.value),delete t.title,delete t.value,delete t.type,delete t.icon,t.template)Object.assign(t,t.template),delete t.template;else{let l=o(this.global.template);Object.assign(t,l)}this.checkComponentIsAdd(t)&&(this.currentIndex===-99?(this.value.push(t),this.currentIndex=this.value.length-1):this.value.splice(++this.currentIndex,0,t),this.currentComponent=t.path)},generateRandom(e=5){return Number(Math.random().toString().substr(3,e)+Date.now()).toString(36)},postMessage(){var e=JSON.stringify({pageMode:this.pageMode,currentIndex:this.currentIndex,global:a(this.global),value:a(this.value)});window.previewIframe.contentWindow.postMessage(e,"*")},changeCurrentIndex(e,n=null){this.currentIndex=e,this.currentIndex==-99?this.currentComponent="edit-page":n&&(this.currentComponent=n.path)},delComponent(){this.currentIndex!=-99&&s.confirm(r("delComponentTips"),r("warning"),{confirmButtonText:r("confirm"),cancelButtonText:r("cancel"),type:"warning",autofocus:!1}).then(()=>{this.value.splice(this.currentIndex,1),this.value.length===0&&(this.currentIndex=-99),this.currentIndex===this.value.length&&this.currentIndex--;let e=o(this.value[this.currentIndex]);this.changeCurrentIndex(this.currentIndex,e)}).catch(()=>{})},moveUpComponent(){if(this.currentIndex-1<0)return;var e=o(this.value[this.currentIndex]);e.id=this.generateRandom();let n=this.currentIndex-1;var t=o(this.value[n]);t.id=this.generateRandom(),this.value[this.currentIndex]=t,this.value[n]=e,this.changeCurrentIndex(n,e)},moveDownComponent(){if(!(this.currentIndex+1>=this.value.length)){var e=this.currentIndex+1,n=o(this.value[this.currentIndex]);n.id=this.generateRandom();var t=o(this.value[e]);t.id=this.generateRandom(),this.value[this.currentIndex]=t,this.value[e]=n,this.changeCurrentIndex(e,n)}},copyComponent(){if(this.currentIndex<0)return;let e=o(this.value[this.currentIndex]);if(e.id=this.generateRandom(),!this.checkComponentIsAdd(e)){i({type:"warning",message:`${r("notCopy")},${e.componentTitle}${r("componentCanOnlyAdd")}${e.uses}${r("piece")}`});return}var n=this.currentIndex+1;this.value.splice(n,0,e),this.changeCurrentIndex(n,e)},checkComponentIsAdd(e){if(e.uses===0)return!0;var n=0;for(var t in this.value)this.value[t].componentName===e.componentName&&n++;return!(n>=e.uses)},resetComponent(){this.currentIndex<0||s.confirm(r("resetComponentTips"),r("warning"),{confirmButtonText:r("confirm"),cancelButtonText:r("cancel"),type:"warning",autofocus:!1}).then(()=>{for(let e=0;e
C&&(e=C),tC&&(e=C),tC&&(e=C),tC&&(e=C),t1&&a&&a.length>1){var i=pm(a)/pm(n);!isFinite(i)&&(i=1),e.pinchScale=i;var o=ML(a);return e.pinchX=o[0],e.pinchY=o[1],{type:"pinch",target:r[0].target,event:e}}}}};function lr(){return[1,0,0,1,0,0]}function rh(r){return r[0]=1,r[1]=0,r[2]=0,r[3]=1,r[4]=0,r[5]=0,r}function ig(r,e){return r[0]=e[0],r[1]=e[1],r[2]=e[2],r[3]=e[3],r[4]=e[4],r[5]=e[5],r}function oa(r,e,t){var a=e[0]*t[0]+e[2]*t[1],n=e[1]*t[0]+e[3]*t[1],i=e[0]*t[2]+e[2]*t[3],o=e[1]*t[2]+e[3]*t[3],s=e[0]*t[4]+e[2]*t[5]+e[4],l=e[1]*t[4]+e[3]*t[5]+e[5];return r[0]=a,r[1]=n,r[2]=i,r[3]=o,r[4]=s,r[5]=l,r}function Wr(r,e,t){return r[0]=e[0],r[1]=e[1],r[2]=e[2],r[3]=e[3],r[4]=e[4]+t[0],r[5]=e[5]+t[1],r}function pi(r,e,t){var a=e[0],n=e[2],i=e[4],o=e[1],s=e[3],l=e[5],u=Math.sin(t),f=Math.cos(t);return r[0]=a*f+o*u,r[1]=-a*u+o*f,r[2]=n*f+s*u,r[3]=-n*u+f*s,r[4]=f*i+u*l,r[5]=f*l-u*i,r}function og(r,e,t){var a=t[0],n=t[1];return r[0]=e[0]*a,r[1]=e[1]*n,r[2]=e[2]*a,r[3]=e[3]*n,r[4]=e[4]*a,r[5]=e[5]*n,r}function go(r,e){var t=e[0],a=e[2],n=e[4],i=e[1],o=e[3],s=e[5],l=t*o-i*a;return l?(l=1/l,r[0]=o*l,r[1]=-i*l,r[2]=-a*l,r[3]=t*l,r[4]=(a*s-o*n)*l,r[5]=(i*n-t*s)*l,r):null}function IL(r){var e=lr();return ig(e,r),e}var LL=function(){function r(e,t){this.x=e||0,this.y=t||0}return r.prototype.copy=function(e){return this.x=e.x,this.y=e.y,this},r.prototype.clone=function(){return new r(this.x,this.y)},r.prototype.set=function(e,t){return this.x=e,this.y=t,this},r.prototype.equal=function(e){return e.x===this.x&&e.y===this.y},r.prototype.add=function(e){return this.x+=e.x,this.y+=e.y,this},r.prototype.scale=function(e){this.x*=e,this.y*=e},r.prototype.scaleAndAdd=function(e,t){this.x+=e.x*t,this.y+=e.y*t},r.prototype.sub=function(e){return this.x-=e.x,this.y-=e.y,this},r.prototype.dot=function(e){return this.x*e.x+this.y*e.y},r.prototype.len=function(){return Math.sqrt(this.x*this.x+this.y*this.y)},r.prototype.lenSquare=function(){return this.x*this.x+this.y*this.y},r.prototype.normalize=function(){var e=this.len();return this.x/=e,this.y/=e,this},r.prototype.distance=function(e){var t=this.x-e.x,a=this.y-e.y;return Math.sqrt(t*t+a*a)},r.prototype.distanceSquare=function(e){var t=this.x-e.x,a=this.y-e.y;return t*t+a*a},r.prototype.negate=function(){return this.x=-this.x,this.y=-this.y,this},r.prototype.transform=function(e){if(e){var t=this.x,a=this.y;return this.x=e[0]*t+e[2]*a+e[4],this.y=e[1]*t+e[3]*a+e[5],this}},r.prototype.toArray=function(e){return e[0]=this.x,e[1]=this.y,e},r.prototype.fromArray=function(e){this.x=e[0],this.y=e[1]},r.set=function(e,t,a){e.x=t,e.y=a},r.copy=function(e,t){e.x=t.x,e.y=t.y},r.len=function(e){return Math.sqrt(e.x*e.x+e.y*e.y)},r.lenSquare=function(e){return e.x*e.x+e.y*e.y},r.dot=function(e,t){return e.x*t.x+e.y*t.y},r.add=function(e,t,a){e.x=t.x+a.x,e.y=t.y+a.y},r.sub=function(e,t,a){e.x=t.x-a.x,e.y=t.y-a.y},r.scale=function(e,t,a){e.x=t.x*a,e.y=t.y*a},r.scaleAndAdd=function(e,t,a,n){e.x=t.x+a.x*n,e.y=t.y+a.y*n},r.lerp=function(e,t,a,n){var i=1-n;e.x=i*t.x+n*a.x,e.y=i*t.y+n*a.y},r}();const st=LL;var El=Math.min,kl=Math.max,sn=new st,ln=new st,un=new st,fn=new st,Po=new st,Ro=new st,PL=function(){function r(e,t,a,n){a<0&&(e=e+a,a=-a),n<0&&(t=t+n,n=-n),this.x=e,this.y=t,this.width=a,this.height=n}return r.prototype.union=function(e){var t=El(e.x,this.x),a=El(e.y,this.y);isFinite(this.x)&&isFinite(this.width)?this.width=kl(e.x+e.width,this.x+this.width)-t:this.width=e.width,isFinite(this.y)&&isFinite(this.height)?this.height=kl(e.y+e.height,this.y+this.height)-a:this.height=e.height,this.x=t,this.y=a},r.prototype.applyTransform=function(e){r.applyTransform(this,this,e)},r.prototype.calculateTransform=function(e){var t=this,a=e.width/t.width,n=e.height/t.height,i=lr();return Wr(i,i,[-t.x,-t.y]),og(i,i,[a,n]),Wr(i,i,[e.x,e.y]),i},r.prototype.intersect=function(e,t){if(!e)return!1;e instanceof r||(e=r.create(e));var a=this,n=a.x,i=a.x+a.width,o=a.y,s=a.y+a.height,l=e.x,u=e.x+e.width,f=e.y,h=e.y+e.height,v=!(i0;)o=l,l=(l<<1)+1,l<=0&&(l=s);l>s&&(l=s),o+=n,l+=n}else{for(s=n+1;l