Files
CloudHome-Ops/lib/screens/admin/admin_hub_page.dart

123 lines
4.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../providers/auth_provider.dart';
import '../../utils/i10n.dart';
import '../../utils/permissions.dart';
import '../../utils/responsive.dart';
/// 管理中心页(底部导航第 4 个 tab):各管理模块入口。
///
/// 模块可见性由 [SessionPermissions] 统一驱动,与 [router.dart] 的路由可达性
/// 保持一致:
/// - 用户管理:所有已登录账号可见(数据范围由后端按会话权限收敛);
/// - 渠道商管理:管理员 + 渠道商可见,代理商不可见;
/// - 其余模块(设备/激活码/公司介绍/滚动字幕)对所有账号可见。
class AdminHubPage extends ConsumerWidget {
const AdminHubPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final t = AppLocalizations.of(context);
// 注:按需求「设备分组」整合进设备管理功能(设备详情/设备列表内可改分组),
// 「应用管理」移除以简化管理页。故网格不再单列这两项。
final scheme = Theme.of(context).colorScheme;
final user = ref.watch(authProvider).user;
// 菜单可见性与路由可达性由同一套 SessionPermissions 谓词驱动:
// - 用户管理:所有已登录账号(各角色看自己范围内用户);
// - 渠道商管理:管理员 + 渠道商(代理商不可见,路由层亦会拦截其深链)。
final showUserManagement = SessionPermissions.canViewUserManagement(user);
final showChannelManagement =
SessionPermissions.canViewChannelManagement(user);
final items = [
_MenuItem(
title: t.deviceManagement,
icon: Icons.devices_outlined,
color: scheme.primary,
route: '/admin/device',
),
_MenuItem(
title: t.activationCode,
icon: Icons.vpn_key_outlined,
color: Colors.amber,
route: '/admin/activation',
),
if (showUserManagement)
_MenuItem(
title: t.userManagement,
icon: Icons.people_outlined,
color: scheme.outline,
route: '/admin/sys/user',
),
_MenuItem(
title: t.companyIntro,
icon: Icons.business_outlined,
color: Colors.teal,
route: '/admin/intro/store-list',
),
_MenuItem(
title: t.marqueeManagement,
icon: Icons.subtitles_outlined,
color: Colors.deepPurple,
route: '/admin/marquee',
),
if (showChannelManagement)
_MenuItem(
title: t.channelManagement,
icon: Icons.account_tree_outlined,
color: Colors.blue,
route: '/admin/channel',
),
];
return Scaffold(
appBar: AppBar(title: Text(t.admin)),
body: GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: context.responsive.gridCount(minTileWidth: 300),
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 1.2,
),
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return Card(
child: InkWell(
onTap: () => context.push(item.route),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(item.icon, size: 40, color: item.color),
const SizedBox(height: 8),
Text(
item.title,
style: Theme.of(context).textTheme.titleMedium,
),
],
),
),
);
},
),
);
}
}
class _MenuItem {
const _MenuItem({
required this.title,
required this.icon,
required this.color,
required this.route,
});
final String title;
final IconData icon;
final Color color;
final String route;
}