Admin.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 海豚PHP框架 [ DolphinPHP ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2016~2019 广东卓锐软件有限公司 [ http://www.zrthink.com ]
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://dolphinphp.com
  8. // +----------------------------------------------------------------------
  9. namespace app\admin\controller;
  10. use app\common\controller\Common;
  11. use app\common\builder\ZBuilder;
  12. use app\admin\model\Menu as MenuModel;
  13. use app\admin\model\Module as ModuleModel;
  14. use app\admin\model\Icon as IconModel;
  15. use app\user\model\Role as RoleModel;
  16. use app\user\model\Message as MessageModel;
  17. use think\facade\Cache;
  18. use think\Db;
  19. use think\facade\App;
  20. use think\helper\Hash;
  21. /**
  22. * 后台公共控制器
  23. * @package app\admin\controller
  24. */
  25. class Admin extends Common
  26. {
  27. /**
  28. * 初始化
  29. * @author 蔡伟明 <314013107@qq.com>
  30. * @throws \think\Exception
  31. */
  32. protected function initialize()
  33. {
  34. parent::initialize();
  35. // 是否拒绝ie浏览器访问
  36. if (config('system.deny_ie') && get_browser_type() == 'ie') {
  37. $this->redirect('admin/ie/index');
  38. }
  39. // 判断是否登录,并定义用户ID常量
  40. defined('UID') or define('UID', $this->isLogin());
  41. // 设置当前角色菜单节点权限
  42. role_auth();
  43. // 检查权限
  44. if (!RoleModel::checkAuth()) $this->error('权限不足!');
  45. // 设置分页参数
  46. $this->setPageParam();
  47. // 如果不是ajax请求,则读取菜单
  48. if (!$this->request->isAjax()) {
  49. // 读取顶部菜单
  50. $this->assign('_top_menus', MenuModel::getTopMenu(config('top_menu_max'), '_top_menus'));
  51. // 读取全部顶级菜单
  52. $this->assign('_top_menus_all', MenuModel::getTopMenu('', '_top_menus_all'));
  53. // 获取侧边栏菜单
  54. $this->assign('_sidebar_menus', MenuModel::getSidebarMenu());
  55. // 获取面包屑导航
  56. $this->assign('_location', MenuModel::getLocation('', true));
  57. // 获取当前用户未读消息数量
  58. $this->assign('_message', MessageModel::getMessageCount());
  59. // 获取自定义图标
  60. $this->assign('_icons', IconModel::getUrls());
  61. // 构建侧栏
  62. $data = [
  63. 'table' => 'admin_config', // 表名或模型名
  64. 'prefix' => 1,
  65. 'module' => 'admin',
  66. 'controller' => 'system',
  67. 'action' => 'quickedit',
  68. ];
  69. $table_token = substr(sha1('_aside'), 0, 8);
  70. session($table_token, $data);
  71. $settings = [
  72. [
  73. 'title' => '站点开关',
  74. 'tips' => '站点关闭后将不能访问',
  75. 'checked' => Db::name('admin_config')->where('id', 1)->value('value'),
  76. 'table' => $table_token,
  77. 'id' => 1,
  78. 'field' => 'value'
  79. ]
  80. ];
  81. ZBuilder::make('aside')
  82. ->addBlock('switch', '系统设置', $settings);
  83. }
  84. }
  85. /**
  86. * 获取当前操作模型
  87. * @author 蔡伟明 <314013107@qq.com>
  88. * @return object|\think\db\Query
  89. */
  90. final protected function getCurrModel()
  91. {
  92. $table_token = input('param._t', '');
  93. $module = $this->request->module();
  94. $controller = parse_name($this->request->controller());
  95. $table_token == '' && $this->error('缺少参数');
  96. !session('?'.$table_token) && $this->error('参数错误');
  97. $table_data = session($table_token);
  98. $table = $table_data['table'];
  99. $Model = null;
  100. if ($table_data['prefix'] == 2) {
  101. // 使用模型
  102. try {
  103. $Model = App::model($table);
  104. } catch (\Exception $e) {
  105. $this->error('找不到模型:'.$table);
  106. }
  107. } else {
  108. // 使用DB类
  109. $table == '' && $this->error('缺少表名');
  110. if ($table_data['module'] != $module || $table_data['controller'] != $controller) {
  111. $this->error('非法操作');
  112. }
  113. $Model = $table_data['prefix'] == 0 ? Db::table($table) : Db::name($table);
  114. }
  115. return $Model;
  116. }
  117. /**
  118. * 设置分页参数
  119. * @author 蔡伟明 <314013107@qq.com>
  120. */
  121. final protected function setPageParam()
  122. {
  123. _system_check();
  124. $list_rows = input('?param.list_rows') ? input('param.list_rows') : config('list_rows');
  125. config('paginate.list_rows', $list_rows);
  126. config('paginate.query', input('get.'));
  127. }
  128. /**
  129. * 检查是否登录,没有登录则跳转到登录页面
  130. * @author 蔡伟明 <314013107@qq.com>
  131. * @return int
  132. */
  133. final protected function isLogin()
  134. {
  135. // 判断是否登录
  136. if ($uid = is_signin()) {
  137. // 已登录
  138. return $uid;
  139. } else {
  140. // 未登录
  141. $this->redirect('user/publics/signin');
  142. }
  143. }
  144. /**
  145. * 禁用
  146. * @param array $record 行为日志内容
  147. * @author 蔡伟明 <314013107@qq.com>
  148. * @throws \think\Exception
  149. * @throws \think\exception\PDOException
  150. */
  151. public function disable($record = [])
  152. {
  153. return $this->setStatus('disable', $record);
  154. }
  155. /**
  156. * 启用
  157. * @param array $record 行为日志内容
  158. * @author 蔡伟明 <314013107@qq.com>
  159. * @throws \think\Exception
  160. * @throws \think\exception\PDOException
  161. */
  162. public function enable($record = [])
  163. {
  164. return $this->setStatus('enable', $record);
  165. }
  166. /**
  167. * 启用
  168. * @param array $record 行为日志内容
  169. * @author 蔡伟明 <314013107@qq.com>
  170. * @throws \think\Exception
  171. * @throws \think\exception\PDOException
  172. */
  173. public function delete($record = [])
  174. {
  175. return $this->setStatus('delete', $record);
  176. }
  177. /**
  178. * 快速编辑
  179. * @param array $record 行为日志内容
  180. * @author 蔡伟明 <314013107@qq.com>
  181. */
  182. public function quickEdit($record = [])
  183. {
  184. $field = input('post.name', '');
  185. $value = input('post.value', '');
  186. $type = input('post.type', '');
  187. $id = input('post.pk', '');
  188. $validate = input('post.validate', '');
  189. $validate_fields = input('post.validate_fields', '');
  190. $field == '' && $this->error('缺少字段名');
  191. $id == '' && $this->error('缺少主键值');
  192. $Model = $this->getCurrModel();
  193. $protect_table = [
  194. '__ADMIN_USER__',
  195. '__ADMIN_ROLE__',
  196. config('database.prefix').'admin_user',
  197. config('database.prefix').'admin_role',
  198. ];
  199. // 验证是否操作管理员
  200. if (in_array($Model->getTable(), $protect_table) && $id == 1) {
  201. $this->error('禁止操作超级管理员');
  202. }
  203. // 验证器
  204. if ($validate != '') {
  205. $validate_fields = array_flip(explode(',', $validate_fields));
  206. if (isset($validate_fields[$field])) {
  207. $result = $this->validate([$field => $value], $validate.'.'.$field);
  208. if (true !== $result) $this->error($result);
  209. }
  210. }
  211. switch ($type) {
  212. // 日期时间需要转为时间戳
  213. case 'combodate':
  214. $value = strtotime($value);
  215. break;
  216. // 开关
  217. case 'switch':
  218. $value = $value == 'true' ? 1 : 0;
  219. break;
  220. // 开关
  221. case 'password':
  222. $value = Hash::make((string)$value);
  223. break;
  224. }
  225. // 主键名
  226. $pk = $Model->getPk();
  227. $result = $Model->where($pk, $id)->setField($field, $value);
  228. cache('hook_plugins', null);
  229. cache('system_config', null);
  230. cache('access_menus', null);
  231. if (false !== $result) {
  232. // 记录行为日志
  233. if (!empty($record)) {
  234. call_user_func_array('action_log', $record);
  235. }
  236. $this->success('操作成功');
  237. } else {
  238. $this->error('操作失败');
  239. }
  240. }
  241. /**
  242. * 自动创建添加页面
  243. * @author 蔡伟明 <314013107@qq.com>
  244. * @return mixed
  245. * @throws \think\Exception
  246. */
  247. public function add()
  248. {
  249. // 获取表单项
  250. $cache_name = $this->request->module().'/'.parse_name($this->request->controller()).'/add';
  251. $cache_name = strtolower($cache_name);
  252. $form = Cache::get($cache_name, []);
  253. if (!$form) {
  254. $this->error('自动新增数据不存在,请重新打开此页面');
  255. }
  256. // 保存数据
  257. if ($this->request->isPost()) {
  258. // 表单数据
  259. $data = $this->request->post();
  260. $_pop = $this->request->get('_pop');
  261. // 验证
  262. if ($form['validate'] != '') {
  263. $result = $this->validate($data, $form['validate']);
  264. if(true !== $result) $this->error($result);
  265. }
  266. // 是否需要自动插入时间
  267. if ($form['auto_time'] != '') {
  268. $now_time = $this->request->time();
  269. foreach ($form['auto_time'] as $item) {
  270. if (strpos($item, '|')) {
  271. list($item, $format) = explode('|', $item);
  272. $data[$item] = date($format, $now_time);
  273. } else {
  274. $data[$item] = $form['format'] != '' ? date($form['format'], $now_time) : $now_time;
  275. }
  276. }
  277. }
  278. // 插入数据
  279. if (Db::name($form['table'])->insert($data)) {
  280. if ($_pop == 1) {
  281. $this->success('新增成功', null, '_parent_reload');
  282. } else {
  283. $this->success('新增成功', $form['go_back']);
  284. }
  285. } else {
  286. $this->error('新增失败');
  287. }
  288. }
  289. // 显示添加页面
  290. return ZBuilder::make('form')
  291. ->addFormItems($form['items'])
  292. ->fetch();
  293. }
  294. /**
  295. * 自动创建编辑页面
  296. * @param string $id 主键值
  297. * @author 蔡伟明 <314013107@qq.com>
  298. * @return mixed
  299. * @throws \think\Exception
  300. * @throws \think\db\exception\DataNotFoundException
  301. * @throws \think\db\exception\ModelNotFoundException
  302. * @throws \think\exception\DbException
  303. * @throws \think\exception\PDOException
  304. */
  305. public function edit($id = '')
  306. {
  307. if ($id === '') $this->error('参数错误');
  308. // 获取表单项
  309. $cache_name = $this->request->module().'/'.parse_name($this->request->controller()).'/edit';
  310. $cache_name = strtolower($cache_name);
  311. $form = Cache::get($cache_name, []);
  312. if (!$form) {
  313. $this->error('自动编辑数据不存在,请重新打开此页面');
  314. }
  315. // 保存数据
  316. if ($this->request->isPost()) {
  317. // 表单数据
  318. $data = $this->request->post();
  319. $_pop = $this->request->get('_pop');
  320. // 验证
  321. if ($form['validate'] != '') {
  322. $result = $this->validate($data, $form['validate']);
  323. if(true !== $result) $this->error($result);
  324. }
  325. // 是否需要自动插入时间
  326. if ($form['auto_time'] != '') {
  327. $now_time = $this->request->time();
  328. foreach ($form['auto_time'] as $item) {
  329. if (strpos($item, '|')) {
  330. list($item, $format) = explode('|', $item);
  331. $data[$item] = date($format, $now_time);
  332. } else {
  333. $data[$item] = $form['format'] != '' ? date($form['format'], $now_time) : $now_time;
  334. }
  335. }
  336. }
  337. // 更新数据
  338. if (false !== Db::name($form['table'])->update($data)) {
  339. if ($_pop == 1) {
  340. $this->success('编辑成功', null, '_parent_reload');
  341. } else {
  342. $this->success('编辑成功', $form['go_back']);
  343. }
  344. } else {
  345. $this->error('编辑失败');
  346. }
  347. }
  348. // 获取数据
  349. $info = Db::name($form['table'])->find($id);
  350. // 使用ZBuilder快速创建表单
  351. return ZBuilder::make('form')
  352. ->setPageTitle('编辑')
  353. ->addFormItems($form['items'])
  354. ->setFormData($info)
  355. ->fetch();
  356. }
  357. /**
  358. * 设置状态
  359. * 禁用、启用、删除都是调用这个内部方法
  360. * @param string $type 操作类型:enable,disable,delete
  361. * @param array $record 行为日志内容
  362. * @author 蔡伟明 <314013107@qq.com>
  363. * @throws \think\Exception
  364. * @throws \think\exception\PDOException
  365. */
  366. public function setStatus($type = '', $record = [])
  367. {
  368. $ids = $this->request->isPost() ? input('post.ids/a') : input('param.ids');
  369. $ids = (array)$ids;
  370. $field = input('param.field', 'status');
  371. empty($ids) && $this->error('缺少主键');
  372. $Model = $this->getCurrModel();
  373. $protect_table = [
  374. '__ADMIN_USER__',
  375. '__ADMIN_ROLE__',
  376. '__ADMIN_MODULE__',
  377. config('database.prefix').'admin_user',
  378. config('database.prefix').'admin_role',
  379. config('database.prefix').'admin_module',
  380. ];
  381. // 禁止操作核心表的主要数据
  382. if (in_array($Model->getTable(), $protect_table) && in_array('1', $ids)) {
  383. $this->error('禁止操作');
  384. }
  385. // 主键名称
  386. $pk = $Model->getPk();
  387. $map = [
  388. [$pk, 'in', $ids]
  389. ];
  390. $result = false;
  391. switch ($type) {
  392. case 'disable': // 禁用
  393. $result = $Model->where($map)->setField($field, 0);
  394. break;
  395. case 'enable': // 启用
  396. $result = $Model->where($map)->setField($field, 1);
  397. break;
  398. case 'delete': // 删除
  399. $result = $Model->where($map)->delete();
  400. break;
  401. default:
  402. $this->error('非法操作');
  403. break;
  404. }
  405. if (false !== $result) {
  406. Cache::clear();
  407. // 记录行为日志
  408. if (!empty($record)) {
  409. call_user_func_array('action_log', $record);
  410. }
  411. $this->success('操作成功');
  412. } else {
  413. $this->error('操作失败');
  414. }
  415. }
  416. /**
  417. * 模块设置
  418. * @author 蔡伟明 <314013107@qq.com>
  419. * @return mixed
  420. * @throws \think\Exception
  421. * @throws \think\exception\PDOException
  422. */
  423. public function moduleConfig()
  424. {
  425. // 当前模块名
  426. $module = $this->request->module();
  427. // 保存
  428. if ($this->request->isPost()) {
  429. $data = $this->request->post();
  430. $data = json_encode($data);
  431. if (false !== ModuleModel::where('name', $module)->update(['config' => $data])) {
  432. cache('module_config_'.$module, null);
  433. $this->success('更新成功');
  434. } else {
  435. $this->error('更新失败');
  436. }
  437. }
  438. // 模块配置信息
  439. $module_info = ModuleModel::getInfoFromFile($module);
  440. $config = $module_info['config'];
  441. $trigger = isset($module_info['trigger']) ? $module_info['trigger'] : [];
  442. // 数据库内的模块信息
  443. $db_config = ModuleModel::where('name', $module)->value('config');
  444. $db_config = json_decode($db_config, true);
  445. // 使用ZBuilder快速创建表单
  446. return ZBuilder::make('form')
  447. ->setPageTitle('模块设置')
  448. ->addFormItems($config)
  449. ->setFormdata($db_config) // 设置表格数据
  450. ->setTrigger($trigger) // 设置触发
  451. ->fetch();
  452. }
  453. }