This commit is contained in:
全栈小学生 2025-09-13 10:30:14 +08:00
parent d497fdcc30
commit 29213bc600
46 changed files with 1609 additions and 75 deletions

View File

@ -121,7 +121,7 @@ class ExceptionHandle extends Handle
}
}
private function handleException(\Exception $e) {
private function handleException(Throwable $e) {
$trace = array_map(function ($class){
return str_replace('\\', '/', $class);
}, array_column($e->getTrace(), 'class'));
@ -132,6 +132,8 @@ class ExceptionHandle extends Handle
}
}
return fail("{$trace[0]}{$e->getLine()}行出现异常,异常信息:" .$e->getMessage());
$debug = env("APP_DEBUG", false);
return fail("{$trace[0]}{$e->getLine()}行出现异常,异常信息:" .$e->getMessage(), $debug ? $e->getTrace() : []);
}
}

View File

@ -0,0 +1,162 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\adminapi\controller\channel;
use app\dict\channel\AppDict;
use app\service\admin\channel\AppService;
use app\service\admin\channel\H5Service;
use core\base\BaseAdminController;
use think\Response;
/**
* app端配置
* Class H5
* @package app\adminapi\controller\channel
*/
class App extends BaseAdminController
{
/**
* 获取APP配置信息
* @description 获取APP配置信息
* @return Response
*/
public function get()
{
return success((new AppService())->getConfig());
}
/**
* 设置APP配置信息
* @description 设置APP配置信息
* @return Response
*/
public function set()
{
$data = $this->request->params([
['wechat_app_id', ""],
['wechat_app_secret', ""],
['android_app_key', ''],
['application_id', ''],
['uni_app_id', ''],
['app_name', '']
]);
(new AppService())->setConfig($data);
return success('SET_SUCCESS');
}
public function versionList() {
$data = $this->request->params([
["platform",""],
]);
return success((new AppService())->getVersionPage($data));
}
public function versionInfo($id) {
return success((new AppService())->getVersionInfo($id));
}
/**
* 添加app版本
* @description 添加app版本
* @return \think\Response
*/
public function add(){
$data = $this->request->params([
["version_code",""],
["version_name",""],
["version_desc",""],
["platform",""],
["is_forced_upgrade",0],
["package_path", ""],
["package_type", ""],
["package_type", ""],
["build", []],
["cert", []],
["upgrade_type", ""],
]);
$id = (new AppService())->addVersion($data);
return success('ADD_SUCCESS', ['id' => $id]);
}
/**
* app版本管理编辑
* @description 编辑app版本
* @param $id app版本id
* @return \think\Response
*/
public function edit(int $id){
$data = $this->request->params([
["version_code",""],
["version_name",""],
["version_desc",""],
["platform",""],
["is_forced_upgrade",0],
["package_path", ""],
["package_type", ""],
["package_type", ""],
["build", []],
["cert", []],
["upgrade_type", ""],
]);
(new AppService())->editVersion($id, $data);
return success('EDIT_SUCCESS');
}
/**
* app版本管理删除
* @description 删除app版本
* @param $id app版本id
* @return \think\Response
*/
public function del(int $id){
(new AppService())->delVersion($id);
return success('DELETE_SUCCESS');
}
public function appPlatform() {
return success(AppDict::getAppPlatform());
}
/**
* 获取app生成日志
*/
public function buildLog(string $key) {
return success((new AppService())->getBuildLog($key));
}
/**
* 发布
* @description 发布
* @param $id app版本id
* @return \think\Response
*/
public function release(int $id) {
(new AppService())->release($id);
return success('RELEASE_SUCCESS');
}
public function generateSingCert() {
$data = $this->request->params([
['key_alias', ''],
['key_password', ''],
['store_password', ''],
['limit', 30],
['cn', ''],
['o', ''],
['ou', ''],
['c', ''],
['st', ''],
['l', ''],
]);
return success(data:(new AppService())->generateSingCert($data));
}
}

View File

@ -137,6 +137,7 @@ class Config extends BaseAdminController
{
$data = $this->request->params([
[ 'key', '' ],
[ 'amap_key', ''],
[ 'is_open', 0 ], // 是否开启定位
[ 'valid_time', 0 ] // 定位有效期/分钟过期后将重新获取定位信息0为不过期
]);

View File

@ -29,6 +29,29 @@ Route::group('channel', function () {
//设置微信配置
Route::put('pc/config', 'channel.Pc/set');
/***************************************************** app端 ****************************************************/
Route::get('app/config', 'channel.App/get');
//设置手机端配置
Route::put('app/config', 'channel.App/set');
// 获取app版本列表
Route::get('app/version', 'channel.App/versionList');
// 获取app版本详情
Route::get('app/version/:id', 'channel.App/versionInfo');
// 添加app版本
Route::post('app/version', 'channel.App/add');
// 编辑app版本
Route::put('app/version/:id', 'channel.App/edit');
// 删除app版本
Route::delete('app/version/:id', 'channel.App/del');
// 获取app平台
Route::get('app/platfrom', 'channel.App/appPlatform');
// 获取app生成日志
Route::get('app/build/log/:key', 'channel.App/buildLog');
// 发布
Route::put('app/version/:id/release', 'channel.App/release');
// 生成证书
Route::post('app/generate_sing_cert', 'channel.App/generateSingCert');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,

View File

@ -0,0 +1,73 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\api\controller\channel;
use app\service\api\channel\AppService;
use app\service\api\login\LoginService;
use app\service\api\wechat\WechatAppService;
use core\base\BaseController;
class App extends BaseController
{
public function wechatLogin()
{
$data = $this->request->params([
[ 'code', '' ],
]);
$wechat_app_service = new WechatAppService();
return success($wechat_app_service->loginByCode($data[ 'code' ]));
}
public function register()
{
$data = $this->request->params([
[ 'register_type', '' ],
]);
switch ($data['register_type']) {
case 'wechat':
return $this->wechatRegister();
}
return fail("不支持的注册方式");
}
public function wechatRegister() {
$data = $this->request->params([
[ 'openid', '' ],
[ 'unionid', '' ],
[ 'nickname', '' ],
[ 'avatar', '' ],
[ 'mobile_code', '' ],
[ 'mobile', '' ],
]);
//参数验证
$this->validate($data, [
'mobile' => 'mobile'
]);
// 校验手机验证码(电脑端扫码)
( new LoginService() )->checkMobileCode($data[ 'mobile' ]);
$wechat_app_service = new WechatAppService();
return success($wechat_app_service->register($data[ 'openid' ], $data[ 'mobile' ], $data[ 'nickname' ], $data[ 'avatar' ], $data[ 'avatar' ]));
}
public function getNewVersion()
{
$data = $this->request->params([
[ 'version_code', '' ], // 当前版本
[ 'platform', '' ], // 请求平台
]);
$app_service = new AppService();
return success(data:$app_service->getNewVersion($data));
}
}

View File

@ -18,6 +18,7 @@ use app\service\api\member\MemberLevelService;
use app\service\api\member\MemberService;
use app\service\api\site\SiteService;
use app\service\api\sys\ConfigService;
use app\service\core\sys\CoreSysConfigService;
use core\base\BaseApiController;
use think\Response;
@ -83,13 +84,17 @@ class Config extends BaseApiController
[ 'openid', '' ]
]);
$config_service = new ConfigService();
$res = [];
$res[ 'tabbar_list' ] = ( new DiyConfigService() )->getBottomList();
$res[ 'map_config' ] = ( new ConfigService() )->getMap();
$res[ 'map_config' ] = $config_service->getMap();
$res[ 'site_info' ] = ( new SiteService() )->getSiteCache();
$res[ 'site_info' ]['wap_url'] = $config_service->getSceneDomain()['wap_url'];
$res[ 'member_level' ] = ( new MemberLevelService() )->getList();
$res[ 'login_config' ] = ( new MemberConfigService() )->getLoginConfig($data[ 'url' ]);
$res[ 'theme_list' ] = ( new DiyService() )->getDiyTheme();
$res[ 'app_config' ] = $config_service->getAppConfig();
$openid_field = match ( $this->request->getChannel() ) {
'wechat' => 'wx_openid',

View File

@ -1,28 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\controller;
use core\base\BaseController;
use think\facade\App;
class Index extends BaseController
{
public function index()
{
return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:) </h1><p> ThinkPHP V' . App::version() . '<br/><span style="font-size:30px;">16载初心不改 - 你值得信赖的PHP框架</span></p><span style="font-size:25px;">[ V6.0 版本由 <a href="https://www.yisu.com/" target="yisu">亿速云</a> 独家赞助发布 ]</span></div><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="ee9b1aa918103c4fc"></think>';
}
public function hello($name = 'ThinkPHP6')
{
return 'hello,' . $name;
}
}

View File

@ -33,6 +33,10 @@ class BindDispatch extends Controller
$controller = 'weapp.Weapp';
$action = 'register';
break;
case MemberLoginTypeDict::APP:
$controller = 'channel.App';
$action = 'register';
break;
}
@ -43,4 +47,4 @@ class BindDispatch extends Controller
->setAction($this->actionName);
}
}
}

View File

@ -68,6 +68,12 @@ Route::group(function () {
// 通过外部交易号获取消息跳转路径
Route::get('weapp/getMsgJumpPath', 'weapp.Weapp/getMsgJumpPath');
// app通过wx code登录
Route::post('wxapp/login', 'channel.App/wechatLogin');
// 获取App新的版本
Route::get('app/newversion', 'channel.App/getNewVersion');
//登录
Route::get('login', 'login.Login/login');
//第三方绑定
@ -148,6 +154,7 @@ Route::group(function () {
Route::get('task/growth', 'sys.Task/growth');
// 获取积分任务
Route::get('task/point', 'sys.Task/point');
})->middleware(ApiChannel::class)
->middleware(ApiCheckToken::class)
->middleware(ApiLog::class);

View File

@ -0,0 +1,56 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\dict\channel;
class AppDict
{
// ********** 平台类型 **************
const ANDROID = 'android';
const IOS = 'ios';
public static function getAppPlatform() {
return [
self::ANDROID => 'Android',
// self::IOS => 'ios'
];
}
public static function getAppPlatformName($platform) {
$app_platform = self::getAppPlatform();
return $app_platform[$platform] ?? '';
}
// ********** 版本状态 **************
const STATUS_UPLOAD_SUCCESS = 'upload_success';
const STATUS_CREATE_FAIL = 'create_fail';
const STATUS_PUBLISHED = 'published';
const STATUS_CREATING = 'creating';
public static function getStatus() {
return [
self::STATUS_UPLOAD_SUCCESS => '上传成功',
self::STATUS_CREATE_FAIL => '创建失败',
self::STATUS_PUBLISHED => '已发布',
self::STATUS_CREATING => '创建中'
];
}
public static function getStatusName($status) {
return self::getStatus()[$status] ?? '';
}
}

View File

@ -73,7 +73,7 @@ class CommonActiveDict
'bg_color' => '#FF1C77'
],
];
return !empty($active) ? $data[$active] : $data;
return !empty($active) ? $data[$active] ?? [] : $data;
}
// 活动背景特效

View File

@ -30,6 +30,8 @@ class MemberLoginTypeDict
// PC登录
public const PC = 'pc';
public const APP = 'app';
public static function getType($type = '')
{
$data = [
@ -38,6 +40,7 @@ class MemberLoginTypeDict
self::WECHAT => get_lang('dict_member.login_wechat'),//'微信公众号授权登录',
self::WEAPP => get_lang('dict_member.login_weapp'),//'微信小程序授权登录',
self::PC => get_lang('dict_member.login_pc'),//'微信小程序授权登录',
self::APP => get_lang('dict_member.login_app')
];
if (empty($type)) {
return $data;

View File

@ -30,6 +30,8 @@ class MemberRegisterTypeDict
//手动添加
const MANUAL = 'manual';
const APP = 'app';
public static function getType($type = '')
{
$data = [
@ -45,4 +47,4 @@ class MemberRegisterTypeDict
return $data[$type] ?? '';
}
}
}

View File

@ -262,7 +262,7 @@ return [
'methods' => 'get',
'sort' => '70',
'status' => '1',
'is_show' => '0',
'is_show' => '1',
'children' => [
[
'menu_name' => '新增',

View File

@ -8,7 +8,7 @@ return [
'menu_type' => '0',
'icon' => 'iconfont iconzhuangxiu3',
'api_url' => '',
'router_path' => '',
'router_path' => 'diy/index',
'view_path' => '',
'methods' => '',
'sort' => '90',
@ -329,7 +329,7 @@ return [
'menu_type' => '0',
'icon' => 'iconfont iconhuiyuan',
'api_url' => '',
'router_path' => '',
'router_path' => 'member/member',
'view_path' => '',
'methods' => '',
'sort' => '89',
@ -652,7 +652,7 @@ return [
'menu_type' => '0',
'icon' => 'iconfont iconjifen-xianxing',
'api_url' => '',
'router_path' => '',
'router_path' => 'member/point',
'view_path' => '',
'methods' => '',
'sort' => '51',
@ -743,7 +743,7 @@ return [
'menu_type' => '0',
'icon' => 'iconfont iconcaiwu1',
'api_url' => '',
'router_path' => '',
'router_path' => 'finance/account',
'view_path' => '',
'methods' => '',
'sort' => '88',
@ -877,7 +877,7 @@ return [
'menu_type' => '0',
'icon' => 'iconfont iconyingxiao2',
'api_url' => '',
'router_path' => '',
'router_path' => 'app/marketing',
'view_path' => '',
'methods' => '',
'sort' => '87',
@ -908,7 +908,7 @@ return [
'menu_type' => '0',
'icon' => '',
'api_url' => '',
'router_path' => '',
'router_path' => 'marketing/verify/index',
'view_path' => '',
'methods' => 'get',
'sort' => '48',
@ -1025,7 +1025,7 @@ return [
'menu_type' => '0',
'icon' => 'element FolderChecked',
'api_url' => '',
'router_path' => '',
'router_path' => 'marketing/sign/config',
'view_path' => '',
'methods' => 'get',
'sort' => '30',
@ -1580,6 +1580,64 @@ return [
'status' => '1',
'is_show' => '0',
],
[
'menu_name' => 'App端',
'menu_key' => 'channel_app',
'menu_short_name' => 'App端',
'menu_type' => '1',
'icon' => '',
'api_url' => '',
'router_path' => 'channel/app',
'view_path' => 'channel/app/access',
'methods' => '',
'sort' => '50',
'status' => '1',
'is_show' => '1',
],
[
'menu_name' => 'App端配置',
'menu_key' => 'channel_app_config',
'menu_short_name' => 'app端配置',
'menu_type' => '1',
'icon' => '',
'api_url' => 'channel/app/config',
'router_path' => 'channel/app/config',
'view_path' => 'channel/app/config',
'methods' => 'get',
'sort' => '100',
'status' => '1',
'is_show' => '0',
'children' => [
[
'menu_name' => '设置app端配置',
'menu_key' => 'set_channel_app_config',
'menu_short_name' => '设置app端配置',
'menu_type' => '2',
'icon' => '',
'api_url' => 'channel/app/config',
'router_path' => '',
'view_path' => '',
'methods' => 'put',
'sort' => '100',
'status' => '1',
'is_show' => '1',
]
]
],
[
'menu_name' => 'APP版本管理',
'menu_key' => 'app_version_list',
'menu_short_name' => '版本管理',
'menu_type' => '1',
'icon' => '',
'api_url' => 'channel/app/version',
'router_path' => 'channel/app/version',
'view_path' => 'channel/app/version',
'methods' => 'get',
'sort' => '100',
'status' => '1',
'is_show' => '0',
]
],
],
[
@ -1793,7 +1851,7 @@ return [
'menu_type' => '0',
'icon' => 'iconfont iconshezhi3',
'api_url' => '',
'router_path' => '',
'router_path' => 'setting/system',
'view_path' => '',
'methods' => '',
'sort' => '83',
@ -1807,7 +1865,7 @@ return [
'menu_type' => '0',
'icon' => 'element Basketball',
'api_url' => '',
'router_path' => '',
'router_path' => 'setting/system',
'view_path' => '',
'methods' => '',
'sort' => '100',
@ -1883,7 +1941,7 @@ return [
'menu_type' => '0',
'icon' => 'iconfont iconjiaoseyonghu',
'api_url' => '',
'router_path' => '',
'router_path' => 'setting/member',
'view_path' => '',
'methods' => '',
'sort' => '71',
@ -1959,7 +2017,7 @@ return [
'menu_type' => '1',
'icon' => 'element Wallet',
'api_url' => '',
'router_path' => 'setting/pay',
'router_path' => 'setting/pay/channel',
'view_path' => '',
'methods' => 'get',
'sort' => '60',
@ -2080,7 +2138,7 @@ return [
'menu_type' => '1',
'icon' => 'element ChatLineSquare',
'api_url' => '',
'router_path' => 'setting/notice',
'router_path' => 'setting/notice/template',
'view_path' => '',
'methods' => '',
'sort' => '50',
@ -2168,7 +2226,7 @@ return [
'menu_type' => '0',
'icon' => 'element Message',
'api_url' => '',
'router_path' => '',
'router_path' => 'setting/sms/setting',
'view_path' => '',
'methods' => '',
'sort' => '40',
@ -2287,7 +2345,7 @@ return [
'menu_type' => '0',
'icon' => 'element FolderChecked',
'api_url' => '',
'router_path' => '',
'router_path' => 'setting/agreement',
'view_path' => '',
'methods' => '',
'sort' => '20',

View File

@ -40,4 +40,6 @@ class ConfigKeyDict
public const SMS = 'SMS';//短信配置
public const PINTUAN_ORDER_CONFIG = 'PINTUAN_ORDER_CONFIG';//拼团订单配置
public const APP = 'app';
}

View File

@ -35,6 +35,10 @@ class FileDict
public const EXCEL = 'excel';//excel导入
public const APP_PACKAGE = 'app_package';//应用包
public const ANDROID_CERT = 'android_cert';//android证书
/**
* 附件类型
* @return array
@ -76,6 +80,8 @@ class FileDict
self::AUDIO,//视频上传
self::APPLET,//小程序包上传
self::EXCEL,//excel导入
self::APP_PACKAGE,//应用包
self::ANDROID_CERT,//android证书
];
}
@ -91,4 +97,4 @@ class FileDict
self::SMALL,//图片上传
];
}
}
}

View File

@ -56,6 +56,9 @@ class Index extends BaseInstall
//sodium
$sodium = extension_loaded('sodium');
$system_variables[] = [ "name" => "sodium", "need" => "开启", "status" => $sodium ];
//imagick
$imagick = extension_loaded('imagick');
$system_variables[] = [ "name" => "imagick", "need" => "开启", "status" => $imagick ];
$root_path = str_replace("\\", DIRECTORY_SEPARATOR, dirname(__FILE__, 4));
$root_path = str_replace("../", DIRECTORY_SEPARATOR, $root_path);
@ -88,7 +91,7 @@ class Index extends BaseInstall
$this->assign("name", $name);
$this->assign("verison", $verison);
$this->assign("dirs_list", $dirs_list);
if ($verison && $pdo && $curl && $openssl && $gd && $fileinfo && $is_dir) {
if ($verison && $pdo && $curl && $openssl && $gd && $fileinfo && $is_dir && $imagick) {
$continue = true;
} else {
$continue = false;

View File

@ -35,6 +35,27 @@ CREATE TABLE `addon_log` (
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '插件日志表' ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `app_version`;
CREATE TABLE `app_version` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`site_id` INT(11) NOT NULL DEFAULT 0 COMMENT '站点id',
`version_code` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '版本号',
`version_name` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '版本名称',
`version_desc` VARCHAR(1500) NOT NULL DEFAULT '' COMMENT '版本描述',
`platform` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'app平台 Android Ios',
`package_path` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '安装包路径',
`status` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '状态',
`is_forced_upgrade` INT(11) NOT NULL DEFAULT 0 COMMENT '是否需要强制升级',
`task_key` VARCHAR(255) NOT NULL DEFAULT '',
`fail_reason` VARCHAR(255) NOT NULL DEFAULT '',
`upgrade_type` VARCHAR(255) NOT NULL DEFAULT 'app' COMMENT 'app 整包更新 hot 热更新 market 应用市场更新',
`release_time` INT(11) NOT NULL DEFAULT 0 COMMENT '发布时间',
`create_time` INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间',
`update_time` INT(11) NOT NULL DEFAULT 0 COMMENT '修改时间',
PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'app版本管理' ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `applet_site_version`;
CREATE TABLE `applet_site_version` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',

View File

@ -24,6 +24,7 @@ return [
'ADD_FAIL' => '添加失败',
'ADD_SUCCESS' => '添加成功',
'UPLOAD_FAIL' => '上传失败',
'RELEASE_SUCCESS' => '发布成功',
'ATTACHMENT_DELETE_FAIL' => '附件删除失败',
'DATA_NOT_EXIST' => '数据不存在',
'DOWNLOAD_FAIL' => '下载失败',
@ -205,6 +206,7 @@ return [
//海报
'POSTER_NOT_EXIST' => '海报不存在',
'POSTER_IN_USE_NOT_ALLOW_MODIFY' => '海报使用中禁止修改状态',
'POSTER_CREATE_ERROR' => '海报组件未配置完善,请联系管理员',
//万能表单
'DIY_FORM_NOT_EXIST' => '表单不存在',

View File

@ -12,7 +12,7 @@ class WechatQrcodeListener extends BaseNoticeTemplate
public function handle(array $params)
{
if ('wechat' == $params['channel'] || $params['channel'] == 'h5') {
if ('wechat' == $params['channel'] || $params['channel'] == 'h5' || $params['channel'] == 'app') {
$page = $params['page'];
$url = $params['url'];
$data = $params['data'];
@ -44,4 +44,4 @@ class WechatQrcodeListener extends BaseNoticeTemplate
}
}
}
}

View File

@ -35,7 +35,7 @@ class ShowAppListener
'desc' => '管理核销员及核销记录',
'icon' => 'static/resource/images/marketing/verifier.png',
'key' => 'verify',
'url' => '/marketing/verifier',
'url' => '/marketing/verify/index',
],
[
'title' => '万能表单',

View File

@ -11,6 +11,7 @@
namespace app\model\pay;
use app\dict\common\CommonActiveDict;
use app\dict\pay\PayDict;
use app\dict\pay\RefundDict;
use core\base\BaseModel;
@ -134,4 +135,12 @@ class Refund extends BaseModel
$query->where('refund_no', 'like', "%$value%");
}
}
public function getTradeTypeNameAttr($value, $data)
{
if (empty($data['trade_type'])){
return '';
}
return CommonActiveDict::getActiveShort($data['trade_type'])['active_name'] ?? "";
}
}

View File

@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\model\sys;
use app\dict\channel\AppDict;
use core\base\BaseModel;
use think\db\Query;
class AppVersion extends BaseModel
{
protected $pk = 'id';
//类型
protected $type = [
'release_time' => 'timestamp',
];
/**
* 模型名称
* @var string
*/
protected $name = 'app_version';
public function searchPlatformAttr(Query $query, $value, $data)
{
if ($value) {
$query->where('platform', $value);
}
}
public function getPlatformNameAttr($value, $data)
{
return AppDict::getAppPlatformName($data['platform']);
}
public function getStatusNameAttr($value, $data)
{
return AppDict::getStatusName($data['status']);
}
}

View File

@ -0,0 +1,188 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\admin\channel;
use app\dict\channel\AppDict;
use app\dict\sys\ConfigKeyDict;
use app\model\sys\AppVersion;
use app\service\core\channel\CoreAppCloudService;
use app\service\core\channel\CoreAppService;
use app\service\core\channel\CoreH5Service;
use app\service\core\niucloud\CoreNiucloudConfigService;
use app\service\core\sys\CoreConfigService;
use core\base\BaseAdminService;
use core\exception\CommonException;
/**
* 配置服务层
* Class ConfigService
* @package app\service\core\sys
*/
class AppService extends BaseAdminService
{
public function __construct()
{
parent::__construct();
$this->model = new AppVersion();
}
/**
* 设置app信息
* @param array $value
* @return bool
*/
public function setConfig(array $value)
{
return (new CoreAppService())->setConfig($this->site_id, $value);
}
/**
* 获取app配置
* @return mixed
*/
public function getConfig(){
return (new CoreAppService())->getConfig($this->site_id);
}
/**
* @param array $where
* @return array
* @throws \think\db\exception\DbException
*/
public function getVersionPage(array $where = [])
{
$order = 'id desc';
$search_model = $this->model->where([ [ 'site_id' ,"=", $this->site_id ] ])->withSearch(["platform"], $where)->append(['platform_name', 'status_name'])->field("*")->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
/**
* @param $id
* @return AppVersion|array|mixed|\think\Model
*/
public function getVersionInfo($id) {
return $this->model->where([ [ 'site_id' ,"=", $this->site_id ], ['id', '=', $id] ])->findOrEmpty()->toArray();
}
/**
* 添加版本
* @param array $data
* @return mixed
*/
public function addVersion(array $data) {
$not_release = $this->model->where([['site_id', '=', $this->site_id], ['release_time', '=', 0]])->findOrEmpty();
if (!$not_release->isEmpty()) throw new CommonException("当前已存在未发布的版本");
$last_version = $this->model->where([['site_id', '=', $this->site_id]])->order('id desc')->findOrEmpty();
if (!$last_version->isEmpty() && $data['version_code'] <= $last_version['version_code']) throw new CommonException("版本号必须高于上一版本设置的值");
$data['site_id'] = $this->site_id;
$model = [
'site_id' => $this->site_id,
'version_code' => $data['version_code'],
'version_name' => $data['version_name'],
'version_desc' => $data['version_desc'],
'platform' => $data['platform'],
'is_forced_upgrade' => $data['is_forced_upgrade'],
'package_path' => $data['package_path'],
'upgrade_type' => $data['upgrade_type'],
];
if ($data['package_type'] == 'cloud') {
$task_key = (new CoreAppCloudService())->appCloudBuid($data);
$model['task_key'] = $task_key['key'];
$model['status'] = AppDict::STATUS_CREATING;
} else {
$model['status'] = AppDict::STATUS_UPLOAD_SUCCESS;
}
$res = $this->model->create($model);
return $res->id;
}
/**
* 编辑版本
* @param int $id
* @param array $data
* @return true
*/
public function editVersion(int $id, array $data)
{
$last_version = $this->model->where([['site_id', '=', $this->site_id], ['id', '<>', $id]])->order('id desc')->findOrEmpty();
if (!$last_version->isEmpty() && $data['version_code'] <= $last_version['version_code']) throw new CommonException("版本号必须高于上一版本设置的值");
$data['site_id'] = $this->site_id;
$model = [
'version_code' => $data['version_code'],
'version_name' => $data['version_name'],
'version_desc' => $data['version_desc'],
'platform' => $data['platform'],
'is_forced_upgrade' => $data['is_forced_upgrade'],
'package_path' => $data['package_path'],
'upgrade_type' => $data['upgrade_type'],
];
if ($data['package_type'] == 'cloud') {
$task_key = (new CoreAppCloudService())->appCloudBuid($data);
$model['task_key'] = $task_key['key'];
$model['status'] = AppDict::STATUS_CREATING;
} else {
$model['status'] = AppDict::STATUS_UPLOAD_SUCCESS;
}
$this->model->where([['id', '=', $id],['site_id', '=', $this->site_id]])->update($model);
return true;
}
/**
* 删除app版本
* @param int $id
* @return bool
*/
public function delVersion(int $id)
{
$model = $this->model->where([['id', '=', $id],['site_id', '=', $this->site_id]])->find();
$res = $model->delete();
return $res;
}
public function getBuildLog(string $key) {
$result = (new CoreAppCloudService())->getAppCompileLog($key);
if ($result['status'] == 'fail') {
$this->model->update(['status' => AppDict::STATUS_CREATE_FAIL, 'fail_reason' => $result['fail_reason'], 'update_time' => time() ], ['task_key' => $key, 'site_id' => $this->site_id]);
}
if ($result['status'] == 'success') {
$this->model->update(['status' => AppDict::STATUS_UPLOAD_SUCCESS, 'package_path' => $result['file_path'], 'update_time' => time() ], ['task_key' => $key, 'site_id' => $this->site_id]);
}
return $result;
}
/**
* 发布
* @param string $key
* @return void
*/
public function release(int $id) {
$version = $this->model->where([['id', '=', $id],['site_id', '=', $this->site_id]])->findOrEmpty();
if ($version->isEmpty()) throw new CommonException("版本不存在");
if ($version['status'] != AppDict::STATUS_UPLOAD_SUCCESS) throw new CommonException("版本未上传成功");
$this->model->update(['release_time' => time(), 'status' => AppDict::STATUS_PUBLISHED], ['id' => $id]);
}
public function generateSingCert($data) {
return (new CoreAppCloudService())->generateSingCert($data);
}
}

View File

@ -33,7 +33,7 @@ class NiuSmsService extends BaseAdminService
{
parent::__construct();
$this->template_model = new NiuSmsTemplate();
$this->niu_service = new CoreNiuSmsService();
$this->niu_service = (new CoreNiuSmsService())->setSiteId($this->site_id);
}
public function enableNiuSms($enable)
@ -102,7 +102,11 @@ class NiuSmsService extends BaseAdminService
*/
public function registerAccount($data)
{
$data['imgUrl'] = !empty($data['imgUrl']) ? request()->domain() . "/" . $data['imgUrl'] : "";
if (!empty($data['imgUrl']) && strstr($data['imgUrl'], 'http') === false) {
$data['imgUrl'] = request()->domain() . "/" . $data['imgUrl'];
} else {
$data['imgUrl'] = $data['imgUrl'] ?? '';
}
$res = $this->niu_service->registerAccount($data);
return $res;
}
@ -116,7 +120,7 @@ class NiuSmsService extends BaseAdminService
{
$account_info = $this->niu_service->loginAccount($params);
if ($account_info) {
(new CoreNiuSmsService())->setNiuLoginConfig($params,true);
(new CoreNiuSmsService())->setNiuLoginConfig($params, true);
}
return $account_info;
}
@ -229,7 +233,11 @@ class NiuSmsService extends BaseAdminService
*/
public function signCreate($username, $params)
{
$params['imgUrl'] = !empty($params['imgUrl']) ? request()->domain() . "/" . $params['imgUrl'] : "";
if (!empty($params['imgUrl']) && strstr($params['imgUrl'], 'http') === false) {
$params['imgUrl'] = request()->domain() . '/' . $params['imgUrl'];
} else {
$params['imgUrl'] = $params['imgUrl'] ?? '';
}
$res = $this->niu_service->signCreate($username, $params);
if (!empty($res['failList'])) {
throw new AdminException($res['failList'][0]['msg']);
@ -391,9 +399,9 @@ class NiuSmsService extends BaseAdminService
$audit_status = $report_info['audit_status'] ?? NoticeTypeDict::TEMPLATE_AUDIT_STATUS_NOT_REPORT;
$error_status = '';
if (!empty($report_info) && $variable != $params_json) {
if (empty($params_json)){
if (empty($params_json)) {
$error_status = NoticeTypeDict::TEMPLATE_NEED_PULL;
}else{
} else {
$error_status = $audit_status == NoticeTypeDict::TEMPLATE_AUDIT_STATUS_PASS
? NoticeTypeDict::TEMPLATE_AUDIT_STATUS_NEED_AGAIN_REPORT
: NoticeTypeDict::TEMPLATE_AUDIT_STATUS_NEED_EDIT;

View File

@ -35,7 +35,11 @@ class RefundService extends BaseAdminService
*/
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');
$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','trade_type_name' ])
->order('create_time desc');
return $this->pageQuery($search_model);
}

View File

@ -135,6 +135,7 @@ class ConfigService extends BaseAdminService
{
$data = [
'key' => $value[ 'key' ],
'amap_key' => $value['amap_key'],
'is_open' => $value[ 'is_open' ], // 是否开启定位
'valid_time' => $value[ 'valid_time' ] // 定位有效期/分钟过期后将重新获取定位信息0为不过期
];
@ -154,6 +155,7 @@ class ConfigService extends BaseAdminService
$info = [];
$info[ 'value' ] = [
'key' => '',
'amap_key' => '',
'is_open' => 1, // 是否开启定位
'valid_time' => 5 // 定位有效期/分钟过期后将重新获取定位信息0为不过期
];
@ -161,6 +163,8 @@ class ConfigService extends BaseAdminService
$info[ 'value' ][ 'is_open' ] = $info[ 'value' ][ 'is_open' ] ?? 1;
$info[ 'value' ][ 'valid_time' ] = $info[ 'value' ][ 'valid_time' ] ?? 5;
$info[ 'value' ][ 'amap_key' ] = $info[ 'value' ][ 'amap_key' ] ?? '';
return $info[ 'value' ];
}

View File

@ -85,4 +85,4 @@ class UploadService extends BaseAdminService
$core_upload_service = new CoreUploadService();
return $core_upload_service->document($file, $this->site_id, $type, $dir, StorageDict::LOCAL);
}
}
}

View File

@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\api\channel;
use app\dict\channel\AppDict;
use app\model\sys\AppVersion;
use core\base\BaseApiService;
class AppService extends BaseApiService
{
/**
* 获取新的版本
* @param $data
* @return array
*/
public function getNewVersion($data)
{
$version = (new AppVersion())->where([
['site_id', '=', $this->site_id],
['platform', '=', $data['platform'] ],
['version_code', '>', $data['version_code'] ],
['status', '=', AppDict::STATUS_PUBLISHED],
])->order("version_code desc")->findOrEmpty()->toArray();
return empty($version) ? null : $version;
}
}

View File

@ -119,6 +119,7 @@ class LoginService extends BaseApiService
$openid_field = match ( $this->channel ) {
'wechat' => 'wx_openid',
'weapp' => 'weapp_openid',
'app' => 'wxapp_openid',
default => ''
};

View File

@ -11,7 +11,9 @@
namespace app\service\api\sys;
use app\service\core\channel\CoreAppService;
use app\service\core\sys\CoreSysConfigService;
use app\service\core\weapp\CoreWeappConfigService;
use core\base\BaseApiService;
/**
@ -60,4 +62,11 @@ class ConfigService extends BaseApiService
return (new CoreSysConfigService())->getMap($this->site_id);
}
public function getAppConfig() {
$config = (new CoreAppService())->getConfig($this->site_id);
if (!empty($config) && isset($config['wechat_app_secret'])) unset($config['wechat_app_secret']);
$weapp_config = (new CoreWeappConfigService())->getWeappConfig($this->site_id);
$config['weapp_original'] = $weapp_config['weapp_original'];
return $config;
}
}

View File

@ -0,0 +1,203 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\api\wechat;
use app\dict\member\MemberLoginTypeDict;
use app\dict\member\MemberRegisterTypeDict;
use app\dict\scan\ScanDict;
use app\service\api\login\LoginService;
use app\service\api\login\RegisterService;
use app\service\api\member\MemberConfigService;
use app\service\api\member\MemberService;
use app\service\core\scan\CoreScanService;
use app\service\core\wechat\CoreWechatAppService;
use app\service\core\wechat\CoreWechatFansService;
use app\service\core\wechat\CoreWechatServeService;
use core\base\BaseApiService;
use core\exception\ApiException;
use core\exception\AuthException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* 微信配置模型
* Class WechatConfigService
* @package app\service\core\wechat
*/
class WechatAppService extends BaseApiService
{
/**
* 处理授权回调
* @param string $code
* @return array
*/
public function userFromCode(string $code)
{
$userinfo = CoreWechatAppService::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();//对应微信的 头像地址
}
$unionid = $userinfo->getRaw()[ 'unionid' ] ?? '';
if (empty($openid)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST');
$is_snapshotuser = $userinfo->getRaw()[ 'is_snapshotuser' ] ?? 0;
if ($is_snapshotuser == 1) throw new ApiException('WECHAT_SNAPSHOUTUSER');
//todo 这儿还可能会获取用户昵称 头像 性别 ....用以更新会员信息
return [ $avatar ?? '', $nickname ?? '', $openid, $unionid ];
//todo 业务落地
}
/**
* 登录通过code
* @param string $code
* @return array|string[]|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function loginByCode(string $code)
{
[ $avatar, $nickname, $openid, $unionid ] = $this->userFromCode($code);
return $this->login($openid, $nickname, $avatar, $unionid);
}
/**
* 公众号登录
* @param string $openid
* @param string $nickname
* @param string $avatar
* @param string $unionid
* @return array|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function login(string $openid, string $nickname = '', string $avatar = '', string $unionid = '')
{
$member_service = new MemberService();
$member_info = $member_service->findMemberInfo([ 'wxapp_openid' => $openid, 'site_id' => $this->site_id ]);
if ($member_info->isEmpty() && !empty($unionid)) {
$member_info = $member_service->findMemberInfo([ 'wx_unionid' => $unionid, 'site_id' => $this->site_id ]);
if (!$member_info->isEmpty()) {
$member_info->wx_openid = $openid;
}
}
if ($member_info->isEmpty()) {
$config = ( new MemberConfigService() )->getLoginConfig();
$is_auth_register = $config[ 'is_auth_register' ];
$is_force_access_user_info = $config[ 'is_force_access_user_info' ];
$is_bind_mobile = $config[ 'is_bind_mobile' ];
// 开启自动注册会员
if ($is_auth_register) {
// 开启强制获取会员信息并且开启强制绑定手机号,必须获取手机号才能进行注册,由于公众号无法主动获取,所以不能注册
if ($is_force_access_user_info && $is_bind_mobile) {
return [ 'avatar' => $avatar, 'nickname' => $nickname, 'openid' => $openid, 'unionid' => $unionid ];
} else if ($is_force_access_user_info) {
// 开启强制获取会员信息时,必须获取到昵称和头像才能进行注册
// if (!empty($nickname) && !empty($avatar)) {
if (empty($nickname)){
$nickname = unique_random();
}
return $this->register($openid, '', $nickname, $avatar, $unionid); // 获取到昵称和头像,然后进行注册
// } else {
// return [ 'avatar' => $avatar, 'nickname' => $nickname, 'openid' => $openid, 'unionid' => $unionid ];
// }
} else if ($is_bind_mobile) {
// 开启强制绑定手机号,必须获取手机号才能进行注册,由于公众号无法主动获取,所以不能注册
return [ 'openid' => $openid, 'unionid' => $unionid ];
} else if (!$is_force_access_user_info && !$is_bind_mobile) {
// 关闭强制获取用户信息、并且关闭强制绑定手机号的情况下允许注册
return $this->register($openid, '', $nickname, $avatar, $unionid);
}
} else {
return [ 'openid' => $openid, 'unionid' => $unionid ]; // 将重要信息返回给前端保存
}
} else {
// 可能会更新用户和粉丝表
$login_service = new LoginService();
// 若用户头像为空,那么从微信获取头像和昵称,然后进行更新
if (empty($member_info->headimg)) {
if (!empty($avatar)) $member_info->headimg = $avatar;
if (!empty($nickname)) $member_info->nickname = $nickname;
}
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([ 'wxapp_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
* @param string $wx_unionid
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function register(string $openid, string $mobile = '', string $nickname = '', string $avatar = '', string $wx_unionid = '')
{
$member_service = new MemberService();
$member_info = $member_service->findMemberInfo([ 'wxapp_openid' => $openid, 'site_id' => $this->site_id ]);
if (!$member_info->isEmpty()) throw new AuthException('MEMBER_IS_EXIST');//账号已存在, 不能在注册
if (!empty($wx_unionid)) {
$member_info = $member_service->findMemberInfo([ 'wx_unionid' => $wx_unionid, 'site_id' => $this->site_id ]);
if (!$member_info->isEmpty()) throw new AuthException('MEMBER_IS_EXIST');//账号已存在, 不能在注册
}
$register_service = new RegisterService();
return $register_service->register($mobile,
[
'wxapp_openid' => $openid,
'nickname' => $nickname,
'headimg' => $avatar,
'wx_unionid' => $wx_unionid
],
MemberRegisterTypeDict::APP
);
}
}

View File

@ -38,7 +38,7 @@ trait WapTrait
$content .= " <view v-show=\"component.componentIsShow\"\n";
$content .= " @click=\"diyStore.changeCurrentIndex(index, component)\"\n";
$content .= " :class=\"diyGroup.getComponentClass(index,component)\" :style=\"component.pageStyle\">\n";
$content .= " <view class=\"relative\" :style=\"{ marginTop : component.margin.top < 0 ? (component.margin.top * 2) + 'rpx' : '0' }\">\n";
$content .= " <view class=\"relative\" :style=\"{ marginTop : component.margin.top < 0 ? (component.margin.top * 2) + 'rpx' : '0', marginBottom : component.margin.bottom < 0 ? (component.margin.bottom * 2) + 'rpx' : '0' }\">\n";
$content .= " <!-- 装修模式下,设置负上边距后超出的内容,禁止选中设置 -->\n";
$content .= " <view v-if=\"diyGroup.isShowPlaceHolder(index,component)\" class=\"absolute w-full z-1\" :style=\"{ height : (component.margin.top * 2 * -1) + 'rpx' }\" @click.stop=\"diyGroup.placeholderEvent\"></view>\n";
@ -337,7 +337,6 @@ trait WapTrait
{
$manifest_json = str_replace('/', DIRECTORY_SEPARATOR, $compile_path . 'src/manifest.json');
$manifest_content = $this->jsonStringToArray(file_get_contents($manifest_json));
( new CoreAddonBaseService() )->writeArrayToJsonFile(array_merge2($manifest_content, $merge_data), $manifest_json);
}
@ -348,8 +347,7 @@ trait WapTrait
*/
private function jsonStringToArray($string)
{
$list = explode(PHP_EOL, $string);
$list = explode("\n", $string);
$json_array = [];
foreach ($list as $index => $item) {
if (strpos($item, '/*') === false) {

View File

@ -0,0 +1,415 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\core\channel;
use app\dict\addon\AddonDict;
use app\model\addon\Addon;
use app\service\api\diy\DiyConfigService;
use app\service\core\addon\CoreAddonBaseService;
use app\service\core\addon\CoreAddonDevelopDownloadService;
use app\service\core\addon\WapTrait;
use app\service\core\niucloud\CoreCloudBaseService;
use app\service\core\niucloud\CoreModuleService;
use app\service\core\site\CoreSiteService;
use app\service\core\sys\CoreConfigService;
use app\service\core\sys\CoreSysConfigService;
use core\exception\CommonException;
use core\util\niucloud\BaseNiucloudClient;
use core\util\niucloud\CloudService;
use think\facade\Cache;
/**
* 微信APP云服务
* Class CoreWeappAuthService
* @package app\service\core\weapp
*/
class CoreAppCloudService extends CoreCloudBaseService
{
private $site_id;
private $addon;
private $addon_path;
private $cache_key = 'app_cloud_build';
use WapTrait;
public function __construct()
{
parent::__construct();
$this->root_path = dirname(root_path()) . DIRECTORY_SEPARATOR;
$this->addon_path = root_path() . 'addon' . DIRECTORY_SEPARATOR;
}
/**
* 上传APP
* @param $addon
*/
public function appCloudBuid(array $data)
{
$this->site_id = $data['site_id'];
$action_token = ( new CoreModuleService() )->getActionToken('appbuild', [ 'data' => [ 'product_key' => BaseNiucloudClient::PRODUCT ] ]);
$app_config = (new CoreAppService())->getConfig($this->site_id);
if (empty($app_config['app_name'])) throw new CommonException("请先配置应用名称");
if (empty($app_config['uni_app_id'])) throw new CommonException("请先配置应用ID");
if (empty($app_config['android_app_key'])) throw new CommonException("请先配置应用密钥");
if (empty($app_config['application_id'])) throw new CommonException("请先配置应用包名");
$wap_url = (new CoreSysConfigService())->getSceneDomain($this->site_id)['wap_url'];
$map_config = ( new CoreConfigService() )->getConfigValue($this->site_id, 'MAPKEY');
$build = [
'app_name' => $app_config['app_name'],
'uni_app_id' => $app_config['uni_app_id'],
'wechat_app_id' => $app_config['wechat_app_id'],
'wechat_app_secret' => $app_config['wechat_app_secret'],
'android_app_key' => $app_config['android_app_key'],
'application_id' => $app_config['application_id'],
'privacy_agreement' => $wap_url . '/app/pages/auth/agreement?key=privacy&=',
'service_agreement' => $wap_url . '/app/pages/auth/agreement?key=service&=',
'qq_map_key' => $map_config['key'] ?? '',
'amap_key' => $map_config['amap_key'] ?? '',
'version_name' => $data['version_name'],
'version_code' => $data['version_code'],
'cert' => $data['cert']
];
// 上传任务key
$task_key = time();
// 此次上传任务临时目录
$temp_dir = runtime_path() . 'build_app' . DIRECTORY_SEPARATOR . $task_key;
$package_dir = $temp_dir . DIRECTORY_SEPARATOR . 'package' . DIRECTORY_SEPARATOR;
// uni
$uni_dir = $package_dir . 'uni-app';
dir_copy($this->root_path . 'uni-app', $uni_dir, exclude_dirs: [ 'node_modules', 'unpackage', 'dist' ]);
$this->handleUniapp($uni_dir);
// 替换env文件
$this->weappEnvReplace($uni_dir . DIRECTORY_SEPARATOR . '.env.production');
// 拷贝证书文件
if ($data['cert']['type'] == 'private') {
if (!file_exists($data['cert']['file'])) throw new CommonException('证书文件不存在');
$cert_content = file_get_contents($data['cert']['file']);
file_put_contents($package_dir . 'cert.jks', $cert_content);
}
// 拷贝icon文件
file_copy($data['build']['icon'], $package_dir . 'drawable.zip');
( new CoreAddonBaseService() )->writeArrayToJsonFile($build, $package_dir . 'build.json');
// 处理 mainifest.json
$this->mergeManifestJson($uni_dir . DIRECTORY_SEPARATOR, [
"name" => $app_config['app_name'],
"appid" => $app_config['uni_app_id'],
"versionName" => $data['version_name'],
"versionCode" => $data['version_code'],
]);
// 将临时目录下文件生成压缩包
$zip_file = $temp_dir . DIRECTORY_SEPARATOR . 'app.zip';
( new CoreAddonDevelopDownloadService('') )->compressToZip($package_dir, $zip_file);
$query = [
'authorize_code' => $this->auth_code,
'timestamp' => $task_key,
'token' => $action_token[ 'data' ][ 'token' ] ?? ''
];
$response = ( new CloudService(true, 'http://java.oss.niucloud.com/') )->httpPost('/cloud/appbuild?' . http_build_query($query), [
'multipart' => [
[
'name' => 'file',
'contents' => fopen($zip_file, 'r'),
'filename' => 'app.zip'
]
],
]);
// 删除临时文件
del_target_dir($temp_dir, true);
if (isset($response[ 'code' ]) && $response[ 'code' ] == 0) throw new CommonException($response[ 'msg' ]);
return [ 'key' => $query[ 'timestamp' ] ];
}
/**
* 处理uniapp 查询出站点没有的插件进行移除
* @param string $dir
* @return void
*/
private function handleUniapp(string $dir)
{
$site_addon = (new CoreSiteService())->getAddonKeysBySiteId($this->site_id);
$local_addon = ( new Addon() )->where([ [ 'status', '=', AddonDict::ON ] ])->column('key');
// 移除uniapp中该站点没有的插件
$diff_addon = array_filter(array_map(function ($key) use ($site_addon) {
if (!in_array($key, $site_addon)) return $key;
}, $local_addon));
$this->handlePageCode($dir . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $site_addon);
// $this->handleTabbar($dir . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $site_addon);
if (!empty($diff_addon)) {
foreach ($diff_addon as $addon) {
$this->addon = $addon;
$addon_dir = $dir . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $addon;
if (is_dir($addon_dir)) del_target_dir($addon_dir, true);
// 编译 diy-group 自定义组件代码文件
$this->compileDiyComponentsCode($dir . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $addon);
// 编译 加载插件标题语言包
$this->compileLocale($dir . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $addon);
$manifest_json = root_path() . 'addon' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR . 'package' . DIRECTORY_SEPARATOR . 'manifest.json';
if (file_exists($manifest_json)) {
$this->mergeManifestJson($dir . DIRECTORY_SEPARATOR, json_decode($manifest_json, true));
}
}
}
}
private function handlePageCode($compile_path, $addon_arr)
{
$pages = [];
foreach ($addon_arr as $addon) {
if (!file_exists($this->geAddonPackagePath($addon) . 'uni-app-pages.php')) continue;
$uniapp_pages = require $this->geAddonPackagePath($addon) . 'uni-app-pages.php';
if (empty($uniapp_pages[ 'pages' ])) continue;
$page_begin = strtoupper($addon) . '_PAGE_BEGIN';
$page_end = strtoupper($addon) . '_PAGE_END';
// 对0.2.0之前的版本做处理
$uniapp_pages[ 'pages' ] = preg_replace_callback('/(.*)(\\r\\n.*\/\/ PAGE_END.*)/s', function ($match) {
return $match[ 1 ] . ( substr($match[ 1 ], -1) == ',' ? '' : ',' ) . $match[ 2 ];
}, $uniapp_pages[ 'pages' ]);
$uniapp_pages[ 'pages' ] = str_replace('PAGE_BEGIN', $page_begin, $uniapp_pages[ 'pages' ]);
$uniapp_pages[ 'pages' ] = str_replace('PAGE_END', $page_end, $uniapp_pages[ 'pages' ]);
$uniapp_pages[ 'pages' ] = str_replace('{{addon_name}}', $addon, $uniapp_pages[ 'pages' ]);
$pages[] = $uniapp_pages[ 'pages' ];
}
$content = @file_get_contents($compile_path . "pages.json");
$content = preg_replace_callback('/(.*\/\/ \{\{ PAGE_BEGAIN \}\})(.*)(\/\/ \{\{ PAGE_END \}\}.*)/s', function ($match) use ($pages) {
return $match[ 1 ] . PHP_EOL . implode(PHP_EOL, $pages) . PHP_EOL . $match[ 3 ];
}, $content);
// 找到页面路由文件 pages.json写入内容
return file_put_contents($compile_path . "pages.json", $content);
}
/**
* 处理底部导航【暂时停止调用存在APP兼容性问题】
* @param $compile_path
* @param $addon_arr
* @return void
*/
public function handleTabbar($compile_path, $addon_arr = [])
{
$bottomList = array_column(( new DiyConfigService() )->getBottomList(), null, 'key');
$tabbarList = [];
if (empty($addon_arr)) {
foreach ($bottomList as $app_item) {
array_push($tabbarList, ...$app_item[ 'value' ][ 'list' ]);
}
} else {
foreach ($addon_arr as $addon) {
if (isset($bottomList[ $addon ])) {
array_push($tabbarList, ...$bottomList[ $addon ][ 'value' ][ 'list' ]);
}
}
}
$tabbarList = array_map(function ($item) {
if (strpos($item[ 'link' ][ 'url' ], '?') !== false) {
$item[ 'link' ][ 'url' ] = explode('?', $item[ 'link' ][ 'url' ])[0];
}
$link = array_filter(explode('/', $item[ 'link' ][ 'url' ]));
$item[ 'link' ] = $item[ 'link' ][ 'url' ];
$item[ 'component' ] = implode('-', $link);
$item[ 'name' ] = lcfirst(implode('', array_map(function ($str) {
return ucfirst($str);
}, $link)));
return $item;
}, $tabbarList);
$tabbarList = array_column($tabbarList, null, 'name');
if (isset($tabbarList[ 'appPagesIndexIndex' ])) unset($tabbarList[ 'appPagesIndexIndex' ]);
if (isset($tabbarList[ 'appPagesMemberIndex' ])) unset($tabbarList[ 'appPagesMemberIndex' ]);
// 处理vue文件
$tpl = str_replace('/', DIRECTORY_SEPARATOR, public_path() . 'static/tpl/tabbar.tpl');
$content = view($tpl, [ 'tabbarList' => $tabbarList ])->getContent();
file_put_contents(str_replace('/', DIRECTORY_SEPARATOR, $compile_path . 'app/pages/index/tabbar.vue'), $content);
// 处理tabbar.json
file_put_contents($compile_path . 'tabbar.json', json_encode(array_column($tabbarList, 'link'), JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
}
/**
* 小程序上传env文件处理
* @param string $env_file
* @return void
*/
private function weappEnvReplace(string $env_file)
{
$env = file_get_contents($env_file);
$env = str_replace("VITE_APP_BASE_URL=''", "VITE_APP_BASE_URL='" . (string) url('/', [], '', true) . 'api/' . "'", $env);
$env = str_replace("VITE_IMG_DOMAIN=''", "VITE_IMG_DOMAIN='" . (string) url('/', [], '', true) . "'", $env);
$env = str_replace("VITE_SITE_ID = ''", "VITE_SITE_ID='" . $this->site_id . "'", $env);
file_put_contents($env_file, $env);
}
/**
* 获取APP编译日志
* @param string $timestamp
* @return void
*/
public function getAppCompileLog(string $timestamp)
{
$result = [
'status' => '',
'build_log' => [],
'file_path' => '',
'fail_reason' => ''
];
$query = [
'authorize_code' => $this->auth_code,
'timestamp' => $timestamp
];
$build_log = ( new CloudService(true, 'http://java.oss.niucloud.com/') )->httpGet('cloud/get_appbuild_logs?' . http_build_query($query));
$result['build_log'] = $build_log;
if (isset($build_log['data']) && isset($build_log['data'][0]) && is_array($build_log['data'][0])) {
$last = end($build_log['data'][0]);
if ($last['code'] == 0) {
$result['status'] = 'fail';
$result['fail_reason'] = $last['msg'] ?? '';
return $result;
}
if ($last['percent'] == 100) {
$result = $this->buildSuccess($result, $timestamp);
}
}
return $result;
}
public function buildSuccess(array $result, string $task_key)
{
try {
$query = [
'authorize_code' => $this->auth_code,
'timestamp' => $task_key
];
$chunk_size = 1 * 1024 * 1024;
$temp_dir = 'upload' . DIRECTORY_SEPARATOR . 'download' . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . $task_key . DIRECTORY_SEPARATOR;
if (!is_dir($temp_dir)) mkdirs($temp_dir);
$build_task = Cache::get($this->cache_key . $task_key) ?? [];
if (!isset($build_task[ 'index' ])) {
$response = ( new CloudService(true, 'http://java.oss.niucloud.com/') )->request('HEAD', 'cloud/apk_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);
$filename = $response->getHeader('filename')[0];
$build_task = array_merge($build_task, [ 'step' => $step, 'index' => 0, 'length' => $length, 'file_name' => $filename ]);
Cache::set($this->cache_key . $task_key, $build_task);
} else {
$file = $temp_dir . $build_task[ 'file_name' ];
$file_resource = fopen($file, 'a');
if (( $build_task[ 'index' ] + 1 ) <= $build_task[ 'step' ]) {
$start = $build_task[ 'index' ] * $chunk_size;
$end = ( $build_task[ 'index' ] + 1 ) * $chunk_size;
$end = min($end, $build_task[ 'length' ]);
$response = ( new CloudService(true, 'http://java.oss.niucloud.com/') )->request('GET', 'cloud/apk_download?' . http_build_query($query), [
'headers' => [ 'Range' => "bytes={$start}-{$end}" ]
]);
fwrite($file_resource, $response->getBody());
fclose($file_resource);
$build_task[ 'index' ] += 1;
Cache::set($this->cache_key . $task_key, $build_task);
$result['build_log'][] = [ 'code' => 1, 'action' => '安装包下载中,已下载' . round($build_task[ 'index' ] / $build_task[ 'step' ] * 100) . '%', 'percent' => '99' ];
} else {
$result['build_log'][] = [ 'code' => 1, 'action' => '安装包下载中,已下载' . round($build_task[ 'index' ] / $build_task[ 'step' ] * 100) . '%', 'percent' => '100' ];
$result['status'] = 'success';
$result['file_path'] = $file;
Cache::set($this->cache_key . $task_key, null);
}
}
} catch (\Exception $e) {
$result['status'] = 'fail';
$result['fail_reason'] = $e->getMessage().$e->getFile().$e->getLine();
$result['build_log'][] = [ 'code' => 0, 'msg' => $e->getMessage(), 'action' => '', 'percent' => '100' ];
}
return $result;
}
/**
* 获取插件定义的package目录
* @param string $addon
* @return string
*/
public function geAddonPackagePath(string $addon)
{
return $this->addon_path . $addon . DIRECTORY_SEPARATOR . 'package' . DIRECTORY_SEPARATOR;
}
public function generateSingCert(array $data) {
$dname = "CN={$data['cn']}, OU={$data['ou']}, O={$data['o']}, L={$data['l']}, ST={$data['st']}, C={$data['c']}";
$query = [
'key_alias' => $data['key_alias'],
'key_password' => $data['key_password'],
'store_password' => $data['store_password'],
'limit' => $data['limit'] * 365,
'dname' => $dname
];
$response = ( new CloudService(true, 'http://java.oss.niucloud.com/') )->request('GET', 'cloud/getcert?' . http_build_query($query));
$content_type = $response->getHeaders()['Content-Type'][0];
if ($content_type == 'application/json') {
$content = json_decode($response->getBody()->getContents(), true);
if (isset($content[ 'code' ]) && $content[ 'code' ] == 0) throw new CommonException($content[ 'msg' ]);
}
$dir = 'upload' . DIRECTORY_SEPARATOR . 'download' . DIRECTORY_SEPARATOR . 'cert' . DIRECTORY_SEPARATOR;
if (!is_dir($dir)) mkdirs($dir);
$file = $dir . $data['key_alias'] . '.zip';
if (file_exists($file)) unlink($file);
$file_resource = fopen($file, 'a');
fwrite($file_resource, $response->getBody());
fclose($file_resource);
return $file;
}
}

View File

@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\core\channel;
use app\dict\sys\ConfigKeyDict;
use app\model\sys\SysAttachment;
use app\service\core\addon\WapTrait;
use app\service\core\sys\CoreConfigService;
use core\base\BaseCoreService;
/**
* 素材管理服务层
* Class CoreAttachmentService
* @package app\service\core\sys
*/
class CoreAppService extends BaseCoreService
{
use WapTrait;
public function __construct()
{
parent::__construct();
$this->model = new SysAttachment();
}
/**
* 获取app端配置
* @return array|mixed
*/
public function getConfig(int $site_id)
{
$info = (new CoreConfigService())->getConfig($site_id, ConfigKeyDict::APP)['value'] ?? [];
if (empty($info)) {
$info = [
'wechat_app_id' => '',
'wechat_app_secret' => '',
'uni_app_id' => '',
'app_name' => '',
'android_app_key' => '',
'application_id' => ''
];
}
return $info;
}
public function setConfig(int $site_id, $data)
{
$info = (new CoreConfigService())->setConfig($site_id, ConfigKeyDict::APP, $data);
return $info;
}
}

View File

@ -66,6 +66,17 @@ class CoreH5Service extends BaseCoreService
]
]
]
],
"app-plus" => [
"distribute" => [
"sdkConfigs" => [
"maps" => [
"tencent" => [
"key" => $map_key
]
]
]
]
]
]);
}

View File

@ -49,6 +49,7 @@ class CoreModuleService extends BaseNiucloudClient
'secret' => $this->secret,
'labels' => [ $label_id ],
'order_field' => 'sale_num desc, visit_num desc',
'recommend_type'=>'PHP'
];
return $this->httpGet('store/saas/app', $params);
}
@ -58,6 +59,7 @@ class CoreModuleService extends BaseNiucloudClient
$params = [
'code' => $this->code,
'secret' => $this->secret,
'recommend_type'=>'PHP'
];
return $this->httpGet('promotion_adv', $params);
}

View File

@ -7,9 +7,11 @@ use app\dict\sys\SmsDict;
use app\service\core\http\HttpHelper;
use app\service\core\sys\CoreConfigService;
use core\base\BaseAdminService;
use core\base\BaseCoreService;
class CoreNiuSmsService extends BaseAdminService
class CoreNiuSmsService extends BaseCoreService
{
/*************************牛云短信处理****************************/
private const PACKAGE_LIST_URL = '/niusms/packages';
private const SEND_CODE_URL = '/niusms/send';
@ -43,7 +45,7 @@ class CoreNiuSmsService extends BaseAdminService
private const ORDER_STATUS_URL = '/niusms/order/status/%s/%s';
private $niushop_url_prefix = null;
public $site_id = null;
/**
* @throws \Exception
*/
@ -58,6 +60,11 @@ class CoreNiuSmsService extends BaseAdminService
}
}
public function setSiteId(string $site_id){
$this->site_id = $site_id;
return $this;
}
/**
* 设置账号缓存
* @param $params
@ -65,7 +72,7 @@ class CoreNiuSmsService extends BaseAdminService
*/
public function setNiuLoginConfig($params, $is_login = false)
{
$config = $this->getNiuLoginConfig(true);
$config = $this->setSiteId($this->site_id)->getNiuLoginConfig(true);
$config['default'] = $params['default'] ?? ($config['default'] ?? "");
$config[SmsDict::NIUSMS] = [
'username' => $params['username'] ?? $config[SmsDict::NIUSMS]['username'] ?? "",
@ -151,7 +158,7 @@ class CoreNiuSmsService extends BaseAdminService
{
$url = $this->niushop_url_prefix . sprintf(self::ACCOUNT_INFO_URL, $username);
$res = (new HttpHelper())->get($url);
$config = $this->getNiuLoginConfig();
$config = $this->setSiteId($this->site_id)->getNiuLoginConfig();
if ($config['username'] == $res['username']) {
$res['signature'] = $config['signature'] ?? "";
}

View File

@ -15,6 +15,7 @@ namespace app\service\core\notice;
use app\job\notice\Notice;
use app\model\sys\SysNotice;
use core\base\BaseCoreService;
use core\exception\NoticeException;
use think\facade\Log;
@ -50,7 +51,7 @@ class NoticeService extends BaseCoreService
return Notice::dispatch(['site_id' => $site_id, 'key' => $key, 'data' => $data, 'template' => $template], is_async: $template['async']);
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
throw new NoticeException($e->getMessage());
}
}
}
}

View File

@ -14,6 +14,7 @@ namespace app\service\core\pay;
use app\dict\pay\PayDict;
use app\model\pay\PayChannel;
use app\service\core\channel\CoreAppService;
use app\service\core\weapp\CoreWeappConfigService;
use app\service\core\wechat\CoreWechatConfigService;
use core\base\BaseCoreService;
@ -124,10 +125,15 @@ class CorePayChannelService extends BaseCoreService
//查询公众号配置
$core_weapp_config_service = new CoreWeappConfigService();
$mini_app_id = $core_weapp_config_service->getWeappConfig($site_id)[ 'app_id' ];//小程序appid
// 查询微信移动应用配置
$core_app_service = new CoreAppService();
$app_id = $core_app_service->getConfig($site_id)['wechat_app_id'] ?? ''; //App appid
//todo 查询微信小程序 appid . 应用appid.....
return [
'mp_app_id' => $mp_app_id,
'mini_app_id' => $mini_app_id
'mini_app_id' => $mini_app_id,
'app_id' => $app_id
//............
];
}

View File

@ -0,0 +1,81 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的saas管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\core\wechat;
use app\service\core\channel\CoreAppService;
use app\service\core\wxoplatform\CoreOplatformService;
use core\base\BaseCoreService;
use core\exception\WechatException;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use EasyWeChat\OfficialAccount\Application;
use GuzzleHttp\Exception\GuzzleException;
/**
* 微信服务api提供
* Class CoreWechatApiService
* @package app\service\core\wechat
*/
class CoreWechatAppService extends BaseCoreService
{
/**
* 获取公众号的handle
* @param int $site_id
* @return Application
* @throws InvalidArgumentException
*/
public static function app(int $site_id)
{
$app_config = (new CoreAppService())->getConfig($site_id);
if (empty($app_config['wechat_app_id']) || empty($app_config['wechat_app_secret'])) throw new WechatException('WECHAT_NOT_EXIST');//公众号未配置
$config = array(
'app_id' => $app_config['wechat_app_id'],
'secret' => $app_config['wechat_app_secret'],
'token' => "",
'aes_key' => 'not_encrypt',
'http' => [
'timeout' => 5.0,
'retry' => true, // 使用默认重试配置
]
);
return new Application($config);
}
/**
* 微信实例接口调用
* @param int $site_id
* @return \EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient
* @throws InvalidArgumentException
*/
public static function appApiClient(int $site_id)
{
return self::app($site_id)->getClient();
}
/**
* 处理授权回调
* @param int $site_id
* @param string $code
* @return UserInterface
*/
public static function userFromCode(int $site_id, string $code)
{
try {
$oauth = self::app($site_id)->getOauth();
return $oauth->userFromCode($code);
} catch (\Exception $e) {
throw new CommonException($e->getCode() . '' . $e->getMessage());
}
}
}

View File

@ -0,0 +1,21 @@
DROP TABLE IF EXISTS `app_version`;
CREATE TABLE `app_version`
(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`site_id` INT(11) NOT NULL DEFAULT 0 COMMENT '站点id',
`version_code` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '版本号',
`version_name` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '版本名称',
`version_desc` VARCHAR(1500) NOT NULL DEFAULT '' COMMENT '版本描述',
`platform` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'app平台 Android Ios',
`package_path` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '安装包路径',
`status` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '状态',
`is_forced_upgrade` INT(11) NOT NULL DEFAULT 0 COMMENT '是否需要强制升级',
`task_key` VARCHAR(255) NOT NULL DEFAULT '',
`fail_reason` VARCHAR(255) NOT NULL DEFAULT '',
`upgrade_type` VARCHAR(255) NOT NULL DEFAULT 'app' COMMENT 'app 整包更新 hot 热更新 market 应用市场更新',
`release_time` INT(11) NOT NULL DEFAULT 0 COMMENT '发布时间',
`create_time` INT(11) NOT NULL DEFAULT 0 COMMENT '创建时间',
`update_time` INT(11) NOT NULL DEFAULT 0 COMMENT '修改时间',
PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'app版本管理' ROW_FORMAT = Dynamic;

View File

@ -73,6 +73,22 @@ $system = [
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
],
'size' => 10485760
],
'app_package' => [
'ext' => ['apk', 'wgt'],
'mime' => [
'application/vnd.android.package-archive',
'application/vnd.wap.wgt'
],
'size' => 104857600
],
'android_cert' => [
'ext' => ['jks'],
'mime' => [
'application/octet-stream',
'application/x-java-keystore'
],
'size' => 2097152
]
],
'thumb' => [

View File

@ -1,6 +1,6 @@
<?php
return [
'version' => '1.1.4',
'code' => '202508230001'
'version' => '1.1.5',
'code' => '202509120001'
];

View File

@ -10,6 +10,7 @@
// +----------------------------------------------------------------------
namespace core\poster;
use core\exception\CommonException;
use Kkokk\Poster\Facades\Poster as PosterInstance;
class Poster extends BasePoster
@ -34,6 +35,9 @@ class Poster extends BasePoster
*/
public function createPoster(array $poster_data, string $dir, string $file_path)
{
if (!extension_loaded('imagick')){
throw new CommonException('海报组件未配置完善,请联系管理员');//POSTER_CREATE_ERROR
}
$bg_type = $poster_data[ 'global' ][ 'bgType' ];
$instance = PosterInstance::extension('imagick')->config([
'path' => realpath($dir) . DIRECTORY_SEPARATOR . $file_path,