web_site_title
,调用方法:config(\'web_site_title\')
')
+ ->addTextarea('value', '配置值', '该配置的具体内容')
+ ->addTextarea('options', '配置项', '用于单选、多选、下拉、联动等类型')
+ ->addText('ajax_url', '异步请求地址', "如请求的地址是 url('ajax/getCity')
,那么只需填写 ajax/getCity
,或者直接填写以 http
开头的url地址")
+ ->addText('next_items', '下一级联动下拉框的表单名', "与当前有关联的下级联动下拉框名,多个用逗号隔开,如:area,other")
+ ->addText('param', '请求参数名', "联动下拉框请求参数名,默认为配置名称")
+ ->addNumber('level', '级别', '需要显示的级别数量,默认为2', 2, 2, 4)
+ ->addText('table', '表名', '要查询的表,里面必须含有id、name、pid三个字段,其中id和name字段可在下面重新定义')
+ ->addText('pid', '父级id字段名', '即表中的父级ID字段名,如果表中的主键字段名为pid则可不填写')
+ ->addText('key', '键字段名', '即表中的主键字段名,如果表中的主键字段名为id则可不填写')
+ ->addText('option', '值字段名', '下拉菜单显示的字段名,如果表中的该字段名为name则可不填写')
+ ->addText('ak', 'APPKEY', '百度编辑器APPKEY')
+ ->addText('format', '格式')
+ ->addText('tips', '配置说明', '该配置的具体说明')
+ ->addText('sort', '排序', '', 100)
+ ->setTrigger('type', 'linkage', 'ajax_url,next_items,param')
+ ->setTrigger('type', 'linkages', 'table,pid,level,key,option')
+ ->setTrigger('type', 'bmap', 'ak')
+ ->setTrigger('type', 'masked,date,time,datetime', 'format')
+ ->fetch();
+ }
+
+ /**
+ * 编辑
+ * @param int $id
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed
+ */
+ public function edit($id = 0)
+ {
+ if ($id === 0) $this->error('参数错误');
+
+ // 保存数据
+ if ($this->request->isPost()) {
+ // 表单数据
+ $data = $this->request->post();
+
+ // 验证
+ $result = $this->validate($data, 'Config');
+ if(true !== $result) $this->error($result);
+
+ // 如果是快速联动
+ if ($data['type'] == 'linkages') {
+ $data['key'] = $data['key'] == '' ? 'id' : $data['key'];
+ $data['pid'] = $data['pid'] == '' ? 'pid' : $data['pid'];
+ $data['level'] = $data['level'] == '' ? '2' : $data['level'];
+ $data['option'] = $data['option'] == '' ? 'name' : $data['option'];
+ }
+
+ // 原配置内容
+ $config = ConfigModel::where('id', $id)->find();
+ $details = '原数据:分组('.$config['group'].')、类型('.$config['type'].')、标题('.$config['title'].')、名称('.$config['name'].')';
+
+ if ($config = ConfigModel::update($data)) {
+ cache('system_config', null);
+ $forward = $this->request->param('_pop') == 1 ? null : cookie('__forward__');
+ // 记录行为
+ action_log('config_edit', 'admin_config', $config['id'], UID, $details);
+ $this->success('编辑成功', $forward);
+ } else {
+ $this->error('编辑失败');
+ }
+ }
+
+ // 获取数据
+ $info = ConfigModel::get($id);
+
+ // 使用ZBuilder快速创建表单
+ return ZBuilder::make('form')
+ ->setPageTitle('编辑')
+ ->addHidden('id')
+ ->addRadio('group', '配置分组', '', config('config_group'))
+ ->addSelect('type', '配置类型', '', config('form_item_type'))
+ ->addText('title', '配置标题', '一般由中文组成,仅用于显示')
+ ->addText('name', '配置名称', '由英文字母和下划线组成,如 web_site_title
,调用方法:config(\'web_site_title\')
')
+ ->addTextarea('value', '配置值', '该配置的具体内容')
+ ->addTextarea('options', '配置项', '用于单选、多选、下拉、联动等类型')
+ ->addText('ajax_url', '异步请求地址', "如请求的地址是 url('ajax/getCity')
,那么只需填写 ajax/getCity
,或者直接填写以 http
开头的url地址")
+ ->addText('next_items', '下一级联动下拉框的表单名', "与当前有关联的下级联动下拉框名,多个用逗号隔开,如:area,other")
+ ->addText('param', '请求参数名', "联动下拉框请求参数名,默认为配置名称")
+ ->addNumber('level', '级别', '需要显示的级别数量,默认为2', 2, 2, 4)
+ ->addText('table', '表名', '要查询的表,里面必须含有id、name、pid三个字段,其中id和name字段可在下面重新定义')
+ ->addText('pid', '父级id字段名', '即表中的父级ID字段名,如果表中的主键字段名为pid则可不填写')
+ ->addText('key', '键字段名', '即表中的主键字段名,如果表中的主键字段名为id则可不填写')
+ ->addText('option', '值字段名', '下拉菜单显示的字段名,如果表中的该字段名为name则可不填写')
+ ->addText('ak', 'APPKEY', '百度编辑器APPKEY')
+ ->addText('format', '格式')
+ ->addText('tips', '配置说明', '该配置的具体说明')
+ ->addText('sort', '排序', '', 100)
+ ->setTrigger('type', 'linkage', 'ajax_url,next_items,param')
+ ->setTrigger('type', 'linkages', 'table,pid,level,key,option')
+ ->setTrigger('type', 'bmap', 'ak')
+ ->setTrigger('type', 'masked,date,time,datetime', 'format')
+ ->setFormData($info)
+ ->fetch();
+ }
+
+ /**
+ * 删除配置
+ * @param array $record 行为日志
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed
+ */
+ public function delete($record = [])
+ {
+ return $this->setStatus('delete');
+ }
+
+ /**
+ * 启用配置
+ * @param array $record 行为日志
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed
+ */
+ public function enable($record = [])
+ {
+ return $this->setStatus('enable');
+ }
+
+ /**
+ * 禁用配置
+ * @param array $record 行为日志
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed
+ */
+ public function disable($record = [])
+ {
+ return $this->setStatus('disable');
+ }
+
+ /**
+ * 设置配置状态:删除、禁用、启用
+ * @param string $type 类型:delete/enable/disable
+ * @param array $record
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed
+ */
+ public function setStatus($type = '', $record = [])
+ {
+ $ids = $this->request->isPost() ? input('post.ids/a') : input('param.ids');
+ $uid_delete = is_array($ids) ? '' : $ids;
+ $ids = ConfigModel::where('id', 'in', $ids)->column('title');
+ return parent::setStatus($type, ['config_'.$type, 'admin_config', $uid_delete, UID, implode('、', $ids)]);
+ }
+
+ /**
+ * 快速编辑
+ * @param array $record 行为日志
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed
+ */
+ public function quickEdit($record = [])
+ {
+ $id = input('post.pk', '');
+ $field = input('post.name', '');
+ $value = input('post.value', '');
+ $config = ConfigModel::where('id', $id)->value($field);
+ $details = '字段(' . $field . '),原值(' . $config . '),新值:(' . $value . ')';
+ return parent::quickEdit(['config_edit', 'admin_config', $id, UID, $details]);
+ }
+}
\ No newline at end of file
diff --git a/application/admin/controller/Database.php b/application/admin/controller/Database.php
new file mode 100644
index 00000000..26003f12
--- /dev/null
+++ b/application/admin/controller/Database.php
@@ -0,0 +1,375 @@
+
+ * @return mixed
+ */
+ public function index($group = 'export')
+ {
+ // 配置分组信息
+ $list_group = ['export' =>'备份数据库', 'import' => '还原数据库'];
+ $tab_list = [];
+ foreach ($list_group as $key => $value) {
+ $tab_list[$key]['title'] = $value;
+ $tab_list[$key]['url'] = url('index', ['group' => $key]);
+ }
+
+ switch ($group) {
+ case 'export':
+ $data_list = Db::query("SHOW TABLE STATUS");
+ $data_list = array_map('array_change_key_case', $data_list);
+
+ // 自定义按钮
+ $btn_export = [
+ 'title' => '立即备份',
+ 'icon' => 'fa fa-fw fa-copy',
+ 'class' => 'btn btn-primary ajax-post confirm',
+ 'href' => url('export')
+ ];
+ $btn_optimize_all = [
+ 'title' => '优化表',
+ 'icon' => 'fa fa-fw fa-cogs',
+ 'class' => 'btn btn-success ajax-post',
+ 'href' => url('optimize')
+ ];
+ $btn_repair_all = [
+ 'title' => '修复表',
+ 'icon' => 'fa fa-fw fa-wrench',
+ 'class' => 'btn btn-success ajax-post',
+ 'href' => url('repair')
+ ];
+ $btn_optimize = [
+ 'title' => '优化表',
+ 'icon' => 'fa fa-fw fa-cogs',
+ 'class' => 'btn btn-xs btn-default ajax-get',
+ 'href' => url('optimize', ['ids' => '__id__'])
+ ];
+ $btn_repair = [
+ 'title' => '修复表',
+ 'icon' => 'fa fa-fw fa-wrench',
+ 'class' => 'btn btn-xs btn-default ajax-get',
+ 'href' => url('repair', ['ids' => '__id__'])
+ ];
+
+ // 使用ZBuilder快速创建数据表格
+ return ZBuilder::make('table')
+ ->setPageTitle('数据库管理') // 设置页面标题
+ ->setPrimaryKey('name')
+ ->setTabNav($tab_list, $group) // 设置tab分页
+ ->addColumns([ // 批量添加数据列
+ ['name', '表名'],
+ ['rows', '行数'],
+ ['data_length', '大小', 'byte'],
+ ['data_free', '冗余', 'byte'],
+ ['comment', '备注'],
+ ['right_button', '操作', 'btn']
+ ])
+ ->addTopButton('custom', $btn_export) // 添加单个顶部按钮
+ ->addTopButton('custom', $btn_optimize_all) // 添加单个顶部按钮
+ ->addTopButton('custom', $btn_repair_all) // 添加单个顶部按钮
+ ->addRightButton('custom', $btn_optimize) // 添加右侧按钮
+ ->addRightButton('custom', $btn_repair) // 添加右侧按钮
+ ->setRowList($data_list) // 设置表格数据
+ ->fetch(); // 渲染模板
+ break;
+ case 'import':
+ // 列出备份文件列表
+ $path = config('data_backup_path');
+ if(!is_dir($path)){
+ mkdir($path, 0755, true);
+ }
+ $path = realpath($path);
+ $flag = \FilesystemIterator::KEY_AS_FILENAME;
+ $glob = new \FilesystemIterator($path, $flag);
+
+ $data_list = [];
+ foreach ($glob as $name => $file) {
+ if(preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql(?:\.gz)?$/', $name)){
+ $name = sscanf($name, '%4s%2s%2s-%2s%2s%2s-%d');
+
+ $date = "{$name[0]}-{$name[1]}-{$name[2]}";
+ $time = "{$name[3]}:{$name[4]}:{$name[5]}";
+ $part = $name[6];
+
+ if(isset($data_list["{$date} {$time}"])){
+ $info = $data_list["{$date} {$time}"];
+ $info['part'] = max($info['part'], $part);
+ $info['size'] = $info['size'] + $file->getSize();
+ } else {
+ $info['part'] = $part;
+ $info['size'] = $file->getSize();
+ }
+ $extension = strtoupper(pathinfo($file->getFilename(), PATHINFO_EXTENSION));
+ $info['compress'] = ($extension === 'SQL') ? '-' : $extension;
+ $info['time'] = strtotime("{$date} {$time}");
+ $info['name'] = $info['time'];
+
+ $data_list["{$date} {$time}"] = $info;
+ }
+ }
+
+ $data_list = !empty($data_list) ? array_values($data_list) : $data_list;
+
+ // 自定义按钮
+ $btn_import = [
+ 'title' => '还原',
+ 'icon' => 'fa fa-fw fa-reply',
+ 'class' => 'btn btn-xs btn-default ajax-get confirm',
+ 'href' => url('import', ['time' => '__id__'])
+ ];
+
+ // 使用ZBuilder快速创建数据表格
+ return ZBuilder::make('table')
+ ->setPageTitle('数据库管理') // 设置页面标题
+ ->setPrimaryKey('time')
+ ->hideCheckbox()
+ ->setTabNav($tab_list, $group) // 设置tab分页
+ ->addColumns([ // 批量添加数据列
+ ['name', '备份名称', 'datetime', '', 'Ymd-His'],
+ ['part', '卷数'],
+ ['compress', '压缩'],
+ ['size', '数据大小', 'byte'],
+ ['time', '备份时间', 'datetime', '', 'Y-m-d H:i:s'],
+ ['right_button', '操作', 'btn']
+ ])
+ ->addRightButton('custom', $btn_import) // 添加右侧按钮
+ ->addRightButton('delete') // 添加右侧按钮
+ ->setRowList($data_list) // 设置表格数据
+ ->fetch(); // 渲染模板
+ break;
+ }
+ }
+
+ /**
+ * 备份数据库(参考onthink 麦当苗儿 page_tips
')
+ ->addText('description', '钩子描述')
+ ->fetch();
+ }
+
+ /**
+ * 编辑
+ * @param int $id 钩子id
+ * @author 蔡伟明 <314013107@qq.com>
+ */
+ public function edit($id = 0)
+ {
+ if ($id === 0) return $this->error('参数错误');
+
+ // 保存数据
+ if ($this->request->isPost()) {
+ $data = $this->request->post();
+ // 验证
+ $result = $this->validate($data, 'Hook');
+ if(true !== $result) return $this->error($result);
+
+ if ($hook = HookModel::update($data)) {
+ // 调整插件顺序
+ if ($data['sort'] != '') {
+ HookPluginModel::sort($data['name'], $data['sort']);
+ }
+ cache('hook_plugins', null);
+ // 记录行为
+ action_log('hook_edit', 'admin_hook', $hook['id'], UID, $data['name']);
+ return $this->success('编辑成功', 'index');
+ } else {
+ return $this->error('编辑失败');
+ }
+ }
+
+ // 获取数据
+ $info = HookModel::get($id);
+
+ // 该钩子的所有插件
+ $hooks = HookPluginModel::where('hook', $info['name'])->order('sort')->column('plugin');
+ $hooks = parse_array($hooks);
+
+ // 使用ZBuilder快速创建表单
+ return ZBuilder::make('form')
+ ->setPageTitle('编辑')
+ ->addHidden('id')
+ ->addText('name', '钩子名称', '由字母和下划线组成,如:page_tips
')
+ ->addText('description', '钩子描述')
+ ->addSort('sort', '插件排序', '', $hooks)
+ ->setFormData($info)
+ ->fetch();
+ }
+
+ /**
+ * 快速编辑(启用/禁用)
+ * @param string $status 状态
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed|void
+ */
+ public function quickEdit($status = '')
+ {
+ $id = $this->request->post('pk');
+ $status = $this->request->param('value');
+ $hook_name = HookModel::where('id', $id)->value('name');
+
+ if (false === HookPluginModel::where('hook', $hook_name)->setField('status', $status == 'true' ? 1 : 0)) {
+ return $this->error('操作失败,请重试');
+ }
+ cache('hook_plugins', null);
+ $details = $status == 'true' ? '启用钩子' : '禁用钩子';
+ return parent::quickEdit(['hook_edit', 'admin_hook', $id, UID, $details]);
+ }
+
+ /**
+ * 启用
+ * @param array $record 行为日志内容
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed|void
+ */
+ public function enable($record = [])
+ {
+ return $this->setStatus('enable');
+ }
+
+ /**
+ * 禁用
+ * @param array $record 行为日志内容
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed|void
+ */
+ public function disable($record = [])
+ {
+ return $this->setStatus('disable');
+ }
+
+ /**
+ * 删除钩子
+ * @param array $record 行为日志内容
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed|void
+ */
+ public function delete($record = [])
+ {
+ $ids = $this->request->isPost() ? input('post.ids/a') : input('param.ids');
+ $map['id'] = ['in', $ids];
+ $map['system'] = 1;
+ if (HookModel::where($map)->find()) {
+ $this->error('禁止删除系统钩子');
+ }
+ return $this->setStatus('delete');
+ }
+
+ /**
+ * 设置状态
+ * @param string $type 类型
+ * @param array $record 行为日志内容
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed|void
+ */
+ public function setStatus($type = '', $record = [])
+ {
+ $ids = $this->request->param('ids/a');
+ foreach ($ids as $id) {
+ $hook_name = HookModel::where('id', $id)->value('name');
+ if (false === HookPluginModel::where('hook', $hook_name)->setField('status', $type == 'enable' ? 1 : 0)) {
+ return $this->error('操作失败,请重试');
+ }
+ }
+ cache('hook_plugins', null);
+ $hook_delete = is_array($ids) ? '' : $ids;
+ $hook_names = HookModel::where('id', 'in', $ids)->column('name');
+ return parent::setStatus($type, ['hook_'.$type, 'admin_hook', $hook_delete, UID, implode('、', $hook_names)]);
+ }
+}
diff --git a/application/admin/controller/Index.php b/application/admin/controller/Index.php
new file mode 100644
index 00000000..4fd97fcb
--- /dev/null
+++ b/application/admin/controller/Index.php
@@ -0,0 +1,63 @@
+
+ * @return string
+ */
+ public function index()
+ {
+ $admin_pass = Db::name('admin_user')->where('id', 1)->value('password');
+
+ if (UID == 1 && $admin_pass && Hash::check('admin', $admin_pass)) {
+ $this->assign('default_pass', 1);
+ }
+ return $this->fetch();
+ }
+
+ /**
+ * 清空系统缓存
+ * @author 蔡伟明 <314013107@qq.com>
+ */
+ public function wipeCache()
+ {
+ if (!empty(config('wipe_cache_type'))) {
+ foreach (config('wipe_cache_type') as $item) {
+ if ($item == 'LOG_PATH') {
+ $dirs = (array) glob(constant($item) . '*');
+ foreach ($dirs as $dir) {
+ array_map('unlink', glob($dir . '/*.log'));
+ }
+ array_map('rmdir', $dirs);
+ } else {
+ array_map('unlink', glob(constant($item) . '/*.*'));
+ }
+ }
+ Cache::clear();
+ $this->success('清空成功');
+ } else {
+ $this->error('请在系统设置中选择需要清除的缓存类型');
+ }
+ }
+}
\ No newline at end of file
diff --git a/application/admin/controller/Log.php b/application/admin/controller/Log.php
new file mode 100644
index 00000000..15eb2b74
--- /dev/null
+++ b/application/admin/controller/Log.php
@@ -0,0 +1,90 @@
+
+ * @return mixed
+ */
+ public function index()
+ {
+ // 查询
+ $map = $this->getMap();
+ // 排序
+ $order = $this->getOrder('admin_log.id desc');
+ // 数据列表
+ $data_list = LogModel::getAll($map, $order);
+ // 分页数据
+ $page = $data_list->render();
+
+ // 使用ZBuilder快速创建数据表格
+ return ZBuilder::make('table')
+ ->setPageTitle('系统日志') // 设置页面标题
+ ->setSearch(['admin_action.title' => '行为名称', 'admin_user.username' => '执行者', 'admin_module.title' => '所属模块']) // 设置搜索框
+ ->hideCheckbox()
+ ->addColumns([ // 批量添加数据列
+ ['id', '编号'],
+ ['title', '行为名称'],
+ ['username', '执行者'],
+ ['action_ip', '执行IP', 'callback', 'long2ip'],
+ ['module_title', '所属模块'],
+ ['create_time', '执行时间', 'datetime', '', 'Y-m-d H:i:s'],
+ ['right_button', '操作', 'btn']
+ ])
+ ->addOrder(['title' => 'admin_action', 'username' => 'admin_user', 'module_title' => 'admin_module.title'])
+ ->addFilter(['admin_action.title', 'admin_user.username', 'module_title' => 'admin_module.title'])
+ ->addRightButton('edit', ['icon' => 'fa fa-eye', 'title' => '详情', 'href' => url('details', ['id' => '__id__'])])
+ ->setRowList($data_list) // 设置表格数据
+ ->setPages($page) // 设置分页数据
+ ->fetch(); // 渲染模板
+ }
+
+ /**
+ * 日志详情
+ * @param null $id 日志id
+ * @author 蔡伟明 <314013107@qq.com>
+ */
+ public function details($id = null)
+ {
+ if ($id === null) return $this->error('缺少参数');
+ $info = LogModel::getAll(['admin_log.id' => $id]);
+ $info = $info[0];
+ $info['action_ip'] = long2ip($info['action_ip']);
+
+ // 使用ZBuilder快速创建表单
+ return ZBuilder::make('form')
+ ->setPageTitle('编辑') // 设置页面标题
+ ->addFormItems([ // 批量添加表单项
+ ['hidden', 'id'],
+ ['static', 'title', '行为名称'],
+ ['static', 'username', '执行者'],
+ ['static', 'record_id', '目标ID'],
+ ['static', 'action_ip', '执行IP'],
+ ['static', 'module_title', '所属模块'],
+ ['textarea', 'remark', '备注'],
+ ])
+ ->hideBtn('submit')
+ ->setFormData($info) // 设置表单数据
+ ->fetch();
+ }
+}
\ No newline at end of file
diff --git a/application/admin/controller/Menu.php b/application/admin/controller/Menu.php
new file mode 100644
index 00000000..ac58a9d0
--- /dev/null
+++ b/application/admin/controller/Menu.php
@@ -0,0 +1,351 @@
+
+ * @return mixed
+ */
+ public function index($group = 'admin')
+ {
+ // 保存模块排序
+ if ($this->request->isPost()) {
+ $modules = $this->request->post('sort/a');
+ if ($modules) {
+ foreach ($modules as $key => $module) {
+ $data[] = [
+ 'id' => $module,
+ 'sort' => $key + 1
+ ];
+ }
+ $MenuModel = new MenuModel();
+ if (false !== $MenuModel->saveAll($data)) {
+ return $this->success('保存成功');
+ } else {
+ return $this->error('保存失败');
+ }
+ }
+ }
+
+ cookie('__forward__', $_SERVER['REQUEST_URI']);
+ // 配置分组信息
+ $list_group = MenuModel::getGroup();
+ foreach ($list_group as $key => $value) {
+ $tab_list[$key]['title'] = $value;
+ $tab_list[$key]['url'] = url('index', ['group' => $key]);
+ }
+
+ // 模块排序
+ if ($group == 'module-sort') {
+ $map['status'] = 1;
+ $map['pid'] = 0;
+ $modules = MenuModel::where($map)->order('sort,id')->column('icon,title', 'id');
+ $this->assign('modules', $modules);
+ } else {
+ // 获取节点数据
+ $data_list = MenuModel::getMenusByGroup($group);
+
+ $max_level = $this->request->get('max', 0);
+
+ $this->assign('menus', $this->getNestMenu($data_list, $max_level));
+ }
+
+ $this->assign('tab_nav', ['tab_list' => $tab_list, 'curr_tab' => $group]);
+ $this->assign('page_title', '节点管理');
+ return $this->fetch();
+ }
+
+ /**
+ * 新增节点
+ * @param string $module 所属模块
+ * @param string $pid 所属节点id
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed
+ */
+ public function add($module = 'admin', $pid = '')
+ {
+ // 保存数据
+ if ($this->request->isPost()) {
+ $data = $this->request->post();
+
+ // 验证
+ $result = $this->validate($data, 'Menu');
+ // 验证失败 输出错误信息
+ if(true !== $result) return $this->error($result);
+
+ if ($menu = MenuModel::create($data)) {
+ Cache::clear();
+ // 记录行为
+ $details = '所属模块('.$data['module'].'),所属节点ID('.$data['pid'].'),节点标题('.$data['title'].'),节点链接('.$data['url_value'].')';
+ action_log('menu_add', 'admin_menu', $menu['id'], UID, $details);
+ return $this->success('新增成功', cookie('__forward__'));
+ } else {
+ return $this->error('新增失败');
+ }
+ }
+
+ // 使用ZBuilder快速创建表单
+ return ZBuilder::make('form')
+ ->setPageTitle('新增节点')
+ ->addLinkage('module', '所属模块', '', ModuleModel::getModule(), $module, url('ajax/getModuleMenus'), 'pid')
+ ->addFormItems([
+ ['select', 'pid', '所属节点', '所属上级节点', MenuModel::getMenuTree(0, '', $module), $pid],
+ ['text', 'title', '节点标题'],
+ ['radio', 'url_type', '链接类型', '', ['module' => '模块链接', 'link' => '普通链接'], 'module']
+ ])
+ ->addFormItem(
+ 'text',
+ 'url_value',
+ '节点链接',
+ "可留空,如果是模块链接,请填写模块/控制器/操作
,如:admin/menu/add
。如果是普通链接,则直接填写url地址,如:http://www.dolphinphp.com
"
+ )
+ ->addRadio('url_target', '打开方式', '', ['_self' => '当前窗口', '_blank' => '新窗口'], '_self')
+ ->addIcon('icon', '图标', '导航图标')
+ ->addRadio('online_hide', '网站上线后隐藏', '关闭开发模式后,则隐藏该菜单节点', ['否', '是'], 0)
+ ->addText('sort', '排序', '', 100)
+ ->fetch();
+ }
+
+ /**
+ * 编辑节点
+ * @param int $id 节点ID
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed
+ */
+ public function edit($id = 0)
+ {
+ if ($id === 0) return $this->error('缺少参数');
+
+ // 保存数据
+ if ($this->request->isPost()) {
+ $data = $this->request->post();
+
+ // 验证
+ $result = $this->validate($data, 'Menu');
+ // 验证失败 输出错误信息
+ if(true !== $result) return $this->error($result);
+
+ // 验证是否更改所属模块,如果是,则该节点的所有子孙节点的模块都要修改
+ $map['id'] = $data['id'];
+ $map['module'] = $data['module'];
+ if (!MenuModel::where($map)->find()) {
+ MenuModel::changeModule($data['id'], $data['module']);
+ }
+
+ if (MenuModel::update($data)) {
+ Cache::clear();
+ // 记录行为
+ $details = '节点ID('.$id.')';
+ action_log('menu_edit', 'admin_menu', $id, UID, $details);
+ return $this->success('编辑成功', cookie('__forward__'));
+ } else {
+ return $this->error('编辑失败');
+ }
+ }
+
+ // 获取数据
+ $info = MenuModel::get($id);
+
+ // 使用ZBuilder快速创建表单
+ return ZBuilder::make('form')
+ ->setPageTitle('编辑节点')
+ ->addFormItem('hidden', 'id')
+ ->addLinkage('module', '所属模块', '', ModuleModel::getModule(), '', url('ajax/getModuleMenus'), 'pid')
+ ->addFormItem('select', 'pid', '所属节点', '所属上级节点', MenuModel::getMenuTree(0, '', $info['module']))
+ ->addFormItem('text', 'title', '节点标题')
+ ->addFormItem('radio', 'url_type', '链接类型', '', ['module' => '模块链接', 'link' => '普通链接'], 'module')
+ ->addFormItem(
+ 'text',
+ 'url_value',
+ '节点链接',
+ "可留空,如果是模块链接,请填写模块/控制器/操作
,如:admin/menu/add
。如果是普通链接,则直接填写url地址,如:http://www.dolphinphp.com
"
+ )
+ ->addRadio('url_target', '打开方式', '', ['_self' => '当前窗口', '_blank' => '新窗口'], '_self')
+ ->addIcon('icon', '图标', '导航图标')
+ ->addRadio('online_hide', '网站上线后隐藏', '关闭开发模式后,则隐藏该菜单节点', ['否', '是'])
+ ->addText('sort', '排序', '', 100)
+ ->setFormData($info)
+ ->fetch();
+ }
+
+ /**
+ * 删除节点
+ * @param array $record 行为日志内容
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed
+ */
+ public function delete($record = [])
+ {
+ $id = $this->request->param('id');
+ $menu = MenuModel::where('id', $id)->find();
+
+ if ($menu['system_menu'] == '1') return $this->error('系统节点,禁止删除');
+
+ // 获取该节点的所有后辈节点id
+ $menu_childs = MenuModel::getChildsId($id);
+
+ // 要删除的所有节点id
+ $all_ids = array_merge([(int)$id], $menu_childs);
+
+ // 删除节点
+ if (MenuModel::destroy($all_ids)) {
+ Cache::clear();
+ // 记录行为
+ $details = '节点ID('.$id.'),节点标题('.$menu['title'].'),节点链接('.$menu['url_value'].')';
+ action_log('menu_delete', 'admin_menu', $id, UID, $details);
+ return $this->success('删除成功');
+ } else {
+ return $this->error('删除失败');
+ }
+ }
+
+ /**
+ * 保存节点排序
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return mixed
+ */
+ public function save()
+ {
+ if ($this->request->isPost()) {
+ $data = $this->request->post();
+ if (!empty($data)) {
+ $menus = $this->parseMenu($data['menus']);
+ foreach ($menus as $menu) {
+ if ($menu['pid'] == 0) {
+ continue;
+ }
+ MenuModel::update($menu);
+ }
+ Cache::clear();
+ return $this->success('保存成功');
+ } else {
+ return $this->error('没有需要保存的节点');
+ }
+ }
+ return $this->error('非法请求');
+ }
+
+ /**
+ * 递归解析节点
+ * @param array $menus 节点数据
+ * @param int $pid 上级节点id
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return array 解析成可以写入数据库的格式
+ */
+ private function parseMenu($menus = [], $pid = 0)
+ {
+ $sort = 1;
+ $result = [];
+ foreach ($menus as $menu) {
+ $result[] = [
+ 'id' => (int)$menu['id'],
+ 'pid' => (int)$pid,
+ 'sort' => $sort,
+ ];
+ if (isset($menu['children'])) {
+ $result = array_merge($result, $this->parseMenu($menu['children'], $menu['id']));
+ }
+ $sort ++;
+ }
+ return $result;
+ }
+
+ /**
+ * 获取嵌套式节点
+ * @param array $lists 原始节点数组
+ * @param int $pid 父级id
+ * @param int $max_level 最多返回多少层,0为不限制
+ * @param int $curr_level 当前层数
+ * @author 蔡伟明 <314013107@qq.com>
+ * @return string
+ */
+ private function getNestMenu($lists = [], $max_level = 0, $pid = 0, $curr_level = 1)
+ {
+ $result = '';
+ foreach ($lists as $key => $value) {
+ if ($value['pid'] == $pid) {
+ $disable = $value['status'] == 0 ? 'dd-disable' : '';
+
+ // 组合节点
+ $result .= '超级管理员默认密码未修改,建议马上 修改。
+提示:按住表头可拖动节点,调整后点击【保存节点】。
+{$module.description|default='暂无简介'}
+{$plugin.description|default='暂无简介'}
+