outing_log_create_page.dart 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import 'package:go_router/go_router.dart';
  4. import '../../core/theme/app_colors.dart';
  5. import '../../core/utils/responsive.dart';
  6. import '../../shared/widgets/form_section.dart';
  7. import 'outing_log_api.dart';
  8. import 'outing_log_model.dart';
  9. class OutingLogCreatePage extends ConsumerStatefulWidget {
  10. const OutingLogCreatePage({super.key});
  11. @override
  12. ConsumerState<OutingLogCreatePage> createState() => _OutingLogCreatePageState();
  13. }
  14. class _OutingLogCreatePageState extends ConsumerState<OutingLogCreatePage> {
  15. final _contentCtrl = TextEditingController();
  16. final _clientCtrl = TextEditingController();
  17. final _addressCtrl = TextEditingController();
  18. DateTime _date = DateTime.now();
  19. bool _isSubmitting = false;
  20. @override
  21. void dispose() {
  22. _contentCtrl.dispose();
  23. _clientCtrl.dispose();
  24. _addressCtrl.dispose();
  25. super.dispose();
  26. }
  27. @override
  28. Widget build(BuildContext context) {
  29. final r = ResponsiveHelper.of(context);
  30. return Scaffold(
  31. appBar: AppBar(title: const Text('新建外出日志')),
  32. body: Column(
  33. children: [
  34. Expanded(
  35. child: Align(alignment: Alignment.topCenter,
  36. child: ConstrainedBox(
  37. constraints: BoxConstraints(maxWidth: r.formMaxWidth),
  38. child: SingleChildScrollView(
  39. padding: const EdgeInsets.symmetric(vertical: 8),
  40. child: FormSection(
  41. title: '日志信息',
  42. children: [
  43. ListTile(
  44. title: const Text('日期', style: TextStyle(color: AppColors.textSecondary, fontSize: 13)),
  45. trailing: Text('${_date.year}-${_date.month.toString().padLeft(2, '0')}-${_date.day.toString().padLeft(2, '0')}',
  46. style: const TextStyle(color: AppColors.textPrimary, fontSize: 13)),
  47. onTap: () async {
  48. final picked = await showDatePicker(context: context, initialDate: _date, firstDate: DateTime(2020), lastDate: DateTime(2030));
  49. if (picked != null) setState(() => _date = picked);
  50. },
  51. ),
  52. _buildTextField('拜访客户', _clientCtrl),
  53. _buildTextField('拜访地点', _addressCtrl),
  54. _buildTextField('日志内容', _contentCtrl, maxLines: 5),
  55. ],
  56. ),
  57. ),
  58. ),
  59. ),
  60. ),
  61. Container(
  62. padding: const EdgeInsets.all(12),
  63. decoration: BoxDecoration(color: Colors.white, boxShadow: [BoxShadow(color: Colors.black.withValues(alpha: 0.05), blurRadius: 4, offset: const Offset(0, -1))]),
  64. child: ElevatedButton(
  65. onPressed: _isSubmitting ? null : _submit,
  66. child: _isSubmitting ? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Text('提交'),
  67. ),
  68. ),
  69. ],
  70. ),
  71. );
  72. }
  73. Widget _buildTextField(String label, TextEditingController ctrl, {int maxLines = 1}) {
  74. return Padding(
  75. padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
  76. child: TextField(
  77. controller: ctrl, maxLines: maxLines,
  78. decoration: InputDecoration(labelText: label, border: const OutlineInputBorder(), floatingLabelStyle: const TextStyle(color: AppColors.primary)),
  79. ),
  80. );
  81. }
  82. Future<void> _submit() async {
  83. setState(() => _isSubmitting = true);
  84. try {
  85. await ref.read(outingLogApiProvider).create(OutingLogModel(
  86. id: '', visitNo: '', salespersonId: '', salespersonName: '',
  87. deptId: '', deptName: '', customerName: _clientCtrl.text,
  88. visitDate: _date, visitStartTime: _date, visitEndTime: _date,
  89. visitType: '常规拜访', visitPurpose: '', visitLocation: _addressCtrl.text,
  90. visitSummary: _contentCtrl.text, nextVisitTime: _date,
  91. createTime: DateTime.now(), updateTime: DateTime.now(),
  92. ));
  93. if (context.mounted) context.pop();
  94. } catch (_) {} finally {
  95. if (mounted) setState(() => _isSubmitting = false);
  96. }
  97. }
  98. }