assessment_module.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. import 'dart:convert';
  2. import 'package:fis_common/index.dart';
  3. import 'package:fis_jsonrpc/rpc.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter/services.dart';
  6. import 'package:get/get.dart';
  7. import 'package:vitalapp/architecture/storage/text_storage.dart';
  8. import 'package:vitalapp/architecture/utils/prompt_box.dart';
  9. import 'package:vitalapp/components/appbar.dart';
  10. import 'package:vitalapp/global.dart';
  11. import 'package:vitalapp/managers/interfaces/template.dart';
  12. import 'package:vitalapp/pages/check/models/form.dart';
  13. import 'package:vitalapp/pages/check/widgets/exam_configurable/exam_single_line_radio.dart';
  14. import 'package:vitalapp/store/store.dart';
  15. class SelfCareAssessmentModule extends StatefulWidget {
  16. final String cardKey;
  17. final Future<bool> Function(String, String, dynamic) callBack;
  18. final String? patientCode;
  19. final String? examData;
  20. final bool isEdit;
  21. const SelfCareAssessmentModule({
  22. super.key,
  23. required this.cardKey,
  24. required this.callBack,
  25. this.patientCode,
  26. this.examData,
  27. this.isEdit = false,
  28. });
  29. @override
  30. State<SelfCareAssessmentModule> createState() => _SelfCareAssessmentModule();
  31. }
  32. class _SelfCareAssessmentModule extends State<SelfCareAssessmentModule> {
  33. ///当前最新的模版键值对
  34. Map<String, dynamic> templateRelation = {};
  35. String templateCode = '';
  36. ///是否首次进入页面
  37. bool isFirstEnter = true;
  38. ///当前模版数据
  39. List<FormObject> currentTemplate = [];
  40. ///当前title的下标
  41. int currentTitleIndex = 0;
  42. ///数据存储
  43. Map<String, dynamic> formValue = {};
  44. final _templateManager = Get.find<ITemplateManager>();
  45. @override
  46. void initState() {
  47. super.initState();
  48. initReadCached();
  49. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  50. if (mounted) {
  51. initTemplate();
  52. }
  53. });
  54. }
  55. Future<void> initTemplate() async {
  56. Store.app.busy = true;
  57. await fetchTemplateIndex();
  58. await fetchTemplate(widget.cardKey);
  59. await fetchTemplateData();
  60. Store.app.busy = false;
  61. setState(() {});
  62. }
  63. Future<void> initReadCached() async {
  64. if (widget.patientCode == null) {
  65. return;
  66. }
  67. TextStorage cachedRecord = TextStorage(
  68. fileName: widget.cardKey,
  69. directory: "patient/${widget.patientCode}",
  70. );
  71. String? value = await cachedRecord.read();
  72. if (value == null) {
  73. formValue = {};
  74. Store.resident.handleSaveMedicalData(jsonEncode(formValue));
  75. return;
  76. }
  77. Store.resident.handleSaveMedicalData(value);
  78. formValue = jsonDecode(value);
  79. }
  80. Future<bool?> saveCachedRecord() async {
  81. if (widget.patientCode == null) {
  82. return false;
  83. }
  84. Store.resident.handleSaveMedicalData(jsonEncode(formValue));
  85. TextStorage cachedRecord = TextStorage(
  86. fileName: widget.cardKey,
  87. directory: "patient/${widget.patientCode}",
  88. );
  89. return cachedRecord.save(jsonEncode(formValue));
  90. }
  91. Future<bool?> deleteDirectory() async {
  92. TextStorage cachedRecord = TextStorage(
  93. fileName: widget.cardKey,
  94. directory: "patient/${widget.patientCode}",
  95. );
  96. return cachedRecord.deleteDirectory();
  97. }
  98. Future<void> fetchTemplateIndex() async {
  99. try {
  100. var templates =
  101. await _templateManager.readTemplateRelation("templateRelation");
  102. templateRelation = jsonDecode(templates!);
  103. } catch (e) {}
  104. }
  105. Future<void> fetchTemplate(String key) async {
  106. try {
  107. if (templateRelation[key] == null) {
  108. currentTemplate = [];
  109. if (!FPlatform.isWindows) {
  110. return;
  111. }
  112. }
  113. String? template;
  114. if (templateRelation.containsKey(key)) {
  115. templateCode = templateRelation[key]!;
  116. template = await _templateManager.readTemplate(templateCode);
  117. }
  118. List<Map<String, dynamic>> list = [];
  119. if (template == null) {
  120. var json = await loadJsonFromAssets('assets/templates/${key}.json');
  121. list = jsonDecode(json)["Content"].cast<Map<String, dynamic>>();
  122. } else {
  123. var templateContent =
  124. TemplateDTO.fromJson(jsonDecode(template)).templateContent!;
  125. list = jsonDecode(templateContent).cast<Map<String, dynamic>>();
  126. }
  127. for (var i in list) {
  128. if (i["children"] != null) {
  129. List<FormObject> currentChildren = [];
  130. for (var j in i['children']) {
  131. currentChildren.add(FormObject.fromJson(j));
  132. }
  133. i['children'] = currentChildren;
  134. }
  135. var item = FormObject.fromJson(i);
  136. currentTemplate.add(item);
  137. }
  138. } catch (e) {}
  139. }
  140. Future<void> fetchTemplateData() async {
  141. if (widget.examData?.isNotEmpty ?? false) {
  142. formValue = jsonDecode(widget.examData!);
  143. return;
  144. }
  145. }
  146. Future<String> loadJsonFromAssets(String filePath) async {
  147. String jsonString = await rootBundle.loadString(filePath);
  148. return jsonString;
  149. }
  150. @override
  151. Widget build(BuildContext context) {
  152. return Scaffold(
  153. appBar: VAppBar(
  154. titleText: "自理能力评估",
  155. actions: [
  156. TextButton(
  157. child: Padding(
  158. padding: const EdgeInsets.only(right: 16.0),
  159. child: Text(
  160. "提交",
  161. style: const TextStyle(
  162. fontSize: 28,
  163. color: Colors.white,
  164. ),
  165. ),
  166. ),
  167. onPressed: () async {
  168. if (!kIsOnline) {
  169. PromptBox.toast('请检查网络连接');
  170. return;
  171. }
  172. if (!_validateFormValue(formValue)) {
  173. PromptBox.toast('未填写任何评估内容');
  174. return;
  175. }
  176. final result = await widget.callBack(
  177. widget.cardKey,
  178. templateCode,
  179. jsonEncode(formValue),
  180. );
  181. Get.back(result: formValue["SelfCareScore"]);
  182. if (result) {
  183. if (!widget.isEdit) formValue.clear();
  184. if (!FPlatform.isWindows) {
  185. deleteDirectory();
  186. }
  187. PromptBox.toast('提交成功');
  188. setState(() {});
  189. }
  190. },
  191. )
  192. ],
  193. ),
  194. body: Column(
  195. mainAxisAlignment: MainAxisAlignment.start,
  196. crossAxisAlignment: CrossAxisAlignment.start,
  197. children: [
  198. const SizedBox(
  199. height: 20,
  200. ),
  201. Expanded(
  202. child: Row(
  203. mainAxisAlignment: MainAxisAlignment.start,
  204. crossAxisAlignment: CrossAxisAlignment.start,
  205. children: [
  206. SizedBox(
  207. width: 50,
  208. ),
  209. //内容展示
  210. _buildContent(),
  211. SizedBox(
  212. width: 50,
  213. ),
  214. ],
  215. ),
  216. ),
  217. Row(
  218. children: [
  219. SizedBox(
  220. width: 30,
  221. ),
  222. Text(
  223. '评估得分:${formValue["SelfCareScore"] ?? 0} 评估结论:${formValue["SelfCareConclusion"] ?? "可自理"}',
  224. style: TextStyle(fontSize: 32),
  225. ),
  226. ],
  227. ),
  228. ],
  229. ),
  230. );
  231. }
  232. ///加载主界面
  233. Widget _buildContent() {
  234. int itemCount = 0; //选项数量
  235. if (currentTemplate.isNotEmpty) {
  236. itemCount = currentTemplate[currentTitleIndex].children?.length ?? 0;
  237. }
  238. List<Widget> items = List.generate(itemCount, (index) {
  239. FormObject? currentFormObject =
  240. currentTemplate[currentTitleIndex].children?[index];
  241. int span = currentFormObject?.span ?? 12;
  242. currentFormObject!.options = currentFormObject.options!
  243. .where((element) => element.label != "-")
  244. .toList();
  245. return buildSingleItem(buildWidget(currentFormObject), span);
  246. });
  247. return Expanded(
  248. child: Scrollbar(
  249. child: SingleChildScrollView(
  250. child: Column(
  251. children: [
  252. Container(
  253. alignment: Alignment.topCenter,
  254. padding: const EdgeInsets.all(15),
  255. child: Column(
  256. children: [
  257. Wrap(
  258. runSpacing: 10,
  259. alignment: WrapAlignment.start,
  260. children: items,
  261. ),
  262. ],
  263. ),
  264. ),
  265. ],
  266. ),
  267. )));
  268. }
  269. Widget buildSingleItem(Widget item, int span) {
  270. return Column(
  271. children: [
  272. FractionallySizedBox(
  273. widthFactor: span == 24 ? 1 : 0.5,
  274. child: item,
  275. ),
  276. ],
  277. );
  278. }
  279. Widget buildWidget(FormObject? currentFormObject) {
  280. Map<String, Widget Function(FormObject)> widgetMap = {
  281. 'radio': _buildRadio,
  282. };
  283. Widget Function(FormObject) builder = widgetMap[currentFormObject?.type]!;
  284. return builder(currentFormObject!);
  285. }
  286. /// 单选框组件
  287. Widget _buildRadio(FormObject currentFormObject) {
  288. List<Option> options = currentFormObject.options ?? [];
  289. String currentSelected = formValue[currentFormObject.key!] ?? "";
  290. void selectRaidoChange(Option e) {
  291. currentSelected = e.value ?? '';
  292. setState(() {
  293. optionUpdate(currentFormObject, currentSelected);
  294. });
  295. }
  296. return Container(
  297. child: ExamSingleLineRadio(
  298. options: options,
  299. currentFormObject: currentFormObject,
  300. selectRaidoChange: selectRaidoChange,
  301. currentSelected: currentSelected,
  302. ),
  303. );
  304. }
  305. Future<void> optionUpdate(
  306. FormObject formObject, String currentSelected) async {
  307. formValue[formObject.key!] = currentSelected;
  308. caculationConclusion();
  309. // saveCachedRecord();
  310. }
  311. Future<void> caculationConclusion() async {
  312. int score = 0;
  313. var currentTemplateStoreList = currentTemplate[0].children!;
  314. for (var element in currentTemplateStoreList) {
  315. var elementStore = formValue[element.key!];
  316. if (elementStore != null) {
  317. score += int.parse(elementStore);
  318. }
  319. }
  320. formValue["SelfCareScore"] = score.toString();
  321. var result = "可自理";
  322. if (score <= 3) {
  323. result = "可自理";
  324. } else if (score <= 8) {
  325. result = "轻度依赖";
  326. } else if (score <= 18) {
  327. result = "中度依赖";
  328. } else {
  329. result = "不能自理";
  330. }
  331. formValue["SelfCareConclusion"] = result;
  332. saveCachedRecord();
  333. }
  334. bool _validateFormValue(Map<String, dynamic> formValue) {
  335. if (formValue.isEmpty) {
  336. return false;
  337. } else {
  338. return true;
  339. }
  340. }
  341. }