import 'package:aioa_mobile/features/admin/application/admin_controller.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; class AdminPage extends ConsumerWidget { const AdminPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final data = ref.watch(adminDashboardProvider); return Scaffold( appBar: AppBar(title: const Text('OA 管理中心')), body: data.when( loading: () => const Center(child: CircularProgressIndicator()), error: (error, _) => Center( child: FilledButton( onPressed: () => ref.invalidate(adminDashboardProvider), child: Text('加载失败,点击重试\n$error'), ), ), data: (value) => DefaultTabController( length: 4, child: Column( children: [ const TabBar( isScrollable: true, tabs: [ Tab(text: '指标'), Tab(text: '组织'), Tab(text: '流程'), Tab(text: '审计'), ], ), Expanded( child: TabBarView( children: [ _Metrics(value['metrics']! as Map), _Organization(value), _Workflow(value), _Audit(value['audits']! as List>), ], ), ), ], ), ), ), ); } } class _Metrics extends StatelessWidget { const _Metrics(this.data); final Map data; @override Widget build(BuildContext context) => GridView.count( padding: const EdgeInsets.all(12), crossAxisCount: 2, childAspectRatio: 1.5, children: data.entries .where((entry) => entry.key != 'leaveByStatus') .map( (entry) => Card( child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( '${entry.value}', style: Theme.of(context).textTheme.headlineSmall, ), Text(entry.key, textAlign: TextAlign.center), ], ), ), ), ) .toList(), ); } class _Organization extends ConsumerWidget { const _Organization(this.data); final Map data; @override Widget build(BuildContext context, WidgetRef ref) { final users = data['users']! as List>; final roles = data['roles']! as List>; return ListView( padding: const EdgeInsets.all(12), children: [ FilledButton.icon( onPressed: () => _add(context, ref), icon: const Icon(Icons.add), label: const Text('新增部门'), ), ...users.map( (user) => Card( child: ListTile( title: Text('${user['displayName']}'), subtitle: Text( '${user['username']} · ${(user['roles'] as List).join('、')}', ), trailing: IconButton( icon: const Icon(Icons.manage_accounts), onPressed: () => _roles(context, ref, user, roles), ), ), ), ), ], ); } Future _add(BuildContext context, WidgetRef ref) async { final code = TextEditingController(); final name = TextEditingController(); final confirmed = await showDialog( context: context, builder: (dialogContext) => AlertDialog( title: const Text('新增部门'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: code, decoration: const InputDecoration(labelText: '编码'), ), TextField( controller: name, decoration: const InputDecoration(labelText: '名称'), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext, false), child: const Text('取消'), ), FilledButton( onPressed: () => Navigator.pop(dialogContext, true), child: const Text('创建'), ), ], ), ); if (confirmed == true) { await ref .read(adminDashboardProvider.notifier) .createDepartment(code.text, name.text); } code.dispose(); name.dispose(); } Future _roles( BuildContext context, WidgetRef ref, Map user, List> available, ) async { final selected = (user['roles'] as List).cast().toSet(); final result = await showDialog>( context: context, builder: (dialogContext) => StatefulBuilder( builder: (context, setState) => AlertDialog( title: Text('${user['displayName']} 的角色'), content: Column( mainAxisSize: MainAxisSize.min, children: available.map((role) { final code = '${role['code']}'; return CheckboxListTile( value: selected.contains(code), title: Text('${role['name']}'), onChanged: (checked) => setState( () => checked == true ? selected.add(code) : selected.remove(code), ), ); }).toList(), ), actions: [ FilledButton( onPressed: () => Navigator.pop(dialogContext, selected), child: const Text('保存'), ), ], ), ), ); if (result != null) { await ref .read(adminDashboardProvider.notifier) .replaceRoles('${user['id']}', result); } } } class _Workflow extends StatelessWidget { const _Workflow(this.data); final Map data; @override Widget build(BuildContext context) => ListView( padding: const EdgeInsets.all(12), children: [ const Text('业务流程绑定'), ...(data['bindings']! as List>).map( (item) => Card( child: ListTile( leading: Icon( item['status'] == 'ACTIVE' ? Icons.link : Icons.link_off, ), title: Text( '${item['business_type']} → ${item['process_definition_key']}', ), subtitle: Text( '表单 ${item['form_key']} v${item['form_version']} · 优先级 ${item['priority']}', ), ), ), ), const Divider(), const Text('表单版本'), ...(data['formVersions']! as List>).map( (item) => ListTile( title: Text('${item['form_key']} v${item['version']}'), subtitle: Text('${item['status']}'), ), ), const Divider(), const Text('流程定义'), ...(data['definitions']! as List>).map( (item) => ListTile( title: Text('${item['name'] ?? item['key']} v${item['version']}'), subtitle: Text('${item['id']}'), ), ), const Divider(), const Text('最近实例'), ...(data['instances']! as List>).map( (item) => ListTile( title: Text('${item['businessKey'] ?? item['id']}'), subtitle: Text(item['active'] == true ? '运行中' : '已结束'), ), ), ], ); } class _Audit extends StatelessWidget { const _Audit(this.items); final List> items; @override Widget build(BuildContext context) => ListView.builder( padding: const EdgeInsets.all(12), itemCount: items.length, itemBuilder: (context, index) { final item = items[index]; return Card( child: ListTile( title: Text('${item['action']}'), subtitle: Text('${item['resourceType']} · ${item['traceId']}'), ), ); }, ); }