* @return mixed */ public function index($group = 'local', $type = '') { // 配置分组信息 $list_group = ['local' => '本地插件']; $tab_list = []; foreach ($list_group as $key => $value) { $tab_list[$key]['title'] = $value; $tab_list[$key]['url'] = url('index', ['group' => $key]); } // 监听tab钩子 Hook::listen('plugin_index_tab_list', $tab_list); switch ($group) { case 'local': // 查询条件 $keyword = $this->request->get('keyword', ''); if (input('?param.status') && input('param.status') != '_all') { $status = input('param.status'); } else { $status = ''; } $PluginModel = new PluginModel; $result = $PluginModel->getAll($keyword, $status); if ($result['plugins'] === false) { $this->error($PluginModel->getError()); } $type_show = Cache::get('plugin_type_show'); $type_show = $type != '' ? $type : ($type_show == false ? 'block' : $type_show); Cache::set('plugin_type_show', $type_show); $type = $type_show == 'block' ? 'list' : 'block'; $this->assign('page_title', '插件管理'); $this->assign('plugins', $result['plugins']); $this->assign('total', $result['total']); $this->assign('tab_nav', ['tab_list' => $tab_list, 'curr_tab' => $group]); $this->assign('type', $type); return $this->fetch(); break; case 'online': break; } } /** * 安装插件 * @param string $name 插件标识 * @author 蔡伟明 <314013107@qq.com> */ public function install($name = '') { // 设置最大执行时间和内存大小 ini_set('max_execution_time', '0'); ini_set('memory_limit', '1024M'); $plug_name = trim($name); if ($plug_name == '') $this->error('插件不存在!'); $plugin_class = get_plugin_class($plug_name); if (!class_exists($plugin_class)) { $this->error('插件不存在!'); } // 实例化插件 $plugin = new $plugin_class; // 插件预安装 if(!$plugin->install()) { $this->error('插件预安装失败!原因:'. $plugin->getError()); } // 添加钩子 if (isset($plugin->hooks) && !empty($plugin->hooks)) { if (!HookPluginModel::addHooks($plugin->hooks, $name)) { $this->error('安装插件钩子时出现错误,请重新安装'); } cache('hook_plugins', null); } // 执行安装插件sql文件 $sql_file = realpath(config('plugin_path').$name.'/install.sql'); if (file_exists($sql_file)) { if (isset($plugin->database_prefix) && $plugin->database_prefix != '') { $sql_statement = Sql::getSqlFromFile($sql_file, false, [$plugin->database_prefix => config('database.prefix')]); } else { $sql_statement = Sql::getSqlFromFile($sql_file); } if (!empty($sql_statement)) { foreach ($sql_statement as $value) { Db::execute($value); } } } // 插件配置信息 $plugin_info = $plugin->info; // 验证插件信息 $result = $this->validate($plugin_info, 'Plugin'); // 验证失败 输出错误信息 if(true !== $result) $this->error($result); // 并入插件配置值 $plugin_info['config'] = $plugin->getConfigValue(); // 将插件信息写入数据库 if (PluginModel::create($plugin_info)) { cache('plugin_all', null); $this->success('插件安装成功'); } else { $this->error('插件安装失败'); } } /** * 卸载插件 * @param string $name 插件标识 * @author 蔡伟明 <314013107@qq.com> * @throws \think\Exception * @throws \think\exception\PDOException */ public function uninstall($name = '') { $plug_name = trim($name); if ($plug_name == '') $this->error('插件不存在!'); $class = get_plugin_class($plug_name); if (!class_exists($class)) { $this->error('插件不存在!'); } // 实例化插件 $plugin = new $class; // 插件预卸 if(!$plugin->uninstall()) { $this->error('插件预卸载失败!原因:'. $plugin->getError()); } // 卸载插件自带钩子 if (isset($plugin->hooks) && !empty($plugin->hooks)) { if (false === HookPluginModel::deleteHooks($plug_name)) { $this->error('卸载插件钩子时出现错误,请重新卸载'); } cache('hook_plugins', null); } // 执行卸载插件sql文件 $sql_file = realpath(config('plugin_path').$plug_name.'/uninstall.sql'); if (file_exists($sql_file)) { if (isset($plugin->database_prefix) && $plugin->database_prefix != '') { $sql_statement = Sql::getSqlFromFile($sql_file, true, [$plugin->database_prefix => config('database.prefix')]); } else { $sql_statement = Sql::getSqlFromFile($sql_file, true); } if (!empty($sql_statement)) { Db::execute($sql_statement); } } // 删除插件信息 if (PluginModel::where('name', $plug_name)->delete()) { cache('plugin_all', null); $this->success('插件卸载成功'); } else { $this->error('插件卸载失败'); } } /** * 插件管理 * @param string $name 插件名 * @author 蔡伟明 <314013107@qq.com> * @return mixed * @throws \think\Exception */ public function manage($name = '') { cookie('__forward__', $_SERVER['REQUEST_URI']); // 加载自定义后台页面 if (plugin_action_exists($name, 'Admin', 'index')) { return plugin_action($name, 'Admin', 'index'); } // 加载系统的后台页面 $class = get_plugin_class($name); if (!class_exists($class)) { $this->error($name.'插件不存在!'); } // 实例化插件 $plugin = new $class; // 获取后台字段信息,并分析 if (isset($plugin->admin)) { $admin = $this->parseAdmin($plugin->admin); } else { $admin = $this->parseAdmin(); } if (!plugin_model_exists($name)) { $this->error('插件: '.$name.' 缺少模型文件!'); } // 获取插件模型实例 $PluginModel = get_plugin_model($name); $order = $this->getOrder(); $map = $this->getMap(); $data_list = $PluginModel->where($map)->order($order)->paginate(); $page = $data_list->render(); // 使用ZBuilder快速创建数据表格 $builder = ZBuilder::make('table') ->setPageTitle($admin['title']) // 设置页面标题 ->setPluginName($name) ->setTableName($admin['table_name']) ->setSearch($admin['search_field'], $admin['search_title']) // 设置搜索框 ->addOrder($admin['order']) ->addTopButton('back', [ 'title' => '返回插件列表', 'icon' => 'fa fa-reply', 'href' => url('index') ]) ->addTopButtons($admin['top_buttons']) // 批量添加顶部按钮 ->addRightButtons($admin['right_buttons']); // 批量添加右侧按钮 // 自定义顶部按钮 if (!empty($admin['custom_top_buttons'])) { foreach ($admin['custom_top_buttons'] as $custom) { $builder->addTopButton('custom', $custom); } } // 自定义右侧按钮 if (!empty($admin['custom_right_buttons'])) { foreach ($admin['custom_right_buttons'] as $custom) { $builder->addRightButton('custom', $custom); } } // 表头筛选 if (is_array($admin['filter'])) { foreach ($admin['filter'] as $column => $params) { $options = isset($params[0]) ? $params[0] : []; $default = isset($params[1]) ? $params[1] : []; $type = isset($params[2]) ? $params[2] : 'checkbox'; $builder->addFilter($column, $options, $default, $type); } } else { $builder->addFilter($admin['filter']); } return $builder ->addColumns($admin['columns']) // 批量添加数据列 ->setRowList($data_list) // 设置表格数据 ->setPages($page) // 设置分页数据 ->fetch(); // 渲染模板 } /** * 插件新增方法 * @param string $plugin_name 插件名称 * @author 蔡伟明 <314013107@qq.com> * @return mixed * @throws \think\Exception */ public function add($plugin_name = '') { // 如果存在自定义的新增方法,则优先执行 if (plugin_action_exists($plugin_name, 'Admin', 'add')) { $params = $this->request->param(); return plugin_action($plugin_name, 'Admin', 'add', $params); } // 保存数据 if ($this->request->isPost()) { $data = $this->request->post(); // 执行插件的验证器(如果存在的话) if (plugin_validate_exists($plugin_name)) { $plugin_validate = get_plugin_validate($plugin_name); if (!$plugin_validate->check($data)) { // 验证失败 输出错误信息 $this->error($plugin_validate->getError()); } } // 实例化模型并添加数据 $PluginModel = get_plugin_model($plugin_name); if ($PluginModel->data($data)->save()) { $this->success('新增成功', cookie('__forward__')); } else { $this->error('新增失败'); } } // 获取插件模型 $class = get_plugin_class($plugin_name); if (!class_exists($class)) { $this->error('插件不存在!'); } // 实例化插件 $plugin = new $class; if (!isset($plugin->fields)) { $this->error('插件新增、编辑字段不存在!'); } // 使用ZBuilder快速创建表单 return ZBuilder::make('form') ->setPageTitle('新增') ->addFormItems($plugin->fields) ->fetch(); } /** * 编辑插件方法 * @param string $id 数据id * @param string $plugin_name 插件名称 * @author 蔡伟明 <314013107@qq.com> * @return mixed * @throws \think\Exception */ public function edit($id = '', $plugin_name = '') { // 如果存在自定义的编辑方法,则优先执行 if (plugin_action_exists($plugin_name, 'Admin', 'edit')) { $params = $this->request->param(); return plugin_action($plugin_name, 'Admin', 'edit', $params); } // 保存数据 if ($this->request->isPost()) { $data = $this->request->post(); // 执行插件的验证器(如果存在的话) if (plugin_validate_exists($plugin_name)) { $plugin_validate = get_plugin_validate($plugin_name); if (!$plugin_validate->check($data)) { // 验证失败 输出错误信息 $this->error($plugin_validate->getError()); } } // 实例化模型并添加数据 $PluginModel = get_plugin_model($plugin_name); if (false !== $PluginModel->isUpdate(true)->save($data)) { $this->success('编辑成功', cookie('__forward__')); } else { $this->error('编辑失败'); } } // 获取插件类名 $class = get_plugin_class($plugin_name); if (!class_exists($class)) { $this->error('插件不存在!'); } // 实例化插件 $plugin = new $class; if (!isset($plugin->fields)) { $this->error('插件新增、编辑字段不存在!'); } // 获取数据 $PluginModel = get_plugin_model($plugin_name); $info = $PluginModel->find($id); if (!$info) { $this->error('找不到数据!'); } // 使用ZBuilder快速创建表单 return ZBuilder::make('form') ->setPageTitle('编辑') ->addHidden('id') ->addFormItems($plugin->fields) ->setFormData($info) ->fetch(); } /** * 插件参数设置 * @param string $name 插件名称 * @author 蔡伟明 <314013107@qq.com> * @return mixed * @throws \think\Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException * @throws \think\exception\PDOException */ public function config($name = '') { // 更新配置 if ($this->request->isPost()) { $data = $this->request->post(); $data = json_encode($data); if (false !== PluginModel::where('name', $name)->update(['config' => $data])) { $this->success('更新成功', 'index'); } else { $this->error('更新失败'); } } $plugin_class = get_plugin_class($name); // 实例化插件 $plugin = new $plugin_class; $trigger = isset($plugin->trigger) ? $plugin->trigger : []; // 插件配置值 $info = PluginModel::where('name', $name)->field('id,name,config')->find(); $db_config = json_decode($info['config'], true); // 插件配置项 $config = include config('plugin_path'). $name. '/config.php'; // 使用ZBuilder快速创建表单 return ZBuilder::make('form') ->setPageTitle('插件设置') ->addFormItems($config) ->setFormData($db_config) ->setTrigger($trigger) ->fetch(); } /** * 设置状态 * @param string $type 状态类型:enable/disable * @param array $record 行为日志内容 * @author 蔡伟明 <314013107@qq.com> * @throws \think\Exception * @throws \think\exception\PDOException */ public function setStatus($type = '', $record = []) { $_t = input('param._t', ''); $ids = $this->request->isPost() ? input('post.ids/a') : input('param.ids'); empty($ids) && $this->error('缺少主键'); $status = $type == 'enable' ? 1 : 0; if ($_t != '') { parent::setStatus($type, $record); } else { $plugins = PluginModel::where('id', 'in', $ids)->value('name'); if ($plugins) { HookPluginModel::$type($plugins); } if (false !== PluginModel::where('id', 'in', $ids)->setField('status', $status)) { $this->success('操作成功'); } else { $this->error('操作失败'); } } } /** * 禁用插件/禁用插件数据 * @param array $record 行为日志内容 * @author 蔡伟明 <314013107@qq.com> * @throws \think\Exception * @throws \think\exception\PDOException */ public function disable($record = []) { $this->setStatus('disable'); } /** * 启用插件/启用插件数据 * @param array $record 行为日志内容 * @author 蔡伟明 <314013107@qq.com> * @throws \think\Exception * @throws \think\exception\PDOException */ public function enable($record = []) { $this->setStatus('enable'); } /** * 删除插件数据 * @param array $record * @author 蔡伟明 <314013107@qq.com> * @throws \think\Exception * @throws \think\exception\PDOException */ public function delete($record = []) { $this->setStatus('delete'); } /** * 执行插件内部方法 * @author 蔡伟明 <314013107@qq.com> * @return mixed */ public function execute() { $plugin = input('param._plugin'); $controller = input('param._controller'); $action = input('param._action'); $params = $this->request->except(['_plugin', '_controller', '_action'], 'param'); if (empty($plugin) || empty($controller) || empty($action)) { $this->error('没有指定插件名称、控制器名称或操作名称'); } if (!plugin_action_exists($plugin, $controller, $action)) { $this->error("找不到方法:{$plugin}/{$controller}/{$action}"); } return plugin_action($plugin, $controller, $action, $params); } /** * 分析后台字段信息 * @param array $data 字段信息 * @author 蔡伟明 <314013107@qq.com> * @return array */ private function parseAdmin($data = []) { $admin = [ 'title' => '数据列表', 'search_title' => '', 'search_field' => [], 'order' => '', 'filter' => '', 'table_name' => '', 'columns' => [], 'right_buttons' => [], 'top_buttons' => [], 'customs' => [], ]; if (empty($data)) { return $admin; } // 处理工具栏按钮链接 if (isset($data['top_buttons']) && !empty($data['top_buttons'])) { $this->parseButton('top_buttons', $data); } // 处理右侧按钮链接 if (isset($data['right_buttons']) && !empty($data['right_buttons'])) { $this->parseButton('right_buttons', $data); } return array_merge($admin, $data); } /** * 解析按钮链接 * @param string $button 按钮名称 * @param array $data 字段信息 * @author 蔡伟明 <314013107@qq.com> */ private function parseButton($button, &$data) { foreach ($data[$button] as $key => &$value) { // 处理自定义按钮 if ($key === 'customs') { if (!empty($value)) { foreach ($value as &$custom) { if (isset($custom['href']['url']) && $custom['href']['url'] != '') { $params = isset($custom['href']['params']) ? $custom['href']['params'] : []; $custom['href'] = plugin_url($custom['href']['url'], $params); $data['custom_'.$button][] = $custom; } } } unset($data[$button][$key]); } if (!is_numeric($key) && isset($value['href']['url']) && $value['href']['url'] != '') { $value['href'] = plugin_url($value['href']['url']); } } } }