view.dart 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:vitalapp/architecture/utils/advance_debounce.dart';
  4. import 'package:vitalapp/components/alert_dialog.dart';
  5. import 'package:vitalapp/pages/medical/controllers/waist.dart';
  6. import 'package:vitalapp/pages/medical/widgets/heart_rate.dart';
  7. import 'package:vitalapp/pages/medical/widgets/twelve_ecg.dart';
  8. import 'package:vitalapp/pages/medical/widgets/urinalysis.dart';
  9. import 'package:vitalapp/pages/medical/widgets/waist.dart';
  10. import 'package:vnote_device_plugin/consts/types.dart';
  11. import 'package:vitalapp/components/button.dart';
  12. import 'package:vitalapp/pages/medical/controller.dart';
  13. import 'package:vitalapp/pages/medical/widgets/blood_pressure.dart';
  14. import 'package:vitalapp/pages/medical/widgets/blood_sugar.dart';
  15. import 'package:vitalapp/pages/medical/widgets/body_temperature.dart';
  16. import 'package:vitalapp/pages/medical/widgets/body_bmi.dart';
  17. import 'package:vitalapp/pages/medical/widgets/bool_oxygen.dart';
  18. import 'package:vitalapp/store/store.dart';
  19. class MedicalPage extends GetView<MedicalController> {
  20. const MedicalPage({
  21. super.key,
  22. this.isHealthCheck,
  23. });
  24. final bool? isHealthCheck;
  25. @override
  26. Widget build(BuildContext context) {
  27. return Scaffold(
  28. resizeToAvoidBottomInset: false,
  29. body: SizedBox(height: double.maxFinite, child: _buildMedical()),
  30. floatingActionButton: _buildSaveButton(context),
  31. );
  32. }
  33. Widget _buildMedical() {
  34. return Row(
  35. children: [
  36. _buildMedicalMenus(),
  37. Obx(
  38. () => _buildDeviceImage(controller.state.currentTab),
  39. ),
  40. Obx(
  41. () => _buildMedicalInput(controller.state.currentTab),
  42. ),
  43. ],
  44. );
  45. }
  46. Widget _buildMedicalMenus() {
  47. return Expanded(
  48. flex: 3,
  49. child: Obx(
  50. () => Column(
  51. mainAxisAlignment: MainAxisAlignment.center,
  52. children: [
  53. ListView(
  54. shrinkWrap: true,
  55. children: controller.state.medicalMenuList
  56. .map(
  57. (e) => Material(
  58. borderRadius: const BorderRadius.only(
  59. topRight: Radius.circular(30),
  60. bottomRight: Radius.circular(30),
  61. ),
  62. child: Ink(
  63. decoration: const BoxDecoration(
  64. borderRadius: BorderRadius.only(
  65. topRight: Radius.circular(30),
  66. bottomRight: Radius.circular(30),
  67. ),
  68. ),
  69. child: InkWell(
  70. borderRadius: const BorderRadius.only(
  71. topRight: Radius.circular(30),
  72. bottomRight: Radius.circular(30),
  73. ),
  74. onTap: () {
  75. controller.state.currentTab = e.key;
  76. },
  77. child: Obx(
  78. () => _SideBar(
  79. title: e.diagnosticItem,
  80. isActive: controller.state.currentTab == e.key,
  81. ),
  82. )),
  83. ),
  84. ),
  85. )
  86. .toList(),
  87. ),
  88. ],
  89. ),
  90. ),
  91. );
  92. }
  93. Widget _buildMedicalInput(String? currentTab) {
  94. return Expanded(
  95. flex: currentTab == DeviceTypes.TWELVEHEART ? 18 : 11,
  96. child: Stack(
  97. children: [
  98. Container(
  99. padding: const EdgeInsets.all(16),
  100. child: Column(
  101. children: [
  102. _buildContent(),
  103. ],
  104. ),
  105. ),
  106. ],
  107. ),
  108. );
  109. }
  110. String _deviceImageUrl(String? currentTab) {
  111. switch (currentTab) {
  112. case DeviceTypes.TEMP:
  113. return 'assets/images/healthCheck/temp.png';
  114. case DeviceTypes.SUGAR:
  115. return 'assets/images/healthCheck/sugar.png';
  116. case DeviceTypes.NIBP:
  117. return 'assets/images/healthCheck/nibp.png';
  118. case DeviceTypes.SPO2:
  119. return 'assets/images/healthCheck/spo2.png';
  120. case DeviceTypes.WEIGHT:
  121. return 'assets/images/healthCheck/bmi.png';
  122. case DeviceTypes.URINE:
  123. return 'assets/images/healthCheck/urine.png';
  124. case DeviceTypes.WAIST:
  125. return 'assets/images/healthCheck/whb.png';
  126. default:
  127. return 'assets/images/exam/normalMeasurementChart.png';
  128. }
  129. }
  130. Widget _buildDeviceImage(String? currentTab) {
  131. if (currentTab == DeviceTypes.TWELVEHEART) {
  132. return const SizedBox();
  133. }
  134. return Expanded(
  135. flex: 7,
  136. child: Container(
  137. alignment: Alignment.topCenter,
  138. margin: const EdgeInsets.all(16).copyWith(top: 10),
  139. child: Obx(
  140. () => ClipRect(
  141. child: Align(
  142. alignment: Alignment.bottomCenter,
  143. heightFactor: 0.8,
  144. child: controller.state.currentTab != null
  145. ? Image.asset(
  146. _deviceImageUrl(controller.state.currentTab),
  147. height: double.infinity,
  148. fit: BoxFit.contain, // 设置图像的适应方式
  149. )
  150. : Container(),
  151. ),
  152. ),
  153. ),
  154. ),
  155. );
  156. }
  157. Widget _buildGenerateReport() {
  158. return Positioned(
  159. bottom: 100,
  160. left: 16,
  161. child: VButton(
  162. onTap: () {
  163. Get.dialog(
  164. VAlertDialog(
  165. title: '提示',
  166. content: Container(
  167. margin: const EdgeInsets.only(bottom: 20),
  168. child: const Text(
  169. '当前检测是否已完成,请确定是否结束本次检测',
  170. style: TextStyle(fontSize: 20),
  171. textAlign: TextAlign.center,
  172. ),
  173. ),
  174. showCancel: true,
  175. onConfirm: () {
  176. controller.saveCachedAppDataId();
  177. },
  178. ),
  179. );
  180. },
  181. child: const Text(
  182. '生成检测',
  183. style: TextStyle(fontSize: 26),
  184. ),
  185. ),
  186. );
  187. }
  188. Widget _buildSaveButton(BuildContext context) {
  189. return Obx(() {
  190. if (Store.user.currentSelectPatientInfo == null) {
  191. return const SizedBox();
  192. }
  193. return FloatingActionButton.extended(
  194. backgroundColor: Theme.of(context).primaryColor,
  195. onPressed: () {
  196. // controller.createDiagnosis(isHealthCheck: isHealthCheck ?? false);
  197. Debouncer.run(
  198. () => controller.createDiagnosis(
  199. isHealthCheck: isHealthCheck ?? false,
  200. ),
  201. );
  202. },
  203. label: const SizedBox(
  204. width: 240,
  205. height: 60,
  206. child: Center(
  207. child: Text(
  208. '提交',
  209. style: TextStyle(
  210. fontSize: 26,
  211. color: Colors.white,
  212. ),
  213. ),
  214. ),
  215. ),
  216. );
  217. });
  218. }
  219. Widget _buildContent() {
  220. return Obx(() {
  221. switch (controller.state.currentTab) {
  222. case DeviceTypes.TEMP:
  223. return const BodyTemperature();
  224. case DeviceTypes.SUGAR:
  225. return const BloodSugar();
  226. case DeviceTypes.NIBP:
  227. return const BloodPressure();
  228. case DeviceTypes.SPO2:
  229. return const BloodOxygen();
  230. case DeviceTypes.WEIGHT:
  231. return const BodyWeight();
  232. case DeviceTypes.URINE:
  233. return const Urinalysis();
  234. case DeviceTypes.HEART:
  235. return const HeartRate();
  236. case DeviceTypes.TWELVEHEART:
  237. return const TwelveHeartRate();
  238. case DeviceTypes.WAIST:
  239. // TODO: 待统一各检测项
  240. return GetBuilder(
  241. init: WaistDeviceController(),
  242. builder: (_) => const WaistView(),
  243. );
  244. default:
  245. return const SizedBox();
  246. }
  247. });
  248. }
  249. }
  250. class _SideBar extends StatelessWidget {
  251. const _SideBar({
  252. required this.title,
  253. this.isActive,
  254. });
  255. final String title;
  256. final bool? isActive;
  257. @override
  258. Widget build(BuildContext context) {
  259. return Container(
  260. alignment: Alignment.centerLeft,
  261. width: 156,
  262. child: Container(
  263. margin: const EdgeInsets.only(bottom: 2),
  264. decoration: BoxDecoration(
  265. color: isActive!
  266. ? Theme.of(context).primaryColor
  267. : Theme.of(context).primaryColor.withOpacity(.2),
  268. borderRadius: const BorderRadius.only(
  269. topRight: Radius.circular(30),
  270. bottomRight: Radius.circular(30),
  271. ),
  272. ),
  273. alignment: Alignment.center,
  274. width: 156,
  275. height: 60,
  276. child: Text(
  277. title,
  278. style: TextStyle(
  279. fontSize: 26,
  280. color: isActive! ? Colors.white : Colors.black,
  281. ),
  282. ),
  283. ),
  284. );
  285. }
  286. }