267 lines
8.2 KiB
Dart
267 lines
8.2 KiB
Dart
// route_service.dart
|
||
import 'dart:convert';
|
||
|
||
import 'package:flutter/foundation.dart';
|
||
import 'package:qhd_prevention/common/route_model.dart';
|
||
import 'package:qhd_prevention/tools/tools.dart';
|
||
|
||
class RouteService extends ChangeNotifier {
|
||
static final RouteService _instance = RouteService._internal();
|
||
factory RouteService() => _instance;
|
||
RouteService._internal();
|
||
|
||
// 存储顶级菜单(直接从接口解析的数组)
|
||
List<RouteModel> _allRoutes = [];
|
||
|
||
/// 对外暴露全部顶级 routes(如果需要遍历所有顶级项)
|
||
List<RouteModel> get allRoutes => _allRoutes;
|
||
|
||
/// 初始化路由配置(允许传 null)
|
||
void initializeRoutes(List<dynamic>? routeList) {
|
||
_allRoutes = [];
|
||
if (routeList == null) return;
|
||
for (final item in routeList) {
|
||
try {
|
||
if (item is Map<String, dynamic>) {
|
||
_allRoutes.add(RouteModel.fromJson(item));
|
||
} else if (item is Map) {
|
||
_allRoutes.add(RouteModel.fromJson(Map<String, dynamic>.from(item)));
|
||
}
|
||
} catch (e) {
|
||
debugPrint('RouteService: parse route item failed: $e');
|
||
}
|
||
}
|
||
|
||
// 对顶级和子节点进行排序(如果有 sort 字段)
|
||
try {
|
||
_allRoutes.sort((a, b) => a.sort.compareTo(b.sort));
|
||
for (final r in _allRoutes) {
|
||
_sortRecursive(r);
|
||
}
|
||
} catch (_) {}
|
||
|
||
notifyListeners();
|
||
}
|
||
|
||
void _sortRecursive(RouteModel node) {
|
||
try {
|
||
node.children.sort((a, b) => a.sort.compareTo(b.sort));
|
||
for (final c in node.children) {
|
||
_sortRecursive(c);
|
||
}
|
||
} catch (_) {}
|
||
}
|
||
|
||
/// 返回所有顶级(parentId == '0' 或 parentId 为空)的菜单作为主Tab(不在这里筛 visible)
|
||
List<RouteModel> get mainTabs {
|
||
final tabs = _allRoutes.where((m) {
|
||
final isTop = m.parentId == '0' || m.parentId.isEmpty;
|
||
return isTop && m.visible; // 只取可见的顶级项
|
||
}).toList();
|
||
try {
|
||
tabs.sort((a, b) => a.sort.compareTo(b.sort));
|
||
} catch (_) {}
|
||
return tabs;
|
||
}
|
||
|
||
// 遍历查找(按 menuUrl)
|
||
RouteModel? findRouteByPath(String path) {
|
||
if (path.isEmpty) return null;
|
||
final needle = path.trim();
|
||
for (final route in _allRoutes) {
|
||
final found = _findRouteRecursive(route, needle);
|
||
if (found != null) return found;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
RouteModel? _findRouteRecursive(RouteModel route, String path) {
|
||
// 如果当前节点不可见,则按照你的要求:不再查找其子级(直接返回 null)
|
||
if (!route.visible) return null;
|
||
|
||
final routeUrl = route.menuUrl.trim();
|
||
if (routeUrl == path) return route;
|
||
|
||
for (final child in route.children) {
|
||
final found = _findRouteRecursive(child, path);
|
||
if (found != null) return found;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// 获取某个Tab下的所有可显示路由(visible == true,且收集叶子节点)
|
||
List<RouteModel> getRoutesForTab(RouteModel tab) {
|
||
final routes = <RouteModel>[];
|
||
_collectVisibleLeafRoutes(tab, routes);
|
||
return routes;
|
||
}
|
||
|
||
/// 关键修改:如果当前节点不可见,则不再递归其 children(按你的要求)
|
||
void _collectVisibleLeafRoutes(RouteModel route, List<RouteModel> collector) {
|
||
if (!route.visible) return; // 如果父节点不可见,跳过整个子树
|
||
if (route.isLeaf) {
|
||
collector.add(route);
|
||
return;
|
||
}
|
||
for (final child in route.children) {
|
||
_collectVisibleLeafRoutes(child, collector);
|
||
}
|
||
}
|
||
|
||
// --------------------- 权限检查相关 ---------------------
|
||
|
||
/// 判断整个路由树(所有顶级及其子孙)是否存在 menuPerms == perm 且可见的节点
|
||
/// 如果父节点不可见,会跳过该父及其子树(按你的要求)
|
||
bool hasPerm(String perm) {
|
||
if (perm.isEmpty) return false;
|
||
final needle = perm.trim();
|
||
bool found = false;
|
||
|
||
void visit(RouteModel m) {
|
||
if (found) return;
|
||
// 若父节点不可见,跳过(不再遍历子节点)
|
||
if (!m.visible) return;
|
||
|
||
final mp = (m.menuPerms ?? '').trim();
|
||
if (mp.isNotEmpty && mp == needle) {
|
||
found = true;
|
||
return;
|
||
}
|
||
for (final c in m.children) {
|
||
visit(c);
|
||
if (found) return;
|
||
}
|
||
}
|
||
|
||
for (final top in _allRoutes) {
|
||
visit(top);
|
||
if (found) break;
|
||
}
|
||
return found;
|
||
}
|
||
|
||
bool hasAnyPerms(List<String> perms) {
|
||
for (final p in perms) {
|
||
if (hasPerm(p)) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
Map<String, bool> permsMap(List<String> perms) {
|
||
final Map<String, bool> map = {};
|
||
for (final p in perms) {
|
||
map[p] = hasPerm(p);
|
||
}
|
||
return map;
|
||
}
|
||
|
||
/// 尝试按 menuPerms 找到第一个匹配的 RouteModel(若需要路由信息)
|
||
/// 如果某个父节点不可见,则不会进入其子树
|
||
RouteModel? findRouteByPerm(String perm) {
|
||
if (perm.isEmpty) return null;
|
||
final needle = perm.trim();
|
||
RouteModel? result;
|
||
|
||
void visit(RouteModel m) {
|
||
// printLongString(json.encode(m.toJson()));
|
||
if (result != null) return;
|
||
if (!m.visible) return; // 父不可见,跳过
|
||
final mp = (m.menuPerms ?? '').trim();
|
||
if (mp.isNotEmpty && mp == needle) {
|
||
result = m;
|
||
return;
|
||
}
|
||
for (final c in m.children) {
|
||
visit(c);
|
||
if (result != null) return;
|
||
}
|
||
}
|
||
|
||
for (final top in _allRoutes) {
|
||
visit(top);
|
||
if (result != null) break;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/// 可返回所有收集到的 menuPerms(仅包含可见节点及其可见子节点)
|
||
List<String> collectAllPerms() {
|
||
final List<String> perms = [];
|
||
void visit(RouteModel m) {
|
||
if (!m.visible) return; // 父不可见则跳过子树
|
||
final mp = (m.menuPerms ?? '').trim();
|
||
if (mp.isNotEmpty) perms.add(mp);
|
||
for (final c in m.children) visit(c);
|
||
}
|
||
|
||
for (final top in _allRoutes) visit(top);
|
||
return perms;
|
||
}
|
||
/// 严格查找某个子树(仅包含可见节点及其可见子节点)
|
||
static Future<String> getMenuPath(parentPerm,targetPerm) async {
|
||
try {
|
||
final routeService = RouteService();
|
||
// 如果子节点为'',那么查父节点children中第一个
|
||
if (targetPerm.isEmpty) {
|
||
final route = routeService.findRouteByPerm(parentPerm);
|
||
if (route != null) {
|
||
// 优先在该节点的子孙中找第一个可见且有 menuUrl 的节点
|
||
final childUrl = findFirstVisibleChildUrl(route);
|
||
if (childUrl.isNotEmpty) return childUrl;
|
||
return '';
|
||
|
||
}
|
||
}
|
||
//branchCompany-plan-execute-inspection-records
|
||
RouteModel? parent = routeService.findRouteByPerm(parentPerm);
|
||
if (parent != null) {
|
||
// 在 parent 子树中严格查找 targetPerm
|
||
final RouteModel? foundInParent = _findRouteInSubtreeByPerm(parent, targetPerm);
|
||
if (foundInParent != null && foundInParent.menuUrl.trim().isNotEmpty) {
|
||
return foundInParent.menuUrl.trim();
|
||
}
|
||
}
|
||
|
||
// 未找到 -> 返回空字符串(调用方需做好空串处理)
|
||
return '';
|
||
} catch (e, st) {
|
||
debugPrint('_getMenuPath error: $e\n$st');
|
||
return '';
|
||
}
|
||
}
|
||
/// 在给定节点的子树中(含自身)查找 menuPerm 完全匹配的节点(只返回可见节点)
|
||
static RouteModel? _findRouteInSubtreeByPerm(RouteModel node, String perm) {
|
||
if (node.menuPerms.trim() == perm && node.visible) return node;
|
||
for (final c in node.children) {
|
||
final res = _findRouteInSubtreeByPerm(c, perm);
|
||
if (res != null) return res;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// 在整个路由列表中查找 menuPerm 完全匹配的节点(只返回可见节点)
|
||
RouteModel? _findRouteInAllByPerm(List<RouteModel> roots, String perm) {
|
||
for (final r in roots) {
|
||
final res = _findRouteInSubtreeByPerm(r, perm);
|
||
if (res != null) return res;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// 递归在 node 的子孙中按顺序查找第一个 visible 且有 menuUrl 的节点
|
||
/// 如果没找到返回空字符串
|
||
static String findFirstVisibleChildUrl(RouteModel node) {
|
||
final children = node.children;
|
||
if (children == null || children.isEmpty) return '';
|
||
|
||
for (final c in children) {
|
||
// 若该子节点可见并有 menuUrl,直接返回
|
||
if ((c.showFlag == 1) && (c.menuUrl ?? '').isNotEmpty) {
|
||
return c.menuUrl;
|
||
}
|
||
// return '';
|
||
}
|
||
return '';
|
||
}
|
||
}
|