// +---------------------------------------------------------------------- declare (strict_types = 1); namespace app\backend\controller; use think\facade\Cache; use think\facade\Request; use think\facade\View; use ywxapp\model\CommonNavMenu as NavMenu; use ywxapp\controller\BackendBase; /** * 前台主导航菜单管理(支持两级下拉,可后台配置). */ class Navbar extends BackendBase { protected function initialize() { } /** * 列表页. */ public function index() { if (Request::isAjax()) { $title = trim((string) Request::param('title', '')); $rows = NavMenu::getAdminTree($title); // 拍平成 treeTable isSimpleData 所需的扁平 pid 列表(treeTable 用 pid 自动建树) $flat = []; foreach ($rows as $p) { $p['pid'] = (int) $p['parent_id']; $flat[] = $p; foreach (($p['child'] ?? []) as $c) { $c['pid'] = (int) $c['parent_id']; $flat[] = $c; } } foreach ($flat as &$row) { unset($row['child']); } return json(['code' => 0, 'msg' => 'ok', 'data' => $flat, 'count' => count($flat)]); } // 已启用插件列表:导航「所属应用」可选插件(插件页面同样支持绑定域名) View::assign('plugins', $this->enabledPlugins()); return View::fetch(); } /** * 获取已启用插件名列表. */ private function enabledPlugins(): array { $raw = Cache::get('addon_loaded_config'); if (! is_array($raw) || empty($raw)) { $addonDir = root_path() . 'addon' . DIRECTORY_SEPARATOR; $raw = []; if (is_dir($addonDir)) { foreach (array_diff(scandir($addonDir), ['.', '..']) as $dir) { $info = @include $addonDir . $dir . DIRECTORY_SEPARATOR . 'info.php'; if (is_array($info)) { $raw[$dir] = $info; } } } } $plugins = []; foreach ($raw as $info) { if (! empty($info['state']) && ! empty($info['name'])) { $plugins[] = (string) $info['name']; } } sort($plugins); return $plugins; } /** * 添加/编辑页(页面式,复用 edit.html). */ public function edit($id = 0) { $row = $id ? NavMenu::find($id) : null; if (Request::isPost()) { $data = [ 'parent_id' => (int) Request::post('parent_id', 0), 'title' => trim((string) Request::post('title', '')), 'url' => trim((string) Request::post('url', '')), 'app' => trim((string) Request::post('app', '')), 'icon' => trim((string) Request::post('icon', '')), 'sort' => (int) Request::post('sort', 0), 'status' => (int) Request::post('status', 1), ]; if ($data['title'] === '') { return json(['code' => 1, 'msg' => '请输入菜单名称']); } // 不能把自己设为自己的父级 if ($id && $data['parent_id'] === (int) $id) { return json(['code' => 1, 'msg' => '父级不能选择自己']); } if ($id) { $row = NavMenu::find($id); $row->save($data); return json(['code' => 0, 'msg' => '已保存']); } NavMenu::create($data); return json(['code' => 0, 'msg' => '已添加']); } // 父级下拉选项(仅一级) $parents = NavMenu::where('parent_id', 0) ->where('delete_at', 0) ->order('sort', 'asc') ->field('id,title') ->select(); View::assign('parents', $parents); View::assign('row', $row); return View::fetch(); } /** * 保存(弹窗式 AJAX 提交,与前端 nav.js 对应). */ public function save() { $data = [ 'parent_id' => (int) Request::post('parent_id', 0), 'title' => trim((string) Request::post('title', '')), 'url' => trim((string) Request::post('url', '')), 'app' => trim((string) Request::post('app', '')), 'icon' => trim((string) Request::post('icon', '')), 'sort' => (int) Request::post('sort', 0), 'status' => (int) Request::post('status', 1), ]; if ($data['title'] === '') { return json(['code' => 1, 'msg' => '请输入菜单名称']); } $id = (int) Request::post('id', 0); if ($id) { if ($data['parent_id'] === $id) { return json(['code' => 1, 'msg' => '父级不能选择自己']); } NavMenu::find($id)->save($data); return json(['code' => 0, 'msg' => '已保存']); } NavMenu::create($data); return json(['code' => 0, 'msg' => '已添加']); } /** * 更新(与 save 同逻辑,兼容 PUT). */ public function update() { return $this->save(); } /** * 删除(支持单 id 或批量 ids 逗号分隔;有子项时拒绝,避免孤儿). */ public function delete($id = 0) { $ids = Request::post('ids', ''); if ($ids !== '' && $ids !== null) { $ids = array_values(array_unique(array_filter(array_map('intval', explode(',', (string) $ids))))); } else { $id = $id ?: (int) Request::post('id', 0); $ids = $id ? [$id] : []; } if (empty($ids)) { return json(['code' => 1, 'msg' => '请选择要删除的项']); } $hasChild = NavMenu::where('parent_id', 'in', $ids)->where('delete_at', 0)->count(); if ($hasChild) { return json(['code' => 1, 'msg' => '请先删除所选菜单下的子项']); } NavMenu::destroy($ids); return json(['code' => 0, 'msg' => '已删除']); } /** * 切换显示/隐藏. */ public function status($id = 0, $status = 1) { $id = $id ?: (int) Request::post('id', 0); if (! $id) { return json(['code' => 1, 'msg' => '参数错误']); } NavMenu::find($id)->save(['status' => (int) $status]); return json(['code' => 0, 'msg' => '已更新']); } }