- VisionAsync 新增 Temperature=0.7, TopP=0.8 - system prompt 用专业营养识别指令 - userText 用简短"请看图识别食物"配合图片 - 修复重复 prompt 导致 VLM 误读文本的 bug
98 lines
6.3 KiB
Dart
98 lines
6.3 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
||
class MedicationEditPage extends ConsumerStatefulWidget {
|
||
final String? medicationId;
|
||
const MedicationEditPage({super.key, this.medicationId});
|
||
|
||
@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 = '长期服用';
|
||
|
||
@override void dispose() { _nameCtrl.dispose(); _dosageCtrl.dispose(); super.dispose(); }
|
||
|
||
@override Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
backgroundColor: Colors.white,
|
||
appBar: AppBar(
|
||
backgroundColor: Colors.white,
|
||
elevation: 0,
|
||
leading: IconButton(icon: const Icon(Icons.chevron_left), onPressed: () => Navigator.pop(context)),
|
||
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)),
|
||
),
|
||
],
|
||
),
|
||
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),
|
||
]),
|
||
),
|
||
);
|
||
}
|
||
|
||
void _pickFrequency() async {
|
||
final options = ['每日1次', '每日2次', '每日3次', '每周1次', '按需服用'];
|
||
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())),
|
||
);
|
||
if (selected != null && mounted) setState(() => _frequency = selected);
|
||
}
|
||
|
||
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>(
|
||
context: context,
|
||
builder: (ctx) => SafeArea(child: Column(mainAxisSize: MainAxisSize.min, children: options.map((o) => ListTile(title: Text(o), onTap: () => Navigator.pop(ctx, o))).toList())),
|
||
);
|
||
if (selected != null && mounted) setState(() => _duration = selected);
|
||
}
|
||
}
|