|
@@ -3,7 +3,11 @@ import 'dart:convert';
|
|
|
import 'package:fis_jsonrpc/rpc.dart';
|
|
|
import 'package:flutter/material.dart';
|
|
|
import 'package:get/get.dart';
|
|
|
+import 'package:vnoteapp/architecture/utils/datetime.dart';
|
|
|
+import 'package:vnoteapp/components/alert_dialog.dart';
|
|
|
import 'package:vnoteapp/components/button.dart';
|
|
|
+import 'package:vnoteapp/components/cell.dart';
|
|
|
+import 'package:vnoteapp/components/dialog_date.dart';
|
|
|
import 'package:vnoteapp/components/dialog_input.dart';
|
|
|
import 'package:vnoteapp/components/dialog_number.dart';
|
|
|
import 'package:vnoteapp/components/dynamic_drawer.dart';
|
|
@@ -24,10 +28,9 @@ import 'dart:math' as math;
|
|
|
import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_radio.dart';
|
|
|
import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_radio_score.dart';
|
|
|
import 'package:vnoteapp/pages/check/widgets/device_controller.dart';
|
|
|
-
|
|
|
-const double _width = 170;
|
|
|
-const double _height = 38;
|
|
|
-String tw = '00.0';
|
|
|
+import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_table.dart';
|
|
|
+import 'package:vnoteapp/pages/check/widgets/exam_configurable/exam_toxic_substance.dart';
|
|
|
+import 'package:vnoteapp/pages/check/widgets/title_clip_path.dart';
|
|
|
|
|
|
class ConfigurableCard extends StatefulWidget {
|
|
|
final String cardKey;
|
|
@@ -63,9 +66,10 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
|
|
|
|
|
|
final _templateManager = Get.find<ITemplateManager>();
|
|
|
final _cachedRecordManager = Get.find<ICachedRecordManager>();
|
|
|
- final arrowHeight = math.tan(120 / 180) * (_height / 2);
|
|
|
+ final arrowHeight = math.tan(120 / 180) * 19;
|
|
|
List<String> deviceList = ['Temp', 'GLU', 'NIBP', 'SpO2', 'BMI'];
|
|
|
Map<String, dynamic> deviceCached = {};
|
|
|
+
|
|
|
@override
|
|
|
void initState() {
|
|
|
Get.put(DeviceController());
|
|
@@ -323,7 +327,11 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
|
|
|
'weight': _buildBodyWeight,
|
|
|
'sugar': _buildBodySugar,
|
|
|
'bloodOxygen': _buildBloodOxygen,
|
|
|
- 'healthGuidanceCheckBox': _buildHealthGuidanceCheckBox
|
|
|
+ 'healthGuidanceCheckBox': _buildHealthGuidanceCheckBox,
|
|
|
+ 'medicalHistory': _buildMedicalHistory,
|
|
|
+ 'homecareBedHistor': _buildHomecareBedHistory,
|
|
|
+ 'table': _buildMainMedicationHistory,
|
|
|
+ 'safetyPrecautions': _buildToxicSubstance,
|
|
|
};
|
|
|
Widget Function(FormObject) builder =
|
|
|
widgetMap[currentFormObject?.type] ?? _buildInput;
|
|
@@ -415,6 +423,9 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
|
|
|
|
|
|
/// 示意图
|
|
|
Widget _buildDiagram() {
|
|
|
+ if (widget.cardKey == 'ZYYYFMYGHYFJZS') {
|
|
|
+ return const SizedBox();
|
|
|
+ }
|
|
|
return Expanded(
|
|
|
flex: 1,
|
|
|
child: Stack(
|
|
@@ -712,6 +723,7 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
|
|
|
List<Option> options = currentFormObject.options ?? [];
|
|
|
String currentSelected =
|
|
|
formValue[currentFormObject.childrenKey!.first] ?? "";
|
|
|
+ String currentScore = formValue[currentFormObject.childrenKey!.last] ?? "";
|
|
|
|
|
|
void selectRaidoChange(Option e) {
|
|
|
currentSelected = e.value ?? '';
|
|
@@ -719,11 +731,19 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
|
|
|
setState(() {});
|
|
|
}
|
|
|
|
|
|
+ void changeScore(String? score) {
|
|
|
+ currentScore = score ?? '';
|
|
|
+ formValue[currentFormObject.childrenKey!.last] = currentScore;
|
|
|
+ setState(() {});
|
|
|
+ }
|
|
|
+
|
|
|
return ExamRadioScore(
|
|
|
options: options,
|
|
|
currentFormObject: currentFormObject,
|
|
|
selectRaidoChange: selectRaidoChange,
|
|
|
currentSelected: currentSelected,
|
|
|
+ changeScore: changeScore,
|
|
|
+ currentScore: currentScore,
|
|
|
);
|
|
|
}
|
|
|
|
|
@@ -744,6 +764,25 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ Widget _buildToxicSubstance(FormObject currentFormObject) {
|
|
|
+ List<Option> options = currentFormObject.options ?? [];
|
|
|
+ String currentSelected =
|
|
|
+ formValue[currentFormObject.childrenKey!.first] ?? "";
|
|
|
+ String currentScore = formValue[currentFormObject.childrenKey!.last] ?? "";
|
|
|
+ void selectRaidoChange(Option e) {
|
|
|
+ currentSelected = e.value ?? '';
|
|
|
+ formValue[currentFormObject.childrenKey!.first] = currentSelected;
|
|
|
+ setState(() {});
|
|
|
+ }
|
|
|
+
|
|
|
+ return ExamToxicSubstance(
|
|
|
+ currentFormObject: currentFormObject,
|
|
|
+ currentSelected: currentSelected,
|
|
|
+ options: options,
|
|
|
+ selectRaidoChange: selectRaidoChange,
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
/// 血氧
|
|
|
Widget _buildBloodOxygen(FormObject currentFormObject) {
|
|
|
Map<String, dynamic> currentValue = formValue;
|
|
@@ -761,6 +800,142 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ /// 住院史
|
|
|
+ Widget _buildMedicalHistory(FormObject currentFormObject) {
|
|
|
+ List<Map> currentValue = formValue[currentFormObject.key!] ?? [];
|
|
|
+ int currentId = currentValue.length + 1;
|
|
|
+ Map currentTable = {
|
|
|
+ 'id': currentId.toString(),
|
|
|
+ };
|
|
|
+
|
|
|
+ Future<void> addTableData() async {
|
|
|
+ await VAlertDialog.showDialog(
|
|
|
+ VAlertDialog(
|
|
|
+ title: "住院史填写",
|
|
|
+ width: 460,
|
|
|
+ content: Container(
|
|
|
+ height: 350,
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
|
+ alignment: Alignment.center,
|
|
|
+ child: VListFormCellGroup(
|
|
|
+ children: [
|
|
|
+ VListFormCell(
|
|
|
+ label: '入院日期',
|
|
|
+ content: DataTimeUtils.formatDateString(
|
|
|
+ currentTable['Admission_Date'],
|
|
|
+ ),
|
|
|
+ onTap: () async {
|
|
|
+ final result = await VDialogDate(
|
|
|
+ title: '入院日期',
|
|
|
+ initialValue: currentTable['Admission_Date'],
|
|
|
+ ).show();
|
|
|
+ currentTable['Admission_Date'] = result;
|
|
|
+ print(result);
|
|
|
+ // setState(() {});
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ VListFormCell(
|
|
|
+ label: '出院日期',
|
|
|
+ onTap: () async {
|
|
|
+ final result = await VDialogDate(
|
|
|
+ title: '出院日期',
|
|
|
+ initialValue: DateTime.now(),
|
|
|
+ ).show();
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ VListFormCell(
|
|
|
+ label: '原因',
|
|
|
+ onTap: () {},
|
|
|
+ ),
|
|
|
+ VListFormCell(
|
|
|
+ label: '医疗机构名称',
|
|
|
+ onTap: () {},
|
|
|
+ ),
|
|
|
+ VListFormCell(
|
|
|
+ label: '病案号',
|
|
|
+ onTap: () {},
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ onConfirm: () {
|
|
|
+ Get.back();
|
|
|
+ currentValue.add({
|
|
|
+ 'id': currentId.toString(),
|
|
|
+ 'Admission_Date': '',
|
|
|
+ 'Discharge_Date': '',
|
|
|
+ 'Reason': '',
|
|
|
+ 'Name_Of_Medical_Institution': '',
|
|
|
+ 'Patient_Number': ''
|
|
|
+ });
|
|
|
+ formValue[currentFormObject.key!] = currentValue;
|
|
|
+ setState(() {});
|
|
|
+ // controller.logOut();
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ return ExamTable(
|
|
|
+ tableThList: const ['序号', '入院日期', '出院日期', '原因', '医疗机构名称', '病案号'],
|
|
|
+ currentFormObject: currentFormObject,
|
|
|
+ currentValue: currentValue,
|
|
|
+ addTableData: addTableData,
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 家庭病床史
|
|
|
+ Widget _buildHomecareBedHistory(FormObject currentFormObject) {
|
|
|
+ List<Map> currentValue = formValue[currentFormObject.key!] ?? [];
|
|
|
+ int currentId = currentValue.length + 1;
|
|
|
+ void addTableData() {
|
|
|
+ currentValue.add({
|
|
|
+ 'id': currentId.toString(),
|
|
|
+ 'Bed_Construction_Date': '',
|
|
|
+ 'Discharge_Date': '',
|
|
|
+ 'Reason': '',
|
|
|
+ 'Name_Of_Medical_Institution': '',
|
|
|
+ 'Patient_Number': ''
|
|
|
+ });
|
|
|
+ formValue[currentFormObject.key!] = currentValue;
|
|
|
+ setState(() {});
|
|
|
+ }
|
|
|
+
|
|
|
+ return ExamTable(
|
|
|
+ tableThList: const ['序号', '建床日期', '撤床日期', '原因', '医疗机构名称', '病案号'],
|
|
|
+ currentFormObject: currentFormObject,
|
|
|
+ currentValue: currentValue,
|
|
|
+ addTableData: addTableData,
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildMainMedicationHistory(FormObject currentFromObject) {
|
|
|
+ List<Map> currentValue = formValue[currentFromObject.key!] ?? [];
|
|
|
+ int currentId = currentValue.length + 1;
|
|
|
+ Future<void> addTableData() async {
|
|
|
+ await VAlertDialog.showDialog(Container(
|
|
|
+ child: const Text(''),
|
|
|
+ ));
|
|
|
+ currentValue.add({
|
|
|
+ 'id': currentId.toString(),
|
|
|
+ 'Bed_Construction_Date': '',
|
|
|
+ 'Discharge_Date': '',
|
|
|
+ 'Reason': '',
|
|
|
+ 'Name_Of_Medical_Institution': '',
|
|
|
+ 'Patient_Number': ''
|
|
|
+ });
|
|
|
+ formValue[currentFromObject.key!] = currentValue;
|
|
|
+ setState(() {});
|
|
|
+ }
|
|
|
+
|
|
|
+ return ExamTable(
|
|
|
+ tableThList: const ['序号', '药物名称', '用法', '用量', '用药时间', '服药依从性'],
|
|
|
+ currentFormObject: currentFromObject,
|
|
|
+ currentValue: currentValue,
|
|
|
+ addTableData: addTableData,
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
/// 体重
|
|
|
Widget _buildBodyWeight(FormObject currentFormObject) {
|
|
|
String currentInputValue = formValue[currentFormObject.key!] ?? '';
|
|
@@ -795,174 +970,3 @@ class _ConfigurableFormState extends State<ConfigurableCard> {
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-class TitleClipRect extends StatelessWidget {
|
|
|
- const TitleClipRect({
|
|
|
- super.key,
|
|
|
- this.color = Colors.grey,
|
|
|
- required this.title,
|
|
|
- required this.arrowHeight,
|
|
|
- required this.clickTitle,
|
|
|
- });
|
|
|
-
|
|
|
- final Color? color;
|
|
|
- final String title;
|
|
|
- final double arrowHeight;
|
|
|
- final Function clickTitle;
|
|
|
-
|
|
|
- @override
|
|
|
- Widget build(BuildContext context) {
|
|
|
- return InkWell(
|
|
|
- onTap: () {
|
|
|
- clickTitle.call();
|
|
|
- },
|
|
|
- customBorder: HoleShapeBorder(arrowHeight),
|
|
|
- child: Card(
|
|
|
- margin: const EdgeInsets.all(0),
|
|
|
- shape: HoleShapeBorder(arrowHeight),
|
|
|
- color: color,
|
|
|
- elevation: color == null ? 5 : 0,
|
|
|
- shadowColor: Theme.of(context).primaryColor.withOpacity(0.8),
|
|
|
- child: ClipPath(
|
|
|
- clipper: _TitleClipPath(arrowHeight),
|
|
|
- child: Container(
|
|
|
- width: _width,
|
|
|
- height: _height,
|
|
|
- padding: const EdgeInsets.symmetric(
|
|
|
- horizontal: 15,
|
|
|
- ),
|
|
|
- decoration: BoxDecoration(
|
|
|
- boxShadow: [
|
|
|
- BoxShadow(
|
|
|
- color: Theme.of(context).primaryColor.withOpacity(1),
|
|
|
- ),
|
|
|
- ],
|
|
|
- color: color,
|
|
|
- ),
|
|
|
- alignment: Alignment.center,
|
|
|
- child: FittedBox(
|
|
|
- child: Text(
|
|
|
- title,
|
|
|
- style: const TextStyle(color: Colors.white, fontSize: 20),
|
|
|
- ),
|
|
|
- ),
|
|
|
- ),
|
|
|
- ),
|
|
|
- ),
|
|
|
- );
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-class _TitleClipPath extends CustomClipper<Path> {
|
|
|
- final double arrowHeight;
|
|
|
-
|
|
|
- _TitleClipPath(this.arrowHeight);
|
|
|
-
|
|
|
- @override
|
|
|
- Path getClip(Size size) {
|
|
|
- final height = size.height;
|
|
|
- final arrowBase = height / 2;
|
|
|
- // final arrowPLine = math.tan(120 / 180) * arrowBase;
|
|
|
- final path = Path();
|
|
|
- path.moveTo(0, 0); // 左上角
|
|
|
- path.lineTo(size.width - arrowHeight, 0); // 右上角
|
|
|
- path.lineTo(size.width, arrowBase); // 右端点
|
|
|
- path.lineTo(size.width - arrowHeight, height); // 右下角
|
|
|
-
|
|
|
- path.lineTo(0, height); // 左下角
|
|
|
- path.lineTo(arrowHeight, arrowBase); // 左端点
|
|
|
- path.lineTo(0, 0); // 左上角
|
|
|
-
|
|
|
- return path;
|
|
|
- }
|
|
|
-
|
|
|
- @override
|
|
|
- bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-class HoleShapeBorder extends ShapeBorder {
|
|
|
- final Offset offset;
|
|
|
- final double size;
|
|
|
- final double arrowHeight;
|
|
|
- const HoleShapeBorder(this.arrowHeight,
|
|
|
- {this.offset = const Offset(0, 0), this.size = 0});
|
|
|
-
|
|
|
- @override
|
|
|
- EdgeInsetsGeometry get dimensions => throw UnimplementedError();
|
|
|
-
|
|
|
- @override
|
|
|
- void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {}
|
|
|
-
|
|
|
- @override
|
|
|
- Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
|
|
|
- var path = Path();
|
|
|
-
|
|
|
- final height = rect.size.height;
|
|
|
- final arrowBase = height / 2;
|
|
|
- path.moveTo(0, 0); // 左上角
|
|
|
- path.lineTo(rect.size.width - arrowHeight, 0); // 右上角
|
|
|
- path.lineTo(rect.size.width, arrowBase); // 右端点
|
|
|
- path.lineTo(rect.size.width - arrowHeight, height); // 右下角
|
|
|
-
|
|
|
- path.lineTo(0, height); // 左下角
|
|
|
- path.lineTo(arrowHeight, arrowBase); // 左端点
|
|
|
- path.lineTo(0, 0); // 左上角
|
|
|
-
|
|
|
- return path;
|
|
|
- }
|
|
|
-
|
|
|
- @override
|
|
|
- ShapeBorder scale(double t) {
|
|
|
- // TODO: implement scale
|
|
|
- throw UnimplementedError();
|
|
|
- }
|
|
|
-
|
|
|
- @override
|
|
|
- Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
|
|
|
- // TODO: implement getInnerPath
|
|
|
- throw UnimplementedError();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// ClipPath(
|
|
|
-// clipper: TriangleClipper(),
|
|
|
-// child: Container(
|
|
|
-// width: 50,
|
|
|
-// height: 50,
|
|
|
-// padding:
|
|
|
-// const EdgeInsets.all(
|
|
|
-// 2),
|
|
|
-// alignment:
|
|
|
-// Alignment.topRight,
|
|
|
-// decoration:
|
|
|
-// const BoxDecoration(
|
|
|
-// color: Colors.blue,
|
|
|
-// borderRadius:
|
|
|
-// BorderRadius.only(
|
|
|
-// topRight:
|
|
|
-// Radius.circular(
|
|
|
-// 8,
|
|
|
-// ),
|
|
|
-// ),
|
|
|
-// ),
|
|
|
-// child: const Icon(
|
|
|
-// Icons.check,
|
|
|
-// color: Colors.white,
|
|
|
-// ),
|
|
|
-// ))
|
|
|
-// class TriangleClipper extends CustomClipper<Path> {
|
|
|
-// @override
|
|
|
-// Path getClip(Size size) {
|
|
|
-// final path = Path()
|
|
|
-// ..moveTo(size.width, 0)
|
|
|
-// ..lineTo(0, 0)
|
|
|
-// ..lineTo(size.width, size.height)
|
|
|
-// ..close();
|
|
|
-// return path;
|
|
|
-// }
|
|
|
-
|
|
|
-// @override
|
|
|
-// bool shouldReclip(CustomClipper<Path> oldClipper) => false;
|
|
|
-// }
|