outing_log_create_page.dart 4.5 KB

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