import 'package:flutter/material.dart'; import '../api/oa_client.dart'; import '../labels.dart'; import '../widgets/common.dart'; import 'record_detail_page.dart'; class RestShell { const RestShell(this.path, {this.query}); final String path; final Map? query; } RestShell? shellFor(String code, String? path) { final p = path ?? ''; final c = code.toLowerCase(); if (c.startsWith('bid') || p.startsWith('/bid')) return const RestShell('/bid-cases'); if (c.startsWith('contract:hr') || p.startsWith('/contract/hr') || p.contains('labor-contract')) { return const RestShell('/labor-contracts'); } if (c.startsWith('contract') || p.startsWith('/contract')) return const RestShell('/contracts'); if (p.startsWith('/party/entities') || c == 'party:entities') return const RestShell('/legal-entities'); if (p.startsWith('/party/contacts') || c == 'party:contacts') return const RestShell('/contacts'); if (c.startsWith('party') || p.startsWith('/party')) return const RestShell('/parties'); if (c == 'seal:borrows' || p.contains('borrow')) return const RestShell('/credential-borrows'); if (c == 'seal:requests' || p.contains('seal-apply') || p.contains('/seal/requests')) { return const RestShell('/seal-requests'); } if (c == 'seal:registry' || p.contains('/seal/registry')) return const RestShell('/seals'); if (c.startsWith('seal') || p.startsWith('/seal')) return const RestShell('/qualifications'); if (c.startsWith('asset') || p.startsWith('/asset') || p.contains('registered-asset')) { return const RestShell('/registered-assets'); } if (p.contains('asset-purchase')) return const RestShell('/asset-purchases'); if (p.contains('purchase') || c.contains('purchase')) return const RestShell('/purchase-requests'); if (p.contains('/assets') && !p.contains('registered')) return const RestShell('/assets'); if (c.contains('timesheet') || p.contains('timesheet')) return const RestShell('/timesheets'); if (c.contains('task') || p.contains('task')) return const RestShell('/project-tasks'); if (p.contains('project-change')) return const RestShell('/project-changes'); if (p.contains('resource-board')) return const RestShell('/resource-board'); if (c.startsWith('project') || p.startsWith('/project')) return const RestShell('/projects'); if (p.contains('loan') || c.contains('loan')) return const RestShell('/loans'); if (p.contains('bond')) return const RestShell('/bonds'); if (p.contains('invoice')) return const RestShell('/invoices'); if (p.contains('payment')) return const RestShell('/payments'); if (p.contains('expense') || c.contains('expense')) return const RestShell('/expenses'); if (p.contains('my-expense')) return const RestShell('/office/my-expenses'); if (p.contains('payroll') || c.contains('payroll')) return const RestShell('/payroll'); if (p.contains('leave') || c.contains('leave')) return const RestShell('/leave-requests'); if (p.contains('employment')) return const RestShell('/employment-events'); if (p.contains('departments') || c.contains('dept')) return const RestShell('/departments'); if (p.contains('applies') || c.contains('apply')) return const RestShell('/office/applies'); if (p.contains('work-assign')) return const RestShell('/office/work-assignments'); if (p.contains('cost-target')) return const RestShell('/cost-targets'); if (p.contains('attendance/punch')) return const RestShell('/attendance/punches'); if (c.contains('attendance') || p.contains('attendance')) return const RestShell('/attendance'); if (p.contains('employee') || c.contains('employee') || p.startsWith('/hr')) { return const RestShell('/employees', query: {'page': '1', 'pageSize': '100'}); } if (c.startsWith('report') || p.startsWith('/reports') || p.startsWith('/office/reports')) { return const RestShell('/office/reports'); } if (c.startsWith('legal') || p.startsWith('/legal')) return null; return null; } class ModuleListPage extends StatefulWidget { const ModuleListPage({super.key, required this.api, required this.title, required this.shell}); final OaClient api; final String title; final RestShell shell; @override State createState() => _ModuleListPageState(); } class _ModuleListPageState extends State { List> _items = []; String _err = ''; bool _loading = true; @override void initState() { super.initState(); _load(); } Future _load() async { setState(() { _loading = true; _err = ''; }); try { final data = await widget.api.get( widget.shell.path, query: { 'page': '1', 'pageSize': '100', ...?widget.shell.query, }, ); if (!mounted) return; setState(() { _items = asMaps(data); _loading = false; }); } catch (e) { if (!mounted) return; setState(() { _err = '$e'; _loading = false; }); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title)), body: _loading ? const Center(child: CircularProgressIndicator()) : _err.isNotEmpty ? EmptyHint(_err) : _items.isEmpty ? EmptyHint('暂无${widget.title}') : RefreshIndicator( onRefresh: _load, child: ListView( children: [ for (final r in _items) KvTile( title: pickTitle(r), subtitle: zh(pickSub(r)), status: r['status'], onTap: () { final seed = Map.from(r); if ('${r['id']}'.length >= 8) seed['_fetch'] = '${widget.shell.path}/${r['id']}'; openRecord(context, widget.api, seed, title: pickTitle(r)); }, ), ], ), ), ); } }