excel_datas_view.dart 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import 'package:fis_common/index.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:get/get.dart';
  4. import 'package:vitalapp/architecture/utils/prompt_box.dart';
  5. import 'package:vitalapp/components/appbar.dart';
  6. import 'package:vitalapp/components/search_input.dart';
  7. import 'package:vitalapp/components/table/table.dart';
  8. import 'package:vitalapp/components/table/table_column.dart';
  9. import 'package:vitalapp/managers/interfaces/excelData.dart';
  10. import 'package:vitalapp/managers/interfaces/models/excel_data.dart';
  11. import 'package:vitalapp/pages/widgets/overflow_tooltip_wrapper.dart';
  12. import 'package:vitalapp/pages/widgets/text_tooltip.dart';
  13. class ExcelDatasView extends StatefulWidget {
  14. final List<ExcelDataRecord> records;
  15. final String templateKey;
  16. ExcelDatasView(this.records, this.templateKey);
  17. @override
  18. State<StatefulWidget> createState() {
  19. return ExcelDatasViewState();
  20. }
  21. }
  22. class ExcelDatasViewState extends State<ExcelDatasView> {
  23. final _searchController = TextEditingController();
  24. List<ExcelDataRecord> _pendingUploadDatas = [];
  25. List<ExcelDataRecord> _errorDatas = [];
  26. List<int> _selecteds = [];
  27. bool _isShowErrorData = false;
  28. bool _isSelectedAll = true;
  29. @override
  30. void initState() {
  31. //sampleBarcode对应的就是体检系统的条码
  32. _pendingUploadDatas = widget.records
  33. .where((element) =>
  34. element.excelDatas
  35. .firstWhereOrNull((element) => element.key == "sampleBarcode")
  36. ?.value
  37. .isNotNullOrEmpty ??
  38. false)
  39. .toList();
  40. _errorDatas = widget.records
  41. .where((element) =>
  42. element.excelDatas
  43. .firstWhereOrNull((element) => element.key == "sampleBarcode")
  44. ?.value
  45. .isNullOrEmpty ??
  46. false)
  47. .toList();
  48. _selectedAll();
  49. super.initState();
  50. }
  51. @override
  52. Widget build(BuildContext context) {
  53. return Scaffold(
  54. backgroundColor: Colors.white,
  55. appBar: VAppBar(
  56. titleWidget: Text(
  57. "数据上传",
  58. style: const TextStyle(fontSize: 24, color: Colors.white),
  59. ),
  60. actions: [
  61. if (!_isShowErrorData)
  62. TextButton.icon(
  63. onPressed: () async {
  64. List<ExcelDataRecord> pendingUploadDatas = [];
  65. for(int i in _selecteds){
  66. pendingUploadDatas.add(_pendingUploadDatas[i]);
  67. }
  68. var result = await Get.find<IExcelDataManager>()
  69. .uploadDatas(pendingUploadDatas, widget.templateKey);
  70. if (result) {
  71. PromptBox.toast('上传成功');
  72. Get.back();
  73. } else {
  74. PromptBox.toast('上传失败');
  75. }
  76. },
  77. label: Text(
  78. '提交',
  79. style: TextStyle(fontSize: 20, color: Colors.white),
  80. ),
  81. icon: Icon(Icons.save, size: 32, color: Colors.white),
  82. ),
  83. ],
  84. ),
  85. body: _buildBody(),
  86. );
  87. }
  88. Widget _buildBody() {
  89. return Column(
  90. children: [
  91. Container(
  92. height: 40,
  93. child: _buildHead(),
  94. margin: EdgeInsets.symmetric(vertical: 10),
  95. ),
  96. Expanded(
  97. child: VitalTable<ExcelDataRecord>(
  98. source: _isShowErrorData ? _errorDatas : _pendingUploadDatas,
  99. columns: _buildColumns(),
  100. headerTextStyle: const TextStyle(
  101. fontSize: 12,
  102. ),
  103. autoHeight: false,
  104. showSelect: !_isShowErrorData,
  105. onRowSelected: (value, index, selectedIndexs) {
  106. _selecteds.add(index);
  107. },
  108. selecteds: _selecteds,
  109. checkCellWidth: 40,
  110. cellPadding: EdgeInsets.symmetric(vertical: 2, horizontal: 1),
  111. ),
  112. ),
  113. ],
  114. );
  115. }
  116. Widget _buildHead() {
  117. return Row(
  118. children: [
  119. SizedBox(width: 10),
  120. _buildSearchInput(),
  121. SizedBox(width: 20),
  122. _buildTips(),
  123. SizedBox(width: 10),
  124. if (_errorDatas.isNotEmpty) _buildSwichButton(),
  125. if (_isShowErrorData) ...[
  126. SizedBox(width: 10),
  127. Icon(
  128. Icons.warning,
  129. color: Colors.orange,
  130. ),
  131. Text(
  132. "请检查样本号是否正确!",
  133. style: TextStyle(color: Colors.orange),
  134. ),
  135. ],
  136. ],
  137. );
  138. }
  139. void _selectedAll() {
  140. int index = 0;
  141. for (var data in _pendingUploadDatas) {
  142. _selecteds.add(index);
  143. index++;
  144. }
  145. }
  146. Widget _buildSearchInput() {
  147. return Container(
  148. width: 400,
  149. margin: EdgeInsets.only(left: 20),
  150. child: VSearchInput(
  151. textEditingController: _searchController,
  152. placeholder: "请输入姓名",
  153. onSearch: (v) {
  154. if (_isShowErrorData) {
  155. var errorDatas = widget.records
  156. .where((element) =>
  157. element.excelDatas
  158. .firstWhereOrNull(
  159. (element) => element.key == "sampleBarcode")
  160. ?.value
  161. .isNullOrEmpty ??
  162. false)
  163. .toList();
  164. _errorDatas = errorDatas
  165. .where((element) =>
  166. element.excelDatas
  167. .firstWhereOrNull(
  168. (element) => element.key == "patientName")
  169. ?.value
  170. .contains(v) ??
  171. false)
  172. .toList();
  173. } else {
  174. var pendingUploadDatas = widget.records
  175. .where((element) =>
  176. element.excelDatas
  177. .firstWhereOrNull(
  178. (element) => element.key == "sampleBarcode")
  179. ?.value
  180. .isNotNullOrEmpty ??
  181. false)
  182. .toList();
  183. _pendingUploadDatas = pendingUploadDatas
  184. .where((element) =>
  185. element.excelDatas
  186. .firstWhereOrNull(
  187. (element) => element.key == "patientName")
  188. ?.value
  189. .contains(v) ??
  190. false)
  191. .toList();
  192. if (_isSelectedAll) {
  193. _selecteds.clear();
  194. int index = 0;
  195. for (var data in _pendingUploadDatas) {
  196. _selecteds.add(index);
  197. index++;
  198. }
  199. }
  200. }
  201. setState(() {});
  202. },
  203. ),
  204. );
  205. }
  206. Widget _buildTips() {
  207. var tips =
  208. "共计 ${widget.records.length} 条数据,其中校验通过 ${_pendingUploadDatas.length} 条数据";
  209. if (_errorDatas.length > 0) {
  210. tips += ",校验不通过${_errorDatas.length}条数据";
  211. }
  212. return Text(tips);
  213. }
  214. Widget _buildSwichButton() {
  215. return OutlinedButton(
  216. onPressed: () {
  217. setState(() {
  218. _isShowErrorData = !_isShowErrorData;
  219. });
  220. },
  221. child: Text(
  222. _isShowErrorData ? "查看校验通过数据" : "查看校验不通过数据",
  223. ),
  224. );
  225. }
  226. List<TableColumn<ExcelDataRecord>> _buildColumns() {
  227. if (widget.records.isEmpty) {
  228. return [];
  229. }
  230. ExcelDataRecord firstRecord = widget.records.first;
  231. var items = firstRecord.excelDatas;
  232. var textStyle = TextStyle(
  233. fontSize: 12,
  234. overflow: TextOverflow.ellipsis,
  235. fontFamily: "NotoSansSC",
  236. );
  237. return [
  238. ...items.map(
  239. (e) => TableColumn<ExcelDataRecord>(
  240. headerText: e.des,
  241. flex: (e.key == "sampleBarcode" || e.key == "samplingTime") ? 6 : 5,
  242. render: (rowData, index) => Center(
  243. child: Text(
  244. rowData.excelDatas
  245. .firstWhere((element) => element.key == e.key)
  246. .value,
  247. style: textStyle,
  248. ),
  249. ),
  250. ),
  251. )
  252. ];
  253. }
  254. }