import 'package:flutter/material.dart'; import '../api/oa_client.dart'; import '../session/session.dart'; import '../widgets/common.dart'; import 'record_detail_page.dart'; class WorkAssignPage extends StatefulWidget { const WorkAssignPage({super.key, required this.session, required this.api}); final SessionStore session; final OaClient api; @override State createState() => _WorkAssignPageState(); } class _WorkAssignPageState extends State { List> _items = []; bool _loading = true; bool get _canAssign { const codes = ['admin', 'owner', 'biz_director', 'tech_director', 'rd_director', '3d_director', 'video_director', 'material_director', 'pm']; return widget.session.roles.any(codes.contains); } @override void initState() { super.initState(); _load(); } Future _load() async { try { final data = await widget.api.get('/office/work-assignments'); if (!mounted) return; setState(() { _items = asMaps(data); _loading = false; }); } catch (_) { if (mounted) setState(() => _loading = false); } } Future _create() async { final staff = asMaps(await widget.api.get('/staff')); if (!mounted) return; final title = TextEditingController(); final content = TextEditingController(); String? assignee; final ok = await showDialog( context: context, builder: (ctx) => StatefulBuilder( builder: (ctx, setSt) => AlertDialog( title: const Text('安排工作'), content: SizedBox( width: 420, child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField(controller: title, decoration: const InputDecoration(labelText: '标题')), const SizedBox(height: 8), TextField(controller: content, decoration: const InputDecoration(labelText: '内容'), maxLines: 3), const SizedBox(height: 8), DropdownButtonFormField( decoration: const InputDecoration(labelText: '执行人'), items: [ for (final s in staff) DropdownMenuItem(value: '${s['id']}', child: Text('${s['name'] ?? ''} ${s['department'] ?? ''}')), ], onChanged: (v) => setSt(() => assignee = v), ), ], ), ), actions: [ TextButton(onPressed: () => Navigator.pop(ctx, false), child: const Text('取消')), FilledButton(onPressed: () => Navigator.pop(ctx, true), child: const Text('下达')), ], ), ), ); if (ok != true) return; try { await widget.api.post('/office/work-assignments', { 'title': title.text.trim(), 'content': content.text.trim(), 'assigneeId': assignee, }); await _load(); } catch (e) { if (mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('$e'))); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('工作安排'), actions: [ if (_canAssign) IconButton(onPressed: _create, icon: const Icon(Icons.add)), ], ), body: _loading ? const Center(child: CircularProgressIndicator()) : _items.isEmpty ? const EmptyHint('没有工作安排') : RefreshIndicator( onRefresh: _load, child: ListView( children: [ for (final r in _items) KvTile( title: '${r['title'] ?? ''}', subtitle: '${r['assignee'] is Map ? r['assignee']['displayName'] : ''} ${fmtTime(r['dueAt'] ?? r['createdAt'])}', status: r['status'], onTap: () => openRecord(context, widget.api, r), ), ], ), ), ); } }