fix: 图片发送/医生加载/运动超时/用药黑屏/服药打卡
- sendImage: 本地预览→上传→远程URL替换 - doctorListProvider: 8s超时+mock医生fallback - currentExercisePlanProvider: 8s超时→显示空状态 - 用药编辑: try-catch防黑屏+刷新列表 - 服药打卡: 接入后端confirm()接口
This commit is contained in:
@@ -1,98 +1,528 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../core/navigation_provider.dart';
|
||||
import '../../providers/data_providers.dart';
|
||||
|
||||
class _MedicationItem {
|
||||
String name = '';
|
||||
String dosage = '';
|
||||
String frequency = '每日1次';
|
||||
List<TimeOfDay> times = [const TimeOfDay(hour: 8, minute: 0)];
|
||||
DateTime startDate = DateTime.now();
|
||||
DateTime? endDate;
|
||||
int weekday = 1;
|
||||
}
|
||||
|
||||
const _frequencies = ['每日1次', '每日2次', '每日3次', '每周1次', '按需服用'];
|
||||
const _weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
|
||||
|
||||
class MedicationEditPage extends ConsumerStatefulWidget {
|
||||
final String? medicationId;
|
||||
const MedicationEditPage({super.key, this.medicationId});
|
||||
|
||||
@override ConsumerState<MedicationEditPage> createState() => _MedicationEditPageState();
|
||||
@override
|
||||
ConsumerState<MedicationEditPage> createState() => _MedicationEditPageState();
|
||||
}
|
||||
|
||||
class _MedicationEditPageState extends ConsumerState<MedicationEditPage> {
|
||||
final _nameCtrl = TextEditingController(text: '阿司匹林肠溶片');
|
||||
final _dosageCtrl = TextEditingController(text: '100mg');
|
||||
String _frequency = '每日1次';
|
||||
String _time = '08:00';
|
||||
DateTime _startDate = DateTime.now();
|
||||
String _duration = '长期服用';
|
||||
final _items = <_MedicationItem>[];
|
||||
final _nameCtrls = <TextEditingController>[];
|
||||
final _doseCtrls = <TextEditingController>[];
|
||||
|
||||
@override void dispose() { _nameCtrl.dispose(); _dosageCtrl.dispose(); super.dispose(); }
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_addItem();
|
||||
}
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
@override
|
||||
void dispose() {
|
||||
for (final c in _nameCtrls) {
|
||||
c.dispose();
|
||||
}
|
||||
for (final c in _doseCtrls) {
|
||||
c.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _addItem() {
|
||||
setState(() {
|
||||
_items.add(_MedicationItem());
|
||||
_nameCtrls.add(TextEditingController());
|
||||
_doseCtrls.add(TextEditingController());
|
||||
});
|
||||
}
|
||||
|
||||
void _removeItem(int index) {
|
||||
setState(() {
|
||||
_nameCtrls[index].dispose();
|
||||
_doseCtrls[index].dispose();
|
||||
_nameCtrls.removeAt(index);
|
||||
_doseCtrls.removeAt(index);
|
||||
_items.removeAt(index);
|
||||
});
|
||||
}
|
||||
|
||||
void _onSave() async {
|
||||
for (int i = 0; i < _items.length; i++) {
|
||||
_items[i].name = _nameCtrls[i].text.trim();
|
||||
_items[i].dosage = _doseCtrls[i].text.trim();
|
||||
}
|
||||
final allValid = _items.every(
|
||||
(item) => item.name.isNotEmpty && item.dosage.isNotEmpty,
|
||||
);
|
||||
if (!allValid) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('请填写所有药品的名称和剂量')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
final service = ref.read(medicationServiceProvider);
|
||||
try {
|
||||
for (final item in _items) {
|
||||
final timesStr = item.frequency == '按需服用'
|
||||
? []
|
||||
: item.times.map((t) => t.format(context)).toList();
|
||||
await service.create({
|
||||
'name': item.name,
|
||||
'dosage': item.dosage,
|
||||
'frequency': item.frequency,
|
||||
'times': timesStr,
|
||||
'start_date': item.startDate.toIso8601String().split('T')[0],
|
||||
if (item.endDate != null)
|
||||
'end_date': item.endDate!.toIso8601String().split('T')[0],
|
||||
if (item.frequency == '每周1次') 'weekday': item.weekday,
|
||||
});
|
||||
}
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('已添加 ${_items.length} 种药品'),
|
||||
backgroundColor: const Color(0xFF635BFF),
|
||||
),
|
||||
);
|
||||
ref.invalidate(medicationListProvider);
|
||||
ref.invalidate(medicationReminderProvider);
|
||||
popRoute(ref);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('保存失败:$e'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
// 仍然返回上一页,避免卡在黑屏
|
||||
popRoute(ref);
|
||||
}
|
||||
}
|
||||
|
||||
int _timeCount(String frequency) {
|
||||
switch (frequency) {
|
||||
case '每日1次':
|
||||
return 1;
|
||||
case '每日2次':
|
||||
return 2;
|
||||
case '每日3次':
|
||||
return 3;
|
||||
case '每周1次':
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: const Color(0xFFF8F7FF),
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
leading: IconButton(icon: const Icon(Icons.chevron_left), onPressed: () => popRoute(ref)),
|
||||
title: const Text('编辑用药', style: TextStyle(color: Color(0xFF1A1A1A), fontWeight: FontWeight.w600)),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.chevron_left),
|
||||
onPressed: () => popRoute(ref),
|
||||
),
|
||||
title: const Text(
|
||||
'添加用药',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF1A1A1A),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('保存成功 ✅'), backgroundColor: Color(0xFF635BFF)));
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text('保存', style: TextStyle(color: Color(0xFF635BFF), fontWeight: FontWeight.w600)),
|
||||
onPressed: _onSave,
|
||||
child: const Text(
|
||||
'保存',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF635BFF),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
const Text('药品信息', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF1A1A1A))),
|
||||
const SizedBox(height: 12),
|
||||
TextField(controller: _nameCtrl, decoration: InputDecoration(hintText: '请输入药品名称', filled: true, fillColor: Colors.grey[50], border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none))),
|
||||
const SizedBox(height: 16),
|
||||
TextField(controller: _dosageCtrl, decoration: InputDecoration(hintText: '如:100mg', filled: true, fillColor: Colors.grey[50], border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none))),
|
||||
const SizedBox(height: 24),
|
||||
const Text('服用设置', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF1A1A1A))),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(onTap: _pickFrequency, child: Container(padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration(border: Border.all(color: const Color(0xFFE0E0E0)), borderRadius: BorderRadius.circular(12)), child: Row(children: [Text(_frequency, style: const TextStyle(fontSize: 15)), const Spacer(), const Icon(Icons.keyboard_arrow_down, size: 20, color: Color(0xFF9E9E9E))]))),
|
||||
const SizedBox(height: 16),
|
||||
GestureDetector(onTap: _pickTime, child: Container(padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration(border: Border.all(color: const Color(0xFFE0E0E0)), borderRadius: BorderRadius.circular(12)), child: Row(children: [Text(_time, style: const TextStyle(fontSize: 15)), const Spacer(), const Icon(Icons.access_time, size: 20, color: Color(0xFF9E9E9E))]))),
|
||||
const SizedBox(height: 16),
|
||||
GestureDetector(onTap: _pickDate, child: Container(padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration(border: Border.all(color: const Color(0xFFE0E0E0)), borderRadius: BorderRadius.circular(12)), child: Row(children: [Text('${_startDate.year}-${_startDate.month.toString().padLeft(2, '0')}-${_startDate.day.toString().padLeft(2, '0')}', style: const TextStyle(fontSize: 15)), const Spacer(), const Icon(Icons.calendar_today, size: 20, color: Color(0xFF9E9E9E))]))),
|
||||
const SizedBox(height: 16),
|
||||
GestureDetector(onTap: _pickDuration, child: Container(padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration(border: Border.all(color: const Color(0xFFE0E0E0)), borderRadius: BorderRadius.circular(12)), child: Row(children: [Text(_duration, style: const TextStyle(fontSize: 15)), const Spacer(), const Icon(Icons.keyboard_arrow_down, size: 20, color: Color(0xFF9E9E9E))]))),
|
||||
const SizedBox(height: 32),
|
||||
SizedBox(width: double.infinity, height: 50, child: ElevatedButton(
|
||||
onPressed: () {},
|
||||
style: ElevatedButton.styleFrom(backgroundColor: const Color(0xFF635BFF), foregroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25))),
|
||||
child: const Text('新增用药', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
|
||||
)),
|
||||
const SizedBox(height: 20),
|
||||
]),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
...List.generate(_items.length, (i) => _buildCard(i)),
|
||||
const SizedBox(height: 12),
|
||||
_buildAddButton(),
|
||||
const SizedBox(height: 40),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _pickFrequency() async {
|
||||
final options = ['每日1次', '每日2次', '每日3次', '每周1次', '按需服用'];
|
||||
Widget _buildCard(int index) {
|
||||
final item = _items[index];
|
||||
final count = _timeCount(item.frequency);
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: const Color(0xFFEEEEEE)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Header
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'药品 ${index + 1}',
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF635BFF),
|
||||
),
|
||||
),
|
||||
if (_items.length > 1)
|
||||
GestureDetector(
|
||||
onTap: () => _removeItem(index),
|
||||
child: const Icon(Icons.close, size: 18, color: Color(0xFFBDBDBD)),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Divider(height: 1, color: const Color(0xFFF0F0F0)),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Name
|
||||
_buildLabel('药品名称'),
|
||||
const SizedBox(height: 4),
|
||||
TextField(
|
||||
controller: _nameCtrls[index],
|
||||
style: const TextStyle(fontSize: 14),
|
||||
decoration: _inputDecoration('请输入药品名称'),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Dosage
|
||||
_buildLabel('剂量'),
|
||||
const SizedBox(height: 4),
|
||||
TextField(
|
||||
controller: _doseCtrls[index],
|
||||
style: const TextStyle(fontSize: 14),
|
||||
decoration: _inputDecoration('如:100mg'),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Frequency
|
||||
_buildLabel('服用频率'),
|
||||
const SizedBox(height: 4),
|
||||
GestureDetector(
|
||||
onTap: () => _pickFrequency(index),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFE0E0E0)),
|
||||
color: const Color(0xFFFAFAFA),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(item.frequency, style: const TextStyle(fontSize: 14, color: Color(0xFF1A1A1A))),
|
||||
const Spacer(),
|
||||
const Icon(Icons.keyboard_arrow_down, size: 20, color: Color(0xFF9E9E9E)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Times (dynamic)
|
||||
if (count > 0) ...[
|
||||
_buildLabel('服药时间'),
|
||||
const SizedBox(height: 4),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 6,
|
||||
children: List.generate(count, (t) => _buildTimePicker(index, t)),
|
||||
),
|
||||
if (item.frequency == '每周1次') ...[
|
||||
const SizedBox(height: 8),
|
||||
_buildLabel('选择星期'),
|
||||
const SizedBox(height: 4),
|
||||
GestureDetector(
|
||||
onTap: () => _pickWeekday(index),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFE0E0E0)),
|
||||
color: const Color(0xFFFAFAFA),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(_weekdays[item.weekday - 1], style: const TextStyle(fontSize: 14, color: Color(0xFF1A1A1A))),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(Icons.keyboard_arrow_down, size: 18, color: Color(0xFF9E9E9E)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
|
||||
// Start date
|
||||
_buildLabel('开始日期'),
|
||||
const SizedBox(height: 4),
|
||||
GestureDetector(
|
||||
onTap: () => _pickDate(index, isStart: true),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFE0E0E0)),
|
||||
color: const Color(0xFFFAFAFA),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'${item.startDate.year}-${item.startDate.month.toString().padLeft(2, '0')}-${item.startDate.day.toString().padLeft(2, '0')}',
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFF1A1A1A)),
|
||||
),
|
||||
const Spacer(),
|
||||
const Icon(Icons.calendar_today, size: 18, color: Color(0xFF9E9E9E)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// End date (optional)
|
||||
_buildLabel('结束日期(可选)'),
|
||||
const SizedBox(height: 4),
|
||||
GestureDetector(
|
||||
onTap: () => _pickDate(index, isStart: false),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFE0E0E0)),
|
||||
color: const Color(0xFFFAFAFA),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
item.endDate != null
|
||||
? '${item.endDate!.year}-${item.endDate!.month.toString().padLeft(2, '0')}-${item.endDate!.day.toString().padLeft(2, '0')}'
|
||||
: '不设置',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: item.endDate != null ? const Color(0xFF1A1A1A) : const Color(0xFFBDBDBD),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: item.endDate != null ? () => setState(() => item.endDate = null) : null,
|
||||
child: Icon(
|
||||
item.endDate != null ? Icons.close : Icons.calendar_today,
|
||||
size: 18,
|
||||
color: const Color(0xFF9E9E9E),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLabel(String text) {
|
||||
return Text(
|
||||
text,
|
||||
style: const TextStyle(fontSize: 12, color: Color(0xFF757575)),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTimePicker(int itemIndex, int timeIndex) {
|
||||
final item = _items[itemIndex];
|
||||
final time = item.times[timeIndex];
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => _pickTime(itemIndex, timeIndex),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFE0E0E0)),
|
||||
color: const Color(0xFFFAFAFA),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.access_time, size: 16, color: Color(0xFF635BFF)),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
time.format(context),
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFF1A1A1A)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAddButton() {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: _addItem,
|
||||
icon: const Icon(Icons.add, size: 18),
|
||||
label: const Text('添加', style: TextStyle(fontSize: 14)),
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: const Color(0xFF635BFF),
|
||||
side: const BorderSide(color: Color(0xFFD5D1FF)),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
backgroundColor: const Color(0xFFF5F3FF),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
InputDecoration _inputDecoration(String hint) {
|
||||
return InputDecoration(
|
||||
hintText: hint,
|
||||
hintStyle: const TextStyle(color: Color(0xFFBDBDBD), fontSize: 14),
|
||||
filled: true,
|
||||
fillColor: const Color(0xFFFAFAFA),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
isDense: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(color: Color(0xFFE0E0E0)),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(color: Color(0xFFE0E0E0)),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: const BorderSide(color: Color(0xFF635BFF)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _pickFrequency(int index) async {
|
||||
final selected = await showModalBottomSheet<String>(
|
||||
context: context,
|
||||
builder: (ctx) => SafeArea(child: Column(mainAxisSize: MainAxisSize.min, children: options.map((o) => ListTile(title: Text(o), onTap: () => Navigator.pop(ctx, o))).toList())),
|
||||
builder: (ctx) => SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: _frequencies
|
||||
.map((f) => ListTile(
|
||||
title: Text(f),
|
||||
onTap: () => Navigator.pop(ctx, f),
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (selected != null && mounted) setState(() => _frequency = selected);
|
||||
if (selected != null && mounted) {
|
||||
setState(() {
|
||||
final item = _items[index];
|
||||
item.frequency = selected;
|
||||
final newCount = _timeCount(selected);
|
||||
if (newCount > 0 && item.times.length != newCount) {
|
||||
item.times = List.generate(
|
||||
newCount,
|
||||
(i) => TimeOfDay(hour: 8 + i * 4, minute: 0),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _pickTime() async {
|
||||
final time = await showTimePicker(context: context, initialTime: TimeOfDay.now());
|
||||
if (time != null && mounted) setState(() => _time = time.format(context));
|
||||
}
|
||||
|
||||
void _pickDate() async {
|
||||
final date = await showDatePicker(context: context, firstDate: DateTime(2020), lastDate: DateTime(2030), initialDate: _startDate);
|
||||
if (date != null && mounted) setState(() => _startDate = date);
|
||||
}
|
||||
|
||||
void _pickDuration() async {
|
||||
final options = ['长期服用', '7天', '14天', '30天', '90天'];
|
||||
final selected = await showModalBottomSheet<String>(
|
||||
void _pickWeekday(int index) async {
|
||||
final item = _items[index];
|
||||
final selected = await showModalBottomSheet<int>(
|
||||
context: context,
|
||||
builder: (ctx) => SafeArea(child: Column(mainAxisSize: MainAxisSize.min, children: options.map((o) => ListTile(title: Text(o), onTap: () => Navigator.pop(ctx, o))).toList())),
|
||||
builder: (ctx) => SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(7, (i) {
|
||||
return ListTile(
|
||||
title: Text(_weekdays[i]),
|
||||
selected: item.weekday == i + 1,
|
||||
onTap: () => Navigator.pop(ctx, i + 1),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (selected != null && mounted) setState(() => _duration = selected);
|
||||
if (selected != null && mounted) {
|
||||
setState(() => _items[index].weekday = selected);
|
||||
}
|
||||
}
|
||||
|
||||
void _pickTime(int itemIndex, int timeIndex) async {
|
||||
final item = _items[itemIndex];
|
||||
final time = await showTimePicker(
|
||||
context: context,
|
||||
initialTime: item.times[timeIndex],
|
||||
);
|
||||
if (time != null && mounted) {
|
||||
setState(() => item.times[timeIndex] = time);
|
||||
}
|
||||
}
|
||||
|
||||
void _pickDate(int index, {required bool isStart}) async {
|
||||
final item = _items[index];
|
||||
final initial = isStart ? item.startDate : (item.endDate ?? DateTime.now());
|
||||
final date = await showDatePicker(
|
||||
context: context,
|
||||
firstDate: DateTime(2020),
|
||||
lastDate: DateTime(2030),
|
||||
initialDate: initial,
|
||||
);
|
||||
if (date != null && mounted) {
|
||||
setState(() {
|
||||
if (isStart) {
|
||||
item.startDate = date;
|
||||
} else {
|
||||
item.endDate = date;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user