代码初始化

This commit is contained in:
2025-08-07 20:21:47 +08:00
commit 50f3a2dbb0
2191 changed files with 374790 additions and 0 deletions

View File

@@ -0,0 +1,330 @@
<?php
namespace app\common\controller;
use app\common\library\Auth;
use think\Config;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Hook;
use think\Lang;
use think\Loader;
use think\Request;
use think\Response;
use think\Route;
use think\Validate;
/**
* API控制器基类
*/
class Api
{
/**
* @var Request Request 实例
*/
protected $request;
/**
* @var bool 验证失败是否抛出异常
*/
protected $failException = false;
/**
* @var bool 是否批量验证
*/
protected $batchValidate = false;
/**
* @var array 前置操作方法列表
*/
protected $beforeActionList = [];
/**
* 无需登录的方法,同时也就不需要鉴权了
* @var array
*/
protected $noNeedLogin = [];
/**
* 无需鉴权的方法,但需要登录
* @var array
*/
protected $noNeedRight = [];
/**
* 权限Auth
* @var Auth
*/
protected $auth = null;
/**
* 默认响应输出类型,支持json/xml
* @var string
*/
protected $responseType = 'json';
/**
* 构造方法
* @access public
* @param Request $request Request 对象
*/
public function __construct(Request $request = null)
{
$this->request = is_null($request) ? Request::instance() : $request;
// 控制器初始化
$this->_initialize();
// 前置操作方法
if ($this->beforeActionList) {
foreach ($this->beforeActionList as $method => $options) {
is_numeric($method) ?
$this->beforeAction($options) :
$this->beforeAction($method, $options);
}
}
}
/**
* 初始化操作
* @access protected
*/
protected function _initialize()
{
//跨域请求检测
check_cors_request();
// 检测IP是否允许
check_ip_allowed();
//移除HTML标签
$this->request->filter('trim,strip_tags,htmlspecialchars');
$this->auth = Auth::instance();
$modulename = $this->request->module();
$controllername = Loader::parseName($this->request->controller());
$actionname = strtolower($this->request->action());
// token
$token = $this->request->server('HTTP_TOKEN', $this->request->request('token', \think\Cookie::get('token')));
$path = str_replace('.', '/', $controllername) . '/' . $actionname;
// 设置当前请求的URI
$this->auth->setRequestUri($path);
// 检测是否需要验证登录
if (!$this->auth->match($this->noNeedLogin)) {
//初始化
$this->auth->init($token);
//检测是否登录
if (!$this->auth->isLogin()) {
$this->error(__('Please login first'), null, 401);
}
// 判断是否需要验证权限
if (!$this->auth->match($this->noNeedRight)) {
// 判断控制器和方法判断是否有对应权限
if (!$this->auth->check($path)) {
$this->error(__('You have no permission'), null, 403);
}
}
} else {
// 如果有传递token才验证是否登录状态
if ($token) {
$this->auth->init($token);
}
}
$upload = \app\common\model\Config::upload();
// 上传信息配置后
Hook::listen("upload_config_init", $upload);
Config::set('upload', array_merge(Config::get('upload'), $upload));
// 加载当前控制器语言包
$this->loadlang($controllername);
}
/**
* 加载语言文件
* @param string $name
*/
protected function loadlang($name)
{
$name = Loader::parseName($name);
$name = preg_match("/^([a-zA-Z0-9_\.\/]+)\$/i", $name) ? $name : 'index';
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php');
}
/**
* 操作成功返回的数据
* @param string $msg 提示信息
* @param mixed $data 要返回的数据
* @param int $code 错误码默认为1
* @param string $type 输出类型
* @param array $header 发送的 Header 信息
*/
protected function success($msg = '', $data = null, $code = 1, $type = null, array $header = [])
{
$this->result($msg, $data, $code, $type, $header);
}
/**
* 操作失败返回的数据
* @param string $msg 提示信息
* @param mixed $data 要返回的数据
* @param int $code 错误码默认为0
* @param string $type 输出类型
* @param array $header 发送的 Header 信息
*/
protected function error($msg = '', $data = null, $code = 0, $type = null, array $header = [])
{
$this->result($msg, $data, $code, $type, $header);
}
/**
* 返回封装后的 API 数据到客户端
* @access protected
* @param mixed $msg 提示信息
* @param mixed $data 要返回的数据
* @param int $code 错误码默认为0
* @param string $type 输出类型支持json/xml/jsonp
* @param array $header 发送的 Header 信息
* @return void
* @throws HttpResponseException
*/
protected function result($msg, $data = null, $code = 0, $type = null, array $header = [])
{
$result = [
'code' => $code,
'msg' => $msg,
'time' => Request::instance()->server('REQUEST_TIME'),
'data' => $data,
];
// 如果未设置类型则使用默认类型判断
$type = $type ? : $this->responseType;
if (isset($header['statuscode'])) {
$code = $header['statuscode'];
unset($header['statuscode']);
} else {
//未设置状态码,根据code值判断
$code = $code >= 1000 || $code < 200 ? 200 : $code;
}
$response = Response::create($result, $type, $code)->header($header);
throw new HttpResponseException($response);
}
/**
* 前置操作
* @access protected
* @param string $method 前置操作方法名
* @param array $options 调用参数 ['only'=>[...]] 或者 ['except'=>[...]]
* @return void
*/
protected function beforeAction($method, $options = [])
{
if (isset($options['only'])) {
if (is_string($options['only'])) {
$options['only'] = explode(',', $options['only']);
}
if (!in_array($this->request->action(), $options['only'])) {
return;
}
} elseif (isset($options['except'])) {
if (is_string($options['except'])) {
$options['except'] = explode(',', $options['except']);
}
if (in_array($this->request->action(), $options['except'])) {
return;
}
}
call_user_func([$this, $method]);
}
/**
* 设置验证失败后是否抛出异常
* @access protected
* @param bool $fail 是否抛出异常
* @return $this
*/
protected function validateFailException($fail = true)
{
$this->failException = $fail;
return $this;
}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @param mixed $callback 回调方法(闭包)
* @return array|string|true
* @throws ValidateException
*/
protected function validate($data, $validate, $message = [], $batch = false, $callback = null)
{
if (is_array($validate)) {
$v = Loader::validate();
$v->rule($validate);
} else {
// 支持场景
if (strpos($validate, '.')) {
list($validate, $scene) = explode('.', $validate);
}
$v = Loader::validate($validate);
!empty($scene) && $v->scene($scene);
}
// 批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
// 设置错误信息
if (is_array($message)) {
$v->message($message);
}
// 使用回调验证
if ($callback && is_callable($callback)) {
call_user_func_array($callback, [$v, &$data]);
}
if (!$v->check($data)) {
if ($this->failException) {
throw new ValidateException($v->getError());
}
return $v->getError();
}
return true;
}
/**
* 刷新Token
*/
protected function token()
{
$token = $this->request->param('__token__');
//验证Token
if (!Validate::make()->check(['__token__' => $token], ['__token__' => 'require|token'])) {
$this->error(__('Token verification error'), ['__token__' => $this->request->token()]);
}
//刷新Token
$this->request->token();
}
}

View File

@@ -0,0 +1,614 @@
<?php
namespace app\common\controller;
use app\admin\library\Auth;
use think\Config;
use think\Controller;
use think\Hook;
use think\Lang;
use think\Loader;
use think\Model;
use think\Session;
use fast\Tree;
use think\Validate;
/**
* 后台控制器基类
*/
class Backend extends Controller
{
/**
* 无需登录的方法,同时也就不需要鉴权了
* @var array
*/
protected $noNeedLogin = [];
/**
* 无需鉴权的方法,但需要登录
* @var array
*/
protected $noNeedRight = [];
/**
* 布局模板
* @var string
*/
protected $layout = 'default';
/**
* 权限控制类
* @var Auth
*/
protected $auth = null;
/**
* 模型对象
* @var \think\Model
*/
protected $model = null;
/**
* 快速搜索时执行查找的字段
*/
protected $searchFields = 'id';
/**
* 是否是关联查询
*/
protected $relationSearch = false;
/**
* 是否开启数据限制
* 支持auth/personal
* 表示按权限判断/仅限个人
* 默认为禁用,若启用请务必保证表中存在admin_id字段
*/
protected $dataLimit = false;
/**
* 数据限制字段
*/
protected $dataLimitField = 'admin_id';
/**
* 数据限制开启时自动填充限制字段值
*/
protected $dataLimitFieldAutoFill = true;
/**
* 是否开启Validate验证
*/
protected $modelValidate = false;
/**
* 是否开启模型场景验证
*/
protected $modelSceneValidate = false;
/**
* Multi方法可批量修改的字段
*/
protected $multiFields = 'status';
/**
* Selectpage可显示的字段
*/
protected $selectpageFields = '*';
/**
* 前台提交过来,需要排除的字段数据
*/
protected $excludeFields = "";
/**
* 导入文件首行类型
* 支持comment/name
* 表示注释或字段名
*/
protected $importHeadType = 'comment';
/**
* 引入后台控制器的traits
*/
// use \app\admin\library\traits\Backend;
public function _initialize()
{
$modulename = $this->request->module();
$controllername = Loader::parseName($this->request->controller());
$actionname = strtolower($this->request->action());
$path = str_replace('.', '/', $controllername) . '/' . $actionname;
// 定义是否Addtabs请求
!defined('IS_ADDTABS') && define('IS_ADDTABS', (bool)input("addtabs"));
// 定义是否Dialog请求
!defined('IS_DIALOG') && define('IS_DIALOG', (bool)input("dialog"));
// 定义是否AJAX请求
!defined('IS_AJAX') && define('IS_AJAX', $this->request->isAjax());
// 检测IP是否允许
check_ip_allowed();
$this->auth = Auth::instance();
// 设置当前请求的URI
$this->auth->setRequestUri($path);
// 检测是否需要验证登录
if (!$this->auth->match($this->noNeedLogin)) {
//检测是否登录
if (!$this->auth->isLogin()) {
Hook::listen('admin_nologin', $this);
$url = Session::get('referer');
$url = $url ? $url : $this->request->url();
if (in_array($this->request->pathinfo(), ['/', 'index/index'])) {
$this->redirect('index/login', [], 302, ['referer' => $url]);
exit;
}
$this->error(__('Please login first'), url('index/login', ['url' => $url]));
}
// 判断是否需要验证权限
if (!$this->auth->match($this->noNeedRight)) {
// 判断控制器和方法是否有对应权限
if (!$this->auth->check($path)) {
Hook::listen('admin_nopermission', $this);
$this->error(__('You have no permission'), '');
}
}
}
// 非选项卡时重定向
if (!$this->request->isPost() && !IS_AJAX && !IS_ADDTABS && !IS_DIALOG && input("ref") == 'addtabs') {
$url = preg_replace_callback("/([\?|&]+)ref=addtabs(&?)/i", function ($matches) {
return $matches[2] == '&' ? $matches[1] : '';
}, $this->request->url());
if (Config::get('url_domain_deploy')) {
if (stripos($url, $this->request->server('SCRIPT_NAME')) === 0) {
$url = substr($url, strlen($this->request->server('SCRIPT_NAME')));
}
$url = url($url, '', false);
}
$this->redirect('index/index', [], 302, ['referer' => $url]);
exit;
}
// 设置面包屑导航数据
$breadcrumb = [];
if (!IS_DIALOG && !config('fastadmin.multiplenav') && config('fastadmin.breadcrumb')) {
$breadcrumb = $this->auth->getBreadCrumb($path);
array_pop($breadcrumb);
}
$this->view->breadcrumb = $breadcrumb;
// 如果有使用模板布局
if ($this->layout) {
$this->view->engine->layout('layout/' . $this->layout);
}
// 语言检测
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
$site = Config::get("site");
$upload = \app\common\model\Config::upload();
// 上传信息配置后
Hook::listen("upload_config_init", $upload);
// 配置信息
$config = [
'site' => array_intersect_key($site, array_flip(['name', 'indexurl', 'cdnurl', 'version', 'timezone', 'languages'])),
'upload' => $upload,
'modulename' => $modulename,
'controllername' => $controllername,
'actionname' => $actionname,
'jsname' => 'backend/' . str_replace('.', '/', $controllername),
'moduleurl' => rtrim(url("/{$modulename}", '', false), '/'),
'language' => $lang,
'referer' => Session::get("referer")
];
$config = array_merge($config, Config::get("view_replace_str"));
Config::set('upload', array_merge(Config::get('upload'), $upload));
// 配置信息后
Hook::listen("config_init", $config);
//加载当前控制器语言包
$this->loadlang($controllername);
//渲染站点配置
$this->assign('site', $site);
//渲染配置信息
$this->assign('config', $config);
//渲染权限对象
$this->assign('auth', $this->auth);
//渲染管理员对象
$this->assign('admin', Session::get('admin'));
}
/**
* 加载语言文件
* @param string $name
*/
protected function loadlang($name)
{
$name = Loader::parseName($name);
$name = preg_match("/^([a-zA-Z0-9_\.\/]+)\$/i", $name) ? $name : 'index';
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php');
}
/**
* 渲染配置信息
* @param mixed $name 键名或数组
* @param mixed $value 值
*/
protected function assignconfig($name, $value = '')
{
$this->view->config = array_merge($this->view->config ? $this->view->config : [], is_array($name) ? $name : [$name => $value]);
}
/**
* 生成查询所需要的条件,排序方式
* @param mixed $searchfields 快速查询的字段
* @param boolean $relationSearch 是否关联查询
* @return array
*/
protected function buildparams($searchfields = null, $relationSearch = null)
{
$searchfields = is_null($searchfields) ? $this->searchFields : $searchfields;
$relationSearch = is_null($relationSearch) ? $this->relationSearch : $relationSearch;
$search = $this->request->get("search", '');
$filter = $this->request->get("filter", '');
$op = $this->request->get("op", '', 'trim');
$sort = $this->request->get("sort", !empty($this->model) && $this->model->getPk() ? $this->model->getPk() : 'id');
$order = $this->request->get("order", "DESC");
$offset = max(0, $this->request->get("offset/d", 0));
$limit = max(0, $this->request->get("limit/d", 0));
$limit = $limit ?: 999999;
//新增自动计算页码
$page = $limit ? intval($offset / $limit) + 1 : 1;
if ($this->request->has("page")) {
$page = max(0, $this->request->get("page/d", 1));
}
$this->request->get([config('paginate.var_page') => $page]);
$filter = (array)json_decode($filter, true);
$op = (array)json_decode($op, true);
$filter = $filter ? $filter : [];
$where = [];
$alias = [];
$bind = [];
$name = '';
$aliasName = '';
if (!empty($this->model) && $relationSearch) {
$name = $this->model->getTable();
$alias[$name] = Loader::parseName(basename(str_replace('\\', '/', get_class($this->model))));
$aliasName = $alias[$name] . '.';
}
$sortArr = explode(',', $sort);
foreach ($sortArr as $index => & $item) {
$item = stripos($item, ".") === false ? $aliasName . trim($item) : $item;
}
unset($item);
$sort = implode(',', $sortArr);
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
$where[] = [$aliasName . $this->dataLimitField, 'in', $adminIds];
}
if ($search) {
$searcharr = is_array($searchfields) ? $searchfields : explode(',', $searchfields);
foreach ($searcharr as $k => &$v) {
$v = stripos($v, ".") === false ? $aliasName . $v : $v;
}
unset($v);
$where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"];
}
$index = 0;
foreach ($filter as $k => $v) {
if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $k)) {
continue;
}
$sym = $op[$k] ?? '=';
if (stripos($k, ".") === false) {
$k = $aliasName . $k;
}
$v = !is_array($v) ? trim($v) : $v;
$sym = strtoupper($op[$k] ?? $sym);
//null和空字符串特殊处理
if (!is_array($v)) {
if (in_array(strtoupper($v), ['NULL', 'NOT NULL'])) {
$sym = strtoupper($v);
}
if (in_array($v, ['""', "''"])) {
$v = '';
$sym = '=';
}
}
switch ($sym) {
case '=':
case '<>':
$where[] = [$k, $sym, (string)$v];
break;
case 'LIKE':
case 'NOT LIKE':
case 'LIKE %...%':
case 'NOT LIKE %...%':
$where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
break;
case '>':
case '>=':
case '<':
case '<=':
$where[] = [$k, $sym, intval($v)];
break;
case 'FINDIN':
case 'FINDINSET':
case 'FIND_IN_SET':
$v = is_array($v) ? $v : explode(',', str_replace(' ', ',', $v));
$findArr = array_values($v);
foreach ($findArr as $idx => $item) {
$bindName = "item_" . $index . "_" . $idx;
$bind[$bindName] = $item;
$where[] = "FIND_IN_SET(:{$bindName}, `" . str_replace('.', '`.`', $k) . "`)";
}
break;
case 'IN':
case 'IN(...)':
case 'NOT IN':
case 'NOT IN(...)':
$where[] = [$k, str_replace('(...)', '', $sym), is_array($v) ? $v : explode(',', $v)];
break;
case 'BETWEEN':
case 'NOT BETWEEN':
$arr = array_slice(explode(',', $v), 0, 2);
if (stripos($v, ',') === false || !array_filter($arr, function ($v) {
return $v != '' && $v !== false && $v !== null;
})) {
continue 2;
}
//当出现一边为空时改变操作符
if ($arr[0] === '') {
$sym = $sym == 'BETWEEN' ? '<=' : '>';
$arr = $arr[1];
} elseif ($arr[1] === '') {
$sym = $sym == 'BETWEEN' ? '>=' : '<';
$arr = $arr[0];
}
$where[] = [$k, $sym, $arr];
break;
case 'RANGE':
case 'NOT RANGE':
$v = str_replace(' - ', ',', $v);
$arr = array_slice(explode(',', $v), 0, 2);
if (stripos($v, ',') === false || !array_filter($arr)) {
continue 2;
}
//当出现一边为空时改变操作符
if ($arr[0] === '') {
$sym = $sym == 'RANGE' ? '<=' : '>';
$arr = $arr[1];
} elseif ($arr[1] === '') {
$sym = $sym == 'RANGE' ? '>=' : '<';
$arr = $arr[0];
}
$tableArr = explode('.', $k);
if (count($tableArr) > 1 && $tableArr[0] != $name && !in_array($tableArr[0], $alias)
&& !empty($this->model) && $this->relationSearch) {
//修复关联模型下时间无法搜索的BUG
$relation = Loader::parseName($tableArr[0], 1, false);
$alias[$this->model->$relation()->getTable()] = $tableArr[0];
}
$where[] = [$k, str_replace('RANGE', 'BETWEEN', $sym) . ' TIME', $arr];
break;
case 'NULL':
case 'IS NULL':
case 'NOT NULL':
case 'IS NOT NULL':
$where[] = [$k, strtolower(str_replace('IS ', '', $sym))];
break;
default:
break;
}
$index++;
}
if (!empty($this->model)) {
$this->model->alias($alias);
}
$model = $this->model;
$where = function ($query) use ($where, $alias, $bind, &$model) {
if (!empty($model)) {
$model->alias($alias);
$model->bind($bind);
}
foreach ($where as $k => $v) {
if (is_array($v)) {
call_user_func_array([$query, 'where'], $v);
} else {
$query->where($v);
}
}
};
return [$where, $sort, $order, $offset, $limit, $page, $alias, $bind];
}
/**
* 获取数据限制的管理员ID
* 禁用数据限制时返回的是null
* @return mixed
*/
protected function getDataLimitAdminIds()
{
if (!$this->dataLimit) {
return null;
}
if ($this->auth->isSuperAdmin()) {
return null;
}
$adminIds = [];
if (in_array($this->dataLimit, ['auth', 'personal'])) {
$adminIds = $this->dataLimit == 'auth' ? $this->auth->getChildrenAdminIds(true) : [$this->auth->id];
}
return $adminIds;
}
/**
* Selectpage的实现方法
*
* 当前方法只是一个比较通用的搜索匹配,请按需重载此方法来编写自己的搜索逻辑,$where按自己的需求写即可
* 这里示例了所有的参数,所以比较复杂,实现上自己实现只需简单的几行即可
*
*/
protected function selectpage()
{
//设置过滤方法
$this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']);
//搜索关键词,客户端输入以空格分开,这里接收为数组
$word = (array)$this->request->request("q_word/a");
//当前页
$page = $this->request->request("pageNumber");
//分页大小
$pagesize = $this->request->request("pageSize");
//搜索条件
$andor = $this->request->request("andOr", "and", "strtoupper");
//排序方式
$orderby = (array)$this->request->request("orderBy/a");
//显示的字段
$field = $this->request->request("showField");
//主键
$primarykey = $this->request->request("keyField");
//主键值
$primaryvalue = $this->request->request("keyValue");
//搜索字段
$searchfield = (array)$this->request->request("searchField/a");
//自定义搜索条件
$custom = (array)$this->request->request("custom/a");
//是否返回树形结构
$istree = $this->request->request("isTree", 0);
$ishtml = $this->request->request("isHtml", 0);
if ($istree) {
$word = [];
$pagesize = 999999;
}
$order = [];
foreach ($orderby as $k => $v) {
$order[$v[0]] = $v[1];
}
$field = $field ? $field : 'name';
//如果有primaryvalue,说明当前是初始化传值
if ($primaryvalue !== null) {
$where = [$primarykey => ['in', $primaryvalue]];
$pagesize = 999999;
} else {
$where = function ($query) use ($word, $andor, $field, $searchfield, $custom) {
$logic = $andor == 'AND' ? '&' : '|';
$searchfield = is_array($searchfield) ? implode($logic, $searchfield) : $searchfield;
$searchfield = str_replace(',', $logic, $searchfield);
$word = array_filter(array_unique($word));
if (count($word) == 1) {
$query->where($searchfield, "like", "%" . reset($word) . "%");
} else {
$query->where(function ($query) use ($word, $searchfield) {
foreach ($word as $index => $item) {
$query->whereOr(function ($query) use ($item, $searchfield) {
$query->where($searchfield, "like", "%{$item}%");
});
}
});
}
if ($custom && is_array($custom)) {
foreach ($custom as $k => $v) {
if (is_array($v) && 2 == count($v)) {
$query->where($k, trim($v[0]), $v[1]);
} else {
$query->where($k, '=', $v);
}
}
}
};
}
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$list = [];
$total = $this->model->where($where)->count();
if ($total > 0) {
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$fields = is_array($this->selectpageFields) ? $this->selectpageFields : ($this->selectpageFields && $this->selectpageFields != '*' ? explode(',', $this->selectpageFields) : []);
//如果有primaryvalue,说明当前是初始化传值,按照选择顺序排序
if ($primaryvalue !== null && preg_match("/^[a-z0-9_\-]+$/i", $primarykey)) {
$primaryvalue = array_unique(is_array($primaryvalue) ? $primaryvalue : explode(',', $primaryvalue));
//修复自定义data-primary-key为字符串内容时给排序字段添加上引号
$primaryvalue = array_map(function ($value) {
return '\'' . $value . '\'';
}, $primaryvalue);
$primaryvalue = implode(',', $primaryvalue);
$this->model->orderRaw("FIELD(`{$primarykey}`, {$primaryvalue})");
} else {
$this->model->order($order);
}
$datalist = $this->model->where($where)
->page($page, $pagesize)
->select();
foreach ($datalist as $index => $item) {
unset($item['password'], $item['salt']);
if ($this->selectpageFields == '*') {
$result = [
$primarykey => $item[$primarykey] ?? '',
$field => $item[$field] ?? '',
];
} else {
$result = array_intersect_key(($item instanceof Model ? $item->toArray() : (array)$item), array_flip($fields));
}
$result['pid'] = isset($item['pid']) ? $item['pid'] : (isset($item['parent_id']) ? $item['parent_id'] : 0);
$result = array_map("htmlentities", $result);
$list[] = $result;
}
if ($istree && !$primaryvalue) {
$tree = Tree::instance();
$tree->init(collection($list)->toArray(), 'pid');
$list = $tree->getTreeList($tree->getTreeArray(0), $field);
if (!$ishtml) {
foreach ($list as &$item) {
$item = str_replace('&nbsp;', ' ', $item);
}
unset($item);
}
}
}
//这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮
return json(['list' => $list, 'total' => $total]);
}
/**
* 刷新Token
*/
protected function token()
{
$token = $this->request->param('__token__');
//验证Token
if (!Validate::make()->check(['__token__' => $token], ['__token__' => 'require|token'])) {
$this->error(__('Token verification error'), '', ['__token__' => $this->request->token()]);
}
//刷新Token
$this->request->token();
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace app\common\controller;
use think\Controller;
class BaseCom extends Controller
{
public $uid = 0;
public $redis = '';
//初始化
protected function _initialize()
{
//允许跨域
header("Access-Control-Allow-Origin: *"); // 允许所有域访问
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Access-Control-Max-Age: 3600");
//检测系统是否维护中
// $config = get_system_config();
$is_maintenance = get_system_config_value('is_maintenance');
if($is_maintenance == 2){
return V(203, '系统维护中');
}
$token = input('token', '');
if (empty($token)) {
$token = request()->header('token');
if(empty($token)){
return V(301, '登录失效');
}
}
$reslut = model('UserToken')->check_login_token($token);
if($reslut['code'] != 1) {
model('UserToken')->where('token', $token)->update(['token' => 1]);
return V($reslut['code'], $reslut['msg'],$reslut['data']);
} else {
$this->uid = $reslut['data'];
//定义一个常量
define('UID', $this->uid);
}
}
}

View File

@@ -0,0 +1,162 @@
<?php
namespace app\common\controller;
use app\common\library\Auth;
use think\Config;
use think\Controller;
use think\Hook;
use think\Lang;
use think\Loader;
use think\Validate;
/**
* 前台控制器基类
*/
class Frontend extends Controller
{
/**
* 布局模板
* @var string
*/
protected $layout = '';
/**
* 无需登录的方法,同时也就不需要鉴权了
* @var array
*/
protected $noNeedLogin = [];
/**
* 无需鉴权的方法,但需要登录
* @var array
*/
protected $noNeedRight = [];
/**
* 权限Auth
* @var Auth
*/
protected $auth = null;
public function _initialize()
{
//移除HTML标签
$this->request->filter('trim,strip_tags,htmlspecialchars');
$modulename = $this->request->module();
$controllername = Loader::parseName($this->request->controller());
$actionname = strtolower($this->request->action());
// 检测IP是否允许
check_ip_allowed();
// 如果有使用模板布局
if ($this->layout) {
$this->view->engine->layout('layout/' . $this->layout);
}
$this->auth = Auth::instance();
// token
$token = $this->request->server('HTTP_TOKEN', $this->request->request('token', \think\Cookie::get('token')));
$path = str_replace('.', '/', $controllername) . '/' . $actionname;
// 设置当前请求的URI
$this->auth->setRequestUri($path);
// 检测是否需要验证登录
if (!$this->auth->match($this->noNeedLogin)) {
//初始化
$this->auth->init($token);
//检测是否登录
if (!$this->auth->isLogin()) {
$this->error(__('Please login first'), 'index/user/login');
}
// 判断是否需要验证权限
if (!$this->auth->match($this->noNeedRight)) {
// 判断控制器和方法判断是否有对应权限
if (!$this->auth->check($path)) {
$this->error(__('You have no permission'));
}
}
} else {
// 如果有传递token才验证是否登录状态
if ($token) {
$this->auth->init($token);
}
}
$this->view->assign('user', $this->auth->getUser());
// 语言检测
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
$site = Config::get("site");
$upload = \app\common\model\Config::upload();
// 上传信息配置后
Hook::listen("upload_config_init", $upload);
// 配置信息
$config = [
'site' => array_intersect_key($site, array_flip(['name', 'cdnurl', 'version', 'timezone', 'languages'])),
'upload' => $upload,
'modulename' => $modulename,
'controllername' => $controllername,
'actionname' => $actionname,
'jsname' => 'frontend/' . str_replace('.', '/', $controllername),
'moduleurl' => rtrim(url("/{$modulename}", '', false), '/'),
'language' => $lang
];
$config = array_merge($config, Config::get("view_replace_str"));
Config::set('upload', array_merge(Config::get('upload'), $upload));
// 配置信息后
Hook::listen("config_init", $config);
// 加载当前控制器语言包
$this->loadlang($controllername);
$this->assign('site', $site);
$this->assign('config', $config);
}
/**
* 加载语言文件
* @param string $name
*/
protected function loadlang($name)
{
$name = Loader::parseName($name);
$name = preg_match("/^([a-zA-Z0-9_\.\/]+)\$/i", $name) ? $name : 'index';
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php');
}
/**
* 渲染配置信息
* @param mixed $name 键名或数组
* @param mixed $value 值
*/
protected function assignconfig($name, $value = '')
{
$this->view->config = array_merge($this->view->config ? $this->view->config : [], is_array($name) ? $name : [$name => $value]);
}
/**
* 刷新Token
*/
protected function token()
{
$token = $this->request->param('__token__');
//验证Token
if (!Validate::make()->check(['__token__' => $token], ['__token__' => 'require|token'])) {
$this->error(__('Token verification error'), '', ['__token__' => $this->request->token()]);
}
//刷新Token
$this->request->token();
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace app\common\controller;
use AlibabaCloud\SDK\Dypnsapi\V20170525\Dypnsapi;
use Darabonba\OpenApi\Models\Config;
use AlibabaCloud\SDK\Dypnsapi\V20170525\Models\CreateVerifySchemeRequest;
use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;
use AlibabaCloud\Credentials\Credential;
use \Exception;
use AlibabaCloud\Tea\Exception\TeaError;
use AlibabaCloud\Tea\Utils\Utils;
class NumberAuth
{
public static function getClient() {
$config = get_system_config();
$credential = new Credential();
$config = new Config([
"credential" => $credential,
'accessKeyId' => $config['aliyun_access_key_id'],
'accessKeySecret' => $config['aliyun_access_key_secret'],
]);
// Endpoint 请参考 https://api.aliyun.com/product/Dypnsapi
$config->endpoint = "dypnsapi.aliyuncs.com";
return new Dypnsapi($config);
}
/**
* 通过Token获取手机号
* @param string $token 客户端SDK返回的Token
* @return string|null
*/
public static function getMobileByToken($token) {
$client = self::getClient();
$createVerifySchemeRequest = new CreateVerifySchemeRequest([
'accessToken' => $token
]);
try {
$response = $client->getMobileWithOptions($createVerifySchemeRequest, new RuntimeOptions([]));
// var_dump($response->body);die;
if ($response->body->code == 'OK') {
return $response->body->getMobileResultDTO->mobile;
}
}
catch (Exception $error) {
if (!($error instanceof TeaError)) {
$error = new TeaError([], $error->getMessage(), $error->getCode(), $error);
}
}
}
}
$path = __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . 'vendor' . \DIRECTORY_SEPARATOR . 'autoload.php';
if (file_exists($path)) {
require_once $path;
}
//NumberAuth::getMobileByToken(array_slice($token, 1));

View File

@@ -0,0 +1,699 @@
<?php
namespace app\common\controller;
use think\Loader;
class Push
{
const PUSH_POPULARITY = 5001;//推送房间-人气变化
const PUSH_RIDE = 5003;//推送房间-坐骑进场特效
const PUSH_NOBILITY = 5004;//推送房间-爵位用户进场特效
const PUSH_APPLY_COUNT = 5005;//推送房间-上麦申请人数变化
const PUSH_BANNED_USER = 5007;//推送房间-用户禁言 1禁言2解禁
const PUSH_CLOSE_PIT = 5011;//推送房间-是否封麦 1封麦2解封
const PUSH_CLEAR_CARDIAC = 5013;//推送房间-清空单个麦位心动值
const PUSH_CLEAR_CARDIAC_ALL = 5014;//推送房间-清空所有麦位心动值
const PUSH_SET_MANAGER = 5015;//推送房间-设置房间管理员
const PUSH_DELETE_MANAGER = 5016;//推送房间-删除房间管理员
const PUSH_SWITCH_VOICE = 5017;//推送房间-开关麦 1开0关
const PUSH_GIFT_BANNER = 5019;//推送所有人-横幅礼物通知
const PUSH_GIFT_CHAT_ROOM = 5020;//推送房间-聊天室礼物通知
const PUSH_FISH = 5021;//推送所有人-许愿池钓到大礼物时通知
const PUSH_ROOM_PASSWORD = 5022;//推送房间-房间密码变化通知 0取消密码1设置或修改密码
const PUSH_CARDIAC_SWITCH = 5023;//推送房间-房间心动值开关变化通知 1开2关
const PUSH_ROOM_WHEAT = 5024;//推送房间-上麦模式变化通知 1自由2排麦
const PUSH_UPDATE_ROOM_NAME = 5025;//推送房间-修改房间名称
const PUSH_WEEK_STAR = 5027;//推送房间-周星用户进场特效
const PUSH_UPDATE_ROOM_BACKGROUND = 5028;//推送房间-修改房间背景
const PUSH_UPDATE_ROOM_PLAYING = 5029;//推送房间-修改房间 玩法|公告
const PUSH_BOSS_ATTACK = 5030;//推送房间-BOSS大作战 超过99999金币 发送所有人消息
const PUSH_BOSS_BLOOD = 5031;//推送所有正在攻击boss的用户-boss大作战血量变化推送
const PUSH_PIT_ON = 5032;//推送房间-上麦
const PUSH_PIT_DOWN = 5033;//推送房间-下麦
const PUSH_KICK_OUT = 5034;//推送单独用户-被踢出房间
const PUSH_APPLY_USER = 5035;//推送单独用户-定向推向给上麦的用户
const PUSH_SHUT_UP = 5036;//推送房间-用户禁麦 1禁麦2解禁
const PUSH_JOIN_ROOM = 5037;//推送房间-用户进入房间
const PUSH_COUNT_DOWN = 5038;//推送房间-麦位倒计时
const PUSH_ROLL = 5039;//推送房间-扔骰子
const PUSH_FM_GOLD = 5040;//推送所有房间-电台房开通黄金守护
const PUSH_FACE = 5041;//推送房间-在麦上发送表情
const PUSH_ZEGO_LOG = 5042;//推送单独用户-上传即构日志
const PUSH_ROOM_CHAT_STATUS = 5043;//推送房间-公屏状态
const PUSH_BALL_START = 5044;//推送房间-球球大作战-开球
const PUSH_BALL_THROW = 5045;//推送房间-球球大作战-弃球
const PUSH_BALL_SHOW = 5046;//推送房间-球球大作战-亮球
const PUSH_SOUND_EFFECT_CHANGE = 5047;//推送房间-房间音效改变
const PUSH_ORDER_RECEIVE = 5048;//推送大神用户-有用户下单
const PUSH_ORDER_REFUND = 5049;//推送给大神-有用户要退款
const PUSH_ROOM_DEMAND_BOSS = 5050;//推送单独用户-推送给8号麦的老板
const PUSH_ROOM_DEMAND_UPDATE = 5051;//推送房间-更新派单需求
const PUSH_ROOM_DEMAND_TO_ANCHOR = 5052;//推送所有用户-将派单需求推送给所有符合条件的大神
const PUSH_ORDER_MESSAGE = 5053;//推送所有的订单消息(浮窗形式)
const PUSH_ROOM_OWNER_MODEL = 5054;//推送房间-更新房主模式
const PUSH_ROOM_QUIT = 5055;//推送房间-用户退出房间
const PUSH_ROOM_OWNER_JOIN = 5056;//推送房间-房主进入房间
const PUSH_LUCKYRANK = 5057;//推送房间-许愿池手气榜推送
const PUSH_GAME_TIPS = 5060;//房间游戏飘屏
const PUSH_CHANGE_HEARTBEAT = 5061;//推送房间-心动值变化
const PUSH_PIT_CHANGE = 5062;//推送房间-换麦位
const PUSH_PIT_JOIN_SMALL_ROOM = 5063;//推送单独用户-进小房间
const PUSH_PIT_OUT_SMALL_ROOM = 5064;//推送单独用户-退出小黑屋
const PUSH_FRIEND_STATUS = 5065;//推送房间-交友环节状态
const PUSH_ONLINE_DATING_NUM = 5066;//推送交友房在线对数发生变化
const PUSH_FRIEND_ADD_TIME = 5067;//推送房间-交友-心动连线环节 延时推送
const PUSH_SMALL_ROOM_ADD_TIME = 5068;//推送房间-送礼物增加时间
const PUSH_CHANGE_PIT = 5069;//自由上麦换麦
const PUSH_CHANGE_ROOM_LABEL = 5070;//推送房间类型发生变化
const PUSH_WISH_PROGRESS = 7001;//游戏进度
//推送系统消息
const PUSH_SYSTEM_MESSAGE = 7000;//推送系统消息
public $user_id, $room_id, $topic_room, $topic_client;
public function __construct($user_id = 0, $room_id = 0)
{
$this->user_id = $user_id;
$this->room_id = $room_id;
$this->topic_room = 'room_' . $this->room_id;
$this->topic_client = 'user_' . $this->user_id;
}
public function setUser($user_id)
{
$this->user_id = $user_id;
$this->topic_client = 'user_' . $user_id;
}
public function setRoom($room_id)
{
$this->room_id = $room_id;
$this->topic_room = 'room_' . $room_id;
}
private function push($push_type, $topic, $data = [])
{
Loader::import('Mqtt.Mqtt', EXTEND_PATH, '.php');
$mqtt = new \Mqtt();
$content = json_encode(
[
'type' => $push_type,
'time' => getMillisecond(),
'msg' => $data,
]
);
$mqtt->publishs($topic, $content);
}
/**
* 推送许愿池手气榜记录
*/
public function luckyRank($data)
{
$topic = 'room';
$this->push(self::PUSH_LUCKYRANK, $topic, $data);
return true;
}
//推送人气
public function updatePopularity($popularity)
{
$topic = '$delayed/1/' . $this->topic_room;
$data = ['popularity' => $popularity, 'room_id' => $this->room_id];
$this->push(self::PUSH_POPULARITY, $topic, $data);
}
//推送上麦
public function pitOn($pit_number, $data)
{
$topic = $this->topic_room;
$data['room_id'] = $this->room_id;
$data['pit_number'] = intval($pit_number);
$ball = S('room:user:ball:' . $this->room_id . ':' . $this->user_id);
$data['ball_state'] = $ball === false ? 0 : 1;
$this->push(self::PUSH_PIT_ON, $topic, $data);
}
//推送下麦
public function pitDown($down_info)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id,
'pit_number' => intval($down_info['pit_number']),
'user_id' => intval($this->user_id),
'emchat_username'=>$down_info['emchat_username']];
$this->push(self::PUSH_PIT_DOWN, $topic, $data);
}
//带坐骑用户进场特效通知
public function ride($ride_info)
{
$topic = '$delayed/1/' . $this->topic_room;
$data = [
'room_id' => $this->room_id,
'ride_url' => $ride_info['special'],
'show_type' => $ride_info['show_type']
];
$this->push(self::PUSH_RIDE, $topic, $data);
}
//带爵位用户进场特效通知
public function nobility($data)
{
$topic = '$delayed/1/' . $this->topic_room;
if ($data['nobilityId'] == 6) {
$special = 'https://yutangyuyin.oss-cn-hangzhou.aliyuncs.com/nobility/' . $data['nobilityId'] . '.svga';
} else {
$special = '';
}
//爵位特效暂时不推
$special = '';
$data = [
'room_id' => $this->room_id,
'user_id' => $this->user_id,
'nobility_name' => $data['nobilityName'],
'nobility_id' => $data['nobilityId'],
'nobility_icon' => $data['nobility_icon'],
'avatar' => $data['headPicture'],
'nickname' => $data['userName'],
'special' => $special,
'sex' => $data['sex'],
];
$this->push(self::PUSH_NOBILITY, $topic, $data);
}
//上麦申请人数变化通知
public function applyCount($count, $user_ids = '')
{
$topic = $this->topic_room;
$count_8 = M('RoomPitApply')->where(['room_id' => $this->room_id, 'pit_number' => 8])->count();
$count_8 = $count_8 > 0 ? $count_8 : 0;
$total_count = $count - $count_8;
$data = [
'room_id' => $this->room_id,
'count' => $total_count > 0 ? $total_count : 0,
'count_8' => $count_8,
'user_ids' => $user_ids
];
$this->push(self::PUSH_APPLY_COUNT, $topic, $data);
}
//用户被禁言 action 1禁言2解禁
public function bannedUser($action)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'user_id' => $this->user_id, 'action' => $action];
$this->push(self::PUSH_BANNED_USER, $topic, $data);
}
//是否封麦 1.封麦 2.解除封麦
public function closePit($pit_number, $action)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'pit_number' => $pit_number, 'action' => $action];
$this->push(self::PUSH_CLOSE_PIT, $topic, $data);
}
//清空单个麦位心动值
public function clearCardiac($pit_number)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'pit_number' => $pit_number];
$this->push(self::PUSH_CLEAR_CARDIAC, $topic, $data);
}
//清空所有麦位心动值
public function clearCardiacAll()
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id];
$this->push(self::PUSH_CLEAR_CARDIAC_ALL, $topic, $data);
}
//设置房间管理员
public function setManager()
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'user_id' => $this->user_id];
$this->push(self::PUSH_SET_MANAGER, $topic, $data);
}
//删除房间管理员
public function deleteManager()
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'user_id' => $this->user_id];
$this->push(self::PUSH_DELETE_MANAGER, $topic, $data);
}
//开关麦 action 1开0关
public function switchVoice($action, $pit_number = 0)
{
$topic = $this->topic_room;
$data = [
'room_id' => $this->room_id,
'user_id' => $this->user_id,
'pit_number' => $pit_number,
'action' => $action
];
$this->push(self::PUSH_SWITCH_VOICE, $topic, $data);
}
// =======================================================================================================
// ========================================羽声使用开始=====================================================================
//横幅礼物通知
public function giftBanner($gift_list)
{
$topic = 'qx_room_topic';
$data = ['room_id' => $this->room_id, 'list' => $gift_list];
$this->push(self::PUSH_GIFT_BANNER, $topic, $data);
}
//系统消息
public function systemMessage($text_list)
{
$topic = 'system_message';
$data = ['list' => $text_list];
$this->push(self::PUSH_SYSTEM_MESSAGE, $topic, $data);
}
// =========================================羽声使用结束=====================================================
// =============================================================================================================
//聊天室礼物通知
public function giftChatRoom($gift_list, $cardiac, $contribution, $show_cat = 0)
{
$topic = $this->topic_room;
$data = [
'room_id' => $this->room_id,
'gift_list' => $gift_list,
'cardiac_list' => $cardiac,
'contribution' => $contribution,
'show_cat' => $show_cat,
'user_id' => $this->user_id
];
$this->push(self::PUSH_GIFT_CHAT_ROOM, $topic, $data);
}
//自由上麦换麦通知
public function sendPitNumber($data)
{
$topic = $this->topic_room;
$data = $data;
$this->push(self::PUSH_CHANGE_PIT, $topic, $data);
}
//聊天室心动值变化通知
public function heartChatRoom($heart)
{
$topic = $this->topic_room;
$data['list'] = $heart;
$data['room_id'] = $this->room_id;
$this->push(self::PUSH_CHANGE_HEARTBEAT, $topic, $data);
}
//推送房间-交友-心动连线环节 延时推送
public function friendDelayed($endtime)
{
$topic = $this->topic_room;
$data = $endtime;
$this->push(self::PUSH_FRIEND_ADD_TIME, $topic, $data);
}
//私密小屋刷礼物后推送
public function heartSmallRoom($heart)
{
$topic = $this->topic_room;
$data = $heart;
$this->push(self::PUSH_SMALL_ROOM_ADD_TIME, $topic, $data);
}
//聊天室排行榜通知
public function rankChatRoom($data_list)
{
$topic = $this->topic_room;
$data['list'] = $data_list;
$data['room_id'] = $this->room_id;
$this->push(self::PUSH_PIT_CHANGE, $topic, $data);
}
//进入小黑屋
//退出小黑屋
public function blackRoom($cp_room_id,$users,$action,$room_on_line_cp=0,$heart_id=0,$heart_value=0)
{
$topic = $this->topic_room;
if($action == 1){ //进入小黑屋
$data = ['room_id' => $this->room_id,'cp_room_id'=>$cp_room_id,'users' => $users,'room_on_line_cp' => $room_on_line_cp,'heart_id'=>$heart_id,'heart_value'=>$heart_value,'end_time'=>time()+600];
$this->push(self::PUSH_PIT_JOIN_SMALL_ROOM, $topic, $data);
}else{//退出小黑屋
$data = ['room_id' => $this->room_id,'pid_room_id'=>$cp_room_id,'users' => $users,'room_on_line_cp' => $room_on_line_cp,'heart_id'=>$heart_id,'heart_value'=>$heart_value];
$this->push(self::PUSH_PIT_OUT_SMALL_ROOM, $topic, $data);
}
}
//交由环节状态
public function stage($roomid,$stage,$end_time="")
{
$topic = $this->topic_room;
if($stage == 2) {
$data = ['room_id' => $roomid, 'status' => $stage,'end_time'=>$end_time];
}else{
$data = ['room_id' => $roomid, 'status' => $stage];
}
$this->push(self::PUSH_FRIEND_STATUS, $topic, $data);
}
//聊天室在线心动人数 PUSH_ONLINE_DATING_NUM
public function onlineDatingNum($room_id,$online_num)
{
$topic = $this->topic_room;
$data = ['room_id' => $room_id, 'online_num' => $online_num];
$this->push(self::PUSH_ONLINE_DATING_NUM, $topic, $data);
}
//许愿池钓到大礼物时通知
public function fish($data, $user_info,$name)
{
$gift_list = $data['gift_list'];
$txt = "<font color='#FFFFFF'>哇塞</font><font color='#B9FF5E'>".$user_info['nickname']."</font><font color='#FFA7E7'>在{$name}中获得</font>";
$txt_extra = [];
foreach ($gift_list as $key => $value) {
if ($value['price'] >= C('WISH_PUSH_MONEY')) {
$txt_extra [] = [
'text' => $txt."<font color='#5AFDFF'>".$value['prize_title']."</font><font color='#FFFFFF'>X".$value['number']."</font>",
'picture' => $value['picture'],
];
}
}
if (!empty($txt_extra)) {
$topic = 'room';
$this->push(self::PUSH_FISH, $topic, $txt_extra);
}
}
//房间密码 0取消密码1设置或修改密码
public function roomPassword($action)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'action' => $action];
$this->push(self::PUSH_ROOM_PASSWORD, $topic, $data);
}
//房间心动值开关 1开2关
public function cardiacSwitch($action)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'action' => $action];
$this->push(self::PUSH_CARDIAC_SWITCH, $topic, $data);
}
//上麦模式变化 1自由2排麦
public function roomWheat($action)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'action' => $action];
$this->push(self::PUSH_ROOM_WHEAT, $topic, $data);
}
//修改房间名称
public function updateRoomName($room_name)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'room_name' => $room_name];
$this->push(self::PUSH_UPDATE_ROOM_NAME, $topic, $data);
}
//周星用户进场
public function weekStar($nickname, $rank)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'nickname' => $nickname, 'rank' => $rank];
$this->push(self::PUSH_WEEK_STAR, $topic, $data);
}
//修改房间背景
public function updateRoomBackground($background)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'background' => $background];
$this->push(self::PUSH_UPDATE_ROOM_BACKGROUND, $topic, $data);
}
//修改房间玩法|公告
public function updateRoomPlaying($playing, $greeting)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'playing' => $playing, 'greeting' => $greeting];
$this->push(self::PUSH_UPDATE_ROOM_PLAYING, $topic, $data);
}
//boss大作战 超过99999金币 发送所有人消息
public function AttackBoss($gift_list, $user_info)
{
$txt = "<font color='#FFFFFF'>哇塞</font><font color='#FD8469'>" . $user_info['nickname'] . "</font><font color='#FFFFFF'>在BOSS大作战中获得</font>";
$txt_extra = [];
foreach ($gift_list as $key => $value) {
if ($value['price'] >= 5200) {
$txt_extra [] = [
'text' => $txt."<font color='#FABA5C'>".$value['prize_title']."</font><font color='#FFFFFF'>X".$value['number']."</font>",
'picture' => $value['picture'],
];
}
}
if (!empty($txt_extra)) {
$topic = 'room';
$this->push(self::PUSH_BOSS_ATTACK, $topic, $txt_extra);
}
}
//boss大作战血量变化推送
public function bossBlood($left_blood = 0, $total_blood = 0, $gift_list = [], $user_info = [])
{
if ($gift_list) {
foreach ($gift_list as $key => $value) {
if ($value['price'] >= 520) {
$gift_list[$key]['nickname'] = $user_info['nickname'];
} else {
unset($gift_list[$key]);
}
}
}
$topic = 'boss';
$data = ['left_blood' => $left_blood, 'total_blood' => $total_blood, 'gift_list' => array_values($gift_list)];
$this->push(self::PUSH_BOSS_BLOOD, $topic, $data);
}
//定向推送给上麦的用户
public function agreeApplyUser($pit_number)
{
$topic = $this->topic_client;
$data = ['room_id' => $this->room_id, 'pit_number' => $pit_number];
$this->push(self::PUSH_APPLY_USER, $topic, $data);
}
//定向推送给被踢出房间的用户
public function kickOut()
{
$topic = $this->topic_client;
$data = ['room_id' => $this->room_id, 'user_id' => $this->user_id];
$this->push(self::PUSH_KICK_OUT, $topic, $data);
}
//用户禁麦 action 1禁麦2解禁
public function shutUp($action, $pit_number)
{
$topic = $this->topic_room;
$data = [
'room_id' => $this->room_id,
'action' => $action,
'pit_number' => $pit_number,
'user_id' => $this->user_id
];
$this->push(self::PUSH_SHUT_UP, $topic, $data);
}
//用户进入房间
public function joinRoom($nickname, $rank_icon, $role, $user_is_new)
{
$topic = $this->topic_room;
$data = [
'room_id' => $this->room_id,
'user_id' => $this->user_id,
'nickname' => $nickname,
'rank_icon' => $rank_icon,
'role' => $role,
'user_is_new' => $user_is_new
];
$this->push(self::PUSH_JOIN_ROOM, $topic, $data);
}
//麦位倒计时
public function countDown($pit_number, $seconds)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'pit_number' => $pit_number, 'seconds' => $seconds];
$this->push(self::PUSH_COUNT_DOWN, $topic, $data);
}
//扔骰子
public function roll($number, $pit_number)
{
$topic = $this->topic_room;
$data = [
'room_id' => $this->room_id,
'user_id' => $this->user_id,
'number' => $number,
'pit_number' => $pit_number
];
$this->push(self::PUSH_ROLL, $topic, $data);
}
//电台房开通黄金守护
public function fmGold($nickname_from, $nickname_to)
{
$topic = 'room';
$data = ['room_id' => $this->room_id, 'nickname_from' => $nickname_from, 'nickname_to' => $nickname_to];
$this->push(self::PUSH_FM_GOLD, $topic, $data);
}
//发送表情
public function face($pit_number, $picture, $special)
{
$topic = $this->topic_room;
$data = [
'room_id' => $this->room_id,
'pit_number' => $pit_number,
'picture' => $picture,
'special' => $special
];
$this->push(self::PUSH_FACE, $topic, $data);
}
//上传即构日志
public function zegoLog()
{
$topic = $this->topic_client;
$data = ['user_id' => $this->user_id];
$this->push(self::PUSH_ZEGO_LOG, $topic, $data);
}
//公屏状态
public function roomChatStatus($status)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'status' => $status];
$this->push(self::PUSH_ROOM_CHAT_STATUS, $topic, $data);
}
//球球大作战-开球
public function ballStart($pit_number)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'pit_number' => $pit_number];
$this->push(self::PUSH_BALL_START, $topic, $data);
}
//球球大作战-弃球
public function ballThrow($pit_number)
{
$topic = $this->topic_room;
$data = ['room_id' => $this->room_id, 'pit_number' => $pit_number];
$this->push(self::PUSH_BALL_THROW, $topic, $data);
}
//球球大作战-亮球
public function ballShow($pit_number, $first, $second, $third)
{
$topic = $this->topic_room;
$data = [
'room_id' => $this->room_id,
'pit_number' => $pit_number,
'first' => $first,
'second' => $second,
'third' => $third,
'user_id' => $this->user_id
];
$this->push(self::PUSH_BALL_SHOW, $topic, $data);
}
//房间音效改变
public function soundEffectChange($sound_effect_detail)
{
$topic = $this->topic_room;
$data = [
'room_id' => $this->room_id,
'id' => $sound_effect_detail['id'],
'config' => $sound_effect_detail['config']
];
$this->push(self::PUSH_SOUND_EFFECT_CHANGE, $topic, $data);
}
//更新房主模式
public function ownerModel($data)
{
$topic = $this->topic_room;
$this->push(self::PUSH_ROOM_OWNER_MODEL, $topic, $data);
}
//退出房间
public function quitRoom($data)
{
$topic = $this->topic_room;
$this->push(self::PUSH_ROOM_QUIT, $topic, $data);
}
public function gamePush($data){
$topic = 'room';
$this->push(self::PUSH_GAME_TIPS, $topic, $data);
}
public function gameProgressPush($data){
$topic = 'room';
$this->push(self::PUSH_WISH_PROGRESS, $topic, $data);
}
//游戏达到大礼物时通知
public function game($giftInfo, $nickname,$title)
{
$txt = "<font color='#FFFFFF'>哇塞</font><font color='#FD8469'>".$nickname."</font><font color='#FFFFFF'>在{$title}中获得</font>";
$txt_extra = [];
foreach ($giftInfo as $key => $value) {
if ($value['price'] >= 5200) {
$txt_extra [] = [
'text' => $txt."<font color='#FABA5C'>".$value['prize_title']."</font><font color='#FFFFFF'>X".$value['number']."</font>",
'picture' => $value['picture']
];
}
}
if (!empty($txt_extra)) {
$topic = 'room';
$this->push(self::PUSH_FISH, $topic, $txt_extra);
}
}
//推送房间类型发生变化
public function roomTypeChange($data)
{
$topic = $this->topic_room;
$this->push(self::PUSH_CHANGE_ROOM_LABEL, $topic, $data);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace app\common\controller;
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\Core\OssException;
class Upload
{
// 显式声明属性
private $config;
private $ossClient; // 修复点:添加该属性声明
private $bucket;
public function __construct()
{
$this->config = get_system_config();
$endpoint = $this->config['oss_region_url'];
$this->bucket= $this->config['oss_bucket_name'];
//获取配置
$this->ossClient = new OssClient(
$this->config['oss_access_key_id'],
$this->config['oss_access_key_secret'],
$endpoint
);
}
/*
* 上传文件
* 参数:
* $bucket: 存储空间名称
* $object: 文件名
* $filePath: 文件路径
* 返回:
* true: 上传成功
* false: 上传失败
*/
public function uploadFile($object, $filePath) {
try {
$result = $this->ossClient->uploadFile($this->bucket, $object, $filePath);
return true; // 上传成功返回true
} catch (OssException $e) {
return false; // 上传失败返回false并记录错误信息例如echo $e->getMessage();
}
}
}

View File

@@ -0,0 +1,622 @@
<?php
namespace app\common\controller;
use app\admin\library\Auth;
use think\Config;
use think\Controller;
use think\Hook;
use think\Lang;
use think\Loader;
use think\Model;
use think\Session;
use fast\Tree;
use think\Validate;
/**
* 后台控制器基类
*/
class adminApi extends Controller
{
/**
* 无需登录的方法,同时也就不需要鉴权了
* @var array
*/
protected $noNeedLogin = [];
/**
* 无需鉴权的方法,但需要登录
* @var array
*/
protected $noNeedRight = [];
/**
* 布局模板
* @var string
*/
protected $layout = 'default';
/**
* 权限控制类
* @var Auth
*/
protected $auth = null;
/**
* 模型对象
* @var \think\Model
*/
protected $model = null;
/**
* 快速搜索时执行查找的字段
*/
protected $searchFields = 'id';
/**
* 是否是关联查询
*/
protected $relationSearch = false;
/**
* 是否开启数据限制
* 支持auth/personal
* 表示按权限判断/仅限个人
* 默认为禁用,若启用请务必保证表中存在admin_id字段
*/
protected $dataLimit = false;
/**
* 数据限制字段
*/
protected $dataLimitField = 'admin_id';
/**
* 数据限制开启时自动填充限制字段值
*/
protected $dataLimitFieldAutoFill = true;
/**
* 是否开启Validate验证
*/
protected $modelValidate = false;
/**
* 是否开启模型场景验证
*/
protected $modelSceneValidate = false;
/**
* Multi方法可批量修改的字段
*/
protected $multiFields = 'status';
/**
* Selectpage可显示的字段
*/
protected $selectpageFields = '*';
/**
* 前台提交过来,需要排除的字段数据
*/
protected $excludeFields = "";
/**
* 导入文件首行类型
* 支持comment/name
* 表示注释或字段名
*/
protected $importHeadType = 'comment';
/**
* 引入后台控制器的traits
*/
use \app\admin\library\traits\Backend;
public function _initialize()
{
//只记录POST请求的日志
if (request()->isPost() && config('myadmin.auto_record_log')) {
$this_auth_rule_name = db('auth_rule')->where('name', substr(xss_clean(strip_tags(request()->url())), 0, 1500))->value('title');
if(empty($this_auth_rule_name)){
$this_auth_rule_name = '未知操作';
}
\app\admin\model\AdminLog::record($this_auth_rule_name);
}
$modulename = $this->request->module();
$controllername = Loader::parseName($this->request->controller());
$actionname = strtolower($this->request->action());
$path = '/' .$modulename.'/' .str_replace('.', '/', $controllername) . '/' . $actionname;
// 定义是否Addtabs请求
!defined('IS_ADDTABS') && define('IS_ADDTABS', (bool)input("addtabs"));
// 定义是否Dialog请求
!defined('IS_DIALOG') && define('IS_DIALOG', (bool)input("dialog"));
// 定义是否AJAX请求
!defined('IS_AJAX') && define('IS_AJAX', $this->request->isAjax());
// 检测IP是否允许
check_ip_allowed();
$this->auth = Auth::instance();
// 设置当前请求的URI
$this->auth->setRequestUri($path);
// 检测是否需要验证登录
if (!$this->auth->match($this->noNeedLogin)) {
//获取 token
//通过头部信息获取authorization0
$token = $this->request->server('HTTP_AUTHORIZATION', $this->request->request('token', \think\Cookie::get('token')));
//检测是否登录
if (!$this->auth->isLogin($token)) {
Hook::listen('admin_nologin', $this);
$url = Session::get('referer');
$url = $url ? $url : $this->request->url();
if (in_array($this->request->pathinfo(), ['/', 'index/index'])) {
return V(301,"请登录后操作", url('index/login', ['url' => $url]));
exit;
}
return V(301,"请登录后操作", url('index/login', ['url' => $url]));
}
// 判断是否需要验证权限
if (!$this->auth->match($this->noNeedRight)) {
// 判断控制器和方法是否有对应权限
if (!$this->auth->check($path)) {
Hook::listen('admin_nopermission', $this);
return V(302,"你没有权限访问", url('index/login', []));
}
}
}
// 非选项卡时重定向
if (!$this->request->isPost() && !IS_AJAX && !IS_ADDTABS && !IS_DIALOG && input("ref") == 'addtabs') {
$url = preg_replace_callback("/([\?|&]+)ref=addtabs(&?)/i", function ($matches) {
return $matches[2] == '&' ? $matches[1] : '';
}, $this->request->url());
if (Config::get('url_domain_deploy')) {
if (stripos($url, $this->request->server('SCRIPT_NAME')) === 0) {
$url = substr($url, strlen($this->request->server('SCRIPT_NAME')));
}
$url = url($url, '', false);
}
$this->redirect('index/index', [], 302, ['referer' => $url]);
exit;
}
// 设置面包屑导航数据
$breadcrumb = [];
if (!IS_DIALOG && !config('fastadmin.multiplenav') && config('fastadmin.breadcrumb')) {
$breadcrumb = $this->auth->getBreadCrumb($path);
array_pop($breadcrumb);
}
$this->view->breadcrumb = $breadcrumb;
// 如果有使用模板布局
if ($this->layout) {
$this->view->engine->layout('layout/' . $this->layout);
}
// 语言检测
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
$site = Config::get("site");
$upload = \app\common\model\Config::upload();
// 上传信息配置后
Hook::listen("upload_config_init", $upload);
// 配置信息
$config = [
'site' => array_intersect_key($site, array_flip(['name', 'indexurl', 'cdnurl', 'version', 'timezone', 'languages'])),
'upload' => $upload,
'modulename' => $modulename,
'controllername' => $controllername,
'actionname' => $actionname,
'jsname' => 'backend/' . str_replace('.', '/', $controllername),
'moduleurl' => rtrim(url("/{$modulename}", '', false), '/'),
'language' => $lang,
'referer' => Session::get("referer")
];
$config = array_merge($config, Config::get("view_replace_str"));
Config::set('upload', array_merge(Config::get('upload'), $upload));
// 配置信息后
Hook::listen("config_init", $config);
//加载当前控制器语言包
$this->loadlang($controllername);
//渲染站点配置
$this->assign('site', $site);
//渲染配置信息
$this->assign('config', $config);
//渲染权限对象
$this->assign('auth', $this->auth);
//渲染管理员对象
$this->assign('admin', Session::get('admin'));
}
/**
* 加载语言文件
* @param string $name
*/
protected function loadlang($name)
{
$name = Loader::parseName($name);
$name = preg_match("/^([a-zA-Z0-9_\.\/]+)\$/i", $name) ? $name : 'index';
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php');
}
/**
* 渲染配置信息
* @param mixed $name 键名或数组
* @param mixed $value 值
*/
protected function assignconfig($name, $value = '')
{
$this->view->config = array_merge($this->view->config ? $this->view->config : [], is_array($name) ? $name : [$name => $value]);
}
/**
* 生成查询所需要的条件,排序方式
* @param mixed $searchfields 快速查询的字段
* @param boolean $relationSearch 是否关联查询
* @return array
*/
protected function buildparams($searchfields = null, $relationSearch = null)
{
$searchfields = is_null($searchfields) ? $this->searchFields : $searchfields;
$relationSearch = is_null($relationSearch) ? $this->relationSearch : $relationSearch;
$search = $this->request->get("search", '');
$filter = $this->request->get("filter", '');
$op = $this->request->get("op", '', 'trim');
$sort = $this->request->get("sort", !empty($this->model) && $this->model->getPk() ? $this->model->getPk() : 'id');
$order = $this->request->get("order", "DESC");
$offset = max(0, $this->request->get("offset/d", 0));
$limit = max(0, $this->request->get("limit/d", 0));
$limit = $limit ?: 999999;
//新增自动计算页码
$page = $limit ? intval($offset / $limit) + 1 : 1;
if ($this->request->has("page")) {
$page = max(0, $this->request->get("page/d", 1));
}
$this->request->get([config('paginate.var_page') => $page]);
$filter = (array)json_decode($filter, true);
$op = (array)json_decode($op, true);
$filter = $filter ? $filter : [];
$where = [];
$alias = [];
$bind = [];
$name = '';
$aliasName = '';
if (!empty($this->model) && $relationSearch) {
$name = $this->model->getTable();
$alias[$name] = Loader::parseName(basename(str_replace('\\', '/', get_class($this->model))));
$aliasName = $alias[$name] . '.';
}
$sortArr = explode(',', $sort);
foreach ($sortArr as $index => & $item) {
$item = stripos($item, ".") === false ? $aliasName . trim($item) : $item;
}
unset($item);
$sort = implode(',', $sortArr);
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
$where[] = [$aliasName . $this->dataLimitField, 'in', $adminIds];
}
if ($search) {
$searcharr = is_array($searchfields) ? $searchfields : explode(',', $searchfields);
foreach ($searcharr as $k => &$v) {
$v = stripos($v, ".") === false ? $aliasName . $v : $v;
}
unset($v);
$where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"];
}
$index = 0;
foreach ($filter as $k => $v) {
if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $k)) {
continue;
}
$sym = $op[$k] ?? '=';
if (stripos($k, ".") === false) {
$k = $aliasName . $k;
}
$v = !is_array($v) ? trim($v) : $v;
$sym = strtoupper($op[$k] ?? $sym);
//null和空字符串特殊处理
if (!is_array($v)) {
if (in_array(strtoupper($v), ['NULL', 'NOT NULL'])) {
$sym = strtoupper($v);
}
if (in_array($v, ['""', "''"])) {
$v = '';
$sym = '=';
}
}
switch ($sym) {
case '=':
case '<>':
$where[] = [$k, $sym, (string)$v];
break;
case 'LIKE':
case 'NOT LIKE':
case 'LIKE %...%':
case 'NOT LIKE %...%':
$where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
break;
case '>':
case '>=':
case '<':
case '<=':
$where[] = [$k, $sym, intval($v)];
break;
case 'FINDIN':
case 'FINDINSET':
case 'FIND_IN_SET':
$v = is_array($v) ? $v : explode(',', str_replace(' ', ',', $v));
$findArr = array_values($v);
foreach ($findArr as $idx => $item) {
$bindName = "item_" . $index . "_" . $idx;
$bind[$bindName] = $item;
$where[] = "FIND_IN_SET(:{$bindName}, `" . str_replace('.', '`.`', $k) . "`)";
}
break;
case 'IN':
case 'IN(...)':
case 'NOT IN':
case 'NOT IN(...)':
$where[] = [$k, str_replace('(...)', '', $sym), is_array($v) ? $v : explode(',', $v)];
break;
case 'BETWEEN':
case 'NOT BETWEEN':
$arr = array_slice(explode(',', $v), 0, 2);
if (stripos($v, ',') === false || !array_filter($arr, function ($v) {
return $v != '' && $v !== false && $v !== null;
})) {
continue 2;
}
//当出现一边为空时改变操作符
if ($arr[0] === '') {
$sym = $sym == 'BETWEEN' ? '<=' : '>';
$arr = $arr[1];
} elseif ($arr[1] === '') {
$sym = $sym == 'BETWEEN' ? '>=' : '<';
$arr = $arr[0];
}
$where[] = [$k, $sym, $arr];
break;
case 'RANGE':
case 'NOT RANGE':
$v = str_replace(' - ', ',', $v);
$arr = array_slice(explode(',', $v), 0, 2);
if (stripos($v, ',') === false || !array_filter($arr)) {
continue 2;
}
//当出现一边为空时改变操作符
if ($arr[0] === '') {
$sym = $sym == 'RANGE' ? '<=' : '>';
$arr = $arr[1];
} elseif ($arr[1] === '') {
$sym = $sym == 'RANGE' ? '>=' : '<';
$arr = $arr[0];
}
$tableArr = explode('.', $k);
if (count($tableArr) > 1 && $tableArr[0] != $name && !in_array($tableArr[0], $alias)
&& !empty($this->model) && $this->relationSearch) {
//修复关联模型下时间无法搜索的BUG
$relation = Loader::parseName($tableArr[0], 1, false);
$alias[$this->model->$relation()->getTable()] = $tableArr[0];
}
$where[] = [$k, str_replace('RANGE', 'BETWEEN', $sym) . ' TIME', $arr];
break;
case 'NULL':
case 'IS NULL':
case 'NOT NULL':
case 'IS NOT NULL':
$where[] = [$k, strtolower(str_replace('IS ', '', $sym))];
break;
default:
break;
}
$index++;
}
if (!empty($this->model)) {
$this->model->alias($alias);
}
$model = $this->model;
$where = function ($query) use ($where, $alias, $bind, &$model) {
if (!empty($model)) {
$model->alias($alias);
$model->bind($bind);
}
foreach ($where as $k => $v) {
if (is_array($v)) {
call_user_func_array([$query, 'where'], $v);
} else {
$query->where($v);
}
}
};
return [$where, $sort, $order, $offset, $limit, $page, $alias, $bind];
}
/**
* 获取数据限制的管理员ID
* 禁用数据限制时返回的是null
* @return mixed
*/
protected function getDataLimitAdminIds()
{
if (!$this->dataLimit) {
return null;
}
if ($this->auth->isSuperAdmin()) {
return null;
}
$adminIds = [];
if (in_array($this->dataLimit, ['auth', 'personal'])) {
$adminIds = $this->dataLimit == 'auth' ? $this->auth->getChildrenAdminIds(true) : [$this->auth->id];
}
return $adminIds;
}
/**
* Selectpage的实现方法
*
* 当前方法只是一个比较通用的搜索匹配,请按需重载此方法来编写自己的搜索逻辑,$where按自己的需求写即可
* 这里示例了所有的参数,所以比较复杂,实现上自己实现只需简单的几行即可
*
*/
protected function selectpage()
{
//设置过滤方法
$this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']);
//搜索关键词,客户端输入以空格分开,这里接收为数组
$word = (array)$this->request->request("q_word/a");
//当前页
$page = $this->request->request("pageNumber");
//分页大小
$pagesize = $this->request->request("pageSize");
//搜索条件
$andor = $this->request->request("andOr", "and", "strtoupper");
//排序方式
$orderby = (array)$this->request->request("orderBy/a");
//显示的字段
$field = $this->request->request("showField");
//主键
$primarykey = $this->request->request("keyField");
//主键值
$primaryvalue = $this->request->request("keyValue");
//搜索字段
$searchfield = (array)$this->request->request("searchField/a");
//自定义搜索条件
$custom = (array)$this->request->request("custom/a");
//是否返回树形结构
$istree = $this->request->request("isTree", 0);
$ishtml = $this->request->request("isHtml", 0);
if ($istree) {
$word = [];
$pagesize = 999999;
}
$order = [];
foreach ($orderby as $k => $v) {
$order[$v[0]] = $v[1];
}
$field = $field ? $field : 'name';
//如果有primaryvalue,说明当前是初始化传值
if ($primaryvalue !== null) {
$where = [$primarykey => ['in', $primaryvalue]];
$pagesize = 999999;
} else {
$where = function ($query) use ($word, $andor, $field, $searchfield, $custom) {
$logic = $andor == 'AND' ? '&' : '|';
$searchfield = is_array($searchfield) ? implode($logic, $searchfield) : $searchfield;
$searchfield = str_replace(',', $logic, $searchfield);
$word = array_filter(array_unique($word));
if (count($word) == 1) {
$query->where($searchfield, "like", "%" . reset($word) . "%");
} else {
$query->where(function ($query) use ($word, $searchfield) {
foreach ($word as $index => $item) {
$query->whereOr(function ($query) use ($item, $searchfield) {
$query->where($searchfield, "like", "%{$item}%");
});
}
});
}
if ($custom && is_array($custom)) {
foreach ($custom as $k => $v) {
if (is_array($v) && 2 == count($v)) {
$query->where($k, trim($v[0]), $v[1]);
} else {
$query->where($k, '=', $v);
}
}
}
};
}
$adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$list = [];
$total = $this->model->where($where)->count();
if ($total > 0) {
if (is_array($adminIds)) {
$this->model->where($this->dataLimitField, 'in', $adminIds);
}
$fields = is_array($this->selectpageFields) ? $this->selectpageFields : ($this->selectpageFields && $this->selectpageFields != '*' ? explode(',', $this->selectpageFields) : []);
//如果有primaryvalue,说明当前是初始化传值,按照选择顺序排序
if ($primaryvalue !== null && preg_match("/^[a-z0-9_\-]+$/i", $primarykey)) {
$primaryvalue = array_unique(is_array($primaryvalue) ? $primaryvalue : explode(',', $primaryvalue));
//修复自定义data-primary-key为字符串内容时给排序字段添加上引号
$primaryvalue = array_map(function ($value) {
return '\'' . $value . '\'';
}, $primaryvalue);
$primaryvalue = implode(',', $primaryvalue);
$this->model->orderRaw("FIELD(`{$primarykey}`, {$primaryvalue})");
} else {
$this->model->order($order);
}
$datalist = $this->model->where($where)
->page($page, $pagesize)
->select();
foreach ($datalist as $index => $item) {
unset($item['password'], $item['salt']);
if ($this->selectpageFields == '*') {
$result = [
$primarykey => $item[$primarykey] ?? '',
$field => $item[$field] ?? '',
];
} else {
$result = array_intersect_key(($item instanceof Model ? $item->toArray() : (array)$item), array_flip($fields));
}
$result['pid'] = isset($item['pid']) ? $item['pid'] : (isset($item['parent_id']) ? $item['parent_id'] : 0);
$result = array_map("htmlentities", $result);
$list[] = $result;
}
if ($istree && !$primaryvalue) {
$tree = Tree::instance();
$tree->init(collection($list)->toArray(), 'pid');
$list = $tree->getTreeList($tree->getTreeArray(0), $field);
if (!$ishtml) {
foreach ($list as &$item) {
$item = str_replace('&nbsp;', ' ', $item);
}
unset($item);
}
}
}
//这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮
return json(['list' => $list, 'total' => $total]);
}
/**
* 刷新Token
*/
protected function token()
{
$token = $this->request->param('__token__');
//验证Token
if (!Validate::make()->check(['__token__' => $token], ['__token__' => 'require|token'])) {
$this->error(__('Token verification error'), '', ['__token__' => $this->request->token()]);
}
//刷新Token
$this->request->token();
}
}