import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../core/theme/app_colors.dart'; import '../../core/utils/responsive.dart'; import '../../shared/widgets/form_section.dart'; import '../../shared/widgets/form_field_row.dart'; import 'expense_apply_controller.dart'; import 'expense_model.dart'; class ExpenseApplyPage extends ConsumerStatefulWidget { final String? editId; const ExpenseApplyPage({super.key, this.editId}); @override ConsumerState createState() => _ExpenseApplyPageState(); } class _ExpenseApplyPageState extends ConsumerState { final _remarkController = TextEditingController(); static const _types = ['差旅费', '办公用品', '招待费', '交通费', '通讯费', '其他']; @override void dispose() { _remarkController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final controller = ref.watch(expenseApplyProvider(widget.editId).notifier); final state = ref.watch(expenseApplyProvider(widget.editId)); final r = ResponsiveHelper.of(context); return Scaffold( appBar: AppBar( title: Text(widget.editId != null ? '编辑报销' : '费用报销申请'), actions: [ if (state.expense.status == 'draft') const Padding( padding: EdgeInsets.only(right: 12), child: Text('草稿', style: TextStyle(color: Colors.white70, fontSize: 13)), ), ], ), body: Column( children: [ Expanded( child: Align(alignment: Alignment.topCenter, child: ConstrainedBox( constraints: BoxConstraints(maxWidth: r.formMaxWidth), child: SingleChildScrollView( padding: const EdgeInsets.symmetric(vertical: 8), child: _buildForm(controller, state), ), ), ), ), _buildBottomButtons(controller, state), ], ), ); } Widget _buildForm( ExpenseApplyController controller, ExpenseApplyState state) { return Column( children: [ FormSection( title: '基本信息', children: [ FormFieldRow( label: '报销类型', value: state.expense.expenseType, onTap: () => _showTypePicker(controller), ), FormFieldRow( label: '报销金额', value: '¥${state.expense.totalAmount.toStringAsFixed(2)}', showArrow: false, ), FormFieldRow( label: '备注说明', value: state.expense.remark.isEmpty ? null : state.expense.remark, hint: '选填', onTap: () => _showRemarkEditor(), ), ], ), FormSection( title: '报销明细', trailing: TextButton( onPressed: () => _showAddDetailDialog(controller), child: const Text('+ 添加明细', style: TextStyle(fontSize: 12)), ), children: state.expense.details.isEmpty ? [ const Padding( padding: EdgeInsets.all(14), child: Text('暂无明细,点击上方添加', style: TextStyle( color: AppColors.textHint, fontSize: 13)), ), ] : state.expense.details.asMap().entries.map((entry) { final d = entry.value; return ListTile( title: Text(d.expenseDesc, style: const TextStyle( fontSize: 13, color: AppColors.textPrimary)), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ Text( '¥${d.totalAmount.toStringAsFixed(2)}', style: const TextStyle( color: AppColors.primary, fontSize: 13)), IconButton( icon: const Icon(Icons.close, size: 16, color: AppColors.textHint), onPressed: () { controller.removeDetail(entry.key); controller.recalculateAmount(); }, ), ], ), ); }).toList(), ), const SizedBox(height: 16), ], ); } Widget _buildBottomButtons( ExpenseApplyController controller, ExpenseApplyState state) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 4, offset: const Offset(0, -1), ), ], ), child: Row( children: [ Expanded( child: OutlinedButton( onPressed: state.isSubmitting ? null : () async { await controller.saveDraft(); if (context.mounted) context.pop(); }, child: const Text('存草稿'), ), ), const SizedBox(width: 12), Expanded( flex: 2, child: ElevatedButton( onPressed: state.isSubmitting ? null : () async { final ok = await controller.submit(); if (context.mounted && ok) context.pop(); }, child: state.isSubmitting ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white), ) : const Text('提交审批'), ), ), ], ), ); } void _showTypePicker(ExpenseApplyController controller) { showModalBottomSheet( context: context, builder: (_) => Column( mainAxisSize: MainAxisSize.min, children: _types .map((t) => ListTile( title: Text(t), onTap: () { controller.updateType(t); Navigator.pop(context); }, )) .toList(), ), ); } void _showRemarkEditor() { final state = ref.read(expenseApplyProvider(widget.editId)); _remarkController.text = state.expense.remark; showDialog( context: context, builder: (_) => AlertDialog( title: const Text('备注说明'), content: TextField( controller: _remarkController, maxLines: 3, decoration: const InputDecoration( hintText: '请输入备注信息…', border: OutlineInputBorder()), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消')), TextButton( onPressed: () { ref .read(expenseApplyProvider(widget.editId).notifier) .updateRemark(_remarkController.text); Navigator.pop(context); }, child: const Text('确定'), ), ], ), ); } void _showAddDetailDialog(ExpenseApplyController controller) { final nameCtrl = TextEditingController(); final amountCtrl = TextEditingController(); final descCtrl = TextEditingController(); showDialog( context: context, builder: (_) => AlertDialog( title: const Text('添加明细'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: nameCtrl, decoration: const InputDecoration( labelText: '费用名称', border: OutlineInputBorder()), ), const SizedBox(height: 8), TextField( controller: amountCtrl, decoration: const InputDecoration( labelText: '金额', border: OutlineInputBorder()), keyboardType: TextInputType.number, ), const SizedBox(height: 8), TextField( controller: descCtrl, decoration: const InputDecoration( labelText: '描述', border: OutlineInputBorder()), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消')), TextButton( onPressed: () { final amount = double.tryParse(amountCtrl.text) ?? 0.0; controller.addDetail(ExpenseDetailModel( id: DateTime.now().millisecondsSinceEpoch.toString(), expenseId: '', expenseDate: DateTime.now(), expenseType: '', expenseDesc: nameCtrl.text, amount: amount, totalAmount: amount, remark: descCtrl.text, )); controller.recalculateAmount(); Navigator.pop(context); }, child: const Text('添加'), ), ], ), ); } }