mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-01 15:32:48 +08:00
549 lines
16 KiB
PHP
549 lines
16 KiB
PHP
<?php
|
||
|
||
namespace base\common\controller;
|
||
|
||
use app\admin\model\SystemAdmin;
|
||
use app\BaseController;
|
||
use app\common\constants\AdminConstant;
|
||
use app\common\service\AuthService;
|
||
use think\facade\Cache;
|
||
use think\facade\Config;
|
||
use think\facade\Env;
|
||
use think\facade\View;
|
||
use think\Model;
|
||
use think\response\Json;
|
||
use think\template\exception\TemplateNotFoundException;
|
||
use think\Validate;
|
||
|
||
/**
|
||
* Class AdminController.
|
||
*/
|
||
class AdminControllerBase extends BaseController
|
||
{
|
||
use \app\common\traits\JumpTrait;
|
||
|
||
protected $pageKeyName = null;
|
||
|
||
/**
|
||
* 当前模型.
|
||
* @Model
|
||
* @var object
|
||
*/
|
||
protected $model;
|
||
|
||
/**
|
||
* 字段排序.
|
||
* @var array
|
||
*/
|
||
protected $sort = [
|
||
'id' => 'desc',
|
||
];
|
||
|
||
/**
|
||
* 允许修改的字段.
|
||
* @var array
|
||
*/
|
||
protected $allowModifyFields = [
|
||
'status',
|
||
'sort',
|
||
'remark',
|
||
'is_delete',
|
||
'title',
|
||
];
|
||
|
||
/**
|
||
* 不导出的字段信息.
|
||
* @var array
|
||
*/
|
||
protected $noExportFields = ['delete_time', 'update_time'];
|
||
|
||
/**
|
||
* 下拉选择条件.
|
||
* @var array
|
||
*/
|
||
protected $selectWhere = [];
|
||
|
||
/**
|
||
* 是否关联查询.
|
||
* @var bool
|
||
*/
|
||
protected $relationSearch = false;
|
||
|
||
/**
|
||
* 模板布局, false取消.
|
||
* @var string|bool
|
||
*/
|
||
protected $layout = 'layout/default';
|
||
|
||
/**
|
||
* 是否为演示环境.
|
||
* @var bool
|
||
*/
|
||
protected $isDemo = false;
|
||
|
||
/**
|
||
* 多元传参
|
||
*
|
||
* @var array
|
||
*/
|
||
private $dataBrage = [];
|
||
|
||
private $internalDataFields = [];
|
||
|
||
protected $validateRule = null;
|
||
|
||
protected $validateMessage = [];
|
||
|
||
protected $batchValidate = false;
|
||
|
||
/**
|
||
* 导出文件的名称,支持中文,为空则获取模型名称.
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $exportFileName = null;
|
||
|
||
/**
|
||
* 当前登陆的管理员.
|
||
* @var SystemAdmin
|
||
*/
|
||
protected $sessionAdmin;
|
||
|
||
/**
|
||
* 初始化方法.
|
||
*/
|
||
protected function initialize()
|
||
{
|
||
if (empty($this->pageKeyName)) {
|
||
$this->pageKeyName = $this->request->controller() . '_' . $this->request->action();
|
||
}
|
||
|
||
parent::initialize();
|
||
$this->layout && $this->app->view->engine()->layout($this->layout);
|
||
$this->isDemo = Env::get('adminsystem.is_demo', false);
|
||
$this->viewInit();
|
||
$this->checkAuth();
|
||
|
||
$this->initSort();
|
||
}
|
||
|
||
public function initSort()
|
||
{
|
||
$sort = $this->request->param('sort');
|
||
|
||
if (!empty($sort)) {
|
||
$this->sort = $sort;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 模板变量赋值
|
||
* @param string|array $name 模板变量
|
||
* @param mixed $value 变量值
|
||
* @return mixed
|
||
*/
|
||
public function assign($name, $value = null, $isAppendToDataBrage = false, $forceObject = false)
|
||
{
|
||
if (is_array($name)) {
|
||
$forceObject = $isAppendToDataBrage;
|
||
$isAppendToDataBrage = $value;
|
||
|
||
if ($isAppendToDataBrage === true) {
|
||
foreach ($name as $k => $v) {
|
||
$this->setDataBrage($k, $v, $forceObject);
|
||
}
|
||
} elseif ($isAppendToDataBrage === -1) {
|
||
$this->internalDataFields = array_merge($this->internalDataFields, array_keys($name));
|
||
}
|
||
} else {
|
||
if ($isAppendToDataBrage === true) {
|
||
$this->setDataBrage($name, $value, $forceObject);
|
||
} elseif ($isAppendToDataBrage === -1) {
|
||
$this->internalDataFields[] = $name;
|
||
}
|
||
}
|
||
|
||
return $this->app->view->assign($name, $value);
|
||
}
|
||
|
||
public function fetchJS($template = '')
|
||
{
|
||
$content_js = '';
|
||
|
||
$common_template = '_common';
|
||
|
||
if (!empty($template)) {
|
||
$template_arr = explode('/', $template);
|
||
unset($template_arr[count($template_arr) - 1]);
|
||
$template_arr[] = '_common';
|
||
$common_template = implode('/', $template_arr);
|
||
}
|
||
|
||
try {
|
||
$content_js .= View::layout(false)->fetchJS($common_template);
|
||
$content_js .= View::layout(false)->fetchJS($template);
|
||
} catch (TemplateNotFoundException $th) {
|
||
if (Env::get('adminsystem.strict_view_js', true)) {
|
||
throw $th;
|
||
}
|
||
}
|
||
|
||
return "<script>{$content_js}</script>";
|
||
}
|
||
|
||
/**
|
||
* 解析和获取模板内容 用于输出.
|
||
* @param string $template
|
||
* @param array $vars
|
||
* @return mixed
|
||
*/
|
||
public function fetch($template = '', $vars = [])
|
||
{
|
||
$this->assign('data_brage', json_encode($this->dataBrage));
|
||
$this->assign('content_js', $this->fetchJS($template), -1);
|
||
|
||
$content_main = View::layout($this->layout)
|
||
->config([
|
||
'view_suffix' => 'html',
|
||
])->fetch($template, $vars);
|
||
|
||
$html = '';
|
||
$html .= $content_main;
|
||
if ($this->checkParseApi()) {
|
||
$data = $this->parseInternalDataFields(View::fetchData());
|
||
$r = json_message($data);
|
||
|
||
return $r;
|
||
}
|
||
|
||
return $html;
|
||
}
|
||
|
||
public function checkParseApi()
|
||
{
|
||
if (Config::get('app.auto_parse_api')) {
|
||
if ($this->request->isJson() && $this->request->param('get_page_data')) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 处理数据,过滤内部字段.
|
||
* @param array $data 内部数据
|
||
* @return array
|
||
*/
|
||
public function parseInternalDataFields($data)
|
||
{
|
||
foreach ($this->internalDataFields as $field) {
|
||
if (isset($data[$field])) {
|
||
unset($data[$field]);
|
||
}
|
||
}
|
||
|
||
if (isset($data['data_brage'])) {
|
||
$data_brage = json_decode($data['data_brage'], true);
|
||
|
||
// 如果data_brage中的key在data中存在,则删掉data_brage中的
|
||
foreach ($data as $key => $value) {
|
||
if (isset($data_brage[$key])) {
|
||
unset($data_brage[$key]);
|
||
}
|
||
}
|
||
|
||
$data['data_brage'] = $data_brage;
|
||
}
|
||
|
||
return $data;
|
||
}
|
||
|
||
/**
|
||
* 设置dataBrage数据.
|
||
*
|
||
* @param string $name 键
|
||
* @param mixed $value 值
|
||
* @param bool $forceObject 强制转为对象
|
||
* @return void
|
||
*/
|
||
public function setDataBrage($name, $value, $forceObject = false)
|
||
{
|
||
if (is_array($name)) {
|
||
foreach ($name as $k => $v) {
|
||
$this->setDataBrage($k, $v, $forceObject);
|
||
}
|
||
|
||
return $this;
|
||
}
|
||
|
||
if ($forceObject && !is_object($value)) {
|
||
$value = (object) $value;
|
||
}
|
||
|
||
$this->dataBrage[$name] = $value;
|
||
|
||
return $this;
|
||
}
|
||
|
||
/**
|
||
* 重写验证规则.
|
||
* @param array $data
|
||
* @param array|string $validate
|
||
* @param array $message
|
||
* @param bool|null $batch
|
||
* @return array|bool|string|true
|
||
*/
|
||
public function validate(array $data, $validate, array $message = [], bool $batch = null)
|
||
{
|
||
try {
|
||
$message = array_merge($this->validateMessage, $message);
|
||
|
||
if (is_null($batch)) {
|
||
$batch = $this->batchValidate;
|
||
}
|
||
|
||
if ($this->validateRule instanceof Validate) {
|
||
$this->validateRule->message($message);
|
||
|
||
// 是否批量验证
|
||
if ($batch) {
|
||
$this->validateRule->batch(true);
|
||
}
|
||
|
||
$this->validateRule->failException(true)->check($data);
|
||
} elseif (is_array($this->validateRule)) {
|
||
parent::validate($data, $this->validateRule, $message, $batch);
|
||
} else {
|
||
parent::validate($data, $validate, $message, $batch);
|
||
}
|
||
} catch (\Exception $e) {
|
||
$this->error($e->getMessage());
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 构建请求参数.
|
||
* @param array $excludeFields 忽略构建搜索的字段
|
||
* @return array
|
||
*/
|
||
protected function buildTableParames($excludeFields = [])
|
||
{
|
||
$get = $this->request->get('', null);
|
||
|
||
$page = isset($get['page']) && !empty($get['page']) ? $get['page'] : 1;
|
||
$limit = isset($get['limit']) && !empty($get['limit']) ? $get['limit'] : 15;
|
||
$group = isset($get['group']) && !empty($get['group']) ? $get['group'] : null;
|
||
$filters = isset($get['filter']) && !empty($get['filter']) ? $get['filter'] : '{}';
|
||
$ops = isset($get['op']) && !empty($get['op']) ? $get['op'] : '{}';
|
||
// json转数组
|
||
$filters = json_decode($filters, true) ?? [];
|
||
$ops = json_decode($ops, true);
|
||
$where = [];
|
||
$excludes = [];
|
||
|
||
$request_options = [];
|
||
|
||
// 判断是否关联查询
|
||
$tableName = \think\helper\Str::snake(lcfirst($this->model->getName()));
|
||
|
||
foreach ($filters as $key => $val) {
|
||
if (in_array($key, $excludeFields)) {
|
||
$excludes[$key] = $val;
|
||
continue;
|
||
}
|
||
|
||
$op = isset($ops[$key]) && !empty($ops[$key]) ? $ops[$key] : '%*%';
|
||
|
||
if (strpos($key, '[') === 0) {
|
||
$key = str_replace('[', '', $key);
|
||
|
||
$key = explode(']', $key)[0];
|
||
}
|
||
|
||
if ($this->relationSearch && count(explode('.', $key)) == 1) {
|
||
$key = "{$tableName}.{$key}";
|
||
}
|
||
switch (strtolower($op)) {
|
||
case '=':
|
||
$where[] = [$key, '=', $val];
|
||
break;
|
||
case '%*%':
|
||
$where[] = [$key, 'LIKE', "%{$val}%"];
|
||
break;
|
||
case '*%':
|
||
$where[] = [$key, 'LIKE', "{$val}%"];
|
||
break;
|
||
case '%*':
|
||
$where[] = [$key, 'LIKE', "%{$val}"];
|
||
case 'in':
|
||
$where[] = [$key, 'IN', "{$val}"];
|
||
break;
|
||
case 'min':
|
||
$where[] = [$key, '>=', $val];
|
||
break;
|
||
case 'max':
|
||
$where[] = [$key, '<=', $val];
|
||
break;
|
||
case 'min_date':
|
||
$where[] = [$key, '>=', strtotime($val)];
|
||
break;
|
||
case 'max_date':
|
||
$where[] = [$key, '<=', strtotime($val)];
|
||
break;
|
||
case 'range':
|
||
[$beginTime, $endTime] = explode(' - ', $val);
|
||
$where[] = [$key, '>=', strtotime($beginTime)];
|
||
$where[] = [$key, '<=', strtotime($endTime)];
|
||
break;
|
||
case 'none':
|
||
$request_options[$key] = $val;
|
||
break;
|
||
default:
|
||
$where[] = [$key, $op, "%{$val}"];
|
||
}
|
||
}
|
||
|
||
return [$page, $limit, $where, $excludes, $request_options, $group];
|
||
}
|
||
|
||
/**
|
||
* 下拉选择列表.
|
||
* @return Json
|
||
*/
|
||
public function selectList()
|
||
{
|
||
$fields = input('selectFields');
|
||
$data = $this->model
|
||
->where($this->selectWhere)
|
||
->field($fields)
|
||
->select();
|
||
$this->success(null, $data);
|
||
}
|
||
|
||
/**
|
||
* 初始化视图参数.
|
||
*/
|
||
private function viewInit()
|
||
{
|
||
$request = app()->request;
|
||
list($thisModule, $thisController, $thisAction) = [app('http')->getName(), app()->request->controller(), $request->action()];
|
||
list($thisControllerArr, $jsPath) = [explode('.', $thisController), null];
|
||
foreach ($thisControllerArr as $vo) {
|
||
empty($jsPath) ? $jsPath = parse_name($vo) : $jsPath .= '/' . parse_name($vo);
|
||
}
|
||
$autoloadJs = file_exists(root_path('public') . "static/{$thisModule}/js/{$jsPath}.js") ? true : false;
|
||
$thisControllerJsPath = "{$thisModule}/js/{$jsPath}.js";
|
||
$adminModuleName = config('app.admin_alias_name');
|
||
$isSuperAdmin = session('admin.id') == AdminConstant::SUPER_ADMIN_ID ? true : false;
|
||
$data = [
|
||
'adminModuleName' => $adminModuleName,
|
||
'thisController' => parse_name($thisController),
|
||
'thisAction' => $thisAction,
|
||
'thisRequest' => parse_name("{$thisModule}/{$thisController}/{$thisAction}"),
|
||
'thisControllerJsPath' => "{$thisControllerJsPath}",
|
||
'autoloadJs' => $autoloadJs,
|
||
'isSuperAdmin' => $isSuperAdmin,
|
||
'version' => env('app_debug') ? time() : sysconfig('site', 'site_version'),
|
||
'pageKeyName' => $this->pageKeyName,
|
||
];
|
||
|
||
$this->assign($data, -1);
|
||
}
|
||
|
||
/**
|
||
* 检测权限.
|
||
* @throws \think\db\exception\DataNotFoundException
|
||
* @throws \think\db\exception\DbException
|
||
* @throws \think\db\exception\ModelNotFoundException
|
||
*/
|
||
protected function checkAuth($currentNode = null, $haltRequest = true)
|
||
{
|
||
$adminConfig = config('admin');
|
||
|
||
$token = $this->readHeaderToken();
|
||
if (!empty($token)) {
|
||
$admin = Cache::get($token);
|
||
} else {
|
||
$admin = session('admin');
|
||
}
|
||
|
||
$back_url = $this->request->url();
|
||
|
||
$adminId = $admin['id'] ?? '';
|
||
$expireTime = $admin['expire_time'] ?? '';
|
||
|
||
/** @var AuthService $authService */
|
||
$authService = app(AuthService::class, ['adminId' => $adminId]);
|
||
|
||
$currentNode = $authService->getCurrentNode();
|
||
if (is_null($currentNode)) {
|
||
$currentNode = $authService->getCurrentNode();
|
||
}
|
||
|
||
$currentController = parse_name(app()->request->controller());
|
||
|
||
// 验证登录
|
||
if (
|
||
!in_array($currentController, $adminConfig['no_login_controller']) &&
|
||
!in_array($currentNode, $adminConfig['no_login_node'])
|
||
) {
|
||
empty($adminId) && $this->error('请先登录后台', [], __url('admin/login/index', ['back_url' => $back_url]));
|
||
|
||
// 判断是否登录过期
|
||
if ($expireTime !== true && time() > $expireTime) {
|
||
session('admin', null);
|
||
$this->error('登录已过期,请重新登录', [], __url('admin/login/index', ['back_url' => $back_url]));
|
||
}
|
||
}
|
||
|
||
// 验证权限
|
||
if (
|
||
!in_array($currentController, $adminConfig['no_auth_controller']) &&
|
||
!in_array($currentNode, $adminConfig['no_auth_node'])
|
||
) {
|
||
$check = $authService->checkNode($currentNode);
|
||
|
||
if ($haltRequest) {
|
||
if (!$check) {
|
||
$this->error('无权限访问');
|
||
}
|
||
} else {
|
||
return $check;
|
||
}
|
||
|
||
// 判断是否为演示环境
|
||
if (env('adminsystem.is_demo', false) && app()->request->isPost()) {
|
||
$this->error('演示环境下不允许修改');
|
||
}
|
||
}
|
||
|
||
$model_admin = SystemAdmin::autoCache('read', $adminId)->find($adminId);
|
||
|
||
$this->sessionAdmin = $model_admin;
|
||
|
||
$this->assign('session_admin', $model_admin, -1);
|
||
}
|
||
|
||
protected function readHeaderToken(){
|
||
$header_authorization = $this->request->header('Authorization');
|
||
if (!empty($header_authorization)) {
|
||
$token = explode(' ', $header_authorization)[1];
|
||
return $token;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 严格校验接口是否为POST请求
|
||
*/
|
||
protected function checkPostRequest()
|
||
{
|
||
if (!$this->request->isPost()) {
|
||
$this->error('当前请求不合法!');
|
||
}
|
||
}
|
||
}
|