This commit is contained in:
CQ 2025-11-21 14:49:09 +08:00
parent 643eadfd14
commit 54510e953d
147 changed files with 11285 additions and 5164 deletions

View File

@ -89,13 +89,6 @@ class ExceptionHandle extends Handle
'previous' => $e->getPrevious(),
] : [];
// 添加自定义异常处理机制
if (strpos($e->getMessage(), 'open_basedir') !== false) {
return fail('OPEN_BASEDIR_ERROR');
}
if (strpos($e->getMessage(), 'Allowed memory size of') !== false) {
return fail('PHP_SCRIPT_RUNNING_OUT_OF_MEMORY');
}
if ($e instanceof DbException) {
return fail(get_lang('DATA_GET_FAIL').':'.$e->getMessage(), [
'file' => $e->getFile(),
@ -122,17 +115,28 @@ class ExceptionHandle extends Handle
}
private function handleException(Throwable $e) {
// 添加自定义异常处理机制
if (strpos($e->getMessage(), 'open_basedir') !== false) {
return fail('OPEN_BASEDIR_ERROR');
}
if (strpos($e->getMessage(), 'Allowed memory size of') !== false) {
return fail('PHP_SCRIPT_RUNNING_OUT_OF_MEMORY');
}
if (preg_match('/^(fopen|file_get_contents|file_put_contents|include|require)\((.+?)\):.*Permission denied/', $e->getMessage(), $matches)) {
$filePath = $matches[2]; // 提取出来的文件路径
return fail("请检查文件{$filePath}是否存在或权限是否正确");
}
$trace = array_map(function ($class){
return str_replace('\\', '/', $class);
}, array_column($e->getTrace(), 'class'));
$debug = env("APP_DEBUG", false);
foreach ($trace as $class) {
if (preg_match('#^addon/([^/]+)/#', $class, $matches)) {
return fail("{$matches[1]}插件内{$class}{$e->getLine()}行出现异常,异常信息:" .$e->getMessage());
return fail("{$matches[1]}插件内{$class}{$e->getLine()}行出现异常,异常信息:" .$e->getMessage(),$debug?$e->getTrace():[]);
}
}
$debug = env("APP_DEBUG", false);
return fail("{$trace[0]}{$e->getLine()}行出现异常,异常信息:" .$e->getMessage(), $debug ? $e->getTrace() : []);
}

View File

@ -52,14 +52,23 @@ class Request extends \think\Request
*/
public function paramFilter($param, bool $filter = true)
{
if (!$param || !$filter || !is_string($param)) return $param;
// 把数据过滤
if (!$param || !$filter || !is_string($param)) {
return $param;
}
// 过滤危险标签
$filter_rule = [
"/<(\\/?)(script|i?frame|style|html|body|title|link|metaf|alert|font|object|\\?|\\%)([^>]*?)>/isU",
"/(<[^>]*)on[a-zA-Z]+\s*=([^>]*>)/isU",
"/<(\\/?)(script|iframe|frame|style|html|body|title|link|meta|alert|font|object|\\?|\\%)([^>]*?)>/isU",
"/(<[^>]*?)on[a-zA-Z]+\s*=[\s\"'][^\"']*?([\s\"'][^>]*?>)/isU",
"/\\b(select|join|where|drop|like|modify|rename|insert|update|table|database|alter|truncate|\'|\/\*|\.\.\/|\.\/|union|into|load_file|outfile)\\b/is"
];
return preg_replace($filter_rule, '', $param);
$replace = [
'', // 移除整个危险标签
'$1$2', // 仅移除 onxxx 属性,保留标签
''
];
return preg_replace($filter_rule, $replace, $param);
}
/**
@ -89,6 +98,7 @@ class Request extends \think\Request
}
}
/**
* 用户账号
* @param string $username
@ -136,6 +146,7 @@ class Request extends \think\Request
return $this->header(system_name('api_token_name'));
}
/**
* 获取场景
* @return array|string

View File

@ -228,6 +228,21 @@ class Addon extends BaseAdminController
return success(( new AddonService() )->getShowMarketingTools());
}
/**
* 统一展示 安装的插件 应用 营销工具等。。
* @return Response
*/
public function showCustomer()
{
return success((new AddonService())->showCustomer());
}
public function getSpecialMenuList()
{
return success('SUCCESS', (new AddonService())->getSpecialMenuList());
}
/**
* 获取首页应用标签
* @description 获取首页应用标签

View File

@ -75,7 +75,7 @@ class AddonDevelop extends BaseAdminController
/**
* 开发插件更新
* @description 开发插件更新
* @param string $id
* @param string $key
* @return Response
*/
public function edit(string $key)
@ -101,7 +101,7 @@ class AddonDevelop extends BaseAdminController
/**
* 删除开发插件
* @description 删除开发插件
* @param $key
* @param string $key
* @return Response
*/
public function del(string $key)
@ -114,7 +114,7 @@ class AddonDevelop extends BaseAdminController
* 校验key是否被占用
* @description 校验key是否被占用
* @param $key
* @return void
* @return Response
*/
public function checkKey($key)
{

View File

@ -78,7 +78,7 @@ class Backup extends BaseAdminController
/**
* 恢复备份
* @description 恢复备份
* @return Response
* @return array
*/
public function restoreBackup()
{
@ -107,7 +107,7 @@ class Backup extends BaseAdminController
/**
* 手动备份
* @description 手动备份
* @return Response
* @return array
*/
public function manualBackup()
{

View File

@ -12,7 +12,11 @@
namespace app\adminapi\controller\auth;
use app\service\admin\auth\AuthService;
use app\service\admin\auth\AuthSiteService;
use core\base\BaseAdminController;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Response;
@ -31,12 +35,7 @@ class Auth extends BaseAdminController
*/
public function authMenuList()
{
$data = $this->request->params([
[ 'status', 1 ],
[ 'is_tree', 1 ],
[ 'is_button', 1 ]
]);
return success(( new AuthService() )->getAuthMenuList($data[ 'status' ], $data[ 'is_tree' ], $data[ 'is_button' ]));
return success((new AuthService())->getAuthMenuList(1, 1));
}
/**

View File

@ -11,6 +11,7 @@
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;
@ -43,8 +44,117 @@ class App extends BaseAdminController
$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", ""],
["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", ""],
["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

@ -44,6 +44,8 @@ class Config extends BaseAdminController
$data = $this->request->params([
['is_captcha', 0],
['bg', ''],
['login_logo', ''],
['login_bg_img', ''],
]);
(new ConfigService())->setConfig($data);
return success('MODIFY_SUCCESS');

View File

@ -35,7 +35,7 @@ class Transfer extends BaseAdminController
* 设置场景id
* @description 设置场景id
* @param $scene
* @return void
* @return \think\Response
*/
public function setSceneId($scene){
$data = $this->request->params([

View File

@ -74,7 +74,7 @@ class Area extends BaseAdminController
/**
* 根据code获取地址信息
* @description 根据code获取地址信息
* @return void
* @return Response
*/
public function areaByAreaCode(string $code) {
return success((new AreaService())->getAreaByAreaCode($code));

View File

@ -134,6 +134,7 @@ class Config extends BaseAdminController
{
$data = $this->request->params([
[ 'key', '' ],
[ 'amap_key', ''],
[ 'is_open', 0 ], // 是否开启定位
[ 'valid_time', 0 ] // 定位有效期/分钟过期后将重新获取定位信息0为不过期
]);
@ -187,6 +188,56 @@ class Config extends BaseAdminController
return success();
}
/**
* 设置布局设置
* @description 设置布局设置
* @return Response
*/
public function setLayout()
{
$data = $this->request->params([
[ 'key', '' ],
[ 'value', '' ],
]);
( new ConfigService() )->setLayout($data);
return success();
}
/**
* 获取布局设置
* @description 获取布局设置
* @return Response
*/
public function getLayout()
{
return success(data: ( new ConfigService() )->getLayout());
}
/**
* 设置色调设置
* @description 设置色调设置
* @return Response
*/
public function setThemeColor()
{
$data = $this->request->params([
[ 'key', '' ],
[ 'value', '' ],
]);
( new ConfigService() )->setThemeColor($data);
return success();
}
/**
* 获取色调设置
* @description 获取色调设置
* @return Response
*/
public function getThemeColor()
{
return success(data: ( new ConfigService() )->getThemeColor());
}
/**
* 获取install.php配置
* @return Response

View File

@ -79,7 +79,7 @@ class Export extends BaseAdminController
/**
* 获取导出状态列表
* @description 获取导出状态列表
* @param string $type
* @return Response
*/
public function getExportStatus()
{

View File

@ -94,6 +94,21 @@ class Role extends BaseAdminController
return success('EDIT_SUCCESS');
}
/**
* 修改状态
* @description 修改状态
* @return \think\Response
*/
public function modifyStatus()
{
$data = $this->request->params([
[ 'role_id', '' ],
[ 'status', '' ],
]);
( new RoleService() )->modifyStatus($data);
return success('SUCCESS');
}
/**
* 删除单个用户组
* @description 删除单个用户组
@ -107,19 +122,4 @@ class Role extends BaseAdminController
return success('DELETE_SUCCESS');
}
/**
* 设置角色状态
* @description 设置角色状态
* @param $role_id
* @return Response
*/
public function modifyStatus($role_id)
{
$data = $this->request->params([
['status', RoleStatusDict::ON],
]);
(new RoleService())->modifyStatus($role_id, $data['status']);
return success('DELETE_SUCCESS');
}
}

View File

@ -14,13 +14,13 @@ namespace app\adminapi\controller\user;
use app\dict\sys\UserDict;
use app\service\admin\user\UserService;
use core\base\BaseAdminController;
use Exception;
use think\Response;
/**
* 站点用户接口
* @description 站点用户
* 用户管理
* Class User
* @description 用户管理
* @package app\adminapi\controller\user
*/
class User extends BaseAdminController
{
@ -37,28 +37,25 @@ class User extends BaseAdminController
['role', ''],
['create_time', []],
]);
$list = (new UserService())->getPage($data);
return success($list);
}
/**
* 用户详情
* @description 用户详情
* @param $uid
* @return Response
*/
public function info($uid)
{
if(!is_numeric($uid))
{
$uid = 0;
}
return success((new UserService())->getInfo($uid));
}
/**
* 获取全部用户
* @description 获取全部用户
* 获取用户列表
* @description 获取用户列表
* @return Response
*/
public function getUserAll()
@ -73,92 +70,141 @@ class User extends BaseAdminController
}
/**
* 新增用户
* @description 新增用户
* 获取用户下拉框
* @description 获取用户下拉框
* @return Response
* @throws Exception
*/
public function add()
public function getUserSelect()
{
$data = $this->request->params([
['username', '']
]);
$list = (new UserService())->getUserSelect($data);
return success($list);
}
/**
* 检查用户是否存在
* @description 检查用户是否存在
* @return Response
* @throws \think\db\exception\DbException
*/
public function checkUserIsExist() {
$data = $this->request->params([
['username', ''],
]);
$is_exist = (new UserService())->checkUsername($data['username']);
return success(data:$is_exist);
}
/**
* 添加用户
* @description 添加用户
* @return Response
* @throws \Exception
*/
public function add() {
$data = $this->request->params([
['username', ''],
['password', ''],
['mobile', ''],
['real_name', ''],
['head_img', ''],
['status', UserDict::ON],
['role_ids', []]
]);
$this->validate($data, 'app\validate\sys\User.add');
$uid = (new UserService())->addUser($data);
return success('ADD_SUCCESS', ['uid' => $uid]);
(new UserService())->add($data);
return success();
}
/**
* 更新用户
* @description 更新用户
* 编辑用户
* @description 编辑用户
* @return Response
* @throws \Exception
*/
public function edit($uid)
{
public function edit($uid) {
$data = $this->request->params([
['password', ''],
['mobile', ''],
['real_name', ''],
['head_img', ''],
['status', UserDict::ON],
['role_ids', []],
['password', '']
]);
(new UserService())->editUser($uid, $data);
return success('MODIFY_SUCCESS');
(new UserService())->edit($uid, $data);
return success();
}
/**
* 更新字段
* @description 更新字段
* @param $uid
* @param $field
* @return Response
*/
public function modify($uid, $field)
{
$data = $this->request->params([
['value', ''],
['field', $field]
]);
$data[$field] = $data['value'];
// $this->validate($data, 'app\validate\sys\User.modify');
(new UserService())->modify($uid, $field, $data['value']);
return success('MODIFY_SUCCESS');
}
/**
* 删除单个用户
* @description 删除单个用户
* 删除用户
* @description 删除用户
* @param $uid
* @return Response
*/
public function del($uid)
{
public function del($uid) {
(new UserService())->del($uid);
return success('DELETE_SUCCESS');
return success("DELETE_SUCCESS");
}
/**
* 锁定用户
* @description 锁定用户
* 获取用户站点创建限制
* @description 获取用户站点创建限制
* @param $uid
* @return Response
*/
public function lock($uid)
{
(new UserService())->lock($uid);
return success('MODIFY_SUCCESS');
public function getUserCreateSiteLimit($uid){
return success(data:(new UserService())->getUserCreateSiteLimit($uid));
}
/**
* 解锁用户
* @description 解锁用户
* 获取用户站点创建限制
* @description 获取用户站点创建限制
* @param $id
* @return Response
*/
public function unlock($uid)
{
(new UserService())->unlock($uid);
return success('MODIFY_SUCCESS');
public function getUserCreateSiteLimitInfo($id){
return success(data:(new UserService())->getUserCreateSiteLimitInfo($id));
}
/**
* 添加用户站点创建限制
* @description 添加用户站点创建限制
* @param $uid
* @return Response
*/
public function addUserCreateSiteLimit($uid){
$data = $this->request->params([
['uid', 0],
['group_id', 0],
['num', 1],
['month', 1],
]);
(new UserService())->addUserCreateSiteLimit($data);
return success('SUCCESS');
}
/**
* 编辑用户站点创建限制
* @description 编辑用户站点创建限制
* @param $id
* @return Response
*/
public function editUserCreateSiteLimit($id){
$data = $this->request->params([
['num', 1],
['month', 1],
]);
(new UserService())->editUserCreateSiteLimit($id, $data);
return success('SUCCESS');
}
/**
* 删除用户站点创建限制
* @description 删除用户站点创建限制
* @param $id
* @return Response
*/
public function delUserCreateSiteLimit($id){
(new UserService())->delUserCreateSiteLimit($id);
return success('SUCCESS');
}
}

View File

@ -56,5 +56,45 @@ class Config extends BaseAdminController
return success('SET_SUCCESS');
}
/**
* 设置微信小程序域名
* @description 设置微信小程序域名
* @return Response
*/
public function setDomain() {
$data = $this->request->params([
['requestdomain', ''],
['wsrequestdomain', ''],
['uploaddomain', ''],
['downloaddomain', ''],
['udpdomain', ''],
['tcpdomain', '']
]);
(new WeappConfigService())->setDomain($data);
return success('SET_SUCCESS');
}
/**
* 获取微信小程序隐私协议
* @description 获取微信小程序隐私协议
* @return Response
*/
public function getPrivacySetting() {
return success((new WeappConfigService())->getPrivacySetting());
}
/**
* 设置微信小程序隐私协议
* @description 设置微信小程序隐私协议
* @return Response
*/
public function setPrivacySetting() {
$data = $this->request->params([
['setting_list', []],
['owner_setting', []],
['sdk_privacy_info_list', []]
]);
(new WeappConfigService())->setPrivacySetting($data);
return success('SET_SUCCESS');
}
}

View File

@ -24,7 +24,7 @@ class Delivery extends BaseAdminController
/**
* 查询小程序是否已开通发货信息管理服务
* @description 查询小程序是否已开通发货信息管理服务
* @return bool
* @return \think\Response
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
*/
public function getIsTradeManaged()

View File

@ -53,7 +53,8 @@ class Version extends BaseAdminController
public function add()
{
$data = $this->request->params([
['desc', '']
['desc', ''],
['version', '']//特殊指定版本号
]);
return success(data:(new WeappVersionService())->add($data));
}

View File

@ -42,7 +42,8 @@ class Config extends BaseAdminController
['token', ''],
['encoding_aes_key', ''],
['qr_code', ''],
['encryption_type', '']
['encryption_type', ''],
['base_uri', '']
]);
$this->validate($data, 'app\validate\channel\Wechat.set');
(new WechatConfigService())->setWechatConfig($data);

View File

@ -27,6 +27,7 @@ class AdminCheckRole
{
$check_role_service = new AuthService();
$check_role_service->checkRole($request);
//处理用户的权限
return $next($request);
}

View File

@ -16,6 +16,8 @@ use app\Request;
use app\service\admin\user\UserLogService;
use Closure;
use ReflectionClass;
use think\facade\Log;
use think\facade\Route;
/**
* admin用户操作日志
@ -29,20 +31,28 @@ class AdminLog
//写入日志
if ($request->method() != 'GET') {
$path = $request->rule()->getRoute();
if(strstr($path,'@')){
try {
if (strstr($path, '@')) {
$arr = explode('@', $path);
$controller = $arr[0] ?? "";
$action = $arr[1] ?? "";
}else{
} else {
//暂时只有APP目录下使用这样的路由定义
list($controllerStr, $action) = explode('/', $path, 2);
list($module, $controller) = explode('.', $controllerStr, 2);
$parts = preg_split('/[\.\\\\]/', $controllerStr, 2);
list($module, $controller) = $parts;
if (count($parts) >= 2) {
// 拼接完整类名(根据 TP 命名空间规则调整)
$controllerClass = "app\\adminapi\\controller\\{$module}\\{$controller}";
$controller = $controllerClass;
}
}
$operation = $this->extractDescFromAnnotation($controller, $action);
} catch (\Exception $e) {
$operation = "";
Log::write('获取路由描述错误:path' . $path . ' error' . $e->getMessage());
}
$data = [
'uid' => $request->uid(),
'username' => $request->username(),
@ -79,7 +89,7 @@ class AdminLog
$docComment = $method->getDocComment();
if (preg_match('/@description\s+(.+)/', $docComment, $matches)) {
return (empty($controller_desc) ? "" : $controller_desc.'-').$matches[1];
return (empty($controller_desc) ? "" : $controller_desc . '-') . $matches[1];
}
return '';

View File

@ -27,13 +27,13 @@ Route::group(function () {
Route::get('addon/:id', 'addon.Addon/info');
//安装插件
Route::post('addon/install/:addon', 'addon.Addon/install');
Route::post('addon/install/:addon', 'addon.Addon/install')->pattern(['addon' => '[\w|\,]+']);
//云安装插件
Route::post('addon/cloudinstall/:addon', 'addon.Addon/cloudInstall');
Route::post('addon/cloudinstall/:addon', 'addon.Addon/cloudInstall')->pattern(['addon' => '[\w|\,]+']);
// 云编译进度
Route::get('addon/cloudinstall/:addon', 'addon.Addon/cloudInstallLog');
Route::get('addon/cloudinstall/:addon', 'addon.Addon/cloudInstallLog')->pattern(['addon' => '[\w|\,]+']);
//插件安装检测安装环境
Route::get('addon/install/check/:addon', 'addon.Addon/installCheck');
Route::get('addon/install/check/:addon', 'addon.Addon/installCheck')->pattern(['addon' => '[\w|\,]+']);
// 获取安装任务
Route::get('addon/installtask', 'addon.Addon/getInstallTask');
//下载插件
@ -77,6 +77,9 @@ Route::group(function () {
Route::post('addon_develop/download/:key', 'addon.AddonDevelop/download');
//插件标识黑名单
Route::get('addon_develop/key/blacklist', 'addon.AddonDevelop/keyBlackList');
// 获取应用列表
Route::get('addon/showCustomer', 'addon.Addon/showCustomer');
Route::get('addon/special_menu', 'addon.Addon/getSpecialMenuList');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,
@ -89,8 +92,7 @@ Route::group(function () {
Route::group(function () {
//获取已安装插件列表
Route::get('addon/list/install', 'addon.Addon/getInstallList');
// 获取应用列表
Route::get('addon/list/showapp', 'addon.Addon/showApp');
// 获取营销列表
Route::get('addon/list/showApp', 'addon.Addon/showApp');
Route::get('showMarketing', 'addon.Addon/showMarketing');
});

View File

@ -24,12 +24,15 @@ Route::group('auth', function () {
/***************************************************** 授权信息 ****************************************************/
//授权用户站点菜单
Route::get('authmenu', 'auth.Auth/authMenuList');
//授权用户站点应用
Route::get('authaddon', 'auth.Auth/getAuthAddonList');
//授权用户信息
Route::get('get', 'auth.Auth/get');
//授权用户信息
Route::put('edit', 'auth.Auth/edit');
//授权用户信息
Route::put('modify/:field', 'auth.Auth/modify');
//授权用户信息
Route::put('edit', 'auth.Auth/edit');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,

View File

@ -33,6 +33,24 @@ Route::group('channel', function () {
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,

View File

@ -149,9 +149,9 @@ Route::group('member', function() {
//全部会员等级
Route::get('level/all', 'member.MemberLevel/getAll');
// 获取会员权益内容
Route::get('benefits/content', 'member.Member/getMemberBenefitsContent');
Route::post('benefits/content', 'member.Member/getMemberBenefitsContent');
// 获取会员礼包内容
Route::get('gifts/content', 'member.Member/getMemberGiftsContent');
Route::post('gifts/content', 'member.Member/getMemberGiftsContent');
/***************************************************** 会员签到 ****************************************************/
//签到设置
Route::put('sign/config', 'member.MemberSign/setSign');

View File

@ -39,8 +39,6 @@ Route::group('sys', function() {
Route::put('role/:role_id', 'sys.Role/edit');
//删除用户组
Route::delete('role/:role_id', 'sys.Role/del');
// 修改用户组状态
Route::put('role/status', 'sys.Role/modifyStatus');
/***************************************************** 菜单 ****************************************************/
//菜单新增
Route::post('menu', 'sys.Menu/add');
@ -67,8 +65,6 @@ Route::group('sys', function() {
Route::get('menu/system_menu', 'sys.Menu/getSystem');
Route::get('menu/addon_menu/all', 'sys.Menu/getAllAddonMenu');
Route::get('menu/addon_menu/:app_key', 'sys.Menu/getAddonMenu');
Route::get('menu/dir/:addon', 'sys.Menu/getMenuByTypeDir');
@ -99,6 +95,16 @@ Route::group('sys', function() {
// 开发者key
Route::get('config/developer_token', 'sys.Config/getDeveloperToken');
// 布局设置
Route::get('config/layout', 'sys.Config/getLayout');
// 布局设置
Route::put('config/layout', 'sys.Config/setLayout');
// 色调设置
Route::get('config/themecolor', 'sys.Config/getThemeColor');
// 色调设置
Route::put('config/themecolor', 'sys.Config/setThemeColor');
/***************************************************** 图片上传 ****************************************************/
//附件图片上传
Route::post('image', 'upload.Upload/image');
@ -342,6 +348,8 @@ Route::group('sys', function() {
Route::get('web/website', 'sys.Config/getWebsite');
// 获取版权信息
Route::get('web/copyright', 'sys.Config/getCopyright');
// 查询布局设置
Route::get('web/layout', 'sys.Config/getLayout');
// 获取install.php配置
Route::get('install/config', 'sys.Config/getInstallConfig');
});

View File

@ -24,6 +24,12 @@ Route::group('weapp', function() {
Route::get('config', 'weapp.Config/get');
//设置微信配置
Route::put('config', 'weapp.Config/set');
//设置微信域名
Route::put('domain', 'weapp.Config/setDomain');
// 设置微信隐私协议
Route::put('privacysetting', 'weapp.Config/setPrivacySetting');
// 获取微信隐私协议
Route::get('privacysetting', 'weapp.Config/getPrivacySetting');
/***************************************************** 订阅消息 ****************************************************/
//同步订阅消息
@ -41,6 +47,7 @@ Route::group('weapp', function() {
Route::get('upload/:key', 'weapp.Version/uploadLog');
/***************************************************** 小程序发货信息管理服务 ****************************************************/
// 查询小程序是否已开通发货信息管理服务

View File

@ -11,6 +11,7 @@
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;
@ -53,10 +54,20 @@ class App extends BaseController
'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

@ -51,7 +51,7 @@ class Pay extends BaseApiController
['openid', '']
]);
return success('SUCCESS',(new PayService())->pay($data['type'], $data['trade_type'], $data['trade_id'], $data['return_url'], $data['quit_url'], $data['buyer_id'], $data['voucher'], $data['openid']));
return success('SUCCESS',(new PayService())->pay($data['type'], $data['trade_type'], (int)$data['trade_id'], $data['return_url'], $data['quit_url'], $data['buyer_id'], $data['voucher'], $data['openid']));
}
public function info($trade_type, $trade_id)

View File

@ -13,10 +13,6 @@ namespace app\api\controller\pay;
use app\service\api\pay\PayService;
use core\base\BaseApiController;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Response;
/**
* 微信服务端通信以及网页授权
@ -27,7 +23,7 @@ class Transfer extends BaseApiController
/**
* 确认收款
* @return Response
* @return void
*/
public function confirm($transfer_no)
{

View File

@ -29,7 +29,7 @@ class Config extends BaseApiController
*/
public function getCopyright()
{
return success(( new ConfigService() )->getCopyright());
return success((new ConfigService())->getCopyright());
}
/**
@ -38,7 +38,7 @@ class Config extends BaseApiController
*/
public function getSceneDomain()
{
return success(( new ConfigService() )->getSceneDomain());
return success((new ConfigService())->getSceneDomain());
}
/**
@ -47,7 +47,7 @@ class Config extends BaseApiController
*/
public function site()
{
return success(( new ConfigService() )->getWebSite());
return success((new ConfigService())->getWebSite());
}
/**
@ -56,10 +56,10 @@ class Config extends BaseApiController
public function getWapIndexList()
{
$data = $this->request->params([
[ 'title', '' ],
[ 'key', '' ] // 多个查询,逗号隔开
['title', ''],
['key', ''] // 多个查询,逗号隔开
]);
return success(( new ConfigService() )->getWapIndexList($data));
return success((new ConfigService())->getWapIndexList($data));
}
/**
@ -68,7 +68,7 @@ class Config extends BaseApiController
*/
public function getMap()
{
return success(( new ConfigService() )->getMap());
return success((new ConfigService())->getMap());
}
/**
@ -78,35 +78,39 @@ class Config extends BaseApiController
public function init()
{
$data = $this->request->params([
[ 'url', '' ],
[ 'openid', '' ]
['url', ''],
['openid', '']
]);
$config_service = new ConfigService();
$res = [];
$res[ 'tabbar_list' ] = ( new DiyConfigService() )->getBottomList();
$res[ 'map_config' ] = ( new ConfigService() )->getMap();
$res[ 'site_info' ] = ( new ConfigService() )->getWebSite();
$res[ 'member_level' ] = ( new MemberLevelService() )->getList();
$res[ 'login_config' ] = ( new MemberConfigService() )->getLoginConfig($data[ 'url' ]);
$res[ 'theme_list' ] = ( new DiyService() )->getDiyTheme();
$openid_field = match ( $this->request->getChannel() ) {
$res['tabbar_list'] = (new DiyConfigService())->getBottomList();
$res['map_config'] = $config_service->getMap();
$res['site_info'] = $config_service->getWebSite();
$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();
$res['copyright'] = $config_service->getCopyright();
$openid_field = match ($this->request->getChannel()) {
'wechat' => 'wx_openid',
'weapp' => 'weapp_openid',
default => ''
};
// 根据来源查询是否已经存在用户, 如果存在则快捷登录时不再弹出授权弹框
// 根据来源查询是否绑定手机号, 如果绑定并且开启强制绑定则快捷登录时不再弹出绑定手机弹窗
$res[ 'member_exist' ] = 0;
$res[ 'member_mobile_exist' ] = 0;
if (!empty($data[ 'openid' ])) {
if (!empty($openid_field)){
$res[ 'member_exist' ] = ( new MemberService() )->getCount([ [ $openid_field, '=', $data[ 'openid' ] ] ]) > 0 ? 1 : 0;
$res['member_exist'] = 0;
$res['member_mobile_exist'] = 0;
if (!empty($data['openid'])) {
if (!empty($openid_field)) {
$res['member_exist'] = (new MemberService())->getCount([[$openid_field, '=', $data['openid']]]) > 0 ? 1 : 0;
$res[ 'member_mobile_exist' ] = ( new MemberService() )->getCount([ [ $openid_field, '=', $data[ 'openid' ] ], [ 'mobile', '<>', '' ] ]) > 0 ? 1 : 0;
$res['member_mobile_exist'] = (new MemberService())->getCount([[$openid_field, '=', $data['openid']], ['mobile', '<>', '']]) > 0 ? 1 : 0;
}
}
( new MemberService() )->initMemberData();
(new MemberService())->initMemberData();
event('initWap');
return success($res);
@ -119,20 +123,20 @@ class Config extends BaseApiController
public function getMemberMobileExist()
{
$data = $this->request->params([
[ 'openid', '' ]
['openid', '']
]);
$openid_field = match ( $this->request->getChannel() ) {
$openid_field = match ($this->request->getChannel()) {
'wechat' => 'wx_openid',
'weapp' => 'weapp_openid',
default => ''
};
// 根据来源查询是否绑定手机号, 如果绑定并且开启强制绑定则快捷登录时不再弹出绑定手机弹窗
$res[ 'member_mobile_exist' ] = 0;
if (!empty($data[ 'openid' ])) {
$res['member_mobile_exist'] = 0;
if (!empty($data['openid'])) {
if (!empty($openid_field)) {
$res['member_mobile_exist'] = (new MemberService())->getCount([ [ $openid_field, '=', $data['openid'] ], ['mobile', '<>', ''] ]) > 0 ? 1 : 0;
$res['member_mobile_exist'] = (new MemberService())->getCount([[$openid_field, '=', $data['openid']], ['mobile', '<>', '']]) > 0 ? 1 : 0;
}
}

View File

@ -13,6 +13,7 @@ namespace app\api\controller\wechat;
use app\service\api\login\LoginService;
use app\service\api\wechat\WechatAuthService;
use app\service\api\wechat\WechatConfigService;
use core\base\BaseController;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
@ -140,6 +141,16 @@ class Wechat extends BaseController
return success($wechat_auth_service->scanLogin());
}
/**
* 检查微信公众号是否配置
* @return Response
*/
public function checkWechatConfig()
{
return success('SUCCESS', (new WechatConfigService())->checkWechatConfig());
}
/**
* 更新openid
* @return Response

View File

@ -29,9 +29,9 @@ Route::any('weapp/serve', 'weapp.Serve/serve')
->middleware(ApiCheckToken::class)
->middleware(ApiLog::class);
Route::group(function() {
Route::post('niucloud/notify', function() {
return ( new CoreNotifyService() )->notify();
Route::group(function () {
Route::post('niucloud/notify', function () {
return (new CoreNotifyService())->notify();
});
});
@ -73,6 +73,9 @@ Route::group(function () {
// app通过wx code登录
Route::post('wxapp/login', 'channel.App/wechatLogin');
// 获取App新的版本
Route::get('app/newversion', 'channel.App/getNewVersion');
//登录
Route::get('login', 'login.Login/login');
//第三方绑定
@ -153,6 +156,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);
@ -169,4 +173,4 @@ Route::group(function () {
->middleware(ApiCheckToken::class, true)
->middleware(ApiLog::class);
//加载插件路由
( new DictLoader("Route") )->load([ 'app_type' => 'api' ]);
(new DictLoader("Route"))->load(['app_type' => 'api']);

View File

@ -0,0 +1,30 @@
<?php
declare (strict_types=1);
namespace app\command;
use app\upgrade\v156\Upgrade;
use think\console\Command;
use think\console\Input;
use think\console\Output;
class RefreshBottom extends Command
{
public function configure()
{
// 指令配置
$this->setName('refresh:bottom')
->setDescription('升级156版本底部导航异常刷新底部导航。');
}
/**
* 执行任务
* @return void
*/
protected function execute(Input $input, Output $output)
{
$output->writeln('开始处理');
(new Upgrade())->handle();
$output->writeln('刷新完成,请重新发布小程序');
}
}

View File

@ -0,0 +1,26 @@
<?php
declare (strict_types = 1);
namespace app\command;
use app\service\admin\auth\LoginService;
use think\console\Command;
use think\console\Input;
use think\console\Output;
class Resetpassword extends Command
{
protected function configure()
{
// 指令配置
$this->setName('reset')
->setDescription('the reset administrator password command');
}
protected function execute(Input $input, Output $output)
{
LoginService::resetAdministratorPassword();
// 指令输出
$output->writeln('password reset success');
}
}

View File

@ -0,0 +1,27 @@
<?php
declare (strict_types = 1);
namespace app\command;
use app\job\refreshArea;
use app\service\admin\auth\LoginService;
use think\console\Command;
use think\console\Input;
use think\console\Output;
class refreshAreaCommand extends Command
{
protected function configure()
{
// 指令配置
$this->setName('refreshArea')
->setDescription('更新地区命令');
}
protected function execute(Input $input, Output $output)
{
(new refreshArea())->execute($output);
// 指令输出
$output->writeln('地区更新成功');
}
}

View File

@ -774,7 +774,7 @@ function project_path()
/**
* 图片转base64
* @param string $path
* @param $is_delete `转换后是否删除原图`
* @param $is_delete 转换后是否删除原图
* @return string
*/
function image_to_base64(string $path, $is_delete = false)
@ -897,7 +897,7 @@ function file_copy(string $source_file, string $to_file)
function qrcode($url, $page, $data, $dir = '', $channel = 'h5', $style = ['is_transparent' => true], $outfile = true)
{
if ($outfile) {
$dir = $dir ? : 'upload' . '/' . 'qrcode/';//二维码默认存储位置
$dir = $dir ?: 'upload' . '/' . 'qrcode' ;//二维码默认存储位置
if (!is_dir($dir) && !mkdir($dir, 0777, true) && !is_dir($dir)) {
throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir));
}
@ -1051,9 +1051,9 @@ function get_last_time($time = null)
/**
* 检查目录及其子目录的权限
* @param $dir `要检查的目录路径`
* @param $dir 要检查的目录路径
* @param $data
* @param $exclude_dir `排除排除无需检测的的文件夹`
* @param $exclude_dir 排除排除无需检测的的文件夹
* @return array|array[]|mixed
*/
function checkDirPermissions($dir, $data = [], $exclude_dir = [])
@ -1116,8 +1116,8 @@ function checkDirPermissions($dir, $data = [], $exclude_dir = [])
/**
* 下载网络图片
* @param $img_url `图片URL`
* @param $file_name `本地保存位置`
* @param $img_url 图片URL
* @param $file_name 本地保存位置
* @return bool
*/
function downloadImage($img_url, $file_name)

View File

@ -0,0 +1,56 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址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

@ -26,8 +26,10 @@ class CommonActiveDict
const EXCHANGE = 'exchange';// 积分商城 积
const MANJIANSONG = 'manjiansong'; // 满减送 满减
const NEWCOMER_DISCOUNT = 'newcomer_discount'; // 新人专享 新
const FRIEND_HELP = 'friend_help'; // 好友助力 友
const PINTUAN = 'pintuan'; // 新人专享 新
const SECKILL = 'seckill'; // 秒杀 秒
const RELAY = 'relay'; // 接龙 接
public static function getActiveShort($active = '')
{
@ -72,6 +74,16 @@ class CommonActiveDict
'active_name' => get_lang('common_active_short.pintuan_name'),
'bg_color' => '#FF1C77'
],
self::RELAY => [
'name' => get_lang('common_active_short.relay_short'),
'active_name' => get_lang('common_active_short.relay_name'),
'bg_color' => '#0EB108'
],
self::FRIEND_HELP => [
'name' => get_lang('common_active_short.friend_help_short'),
'active_name' => get_lang('common_active_short.friend_help_name'),
'bg_color' => '#F20C8A'
],
];
return !empty($active) ? $data[$active] ?? [] : $data;
}

View File

@ -80,41 +80,41 @@ class PagesDict
if (!empty($wap_index_list)) {
foreach ($wap_index_list as $k => $v) {
$link_list = LinkDict::getLink([ 'addon' => $v[ 'key' ] ]);
$link_list = LinkDict::getLink(['addon' => $v['key']]);
$link = [];
foreach ($link_list as $ck => $cv) {
if ($cv[ 'addon_info' ][ 'key' ] == $v[ 'key' ]) {
foreach ($cv[ 'child_list' ] as $tk => $tv) {
if (isset($cv[ 'type' ]) && $cv[ 'type' ] == 'folder') {
if (!empty($tv[ 'child_list' ])) {
foreach ($tv[ 'child_list' ] as $child_k => $child_v) {
if ($child_v[ 'url' ] == $v[ 'url' ]) {
if ($cv['addon_info']['key'] == $v['key']) {
foreach ($cv['child_list'] as $tk => $tv) {
if (isset($cv['type']) && $cv['type'] == 'folder') {
if (!empty($tv['child_list'])) {
foreach ($tv['child_list'] as $child_k => $child_v) {
if ($child_v['url'] == $v['url']) {
$link = [
"parent" => $ck,
"name" => $child_v[ 'name' ],
"title" => $child_v[ 'title' ],
"url" => $child_v[ 'url' ]
"name" => $child_v['name'],
"title" => $child_v['title'],
"url" => $child_v['url']
];
break;
}
}
}
} else if ($tv[ 'url' ] == $v[ 'url' ]) {
} else if ($tv['url'] == $v['url']) {
$link = [
"parent" => $ck,
"name" => $tv[ 'name' ],
"title" => $tv[ 'title' ],
"url" => $tv[ 'url' ]
"name" => $tv['name'],
"title" => $tv['title'],
"url" => $tv['url']
];
break;
}
}
}
}
$default_index_value[ 'list' ][] = [
"title" => $v[ 'title' ],
$default_index_value['list'][] = [
"title" => $v['title'],
"link" => $link,
"imageUrl" => $v[ 'icon' ],
"imageUrl" => $v['icon'],
"label" => [
"control" => false,
"text" => "热门",
@ -150,7 +150,16 @@ class PagesDict
'imgHeight' => '',
"bottomTabBar" => [
'control' => true,
'isShow' => true
'isShow' => true,
'designNav' => [
'title' => '',
'key' => ''
]
],
"copyright" => [
'control' => true,
'isShow' => false,
'textColor' =>'#ccc'
],
"template" => [
'textColor' => "#303133",
@ -225,7 +234,16 @@ class PagesDict
'imgHeight' => '',
"bottomTabBar" => [
'control' => true,
'isShow' => true
'isShow' => true,
'designNav' => [
'title' => '',
'key' => ''
]
],
"copyright" => [
'control' => true,
'isShow' => false,
'textColor' =>'#ccc'
],
"template" => [
'textColor' => "#303133",
@ -694,7 +712,16 @@ class PagesDict
'imgHeight' => 403,
"bottomTabBar" => [
'control' => true,
'isShow' => true
'isShow' => true,
'designNav' => [
'title' => '',
'key' => ''
],
],
"copyright" => [
'control' => true,
'isShow' => false,
'textColor' =>'#ccc'
],
"template" => [
'textColor' => "#303133",
@ -1147,19 +1174,19 @@ class PagesDict
]
];
if (!empty($params[ 'addon' ])) {
$pages = ( new DictLoader("UniappPages") )->load($params);
if (!empty($params['addon'])) {
$pages = (new DictLoader("UniappPages"))->load($params);
} else {
$pages = ( new DictLoader("UniappPages") )->load($system_pages);
$pages = (new DictLoader("UniappPages"))->load($system_pages);
}
if (!empty($params[ 'type' ])) {
if (!empty($pages[ $params[ 'type' ] ])) {
$temp = $pages[ $params[ 'type' ] ];
if (isset($params[ 'mode' ]) && !empty($params[ 'mode' ])) {
if (!empty($params['type'])) {
if (!empty($pages[$params['type']])) {
$temp = $pages[$params['type']];
if (isset($params['mode']) && !empty($params['mode'])) {
foreach ($temp as $k => $v) {
if ($params[ 'mode' ] != $v[ 'mode' ]) {
unset($temp[ $k ]);
if ($params['mode'] != $v['mode']) {
unset($temp[$k]);
}
}
}

View File

@ -25,14 +25,14 @@ class TemplateDict
*/
public static function getTemplate($params = [])
{
$other_template_data = ( new DictLoader("DiyFormTemplate") )->load([]);
$other_template_data = (new DictLoader("DiyFormTemplate"))->load([]);
$template = self::template();
$data = array_merge($other_template_data, $template);
if (!empty($params) && !empty($params[ 'type' ])) {
if (!empty($params[ 'template_key' ])) {
return $data[ $params[ 'type' ] ][ $params[ 'template_key' ] ] ?? [];
if (!empty($params) && !empty($params['type'])) {
if (!empty($params['template_key'])) {
return $data[$params['type']][$params['template_key']] ?? [];
}
return $data[ $params[ 'type' ] ] ?? [];
return $data[$params['type']] ?? [];
}
return $data;
@ -79,7 +79,16 @@ class TemplateDict
],
"bottomTabBar" => [
'control' => true,
'isShow' => true
'isShow' => true,
'designNav' => [
'title' => '',
'key' => ''
]
],
"copyright" => [
'control' => true,
'isShow' => false,
'textColor' =>'#ccc'
],
"popWindow" => [
"imgUrl" => "",
@ -724,7 +733,16 @@ class TemplateDict
],
"bottomTabBar" => [
'control' => true,
'isShow' => true
'isShow' => true,
'designNav' => [
'title' => '',
'key' => ''
]
],
"copyright" => [
'control' => true,
'isShow' => false,
'textColor' =>'#ccc'
],
"popWindow" => [
"imgUrl" => "",

View File

@ -24,7 +24,6 @@ class MemberRegisterChannelDict extends ChannelDict
public static function getType($type = '')
{
$data = ChannelDict::getType($type);
$data[self::MANUAL] = get_lang('dict_member.register_manual');//手动添加
if (empty($type)) {

View File

@ -0,0 +1,62 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\dict\menu;
/**
* 菜单类
* Class MenuDict
* @package app\dict\sys
*/
class MenuDict
{
public const ADDON_CHILD_MENU_DICT_SYSTEM_TOOL = 'system_tool';
public const ADDON_CHILD_MENU_DICT_MARKING_TOOL = 'marketing_tool';
public const ADDON_CHILD_MENU_DICT_MARKING_ACTIVE = 'marketing_active';
public const ADDON_CHILD_MENU_DICT_ADDON_TOOL = 'addon_tool';
/**
* 站点应用管理特殊子菜单
* @return array
*/
public static function getAddonChildMenu()
{
//注意 sort 倒序排序使用
return [
self::ADDON_CHILD_MENU_DICT_SYSTEM_TOOL => [
'key' => self::ADDON_CHILD_MENU_DICT_SYSTEM_TOOL,
'name' => get_lang('dict_addon_menu.system_tool'),
'short_name' => get_lang('dict_addon_menu.system_tool_short'),
'sort' => 97
],
self::ADDON_CHILD_MENU_DICT_MARKING_TOOL => [
'key' => self::ADDON_CHILD_MENU_DICT_MARKING_TOOL,
'name' => get_lang('dict_addon_menu.marking_tool'),
'short_name' => get_lang('dict_site.marking_tool_short'),
'sort' => 99
],
self::ADDON_CHILD_MENU_DICT_MARKING_ACTIVE => [
'key' => self::ADDON_CHILD_MENU_DICT_MARKING_ACTIVE,
'name' => get_lang('dict_addon_menu.marking_active'),
'short_name' => get_lang('dict_addon_menu.marking_active_short'),
'sort' => 100
],
self::ADDON_CHILD_MENU_DICT_ADDON_TOOL => [
'key' => self::ADDON_CHILD_MENU_DICT_ADDON_TOOL,
'name' => get_lang('dict_addon_menu.addon_tool'),
'short_name' => get_lang('dict_addon_menu.addon_tool_short'),
'sort' => 98
],
];
}
}

View File

@ -1073,37 +1073,37 @@ return [
],
],
],
[
'menu_name' => '营销管理',
'menu_key' => 'active',
'menu_short_name' => '营销',
'parent_key' => '',
'menu_type' => '0',
'icon' => 'iconfont iconyingxiao2',
'api_url' => '',
'router_path' => 'app/marketing',
'view_path' => '',
'methods' => '',
'sort' => '87',
'status' => '1',
'is_show' => '1',
'children' => [
[
'menu_name' => '营销列表',
'menu_key' => 'marketing_list',
'menu_short_name' => '营销列表',
'menu_type' => '1',
'icon' => 'iconfont iconmanage-apply',
'api_url' => 'marketing/list',
'router_path' => 'app/marketing',
'view_path' => 'app/marketing',
'methods' => 'get',
'sort' => '160',
'status' => '1',
'is_show' => '1',
],
],
],
// [
// 'menu_name' => '营销管理',
// 'menu_key' => 'active',
// 'menu_short_name' => '营销',
// 'parent_key' => '',
// 'menu_type' => '0',
// 'icon' => 'iconfont iconyingxiao2',
// 'api_url' => '',
// 'router_path' => 'app/marketing',
// 'view_path' => '',
// 'methods' => '',
// 'sort' => '87',
// 'status' => '1',
// 'is_show' => '1',
// 'children' => [
// [
// 'menu_name' => '营销列表',
// 'menu_key' => 'marketing_list',
// 'menu_short_name' => '营销列表',
// 'menu_type' => '1',
// 'icon' => 'iconfont iconmanage-apply',
// 'api_url' => 'marketing/list',
// 'router_path' => 'app/marketing',
// 'view_path' => 'app/marketing',
// 'methods' => 'get',
// 'sort' => '160',
// 'status' => '1',
// 'is_show' => '1',
// ],
// ],
// ],
[
'menu_name' => '核销管理',
'menu_key' => 'verify',
@ -1225,7 +1225,7 @@ return [
'menu_name' => '签到管理',
'menu_key' => 'sign',
'menu_short_name' => '签到管理',
'parent_key' => 'active',
'parent_key' => 'addon',
'menu_type' => '0',
'icon' => 'element FolderChecked',
'api_url' => '',
@ -1290,8 +1290,8 @@ return [
'menu_type' => '0',
'icon' => 'iconfont iconyingyong21',
'api_url' => '',
'router_path' => '',
'view_path' => '',
'router_path' => 'app/index',
'view_path' => 'app/index',
'methods' => '',
'sort' => '86',
'status' => '1',
@ -1307,7 +1307,7 @@ return [
'router_path' => 'app/index',
'view_path' => 'app/index',
'methods' => 'get',
'sort' => '130',
'sort' => '999',
'status' => '1',
'is_show' => '1',
],
@ -1783,6 +1783,64 @@ return [
'sort' => '0',
'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',
]
],
],
@ -2998,7 +3056,7 @@ return [
'is_show' => '1',
'children' => [
[
'menu_name' => '插件管理',
'menu_name' => '应用管理',
'menu_key' => 'app_store',
'menu_short_name' => '应用',
'menu_type' => '1',
@ -3557,7 +3615,7 @@ return [
'methods' => '',
'sort' => '101',
'status' => '1',
'is_show' => '1',
'is_show' => '0',
],
[
'menu_name' => '升级记录',

View File

@ -16,7 +16,6 @@ use app\dict\common\ChannelDict;
class PayChannelDict
{
/**
* 支付渠道类型
* @return array
@ -49,5 +48,4 @@ class PayChannelDict
return $list;
}
}

View File

@ -40,6 +40,9 @@ class ConfigKeyDict
public const SMS = 'SMS';//短信配置
public const PINTUAN_ORDER_CONFIG = 'PINTUAN_ORDER_CONFIG';//拼团订单配置
public const FRIEND_HELP_CONFIG = 'FRIEND_HELP_CONFIG';//拼团订单配置
public const RELAY_ORDER_CONFIG = 'RELAY_ORDER_CONFIG';//接龙订单配置
public const FRIEND_HELP_ORDER_CONFIG = 'FRIEND_HELP_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
@ -74,8 +78,11 @@ class FileDict
self::IMAGE,//图片上传
self::VIDEO,//视频上传
self::AUDIO,//视频上传
self::DOCUMENT,//文件上传
self::APPLET,//小程序包上传
self::EXCEL,//excel导入
self::APP_PACKAGE,//应用包
self::ANDROID_CERT,//android证书
];
}

View File

@ -11,7 +11,7 @@ $system_event = [
/**
* 系统事件
*/
'AppInit' => [ 'app\listener\system\AppInitListener' ],
'AppInit' => ['app\listener\system\AppInitListener'],
'HttpRun' => [],
'HttpEnd' => [],
'LogLevel' => [],
@ -20,26 +20,26 @@ $system_event = [
* 会员相关事件
*/
//会员注册事件
'MemberRegister' => [ 'app\listener\member\MemberRegisterListener' ],
'MemberRegister' => ['app\listener\member\MemberRegisterListener'],
//会员登录事件
'MemberLogin' => [ 'app\listener\member\MemberLoginListener' ],
'MemberLogin' => ['app\listener\member\MemberLoginListener'],
//会员账户变化事件
'MemberAccount' => [ 'app\listener\member\MemberAccountListener' ],
'MemberAccount' => ['app\listener\member\MemberAccountListener'],
//扫码事件
'Scan' => [ 'app\listener\scan\ScanListener' ],
'Scan' => ['app\listener\scan\ScanListener'],
/**
* 支付相关事件
*/
'PayCreate' => [ 'app\listener\pay\PayCreateListener' ],
'PayCreate' => ['app\listener\pay\PayCreateListener'],
//支付成功
'PaySuccess' => [ 'app\listener\pay\PaySuccessListener' ],
'PaySuccess' => ['app\listener\pay\PaySuccessListener'],
//退款成功
'RefundSuccess' => [ 'app\listener\pay\RefundSuccessListener' ],
'RefundSuccess' => ['app\listener\pay\RefundSuccessListener'],
//转账成功
'TransferSuccess' => [ 'app\listener\pay\TransferSuccessListener' ],
'TransferSuccess' => ['app\listener\pay\TransferSuccessListener'],
// 任务失败统一回调,有四种定义方式
'queue_failed' => [
[ 'app\listener\job\QueueFailedLoggerListener', 'report' ],
['app\listener\job\QueueFailedLoggerListener', 'report'],
],
//系统应用管理加载
'AppManage' => [
@ -47,6 +47,18 @@ $system_event = [
],
//协议类型加载
'AgreementType' => [],
//站点首页加载
'SiteIndex' => [
'app\listener\system\SiteIndexListener'
],
// 站点端布局
'SiteLayout' => [
'app\listener\system\SiteLayout'
],
//平台首页加载
'AdminIndex' => [
'app\listener\system\AdminIndexListener'
],
'BottomNavigation' => [
'app\listener\system\BottomNavigationListener'
],
@ -100,23 +112,31 @@ $system_event = [
'StatField' => [],
// 获取海报数据
'GetPosterType' => [ 'app\listener\system\PosterType' ],
'GetPosterData' => [ 'app\listener\system\Poster' ],
'GetPosterType' => ['app\listener\system\PosterType'],
'GetPosterData' => ['app\listener\system\Poster'],
// 小程序授权变更事件
'WeappAuthChangeAfter' => ['app\listener\system\WeappAuthChangeAfter'],
'ShowApp' => [
'app\listener\system\ShowAppListener'
],
'ShowMarketing' => [
'app\listener\system\ShowMarketingListener'
],
'ShowCustomer' => [
'app\listener\system\ShowCustomerListener'
],
//获取微信转账场景配置
'GetWechatTransferTradeScene' => [
'app\listener\transfer\TransferCashOutListener'
],
//主题色
'ThemeColor' => [ 'app\listener\diy\ThemeColorListener' ],
'ThemeColor' => ['app\listener\diy\ThemeColorListener'],
'AfterCashApply' => ['app\listener\member\cash\AfterCashApplyListener'],
'AfterCashRefuse' => ['app\listener\member\cash\AfterCashRefuseListener'],
'AfterCashFinish' => ['app\listener\member\cash\AfterCashFinishListener'],
],
'subscribe' => [
],
];
return ( new DictLoader("Event") )->load($system_event);
return (new DictLoader("Event"))->load($system_event);

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -27,16 +27,12 @@ class AutoClearPosterAndQrcode extends BaseJob
// 清理海报目录
$dir = 'upload/poster';
$dir = public_path($dir);
Log::write('AutoClearPosterAndQrcode尝试清理海报目录: ' . $dir);
$res = $this->clearDirectory($dir);
Log::write('AutoClearPosterAndQrcode海报目录清理结果: ' . ($res ? '成功' : '失败'));
// 清理二维码目录
$qrcode_dir = 'upload/qrcode';
$qrcode_dir = public_path($qrcode_dir);
Log::write('AutoClearPosterAndQrcode尝试清理二维码目录: ' . $qrcode_dir);
$res = $this->clearDirectory($qrcode_dir);
Log::write('AutoClearPosterAndQrcode二维码目录清理结果: ' . ($res ? '成功' : '失败'));
return true;
} catch (\Exception $e) {

View File

@ -0,0 +1,31 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\job\sys;
use app\service\core\addon\CoreAddonInstallService;
use core\base\BaseJob;
/**
* 队列异步执行插件安装任务
*/
class AddonInstall extends BaseJob
{
public function doJob($addon, $task)
{
(new CoreAddonInstallService($addon))->executeTask($task);
}
public function failed($data)
{
}
}

View File

@ -57,6 +57,7 @@ return [
//用户管理
'USER_NOT_EXIST' => '用户不存在',
'ADMIN_NOT_ALLOW_EDIT_ROLE' => '超级管理员不允许改动权限',
'USERNAME_REPEAT' => '用户名重复',

View File

@ -24,6 +24,7 @@ return [
'ADD_FAIL' => '添加失败',
'ADD_SUCCESS' => '添加成功',
'UPLOAD_FAIL' => '上传失败',
'RELEASE_SUCCESS' => '发布成功',
'ATTACHMENT_DELETE_FAIL' => '附件删除失败',
'DATA_NOT_EXIST' => '数据不存在',
'DOWNLOAD_FAIL' => '下载失败',
@ -65,6 +66,7 @@ return [
'NOT_EXIST_UPGRADE_CONTENT' => '没有获取到可以升级的内容',
'CLOUD_BUILD_AUTH_CODE_NOT_FOUND' => '请先填写授权码',
'TASK_CYCLE_ERROR' => '任务周期填写错误',
'UPGRADE_TASK_EXIST' => '有正在执行的升级任务,可以展开正在升级的任务,也可以在开发>更新缓存中清除缓存重新开始升级',
//登录注册重置账号....
'LOGIN_SUCCESS' => '登录成功',
@ -77,6 +79,7 @@ return [
'OLD_PASSWORD_ERROR' => '原始密码不正确',
'MOBILE_LOGIN_UNOPENED' => '手机号登录注册未开启',
'APP_TYPE_NOT_EXIST' => '无效的登录端口',
"USER_NOT_ALLOW_DEL" => "该用户是一些站点的管理员不允许删除",
"SUPER_ADMIN_NOT_ALLOW_DEL" => "超级管理员不允许删除",
//用户组权限
@ -96,6 +99,7 @@ return [
'USER_NOT_EXIST' => '用户不存在',
'ADMIN_NOT_ALLOW_EDIT_ROLE' => '超级管理员不允许改动权限',
'USERNAME_REPEAT' => '账号重复',
'MOBILE_REPEAT' => '手机号重复',
//角色管理
'USER_ROLE_NOT_EXIST' => '角色不存在',
@ -134,8 +138,6 @@ return [
'NOTICE_SMS_NOT_OPEN' => '短信未启用',
'NOTICE_TEMPLATE_IS_NOT_EXIST' => '消息不存在',
'WEB_ADV_POSITION_NOT_EXIST' => '广告位不存在',
//会员相关
'MOBILE_IS_EXIST' => '当前手机号已绑定账号',
'ACCOUNT_INSUFFICIENT' => '账户余额不足',
@ -216,9 +218,9 @@ return [
'WEAPP_NOT_EXIST' => '微信小程序未配置完善',
'WEAPP_EMPOWER_NOT_EXIST' => '微信小程序授信信息不存在',
'WEAPP_EMPOWER_TEL_NOT_EXIST' => '微信小程序授信手机号不存在',
'CURR_SITE_IS_NOT_OPEN_SSL' => '微信小程序请求地址只支持https请先配置ssl',
'WECHAT_MINI_PROGRAM_CODE_GENERATION_FAILED' => '微信小程序码生成失败',
//支付相关(todo 注意:7段不共享)
'ALIPAY_TRANSACTION_NO_NOT_EXIST' => '无效的支付交易号',
'PAYMENT_METHOD_NOT_SUPPORT' => '您选择到支付方式不受业务支持',
@ -284,6 +286,8 @@ return [
// 授权相关
'AUTH_NOT_EXISTS' => '未获取到授权信息',
/********************************************************* home端专用 **************************************/
// 云服务
'CLOUD_WEAPP_COMPILE_NOT_EXIST' => '未找到微信小程序编译包',
'WEAPP_APPID_EMPTY' => '还没有配置微信小程序',
@ -323,6 +327,14 @@ return [
'DIRECTORY' => '目录',
'WAS_NOT_CREATED' => '创建失败',
/********************************************************* 微信开放平台 **************************************/
'WECHAT_OPLATFORM_NOT_EXIST' => '未配置微信开放平台',
'WEAPP_EXIST' => '该小程序已经授权给其他站点',
'WECHAT_EXIST' => '该公众号已经授权给其他站点',
'NOT_YET_PRESENT_TEMPLATE_LIBRARY' => '平台尚未上传小程序到模板库',
'WEAPP_VERSION_NOT_EXIST' => '未获取到小程序版本提交记录',
'NOT_ALLOWED_CANCEL_AUDIT' => '只有审核中的才可以撤回',
'PRINTER_NOT_EXIST' => '打印机不存在',
/*******************************************牛云短信 start ********************************************************/
'NIU_SMS_ENABLE_FAILED' => '需登录账号并配置签名后才能启用牛云短信',

View File

@ -472,5 +472,23 @@ return [
'pintuan_name' => '拼团',
'seckill_short' => '秒',
'seckill_name' => '秒杀',
'relay_short' => '接',
'relay_name' => '接龙',
'friend_help_short' => '友',
'friend_help_name' => '好友助力',
],
//应用菜单下 特殊菜单定义
'dict_addon_menu' => [
'system_tool_short' => '系统',
'system_tool' => '系统工具',
'marking_tool_short' => '工具',
'marking_tool' => '营销工具',
'marking_active_short' => '活动',
'marking_active' => '营销活动',
'addon_tool_short' => '插件',
'addon_tool' => '应用插件',
]
];

View File

@ -0,0 +1,31 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\listener\member\cash;
use think\facade\Log;
/**
*
* Class AfterCashApplyListener
* @package app\listener\member\cash
*/
class AfterCashApplyListener
{
public function handle($params)
{
$member_id = $params['member_id'];
$data = $params['data'];
Log::write("发起提现后事件接收参数 member_id:{$member_id} data:" . json_encode($data, 256));
return true;
}
}

View File

@ -0,0 +1,30 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\listener\member\cash;
use think\facade\Log;
/**
*提现完成后事件
* Class AfterCashFinishListener
* @package app\listener\member\cash
*/
class AfterCashFinishListener
{
public function handle($params)
{
$cash_out = $params['cash_out'];
Log::write("提现完成后事件接收参数 data:".json_encode($cash_out,256));
return true;
}
}

View File

@ -0,0 +1,30 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\listener\member\cash;
use think\facade\Log;
/**
*提现被拒绝后事件
* Class AfterCashRefuseListener
* @package app\listener\member\cash
*/
class AfterCashRefuseListener
{
public function handle($params)
{
$cash_out = $params['cash_out'];
Log::write("拒绝提现后事件接收参数 data:" . json_encode($cash_out, 256));
return true;
}
}

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'];
@ -33,7 +33,7 @@ class WechatQrcodeListener extends BaseNoticeTemplate
$url .= '?'.implode('&', $scene);
}
ob_start();//开启缓冲区
\core\util\QRcode::png($url, $path, QR_ECLEVEL_L, 4, 1);
\core\util\QRcode::png($url, $path, QR_ECLEVEL_L, 10, 1);
if($outfile === false){
$img = ob_get_contents();//获取缓冲区内容
$path = 'data:image/png;base64,' . base64_encode($img);//转base64

View File

@ -0,0 +1,30 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\listener\system;
/**
* 平台首页加载事件
* Class AdminIndexListenerIndex
* @package app\listener\system
*/
class AdminIndexListener
{
public function handle()
{
return [
[
"name" => get_lang("dict_admin_index.system"),
"view_path" => "index/index"
]
];
}
}

View File

@ -0,0 +1,75 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\listener\system;
use app\dict\menu\MenuDict;
/**
* 查询营销列表
* Class ShowAppListener
* @package app\listener\system
*/
class ShowCustomerListener
{
public function handle()
{
// 应用app、addon 待定
// 营销marketing
// 工具tool
return [
// 应用
MenuDict::ADDON_CHILD_MENU_DICT_SYSTEM_TOOL => [
[
'title' => '核销管理',
'desc' => '管理核销员及核销记录',
'icon' => 'static/resource/images/marketing/verifier.png',
'key' => 'verify',
'url' => '/marketing/verify/index',
],
[
'title' => '万能表单',
'desc' => '适用于各种应用场景,满足多样化的业务需求',
'icon' => 'static/resource/images/diy_form/icon.png',
'key' => 'diy_form',
'url' => '/diy_form/list',
],
[
'title' => '小票打印',
'desc' => '支持打印机添加,便捷创建小票打印模板',
'icon' => 'static/resource/images/tool/printer_icon.png',
'key' => 'printer_management',
'url' => '/printer/list',
],
[
'title' => '数据导出',
'desc' => '展示导出文件,支持删除与下载',
'icon' => 'static/resource/images/tool/export_icon.png',
'key' => 'setting_export',
'url' => '/setting/export',
],
],
// 工具
MenuDict::ADDON_CHILD_MENU_DICT_MARKING_TOOL => [
],
// 营销
MenuDict::ADDON_CHILD_MENU_DICT_MARKING_ACTIVE => [
[
'title' => '签到管理',
'desc' => '客户每日签到发放奖励',
'icon' => 'static/resource/images/marketing/sign.png',
'key' => 'sign',
'url' => '/marketing/sign/config',
],
]
];
}
}

View File

@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址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

@ -45,19 +45,6 @@ class SysNoticeLog extends BaseModel
// 设置JSON数据返回数组
protected $jsonAssoc = true;
/**
* 名称
* @param $value
* @param $data
* @return string
*/
public function getContentAttr($value, $data)
{
if ($value) {
$temp = json_decode($value, true);
}
return $temp ?? $value;
}
/**
* 名称

View File

@ -14,6 +14,7 @@ namespace app\model\sys;
use app\dict\sys\UserDict;
use core\base\BaseModel;
use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
/**
* 系统用户模型
@ -56,22 +57,11 @@ class SysUser extends BaseModel
*/
protected $defaultSoftDelete = 0;
/**
* 状态字段转化
* @param $value
* @param $data
* @return mixed
*/
public function getStatusNameAttr($value, $data)
{
if (empty($data[ 'status' ])) return '';
return UserDict::getStatus()[ $data[ 'status' ] ] ?? '';
}
public function getCreateTimeAttr($value, $data)
{
return $data[ 'create_time' ] ? get_date_by_time($data[ 'create_time' ]) : '';
return $data['create_time'] ? get_date_by_time($data['create_time']) : '';
}
/**
@ -100,6 +90,18 @@ class SysUser extends BaseModel
}
/**
* 角色状态
* @param $value
* @param $data
* @return string
*/
public function getStatusNameAttr($value, $data)
{
if (empty($data['status'])) return '';
return UserDict::getStatus()[$data['status']] ?? '';
}
/**
* 是否删除搜索器
* @param $query
@ -117,14 +119,14 @@ class SysUser extends BaseModel
*/
public function searchCreateTimeAttr($query, $value, $data)
{
$start_time = empty($value[ 0 ]) ? 0 : strtotime($value[ 0 ]);
$end_time = empty($value[ 1 ]) ? 0 : strtotime($value[ 1 ]);
$start_time = empty($value[0]) ? 0 : strtotime($value[0]);
$end_time = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start_time > 0 && $end_time > 0) {
$query->whereBetweenTime('sys_user.create_time', $start_time, $end_time);
} else if ($start_time > 0 && $end_time == 0) {
$query->where([ [ 'sys_user.create_time', '>=', $start_time ] ]);
$query->where([['sys_user.create_time', '>=', $start_time]]);
} else if ($start_time == 0 && $end_time > 0) {
$query->where([ [ 'sys_user.create_time', '<=', $end_time ] ]);
$query->where([['sys_user.create_time', '<=', $end_time]]);
}
}
@ -136,14 +138,14 @@ class SysUser extends BaseModel
*/
public function searchLastTimeAttr($query, $value, $data)
{
$start_time = empty($value[ 0 ]) ? 0 : strtotime($value[ 0 ]);
$end_time = empty($value[ 1 ]) ? 0 : strtotime($value[ 1 ]);
$start_time = empty($value[0]) ? 0 : strtotime($value[0]);
$end_time = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start_time > 0 && $end_time > 0) {
$query->whereBetweenTime('sys_user.last_time', $start_time, $end_time);
} else if ($start_time > 0 && $end_time == 0) {
$query->where([ [ 'sys_user.last_time', '>=', $start_time ] ]);
$query->where([['sys_user.last_time', '>=', $start_time]]);
} else if ($start_time == 0 && $end_time > 0) {
$query->where([ [ 'sys_user.last_time', '<=', $end_time ] ]);
$query->where([['sys_user.last_time', '<=', $end_time]]);
}
}
}

View File

@ -94,7 +94,7 @@ class AddonDevelopService extends BaseAdminService
/**
* 下载
* @param string $key
* @return array|string|string[]|\think\response\File
* @return \think\response\File
*/
public function download(string $key){
return (new CoreAddonDevelopBuildService())->download($key);

View File

@ -13,8 +13,10 @@ namespace app\service\admin\addon;
use app\dict\addon\AddonDict;
use app\dict\menu\MenuDict;
use app\model\addon\Addon;
use app\model\sys\SysMenu;
use app\service\admin\auth\AuthService;
use app\service\core\addon\CoreAddonCloudService;
use app\service\core\addon\CoreAddonDownloadService;
use app\service\core\addon\CoreAddonInstallService;
@ -273,6 +275,112 @@ class AddonService extends BaseAdminService
return $list;
}
/**
* @return array[]
*/
public function showCustomer($is_sort=true)
{
$show_list = event('ShowCustomer', []);
$addon_type_list = MenuDict::getAddonChildMenu();
$return = [];
foreach ($show_list as $item) {
foreach ($addon_type_list as $key => $value) {
if (!isset($return[$key])) {
$return[$key] = [
'title' => $value['name'],
'sort' => $value['sort'],
'list' => [],
];
}
$return[$key]['list'] = array_merge($return[$key]['list'], $item[$key] ?? []);
}
}
//防止有未实现对应事件的插件额外做一次查询 未实现的直接放到 addon_tool 里面
$keys = [];
foreach ($return as $item) {
foreach ($item['list'] as $value) {
$keys[] = $value['key'];
}
}
$addon_list = $this->getAddonList([]);
$menu_model = (new SysMenu());
$addon_urls = $menu_model
->where([['addon', 'in', array_column($addon_list, 'key')], ['addon', 'not in', $keys], ['is_show', '=', 1], ['menu_type', '=', 1]])
->order('id asc')
->group('addon')
->column('router_path', 'addon');
if (!empty($addon_list)) {
foreach ($addon_list as $k => $v) {
if (in_array($v['key'], $keys)) {
continue;
}
$url = $addon_urls[$v['key']] ?? '';
$return['addon_tool']['list'][] = [
'title' => $v['title'],
'desc' => $v['desc'],
'icon' => $v['icon'],
'key' => $v['key'],
'url' => $url ? '/' . $url : ''
];
}
}
if($is_sort){
usort($return, function (array $a, array $b) {
$sortA = isset($a['sort']) ? (int)$a['sort'] : 0;
$sortB = isset($b['sort']) ? (int)$b['sort'] : 0;
return $sortB <=> $sortA;
});
}
return $return;
}
//生成菜单数据
public function getSpecialMenuList()
{
$auth_menu_list = (new AuthService())->getAuthMenuList('all',1);
$auth_menu_list = array_column($auth_menu_list, null, 'menu_key');
$auth_menu_list = $auth_menu_list['addon']['children'] ?? [];
$list = $this->showCustomer(false);//获取对应的需要展示的key
$addon_menu_list = MenuDict::getAddonChildMenu();
$menu_list = [];
foreach ($addon_menu_list as $item) {
$menu_key_list = array_column($list[$item['key']]['list'] ?? [], 'key');
$temp_menu = [
'app_type'=>'admin',
'menu_name' => $item['name'],
'menu_key' => $item['key'],
'menu_short_name' => $item['short_name'],
'parent_key' => 'addon',
'menu_type' => '0',
'icon' => 'iconfont iconzhuangxiu3',
'api_url' => '',
'router_path' => 'app/index',
'view_path' => 'app/index',
'methods' => 'get',
'sort' => $item['sort'],
'status' => '1',
'is_show' => '1',
];
$children = [];
foreach ($auth_menu_list as $datum_item) {
if (in_array($datum_item['menu_key'], $menu_key_list)) {
$children[] = $datum_item;
}
}
$temp_menu['children'] = $children;
$menu_list[] = $temp_menu;
}
usort($menu_list, function (array $a, array $b) {
$sortA = isset($a['sort']) ? (int)$a['sort'] : 0;
$sortB = isset($b['sort']) ? (int)$b['sort'] : 0;
return $sortB <=> $sortA;
});
return [
'parent_key' => 'addon',
'list' => $menu_list
];
}
private function getAllAddonAndTool()
{
$markting_list = $this->getMarketing() ?? [];

View File

@ -38,6 +38,8 @@ class ConfigService extends BaseAdminService
{
$info = (new CoreConfigService())->getConfig(ConfigKeyDict::ADMIN_LOGIN)['value'] ?? [];
return [
'login_logo' => '',
'login_bg_img' => '',
'is_captcha' => $info['is_captcha'] ?? 0,//是否启用验证码
'bg' => $info['bg'] ?? config('install.admin_login_bg'),//平台登录端 背景
];
@ -53,6 +55,8 @@ class ConfigService extends BaseAdminService
$config = [
'is_captcha' => $data['is_captcha'] ?? 0,//是否启用验证码
'bg' => $data['bg'] ?? '',//平台登录端 背景
'login_logo' => $data['login_logo'] ?? '',//平台登录端 背景
'login_bg_img' => $data['login_bg_img'] ?? '',//平台登录端 背景
];
(new CoreConfigService())->setConfig(ConfigKeyDict::ADMIN_LOGIN, $config);
return true;

View File

@ -11,11 +11,12 @@
namespace app\service\admin\channel;
use app\dict\sys\ConfigKeyDict;
use app\dict\channel\AppDict;
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\sys\CoreConfigService;
use core\base\BaseAdminService;
use core\exception\CommonException;
/**
* 配置服务层
@ -24,6 +25,13 @@ use core\base\BaseAdminService;
*/
class AppService extends BaseAdminService
{
public function __construct()
{
parent::__construct();
$this->model = new AppVersion();
}
/**
* 设置app信息
* @param array $value
@ -41,4 +49,133 @@ class AppService extends BaseAdminService
public function getConfig(){
return (new CoreAppService())->getConfig();
}
/**
* @param array $where
* @return array
* @throws \think\db\exception\DbException
*/
public function getVersionPage(array $where = [])
{
$order = 'id desc';
$search_model = $this->model->where([ [ 'id' ,">", 0 ] ])->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([ ['id', '=', $id] ])->findOrEmpty()->toArray();
}
/**
* 添加版本
* @param array $data
* @return mixed
*/
public function addVersion(array $data) {
$not_release = $this->model->where([['release_time', '=', 0]])->findOrEmpty();
if (!$not_release->isEmpty()) throw new CommonException("当前已存在未发布的版本");
$last_version = $this->model->where([['id', '>', 0]])->order('id desc')->findOrEmpty();
if (!$last_version->isEmpty() && $data['version_code'] <= $last_version['version_code']) throw new CommonException("版本号必须高于上一版本设置的值");
$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;
}
$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([ ['id', '<>', $id]])->order('id desc')->findOrEmpty();
if (!$last_version->isEmpty() && $data['version_code'] <= $last_version['version_code']) throw new CommonException("版本号必须高于上一版本设置的值");
$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]])->update($model);
return true;
}
/**
* 删除app版本
* @param int $id
* @return bool
*/
public function delVersion(int $id)
{
$model = $this->model->where([['id', '=', $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]);
}
if ($result['status'] == 'success') {
$this->model->update(['status' => AppDict::STATUS_UPLOAD_SUCCESS, 'package_path' => $result['file_path'], 'update_time' => time() ], ['task_key' => $key]);
}
return $result;
}
/**
* 发布
* @param string $key
* @return void
*/
public function release(int $id) {
$version = $this->model->where([['id', '=', $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

@ -779,7 +779,7 @@ class DiyService extends BaseAdminService
*/
public function getDiyTheme()
{
$addon_list = ( new CoreAddonService() )->getInstallAddonList();
$addon_list = ( new CoreAddonService() )->getInstallAddonList(false);
$apps = [];
foreach ($addon_list as $k => $v) {
if ($v[ 'type' ] == 'app') {

View File

@ -120,7 +120,7 @@ class NiuSmsService extends BaseAdminService
{
$account_info = $this->niu_service->loginAccount($params);
if ($account_info) {
(new CoreNiuSmsService())->setNiuLoginConfig($params, true);
$this->niu_service->setNiuLoginConfig($params, true);
}
return $account_info;
}

View File

@ -150,6 +150,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为不过期
];
@ -167,6 +168,7 @@ class ConfigService extends BaseAdminService
$info = [];
$info[ 'value' ] = [
'key' => '',
'amap_key' => '',
'is_open' => 1, // 是否开启定位
'valid_time' => 5 // 定位有效期/分钟过期后将重新获取定位信息0为不过期
];
@ -174,6 +176,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' ];
}
@ -199,11 +203,56 @@ class ConfigService extends BaseAdminService
/**
* 设置开发者key
* @param array $data
* @return \app\model\sys\SysConfig|array|bool|\think\Model
* @return array
*/
public function setDeveloperToken(array $data)
{
return ( new CoreConfigService() )->setConfig("DEVELOPER_TOKEN", $data);
}
/**
* 获取开发者key
* @return array
*/
public function getLayout()
{
return ( new CoreConfigService() )->getConfigValue("LAYOUT_SETTING");
}
/**
* 设置布局风格
* @param array $data
* @return array
*/
public function setLayout(array $data)
{
$config_service = new CoreConfigService();
$config = $config_service->getConfigValue( "LAYOUT_SETTING");
$config[ $data[ 'key' ] ] = $data[ 'value' ];
return ( new CoreConfigService() )->setConfig( "LAYOUT_SETTING", $config);
}
/**
* 获取色调设置
* @return array
*/
public function getThemeColor()
{
return ( new CoreConfigService() )->getConfigValue( "THEMECOLOR_SETTING");
}
/**
* 设置色调
* @param array $data
* @return array
*/
public function setThemeColor(array $data)
{
$config_service = new CoreConfigService();
$config = $config_service->getConfigValue("THEMECOLOR_SETTING");
$config[ $data[ 'key' ] ] = $data[ 'value' ];
return ( new CoreConfigService() )->setConfig("THEMECOLOR_SETTING", $config);
}
}

View File

@ -125,7 +125,7 @@ class StorageConfigService extends BaseAdminService
{
$config['default'] = $storage_type;
}else if ($config['default'] == $storage_type) {
$config['default'] = '';
throw new AdminException('UPLOAD_STORAGE_TYPE_ALL_CLOSE');
}
foreach ($storage_type_list[$storage_type]['params'] as $k_param => $v_param)
{

View File

@ -48,7 +48,7 @@ class UserService extends BaseAdminService
$field = 'uid,username,head_img,real_name,last_ip,last_time,login_count,status, role_ids, is_admin';
$search = [
'username' => $where[ 'username' ],
'realname' => $where[ 'realname' ],
'real_name' => $where[ 'realname' ],
'create_time' => $where[ 'create_time' ]
];
if (!empty($where[ 'role' ])) {
@ -99,32 +99,13 @@ class UserService extends BaseAdminService
'real_name' => $data[ 'real_name' ],
'password' => create_password($data[ 'password' ]),
'is_admin' => $data[ 'is_admin' ],
'is_admin' => $data[ 'is_admin' ]??0,
'role_ids' => $data[ 'role_ids' ],
];
$user = ( new SysUser() )->create($user_data);
return $user?->uid;
}
/**
* 添加对应站点用户(添加站点,同时添加站点用户,用于添加站点以及站点添加站点用户)
* @param $data
* @return bool
*/
public function addUser($data)
{
$role_ids = $data[ 'role_ids' ] ?? [];
$is_admin = $data[ 'is_admin' ] ?? 0;
$data[ 'is_admin' ] = $is_admin;
if (!$is_admin) {
$data[ 'role_ids' ] = $role_ids;
}
//添加用户
$uid = $this->add($data);
return $uid;
}
/**
* 更新对应站点用户
* @param $uid

View File

@ -11,7 +11,11 @@
namespace app\service\admin\weapp;
use app\dict\sys\CloudDict;
use app\service\core\site\CoreSiteService;
use app\service\core\weapp\CoreWeappCloudService;
use app\service\core\weapp\CoreWeappConfigService;
use app\service\core\weapp\CoreWeappService;
use core\base\BaseAdminService;
use app\model\weapp\WeappVersion;
use core\exception\CommonException;
@ -33,13 +37,16 @@ class WeappVersionService extends BaseAdminService
*/
public function add(array $data)
{
$uploading = $this->model->where([ ['status', '=', 0] ])->field('id')->findOrEmpty();
$uploading = $this->model->where([ ['status', '=', 0]])->field('id')->findOrEmpty();
if (!$uploading->isEmpty()) throw new CommonException('WEAPP_UPLOADING');
$version_no = $this->model->where([ ['id', '>', 0] ])->order('version_no desc')->field('version_no')->findOrEmpty()->toArray()['version_no'] ?? 0;
if (empty($data['version'])) {
$version_no = $this->model->where([['id', '>', 0]])->order('version_no desc')->field('version_no')->findOrEmpty()->toArray()['version_no'] ?? 0;
$version_no += 1;
$version = "1.0.{$version_no}";
}else{
$version_no = 0;//自定义的version_no标记为0 不因自定义版本打断默认的连续性
$version = $data['version'];
}
$upload_res = (new CoreWeappCloudService())->uploadWeapp([
'version' => $version,
'desc' => $data['desc'] ?? ''
@ -55,9 +62,17 @@ class WeappVersionService extends BaseAdminService
return $res->id;
}
public function getPreviewImage() {
public function getPreviewImage()
{
try {
$version = $this->model->where([['id', '>', 0]])->order('id desc')->findOrEmpty();
if (!$version->isEmpty() || in_array($version['status'], [CloudDict::APPLET_UPLOAD_SUCCESS, CloudDict::APPLET_AUDITING])) {
if ($version['from_type'] == 'cloud_build') {
return (new CoreWeappCloudService())->getWeappPreviewImage();
} else {
return image_to_base64((new CoreWeappService())->getWeappPreviewImage(), true);
}
}
} catch (\Exception $e) {
return '';
}
@ -74,7 +89,8 @@ class WeappVersionService extends BaseAdminService
$order = 'create_time desc';
$where[] = ['id', '>', 0];
$search_model = $this->model->where($where)->field($field)->order($order)->append(['status_name']);
return $this->pageQuery($search_model);
$list = $this->pageQuery($search_model);
return $list;
}
/**
@ -87,7 +103,7 @@ class WeappVersionService extends BaseAdminService
{
$data['status'] = 0;
$data['update_time'] = time();
$this->model->where([['id', '=', $id] ])->create($data);
$this->model->where([['id', '=', $id]])->create($data);
return true;
}
@ -96,7 +112,8 @@ class WeappVersionService extends BaseAdminService
* @param int $id
* @return true
*/
public function del(int $id){
public function del(int $id)
{
$this->model->where([['id', '=', $id]])->delete();
return true;
}
@ -106,7 +123,20 @@ class WeappVersionService extends BaseAdminService
* @param string $key
* @return null
*/
public function getUploadLog(string $key) {
return (new CoreWeappCloudService())->getWeappCompileLog($key);
public function getUploadLog(string $key)
{
$build_log = (new CoreWeappCloudService())->getWeappCompileLog($key);
if (isset($build_log['data']) && isset($build_log['data'][0]) && is_array($build_log['data'][0])) {
$last = end($build_log['data'][0]);
if ($last['code'] == 0) {
(new WeappVersion())->update(['status' => CloudDict::APPLET_UPLOAD_FAIL, 'fail_reason' => $last['msg'] ?? '', 'update_time' => time()], ['task_key' => $key]);
return $build_log;
}
if ($last['percent'] == 100) {
(new WeappVersion())->update(['status' => CloudDict::APPLET_UPLOAD_SUCCESS, 'update_time' => time()], ['task_key' => $key]);
}
}
return $build_log;
}
}

View File

@ -0,0 +1,34 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址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([
['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

@ -115,10 +115,11 @@ class LoginService extends BaseApiService
if (!empty($params['openid'])) {
$mobile = $params[ 'mobile' ];
$openid = $params[ 'openid' ];
;
$openid_field = match ( $this->channel ) {
'wechat' => 'wx_openid',
'weapp' => 'weapp_openid',
'app' => 'wxapp_openid',
default => ''
};
@ -185,7 +186,7 @@ class LoginService extends BaseApiService
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 ], $expire_time);
return TokenAuth::createToken($member_info->member_id, AppTypeDict::API, [ 'member_id' => $member_info->member_id, 'username' => $member_info->username ] , $expire_time);
}
/**
@ -335,6 +336,7 @@ class LoginService extends BaseApiService
* 重置密码
* @param string $mobile
* @param string $password
* @return true
*/
public function resetPassword(string $mobile, string $password)
{

View File

@ -12,8 +12,10 @@
namespace app\service\api\sys;
use app\service\core\addon\CoreAddonService;
use app\service\core\channel\CoreAppService;
use app\service\core\sys\CoreConfigService;
use app\service\core\sys\CoreSysConfigService;
use app\service\core\weapp\CoreWeappConfigService;
use core\base\BaseApiService;
/**
@ -88,4 +90,12 @@ class ConfigService extends BaseApiService
return (new CoreSysConfigService())->getMap();
}
public function getAppConfig() {
$config = (new CoreAppService())->getConfig();
if (!empty($config) && isset($config['wechat_app_secret'])) unset($config['wechat_app_secret']);
$weapp_config = (new CoreWeappConfigService())->getWeappConfig();
$config['weapp_original'] = $weapp_config['weapp_original'];
return $config;
}
}

View File

@ -160,6 +160,7 @@ class WechatAuthService extends BaseApiService
if (!empty($avatar)) $member_info->headimg = $avatar;
if (!empty($nickname)) $member_info->nickname = $nickname;
}
if (empty($member_info->wx_unionid) && !empty($unionid)) $member_info->wx_unionid = $unionid;
return $login_service->login($member_info, MemberLoginTypeDict::WECHAT);
}
}

View File

@ -133,6 +133,7 @@ class CoreAddonCloudService extends CoreCloudBaseService
return $build_log;
}
if ($last['percent'] == 100) {
$addon = isset($install_task['addon_list']) ? implode(',', $install_task['addon_list']) : $addon;
$build_log['data'][0] = $this->buildSuccess($addon, $build_log['data'][0], $install_task['timestamp']);
}
}

View File

@ -21,6 +21,7 @@ use think\db\exception\DbException;
use think\db\exception\PDOException;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Log;
/**
* 安装服务层
@ -61,11 +62,14 @@ class CoreAddonInstallService extends CoreAddonBaseService
private $install_task = null;
private $addon_list = [];
public function __construct($addon)
{
parent::__construct();
$this->addon = $addon;
$this->install_addon_path = $this->addon_path . $addon . DIRECTORY_SEPARATOR;
$this->addon_list = explode(',', $addon);
$this->addon = $this->addon_list[0];
$this->install_addon_path = $this->addon_path . $this->addon . DIRECTORY_SEPARATOR;
$this->cache_key = "install_{$addon}";
@ -91,30 +95,17 @@ class CoreAddonInstallService extends CoreAddonBaseService
*/
public function installCheck()
{
$from_admin_dir = $this->install_addon_path . 'admin' . DIRECTORY_SEPARATOR;
$from_web_dir = $this->install_addon_path . 'web' . DIRECTORY_SEPARATOR;
$from_wap_dir = $this->install_addon_path . 'uni-app' . DIRECTORY_SEPARATOR;
$from_resource_dir = $this->install_addon_path . 'resource' . DIRECTORY_SEPARATOR;
// 放入的文件
$to_admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon'. DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon'. DIRECTORY_SEPARATOR;
$to_web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR;
$to_wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon'. DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon'. DIRECTORY_SEPARATOR;
$to_resource_dir = public_path() . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
$to_resource_dir = public_path() . 'addon' . DIRECTORY_SEPARATOR;
if (!is_dir($this->root_path . 'admin' . DIRECTORY_SEPARATOR)) throw new CommonException('ADMIN_DIR_NOT_EXIST');
if (!is_dir($this->root_path . 'web' . DIRECTORY_SEPARATOR)) throw new CommonException('WEB_DIR_NOT_EXIST');
if (!is_dir($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR)) throw new CommonException('UNIAPP_DIR_NOT_EXIST');
// 配置文件
$package_path = $this->install_addon_path . 'package' . DIRECTORY_SEPARATOR;
$package_file = [];
search_dir($package_path, $package_file);
$package_file = array_map(function ($file) use ($package_path) {
return str_replace($package_path . DIRECTORY_SEPARATOR, '', $file);
}, $package_file);
$data = [
// 目录检测
'dir' => [
@ -125,10 +116,7 @@ class CoreAddonInstallService extends CoreAddonBaseService
]
];
if (is_dir($from_admin_dir)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $from_admin_dir), 'status' => is_readable($from_admin_dir)];
if (is_dir($from_web_dir)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $from_web_dir), 'status' => is_readable($from_web_dir)];
if (is_dir($from_wap_dir)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $from_wap_dir), 'status' => is_readable($from_wap_dir)];
if (is_dir($from_resource_dir)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $from_resource_dir), 'status' => is_readable($from_resource_dir)];
if (is_dir($this->addon_path)) $data['dir']['is_readable'][] = ['dir' => str_replace(project_path(), '', $this->addon_path), 'status' => is_readable($this->addon_path)];
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_admin_dir), 'status' => is_dir($to_admin_dir) ? is_write($to_admin_dir) : mkdir($to_admin_dir, 0777, true)];
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_web_dir), 'status' => is_dir($to_web_dir) ? is_write($to_web_dir) : mkdir($to_web_dir, 0777, true)];
@ -136,7 +124,8 @@ class CoreAddonInstallService extends CoreAddonBaseService
$data['dir']['is_write'][] = ['dir' => str_replace(project_path(), '', $to_resource_dir), 'status' => is_dir($to_resource_dir) ? is_write($to_resource_dir) : mkdir($to_resource_dir, 0777, true)];
// 校验niucloud/public下 wap web admin 目录及文件是否可读可写
$check_res = checkDirPermissions(public_path() . 'wap');
$check_res = checkDirPermissions($this->addon_path);
$check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'wap'));
$check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'admin'));
$check_res = array_merge2($check_res, checkDirPermissions(public_path() . 'web'));
@ -151,13 +140,65 @@ class CoreAddonInstallService extends CoreAddonBaseService
}
}
$check_res = array_merge(
array_column($data['dir']['is_readable'], 'status'),
array_column($data['dir']['is_write'], 'status')
);
// 检测插件
$framework_version = config('version.version');
$framework_version_arr = explode('.', $framework_version);
$data['addon_check'] = [];
foreach ($this->addon_list as $addon) {
$install_data = $this->getAddonConfig($addon);
if (empty($install_data)) {
$data['addon_check'][] = [
'msg' => "未找到插件{$addon}的info.json文件",
'status' => false
];
continue;
}
$core_addon_service = new CoreAddonService();
if (!empty($core_addon_service->getInfoByKey($addon))) {
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件已安装,不能重复安装',
'status' => false
];
continue;
}
if (isset($install_data['support_app']) && !empty($install_data['support_app']) &&
empty($core_addon_service->getInfoByKey($install_data['support_app'])) && !in_array($install_data['support_app'], $this->addon_list)) {
$support_app_data = $this->getAddonConfig($install_data['support_app']);
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件的主应用'. (empty($support_app_data) ? $install_data['support_app'] : $support_app_data['title']) .'插件还未安装,请先安装主应用',
'status' => false
];
continue;
}
if (!isset($install_data['support_version']) || empty($install_data['support_version'])) {
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件的info.json文件中未检测到匹配框架当前版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]的信息无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>',
'status' => false
];
continue;
}
$support_framework_arr = explode('.', $install_data['support_version']);
if ($framework_version_arr[0].$framework_version_arr[1] != $support_framework_arr[0].$support_framework_arr[1]) {
if ((float) "$support_framework_arr[0].$support_framework_arr[1]" < (float) "$framework_version_arr[0].$framework_version_arr[1]") {
$data['addon_check'][] = [
'msg' => $install_data['title'] . '插件的info.json文件中检测到支持的框架版本['. $install_data['support_version'] .']低于当前框架版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>',
'status' => false
];
}
}
}
// 是否通过校验
$data['is_pass'] = !in_array(false, $check_res);
$data['is_pass'] = !in_array(false, array_merge(
array_column($data['dir']['is_readable'], 'status'),
array_column($data['dir']['is_write'], 'status'),
array_column($data['addon_check'], 'status')
));
$data['file_permission_is_pass'] = !in_array(false, array_merge(
array_column($data['dir']['is_readable'], 'status'),
array_column($data['dir']['is_write'], 'status'),
));
Cache::set($this->cache_key . '_install_check', $data['is_pass']);
return $data;
}
@ -168,60 +209,36 @@ class CoreAddonInstallService extends CoreAddonBaseService
*/
public function install(string $mode = 'local')
{
$core_addon_service = new CoreAddonService();
if (!empty($core_addon_service->getInfoByKey($this->addon))) throw new AddonException('REPEAT_INSTALL');
$install_data = $this->getAddonConfig($this->addon);
if (empty($install_data)) throw new AddonException('ADDON_INFO_FILE_NOT_EXIST');
$framework_version = config('version.version');
$framework_version_arr = explode('.', $framework_version);
// 检测框架版本是否支持
if (!isset($install_data['support_version']) || empty($install_data['support_version']))
throw new AddonException('您要安装的插件或应用的info.json文件中未检测到匹配框架当前版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]的信息无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>');
$support_framework_arr = explode('.', $install_data['support_version']);
if ($framework_version_arr[0].$framework_version_arr[1] != $support_framework_arr[0].$support_framework_arr[1]) {
if ((float) "$support_framework_arr[0].$support_framework_arr[1]" < (float) "$framework_version_arr[0].$framework_version_arr[1]") {
throw new AddonException('您要安装的插件或应用的info.json文件中检测到支持的框架版本['. $install_data['support_version'] .']低于当前框架版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>');
}
}
$check_res = Cache::get($this->cache_key . '_install_check');
if (!$check_res) throw new CommonException('INSTALL_CHECK_NOT_PASS');
if ($this->install_task) throw new CommonException('ADDON_INSTALLING');
$this->install_task = [ 'mode' => $mode, 'addon' => $this->addon, 'step' => [], 'timestamp' => time() ];
$this->install_task = [ 'mode' => $mode, 'addon' => $this->addon, 'addon_list' => $this->addon_list, 'step' => [], 'fail_addon' => [], 'timestamp' => time() ];
Cache::set('install_task', $this->install_task);
set_time_limit(0);
$install_step = ['installDir','installWap','installDepend'];
if (!empty($install_data['compile']) || $mode == 'cloud') {
// 备份前端目录
$install_step[] = 'backupFrontend';
}
$this->backupFrontend();
$tips = [];
if ($mode != 'cloud') $tips[] = get_lang('dict_addon.install_after_update');
foreach ($this->addon_list as $addon) {
$this->install_task['addon'] = $addon;
Cache::set('install_task', $this->install_task);
$this->addon = $addon;
$this->install_addon_path = $this->addon_path . $this->addon . DIRECTORY_SEPARATOR;
$install_data = $this->getAddonConfig($addon);
$install_step = ['installDir','installDepend'];
// 检测插件是否存在编译内容
if (!empty($install_data['compile'])) {
$install_step[] = 'coverCompile';
}
if ($mode == 'cloud') {
$install_step[] = 'cloudInstall';
} else {
$install_step[] = 'handleAddonInstall';
}
try {
foreach ($install_step as $step) {
$this->install_task['step'][] = $step;
$this->$step();
if ($step != 'handleAddonInstall') Cache::set('install_task', $this->install_task);
}
if ($mode != 'cloud') {
// 配置文件
$package_path = $this->install_addon_path . 'package' . DIRECTORY_SEPARATOR;
@ -231,49 +248,68 @@ class CoreAddonInstallService extends CoreAddonBaseService
return str_replace($package_path . DIRECTORY_SEPARATOR, '', $file);
}, $package_file);
$tips = [get_lang('dict_addon.install_after_update')];
if (in_array('admin-package.json', $package_file)) $tips[] = get_lang('dict_addon.install_after_admin_update');
if (in_array('composer.json', $package_file)) $tips[] = get_lang('dict_addon.install_after_composer_update');
if (in_array('uni-app-package.json', $package_file)) $tips[] = get_lang('dict_addon.install_after_wap_update');
if (in_array('web-package.json', $package_file)) $tips[] = get_lang('dict_addon.install_after_web_update');
return $tips;
if (in_array('admin-package.json', $package_file) && !in_array(get_lang('dict_addon.install_after_admin_update'), $tips)) $tips[] = get_lang('dict_addon.install_after_admin_update');
if (in_array('composer.json', $package_file) && !in_array(get_lang('dict_addon.install_after_composer_update'), $tips)) $tips[] = get_lang('dict_addon.install_after_composer_update');
if (in_array('uni-app-package.json', $package_file) && !in_array(get_lang('dict_addon.install_after_wap_update'), $tips)) $tips[] = get_lang('dict_addon.install_after_wap_update');
if (in_array('web-package.json', $package_file) && !in_array(get_lang('dict_addon.install_after_web_update'), $tips) ) $tips[] = get_lang('dict_addon.install_after_web_update');
}
return true;
} catch (\Exception $e) {
try {
$this->install_task['step'] = [];
foreach ($install_step as $step) {
$this->install_task['step'][] = $step;
Cache::set('install_task', $this->install_task);
$this->installExceptionHandle();
$this->$step();
}
} catch (\Exception $e) {
$this->install_task['fail_addon'] = $this->addon;
$this->installExceptionHandle($addon);
if (count($this->addon_list) == 1) {
throw new CommonException($e->getMessage());
}
Log::write($install_data['title'] . '插件安装失败');
Log::write($e->getTrace());
$tips[] = $install_data['title'] . '插件安装失败';
}
}
$this->installWap();
if ($mode == 'cloud') {
$this->install_task['tips'] = $tips;
Cache::set('install_task', $this->install_task);
$this->cloudInstall();
} else {
$this->handleAddonInstall();
}
return empty($tips) ? true : $tips;
}
/**
* 安装异常处理
* @return void
*/
public function installExceptionHandle() {
public function installExceptionHandle($name = '') {
$install_task = Cache::get('install_task');
if (in_array('installDir', $install_task['step'])) {
foreach ($this->addon_list as $addon) {
if (!empty($name) && $name != $addon) continue;
@$this->uninstallDir();
}
if (in_array('installWap', $install_task['step'])) {
@$this->uninstallWap();
}
if (in_array('backupFrontend', $install_task['step'])) {
@$this->revertFrontendBackup();
}
Cache::set('install_task', null);
}
/**
* 取消安装任务
* @return void
*/
public function cancleInstall() {
if (Cache::get('install_task')) $this->installExceptionHandle();
if (Cache::get('install_task')) {
$this->installExceptionHandle();
Cache::set('install_task', null);
}
}
/**
@ -409,6 +445,16 @@ class CoreAddonInstallService extends CoreAddonBaseService
*/
public function handleAddonInstall()
{
$core_addon_service = new CoreAddonService();
$fail_addon = $this->install_task['fail_addon'] ?? [];
foreach ($this->addon_list as $addon) {
if (in_array($addon, $fail_addon)) continue;
$this->addon = $addon;
$this->install_addon_path = $this->addon_path . $this->addon . DIRECTORY_SEPARATOR;
// 执行安装sql
$this->installSql();
// 安装菜单
@ -416,18 +462,20 @@ class CoreAddonInstallService extends CoreAddonBaseService
// 安装计划任务
$this->installSchedule();
$core_addon_service = new CoreAddonService();
$install_data = $this->getAddonConfig($this->addon);
$install_data['icon'] = 'addon/' . $this->addon . '/icon.png';
$core_addon_service->set($install_data);
//清理缓存
Cache::tag(self::$cache_tag_name)->clear();
//执行命令
//执行插件安装方法
$class = "addon\\" . $this->addon . "\\" . 'Addon';
if (class_exists($class)) {
(new $class())->install();
}
}
//清理缓存
Cache::tag(self::$cache_tag_name)->clear();
// 清除插件安装中标识
Cache::delete('install_task');
Cache::delete($this->cache_key . '_install_check');
@ -505,8 +553,7 @@ class CoreAddonInstallService extends CoreAddonBaseService
/**
* 插件卸载环境检测
* @param string $addon
* @return void
* @return array|array[]
*/
public function uninstallCheck() {
$data = [
@ -546,6 +593,7 @@ class CoreAddonInstallService extends CoreAddonBaseService
*/
public function uninstall()
{
(new CoreAddonDevelopBuildService())->build($this->addon);
//执行插件卸载方法
@ -684,13 +732,13 @@ class CoreAddonInstallService extends CoreAddonBaseService
{
// 编译 diy-group 自定义组件代码文件
$this->compileDiyComponentsCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon);
$this->compileDiyComponentsCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon_list);
// 编译 pages.json 页面路由代码文件
$this->installPageCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR);
$this->installPageCode($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon_list);
// 编译 加载插件标题语言包
$this->compileLocale($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon);
$this->compileLocale($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $this->addon_list);
}
@ -777,7 +825,7 @@ class CoreAddonInstallService extends CoreAddonBaseService
/**
* 处理编译之后的文件
* @return void
* @return true
*/
public function handleBuildFile() {
return true;

View File

@ -219,10 +219,10 @@ class CoreAddonService extends CoreAddonBaseService
* 查询已安装的有效的应用
* @return array
*/
public function getInstallAddonList()
public function getInstallAddonList($is_change_img=true)
{
$addon_list = $this->model->where([['status', '=', AddonDict::ON]])->append(['status_name'])->column('title, icon, key, desc, status, type, support_app', 'key');
if (!empty($addon_list)) {
if (!empty($addon_list) &&$is_change_img) {
foreach ($addon_list as &$data) {
$data['icon'] = is_file($data['icon']) ? image_to_base64($data['icon']) : '';
}

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";
@ -83,7 +83,12 @@ trait WapTrait
}
}
if (!empty($addon)) {
$addon_arr[] = $addon; // 追加新装插件
// 追加新装插件
if (is_array($addon)) {
$addon_arr = array_merge($addon_arr, $addon);
} else if (is_string($addon)) {
$addon_arr[] = $addon;
}
}
$addon_arr = array_unique($addon_arr);
@ -121,9 +126,12 @@ trait WapTrait
$content .= " </view>\n";
$content .= " </view>\n";
$content .= " </template>\n";
$content .= " <template v-if=\"diyStore.mode == '' && data.global && diyGroup.showCopyright.value && data.global.copyright && data.global.copyright.isShow\">\n";
$content .= " <copy-right :textColor=\"data.global.copyright.textColor\" />\n";
$content .= " </template>\n\n";
$content .= " <template v-if=\"diyStore.mode == '' && data.global && data.global.bottomTabBar && data.global.bottomTabBar.isShow\">\n";
$content .= " <view class=\"pt-[20rpx]\"></view>\n";
$content .= " <tabbar />\n";
$content .= " <tabbar :addon=\"data.global.bottomTabBar.designNav.key\" />\n";
$content .= " </template>\n";
$content .= " </view>\n";
$content .= "</template>\n";
@ -181,7 +189,7 @@ trait WapTrait
* @param $compile_path
* @return bool|int|void
*/
public function installPageCode($compile_path)
public function installPageCode($compile_path, $addon = '')
{
if (!file_exists($this->geAddonPackagePath($this->addon) . 'uni-app-pages.php')) return;
@ -192,7 +200,25 @@ trait WapTrait
}
$pages = [];
$addon_arr = array_unique(array_merge([ $this->addon ], array_column(( new CoreAddonService() )->getInstallAddonList(), 'key')));
$addon_service = new CoreAddonService();
$addon_list = $addon_service->getInstallAddonList();
$addon_arr = [];
if (!empty($addon_list)) {
foreach ($addon_list as $k => $v) {
$addon_arr[] = $v[ 'key' ];
}
}
if (!empty($addon)) {
// 追加新装插件
if (is_array($addon)) {
$addon_arr = array_merge($addon_arr, $addon);
} else if (is_string($addon)) {
$addon_arr[] = $addon;
}
}
$addon_arr = array_unique($addon_arr);
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';
@ -281,10 +307,18 @@ trait WapTrait
$json = json_decode($app_json, true);
// 清空当前安装/卸载的插件语言包
foreach ($json as $jk => $jc) {
if (is_array($addon)) {
foreach ($addon as $key) {
if (strpos($jk, $key) !== false) {
unset($json[ $jk ]);
}
}
} else {
if (strpos($jk, $addon) !== false) {
unset($json[ $jk ]);
}
}
}
$locale_data[ $cv ] = [
'path' => $ck,
'json' => $json
@ -302,8 +336,16 @@ trait WapTrait
$addon_arr[] = $v[ 'key' ];
}
}
$addon_arr[] = $addon; // 追加新装插件
if (!empty($addon)) {
// 追加新装插件
if (is_array($addon)) {
$addon_arr = array_merge($addon_arr, $addon);
} else if (is_string($addon)) {
$addon_arr[] = $addon;
}
}
$addon_arr = array_unique($addon_arr);
foreach ($addon_arr as $k => $v) {
$addon_path = $compile_path . str_replace('/', DIRECTORY_SEPARATOR, 'addon/' . $v . '/locale'); // 插件语言包根目录
$addon_file_arr = getFileMap($addon_path, []);
@ -337,7 +379,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 +389,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

@ -90,8 +90,8 @@ class CoreAppletSiteVersionService extends BaseCoreService
$list = $this->model->where($where)->with(['appletVersion'])->select()->toArray();
$list = array_column($list, null, 'version_num');
ksort($list);
$site_version = reset($list);
return $site_version['version'] ?? '';
$version = reset($list);
return $version['version'] ?? '';
}
/**

View File

@ -0,0 +1,328 @@
<?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\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 $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)
{
$action_token = ( new CoreModuleService() )->getActionToken('appbuild', [ 'data' => [ 'product_key' => BaseNiucloudClient::PRODUCT ] ]);
$app_config = (new CoreAppService())->getConfig();
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()['wap_url'];
$map_config = ( new CoreConfigService() )->getConfigValue('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', '.git' ]);
// 替换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' ] ];
}
/**
* 处理底部导航【暂时停止调用存在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);
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;
}
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

@ -39,6 +39,16 @@ class CoreAppService extends BaseCoreService
public function getConfig()
{
$info = (new CoreConfigService())->getConfig(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;
}

View File

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

View File

@ -33,6 +33,7 @@ class CoreMemberAccountService extends BaseCoreService
$member_model = new Member();
$member_account_log_model = new MemberAccountLog();
//账户检测
Db::startTrans();
$member_info = $member_model->where([
[ 'member_id', '=', $member_id ],
])->field($account_type . ',' . $account_type . "_get" . ', username, mobile, nickname')->lock(true)->find();
@ -55,8 +56,6 @@ class CoreMemberAccountService extends BaseCoreService
'memo' => $memo,
'related_id' => $related_id,
];
Db::startTrans();
try {
$res = $member_account_log_model->create($data);

View File

@ -80,6 +80,10 @@ class CoreMemberCashOutService extends BaseCoreService
$cash_out->account_type . '_cash_outing' => $member[$cash_out->account_type . '_cash_outing'] - $cash_out->apply_money
]
);
//提现完成后事件
event('AfterCashFinish',[
'cash_out'=>$cash_out
]);
return true;
}
@ -169,12 +173,16 @@ class CoreMemberCashOutService extends BaseCoreService
$core_member_cash_out_service->audit($cash_out->id, 'agree');
}
Db::commit();
//发起提现后事件
event('AfterCashApply',[
'member_id'=>$member_id,
'data'=>$data
]);
return $cash_out['id'];
} catch ( Exception $e ) {
Db::rollback();
throw new CommonException($e->getMessage());
}
return true;
}
/**
@ -237,7 +245,7 @@ class CoreMemberCashOutService extends BaseCoreService
// try {
//会员提现需要在前端手动发起
// if($cash_out['transfer_type'] != TransferDict::WECHAT){
// $this->transfer($cash_out['id']);
// $this->transfer( $cash_out['id']);
// }
// } catch ( Throwable $e ) {
@ -341,6 +349,10 @@ class CoreMemberCashOutService extends BaseCoreService
$cash_out->account_type . '_cash_outing' => $member[$cash_out->account_type . '_cash_outing'] - $cash_out->apply_money
]
);
//提现拒绝后事件
event('AfterCashRefuse',[
'cash_out'=>$cash_out
]);
return true;
}
@ -382,7 +394,7 @@ class CoreMemberCashOutService extends BaseCoreService
/**
* 取消提现
* @param int $id
* @return void
* @return true
*/
public function cancel(int $id){
$cash_out = $this->find($id);

View File

@ -408,7 +408,7 @@ class CoreNiuSmsService extends BaseAdminService
// 获取域名(含端口)
$host = $_SERVER['HTTP_HOST'];
// 组合成全域名
$return_url = $protocol . '://' . $host . "/site/setting/sms/pay";
$return_url = $protocol . '://' . $host . "/setting/sms/pay";
$url = $this->niushop_url_prefix . sprintf(self::ORDER_PAY_URL, $username);
$params['notify_url'] = $this->niushop_url_prefix . self::ORDER_NOTIFY_URL;

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;
@ -119,10 +120,15 @@ class CorePayChannelService extends BaseCoreService
//查询公众号配置
$core_weapp_config_service = new CoreWeappConfigService();
$mini_app_id = $core_weapp_config_service->getWeappConfig()[ 'app_id' ];//小程序appid
// 查询微信移动应用配置
$core_app_service = new CoreAppService();
$app_id = $core_app_service->getConfig()['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

@ -40,7 +40,7 @@ class CoreConfigService extends BaseCoreService
{
$cache_name = 'config_cache';
$where = array(
[ 'config_key', '=', $key ]
[ 'config_key', '=', $key ],
);
// 缓存清理
$info = cache_remember(
@ -71,7 +71,7 @@ class CoreConfigService extends BaseCoreService
public function setConfig(string $key, array $value)
{
$where = array(
[ 'config_key', '=', $key ]
['config_key', '=', $key]
);
$data = array(
'config_key' => $key,
@ -86,7 +86,7 @@ class CoreConfigService extends BaseCoreService
$res = $this->model->where($where)->save($data);
}
Cache::tag(self::$cache_tag_name)->clear();
Cache::tag(self::$cache_tag_name )->clear();
return $res;
}
@ -96,10 +96,10 @@ class CoreConfigService extends BaseCoreService
* @param string $key
* @return bool
*/
public function modifyStatus(int $status, string $key)
public function modifyStatus( int $status, string $key)
{
$where = array(
[ 'config_key', '=', $key ]
[ 'config_key', '=', $key ],
);
$data = array(
'status' => $status,
@ -112,12 +112,27 @@ class CoreConfigService extends BaseCoreService
* @param string $key
* @return array|mixed
*/
public function getConfigValue(string $key)
public function getConfigValue( string $key)
{
$config_info = $this->getConfig($key);
$config_info = $this->getConfig( $key);
if (empty($config_info)) {
return [];
}
return $config_info[ 'value' ];
}
/**
* 清除配置
* @param string $key
* @param array $value
* @return SysConfig|bool|Model
*/
public function clearConfig(string $key)
{
$where = array(
[ 'config_key', '=', $key ],
);
$this->model->where($where)->delete();
Cache::tag(self::$cache_tag_name)->clear();
}
}

View File

@ -66,6 +66,7 @@ class CoreWeappAuthService extends BaseCoreService
public function getUserPhoneNumber(string $code)
{
$api = CoreWeappService::appApiClient();
CoreWeappService::refreshToken(); // 为防止多次拒绝手机号的情况需要刷新token
return $api->postJson('wxa/business/getuserphonenumber', [
'code' => (string) $code
]);

View File

@ -47,7 +47,6 @@ class CoreWeappCloudService extends CoreCloudBaseService
*/
public function uploadWeapp(array $data)
{
if (!request()->isSsl()) throw new CommonException('CURR_SITE_IS_NOT_OPEN_SSL');
$config = ( new CoreWeappConfigService() )->getWeappConfig();
if (empty($config[ 'app_id' ])) throw new CommonException('WEAPP_APPID_EMPTY');

View File

@ -47,7 +47,6 @@ class CoreWeappConfigService extends BaseCoreService
/**
* 微信小程序配置
* @param
* @param array $data
* @return SysConfig|bool|Model
*/
@ -68,4 +67,33 @@ class CoreWeappConfigService extends BaseCoreService
];
return ( new CoreConfigService() )->setConfig(ConfigKeyDict::WEAPP, $config);
}
/**
* 获取小程序授权信息
* @return mixed
*/
public function getWeappAuthorizationInfo()
{
return ( new CoreConfigService() )->getConfigValue(ConfigKeyDict::WEAPP_AUTHORIZATION_INFO);
}
/**
* 设置小程序授权信息
* @param array $config
* @return SysConfig|bool|Model
*/
public function setWeappAuthorizationInfo(array $config)
{
return ( new CoreConfigService() )->setConfig(ConfigKeyDict::WEAPP_AUTHORIZATION_INFO, $config);
}
/**
* 清除小程序授权信息
* @param array $config
* @return SysConfig|bool|Model
*/
public function clearWeappAuthorizationInfo()
{
return ( new CoreConfigService() )->clearConfig(ConfigKeyDict::WEAPP_AUTHORIZATION_INFO);
}
}

View File

@ -11,6 +11,7 @@
namespace app\service\core\weapp;
use app\service\core\wxoplatform\CoreOplatformService;
use core\base\BaseCoreService;
use core\exception\CommonException;
use core\exception\WechatException;
@ -35,13 +36,13 @@ class CoreWeappService extends BaseCoreService
$core_weapp_service = new CoreWeappConfigService();
$weapp_config = $core_weapp_service->getWeappConfig();
if (empty($weapp_config[ 'app_id' ]) || empty($weapp_config[ 'app_secret' ])) throw new WechatException('WEAPP_NOT_EXIST');//公众号未配置
if (empty($weapp_config['app_id']) || empty($weapp_config['app_secret'])) throw new WechatException('WEAPP_NOT_EXIST');//公众号未配置
$config = array(
'app_id' => $weapp_config[ 'app_id' ],
'secret' => $weapp_config[ 'app_secret' ],
'token' => $weapp_config[ 'token' ],
'aes_key' => $weapp_config[ 'encryption_type' ] == 'not_encrypt' ? '' : $weapp_config[ 'encoding_aes_key' ],// 明文模式请勿填写 EncodingAESKey
'app_id' => $weapp_config['app_id'],
'secret' => $weapp_config['app_secret'],
'token' => $weapp_config['token'],
'aes_key' => $weapp_config['encryption_type'] == 'not_encrypt' ? '' : $weapp_config['encoding_aes_key'],// 明文模式请勿填写 EncodingAESKey
'http' => [
'throw' => true, // 状态码非 200、300 时是否抛出异常,默认为开启
'timeout' => 5.0,
@ -49,6 +50,7 @@ class CoreWeappService extends BaseCoreService
],
);
return new Application($config);
}
@ -62,6 +64,21 @@ class CoreWeappService extends BaseCoreService
return self::app()->getClient();
}
/**
* 刷新token
* @return void
* @throws InvalidArgumentException
*/
public static function refreshToken()
{
$core_weapp_service = new CoreWeappConfigService();
$weapp_config = $core_weapp_service->getWeappConfig();
if (!$weapp_config['is_authorization']) {
self::app()->getAccessToken()->refresh();
}
}
/**
* 生成小程序码
* @param $page
@ -75,7 +92,7 @@ class CoreWeappService extends BaseCoreService
{
$scene = [];
foreach ($data as $v) {
$scene[] = $v[ 'key' ] . '-' . $v[ 'value' ];
$scene[] = $v['key'] . '-' . $v['value'];
}
$response = self::appApiClient()->postJson('/wxa/getwxacodeunlimit', [
'scene' => implode('&', $scene),
@ -86,7 +103,7 @@ class CoreWeappService extends BaseCoreService
]);
if ($response->isFailed()) {
// 出错了,处理异常
throw new CommonException('微信小程序码生成失败errcode:' . $response[ 'errcode' ] . 'errmsg:' . $response[ 'errmsg' ]);
throw new CommonException('微信小程序码生成失败errcode:' . $response['errcode'] . 'errmsg:' . $response['errmsg']);
}
$response->saveAs($filepath);
return $filepath;
@ -94,7 +111,7 @@ class CoreWeappService extends BaseCoreService
/**
* 获取小程序体验码
* @return void
* @return string
*/
public function getWeappPreviewImage()
{

View File

@ -17,6 +17,7 @@ use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use EasyWeChat\Kernel\Support\Collection;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Http\Message\ResponseInterface;
use think\facade\Log;
/**
* 微信小程序服务提供
@ -38,12 +39,13 @@ class CoreWeappTemplateService extends BaseCoreService
*/
public function send(string $template_id, string $touser, array $data, string $page = ''){
$api = CoreWeappService::appApiClient();
$api->postJson('cgi-bin/message/subscribe/send', [
$res = $api->postJson('cgi-bin/message/subscribe/send', [
'template_id' => $template_id, // 所需下发的订阅模板id
'touser' => $touser, // 接收者(用户)的 openid
'page' => $page, // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,示例index?foo=bar。该字段不填则模板无跳转。
'data' => $data,
]);
Log::write('小程序消息发送RESPONSE'.json_encode($res->toArray(),256));
}
/**

View File

@ -0,0 +1,76 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\core\wechat;
use app\service\core\channel\CoreAppService;
use core\base\BaseCoreService;
use core\exception\CommonException;
use core\exception\WechatException;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use EasyWeChat\OfficialAccount\Application;
/**
* 微信服务api提供
* Class CoreWechatApiService
* @package app\service\core\wechat
*/
class CoreWechatAppService extends BaseCoreService
{
/**
* 获取公众号的handle
* @return Application
* @throws InvalidArgumentException
*/
public static function app()
{
$app_config = (new CoreAppService())->getConfig();
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);
}
/**
* 微信实例接口调用
* @return \EasyWeChat\Kernel\HttpClient\AccessTokenAwareClient
* @throws InvalidArgumentException
*/
public static function appApiClient()
{
return self::app()->getClient();
}
/**
* 处理授权回调
* @param string $code
* @return \Overtrue\Socialite\Contracts\UserInterface
*/
public static function userFromCode(string $code)
{
try {
$oauth = self::app()->getOauth();
return $oauth->userFromCode($code);
} catch (\Exception $e) {
throw new CommonException($e->getCode() . '' . $e->getMessage());
}
}
}

View File

@ -32,17 +32,18 @@ class CoreWechatConfigService extends BaseCoreService
*/
public function getWechatConfig()
{
$info = ( new CoreConfigService() )->getConfig(ConfigKeyDict::WECHAT)[ 'value' ] ?? [];
$info = (new CoreConfigService())->getConfig(ConfigKeyDict::WECHAT)['value'] ?? [];
return [
'wechat_name' => $info[ 'wechat_name' ] ?? '',//公众号名称
'wechat_original' => $info[ 'wechat_original' ] ?? '',//原始ID
'app_id' => $info[ 'app_id' ] ?? '',//AppID
'app_secret' => $info[ 'app_secret' ] ?? '',//AppSecret
'qr_code' => $info[ 'qr_code' ] ?? '',//公众号二维码
'token' => $info[ 'token' ] ?? '',
'encoding_aes_key' => $info[ 'encoding_aes_key' ] ?? '',
'encryption_type' => $info[ 'encryption_type' ] ?? 'not_encrypt',//加解密模式 not_encrypt 明文 compatible 兼容 safe 安全
'is_authorization' => $info[ 'is_authorization' ] ?? 0
'wechat_name' => $info['wechat_name'] ?? '',//公众号名称
'wechat_original' => $info['wechat_original'] ?? '',//原始ID
'app_id' => $info['app_id'] ?? '',//AppID
'app_secret' => $info['app_secret'] ?? '',//AppSecret
'qr_code' => $info['qr_code'] ?? '',//公众号二维码
'token' => $info['token'] ?? '',
'encoding_aes_key' => $info['encoding_aes_key'] ?? '',
'encryption_type' => $info['encryption_type'] ?? 'not_encrypt',//加解密模式 not_encrypt 明文 compatible 兼容 safe 安全
'is_authorization' => $info['is_authorization'] ?? 0,
'base_uri' => $info['base_uri'] ?? ''
];
}
@ -55,17 +56,17 @@ class CoreWechatConfigService extends BaseCoreService
{
$old = $this->getWechatConfig();
$config = [
'wechat_name' => $data[ 'wechat_name' ] ?? '',//公众号名称
'wechat_original' => $data[ 'wechat_original' ] ?? '',//原始ID
'app_id' => $data[ 'app_id' ] ?? '',//AppID
'app_secret' => $data[ 'app_secret' ] ?? '',//AppSecret
'qr_code' => $data[ 'qr_code' ] ?? '',//公众号二维码
'token' => $data[ 'token' ] ?? '',
'encoding_aes_key' => $data[ 'encoding_aes_key' ] ?? '',
'encryption_type' => $data[ 'encryption_type' ] ?? '',
'is_authorization' => $data[ 'is_authorization' ] ?? $old[ 'is_authorization' ]
'wechat_name' => $data['wechat_name'] ?? '',//公众号名称
'wechat_original' => $data['wechat_original'] ?? '',//原始ID
'app_id' => $data['app_id'] ?? '',//AppID
'app_secret' => $data['app_secret'] ?? '',//AppSecret
'qr_code' => $data['qr_code'] ?? '',//公众号二维码
'token' => $data['token'] ?? '',
'encoding_aes_key' => $data['encoding_aes_key'] ?? '',
'encryption_type' => $data['encryption_type'] ?? '',
'is_authorization' => $data['is_authorization'] ?? $old['is_authorization']
];
return ( new CoreConfigService() )->setConfig(ConfigKeyDict::WECHAT, $config);
return (new CoreConfigService())->setConfig(ConfigKeyDict::WECHAT, $config);
}
/**
@ -74,15 +75,43 @@ class CoreWechatConfigService extends BaseCoreService
*/
public function getWechatStaticInfo()
{
$wap_domain = ( new CoreSysConfigService() )->getSceneDomain()[ 'wap_domain' ] ?? '';
$wap_domain = (new CoreSysConfigService())->getSceneDomain()['wap_domain'] ?? '';
$wap_domain = str_replace('http://', '', $wap_domain);
$wap_domain = str_replace('https://', '', $wap_domain);
return [
'serve_url' => (string) url('/api/wechat/serve', [], '', true),
'serve_url' => (string)url('/api/wechat/serve', [], '', true),
'business_domain' => $wap_domain,
'js_secure_domain' => $wap_domain,
'web_auth_domain' => $wap_domain,
'encryption_type' => WechatDict::getEncryptionType()
];
}
/**
* 获取小程序授权信息
* @return mixed
*/
public function getWechatAuthorizationInfo()
{
return (new CoreConfigService())->getConfigValue(ConfigKeyDict::WECHAT_AUTHORIZATION_INFO);
}
/**
* 设置小程序授权信息
* @param array $config
* @return SysConfig|bool|Model
*/
public function setWechatAuthorizationInfo(array $config)
{
return (new CoreConfigService())->setConfig(ConfigKeyDict::WECHAT_AUTHORIZATION_INFO, $config);
}
/**
* 清除授权信息
* @return mixed
*/
public function clearWechatAuthorizationInfo()
{
return (new CoreConfigService())->clearConfig(ConfigKeyDict::WECHAT_AUTHORIZATION_INFO);
}
}

View File

@ -41,33 +41,25 @@ class CoreWechatMessageService extends BaseCoreService
case WechatDict::MESSAGE_TYPE_EVENT:
return $this->event($message);
// return '收到事件消息';
break;
case WechatDict::MESSAGE_TYPE_TEXT:
//调用文本回复
return $this->text($message);
// return '收到文字消息';
break;
case WechatDict::MESSAGE_TYPE_IMAGE:
return '收到图片消息';
break;
case WechatDict::MESSAGE_TYPE_VOICE:
return '收到语音消息';
break;
case WechatDict::MESSAGE_TYPE_VIDEO:
return '收到视频消息';
break;
case WechatDict::MESSAGE_TYPE_LOCATION:
return '收到坐标消息';
break;
case WechatDict::MESSAGE_TYPE_LINK:
return '收到链接消息';
break;
case WechatDict::MESSAGE_TYPE_FILE:
return '收到文件消息';
// ... 其它消息
default:
return '收到其它消息';
break;
}
}
@ -75,15 +67,13 @@ class CoreWechatMessageService extends BaseCoreService
* 事件分流
* @return void
*/
public function event($message)
public function event(int $message)
{
switch ($message['Event'] ) {
case WechatDict::EVENT_SUBSCRIBE:
return $this->subscribe($message);
break;
case WechatDict::EVENT_SCAN:
return $this->scan($message);
break;
}
}
@ -93,7 +83,7 @@ class CoreWechatMessageService extends BaseCoreService
* @param $message
* @return Lang
*/
public function scan($message){
public function scan(int $message){
$key = str_replace('qrscene_', '', $message['EventKey']);
$core_scan_service = new CoreScanService();
$core_scan_service->actionByScan($key, ['openid' => $message['FromUserName']]);
@ -103,9 +93,9 @@ class CoreWechatMessageService extends BaseCoreService
/**
* 关注事件
* @param $message
* @return News|Text|false
* @return false
*/
public function subscribe($message){
public function subscribe(int $message){
//todo 新增粉丝或将原有的粉丝改为关注状态
// 因为时间的原因,这里可能需要将实践放在消息队列里面
$core_wechat_fans_service = new CoreWechatFansService();
@ -134,12 +124,12 @@ class CoreWechatMessageService extends BaseCoreService
/**
* 文本回复事件
* @param $message
* @return News|Text|false
* @return false
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
function text($message)
function text(int $message)
{
$core_wechat_reply_service = new CoreWechatReplyService();
return $core_wechat_reply_service->reply(WechatDict::REPLY_KEYWORD, $message['Content'], openid: $message['FromUserName']) ?? false;

View File

@ -33,13 +33,13 @@ class CoreWechatService extends BaseCoreService
$core_wechat_service = new CoreWechatConfigService();
$wechat_config = $core_wechat_service->getWechatConfig();
if (empty($wechat_config[ 'app_id' ]) || empty($wechat_config[ 'app_secret' ])) throw new WechatException('WECHAT_NOT_EXIST');//公众号未配置
if (empty($wechat_config['app_id']) || empty($wechat_config['app_secret'])) throw new WechatException('WECHAT_NOT_EXIST');//公众号未配置
$config = array(
'app_id' => $wechat_config[ 'app_id' ],
'secret' => $wechat_config[ 'app_secret' ],
'token' => $wechat_config[ 'token' ],
'aes_key' => $wechat_config[ 'encryption_type' ] == 'not_encrypt' ? '' : $wechat_config[ 'encoding_aes_key' ],// 明文模式请勿填写 EncodingAESKey
'app_id' => $wechat_config['app_id'],
'secret' => $wechat_config['app_secret'],
'token' => $wechat_config['token'],
'aes_key' => $wechat_config['encryption_type'] == 'not_encrypt' ? '' : $wechat_config['encoding_aes_key'],// 明文模式请勿填写 EncodingAESKey
'http' => [
'timeout' => 5.0,
'retry' => true, // 使用默认重试配置
@ -62,7 +62,7 @@ class CoreWechatService extends BaseCoreService
/**
* 回复文本消息
* @param string $content 文本内容
* @return
* @return string[]
*/
public static function text($content)
{
@ -75,7 +75,7 @@ class CoreWechatService extends BaseCoreService
/**
* 回复图片消息
* @param string $media_id 媒体资源 ID
* @return
* @return void
*/
public static function image($media_id)
{
@ -90,11 +90,10 @@ class CoreWechatService extends BaseCoreService
/**
* 回复声音消息
* @return
* @return void
*/
public static function music()
{
return;
}
/**
@ -110,14 +109,14 @@ class CoreWechatService extends BaseCoreService
'MsgType' => 'MsgType',
];
if (is_array($title)) {
if (isset($title[ 0 ]) && is_array($title[ 0 ])) {
if (isset($title[0]) && is_array($title[0])) {
$newsList = [];
foreach ($title as $news) {
$newsList[] = self::newsMessage($news);
}
return $newsList;
} else {
$data = [ $title ];
$data = [$title];
}
} else {
$data = [
@ -129,8 +128,8 @@ class CoreWechatService extends BaseCoreService
]
];
}
$message[ 'MsgType' ] = count($data);
$message[ 'Articles' ] = $data;
$message['MsgType'] = count($data);
$message['Articles'] = $data;
return $message;
}
}

View File

@ -0,0 +1,92 @@
<?php
namespace app\upgrade\v157;
use app\model\diy\Diy;
use app\model\diy_form\DiyForm;
class Upgrade
{
public function handle()
{
$this->handleDiyData();
$this->handleDiyFormData();
}
/**
* 处理自定义数据
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function handleDiyData()
{
$diy_model = new Diy();
$where = [
['value', '<>', ''],
];
$field = 'id,value';
$list = $diy_model->where($where)->field($field)->select()->toArray();
if (!empty($list)) {
foreach ($list as $k => $v) {
$diy_data = json_decode($v['value'], true);
if (!isset($diy_data['global']['copyright'])) {
$diy_data['global']['copyright'] = [
'control' => true,
'isShow' => false,
'textColor' => '#ccc'
];
}
if (!isset($diy_data['global']['bottomTabBar']['designNav'])) {
$diy_data['global']['bottomTabBar']['designNav'] = ['title'=>'','key'=>''];
}
$diy_data = json_encode($diy_data);
$diy_model->where([['id', '=', $v['id']]])->update(['value' => $diy_data]);
}
}
}
/**
* 处理万能表单数据
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function handleDiyFormData()
{
$diy_form_model = new DiyForm();
$where = [
['value', '<>', '']
];
$field = 'form_id,value';
$list = $diy_form_model->where($where)->field($field)->select()->toArray();
if (!empty($list)) {
foreach ($list as $k => $v) {
$diy_data = $v['value'];
if (!isset($diy_data['global']['copyright'])) {
$diy_data['global']['copyright'] = [
'control' => true,
'isShow' => false,
'textColor' => '#ccc',
];
}
if (!isset($diy_data['global']['bottomTabBar']['designNav'])) {
$diy_data['global']['bottomTabBar']['designNav'] = ['title'=>'','key'=>''];
}
$diy_form_model->where([['form_id', '=', $v['form_id']]])->update(['value' => $diy_data]);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More