measure_images_bar.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. import 'dart:convert';
  2. import 'package:fis_common/logger/logger.dart';
  3. import 'package:fis_jsonrpc/rpc.dart';
  4. import 'package:fis_measure/interfaces/process/workspace/exam_info.dart';
  5. import 'package:fis_measure/process/language/measure_language.dart';
  6. import 'package:fis_measure/process/workspace/measure_controller.dart';
  7. import 'package:fis_measure/process/workspace/measure_data_controller.dart';
  8. import 'package:fis_measure/process/workspace/measure_handler.dart';
  9. import 'package:fis_measure/view/measure/measure_images_bar.dart';
  10. export 'package:fis_lib_business_components/index.dart';
  11. import 'package:fis_ui/index.dart';
  12. import 'package:flutter/material.dart';
  13. import 'package:get/get.dart';
  14. class MeasureImagesBar extends StatefulWidget implements FWidget {
  15. const MeasureImagesBar({Key? key}) : super(key: key);
  16. @override
  17. State<MeasureImagesBar> createState() => _MeasureImagesBarState();
  18. }
  19. class _MeasureImagesBarState extends State<MeasureImagesBar> {
  20. /// 图片滑动控制器
  21. ScrollController scrollController = ScrollController();
  22. /// 数据
  23. final measureData = Get.find<MeasureDataController>();
  24. /// 全部图片list
  25. final measureController = Get.find<MeasureController>();
  26. /// 当前可滑动的范围宽度
  27. late double width = 0;
  28. ///Listview item的宽度
  29. late double itemWidth = 160;
  30. /// 是否滑到最后
  31. bool _isEnd = false;
  32. /// 计算下标
  33. int _currentPage = 0;
  34. /// 左边能否滑动
  35. bool get isLeftCanScroll => _currentPage <= 0;
  36. /// 右边能否滑动
  37. bool get isRightCanScroll => _isEnd;
  38. /// 滑动区域的key值
  39. final GlobalKey globalKey = GlobalKey();
  40. ///当前分辨率下ListView里面的item个数
  41. int _itemsPerPage = 0;
  42. /// 图片左划事件
  43. void onLeftMoveImage() async {
  44. _currentPage--;
  45. await scrollController.animateTo(
  46. (160 * _currentPage * _itemsPerPage).toDouble(),
  47. duration: const Duration(milliseconds: 300),
  48. curve: Curves.linear,
  49. );
  50. }
  51. /// 图片右划事件
  52. void onRightMoveImage() async {
  53. if (!isRightCanScroll) {
  54. _currentPage++;
  55. await scrollController.animateTo(
  56. (160 * _currentPage * _itemsPerPage).toDouble(),
  57. duration: const Duration(milliseconds: 300),
  58. curve: Curves.linear,
  59. );
  60. }
  61. }
  62. @override
  63. Widget build(BuildContext context) {
  64. return FContainer(
  65. height: 120,
  66. margin: const EdgeInsets.symmetric(
  67. vertical: 15,
  68. ),
  69. child: FRow(
  70. children: [
  71. _buildImageListIcon(
  72. FIcons.fis_left_arrow,
  73. isLeftCanScroll,
  74. onLeftMoveImage,
  75. ),
  76. FExpanded(
  77. child: ScrollableImageList(
  78. scrollController: scrollController,
  79. globalKey: globalKey,
  80. remedicalList: measureData.remedicalList,
  81. ),
  82. ),
  83. _buildImageListIcon(
  84. FIcons.fis_right_arrow,
  85. isRightCanScroll,
  86. onRightMoveImage,
  87. ),
  88. ],
  89. ),
  90. );
  91. }
  92. @override
  93. void initState() {
  94. scrollController.addListener(
  95. () async {
  96. // 如果滑动到最右边
  97. if (scrollController.position.pixels ==
  98. scrollController.position.maxScrollExtent) {
  99. setState(() {
  100. _isEnd = true;
  101. });
  102. } else {
  103. setState(
  104. () {
  105. _isEnd = false;
  106. },
  107. );
  108. }
  109. },
  110. );
  111. super.initState();
  112. }
  113. @override
  114. void didChangeDependencies() {
  115. super.didChangeDependencies();
  116. WidgetsBinding.instance.addPostFrameCallback(
  117. (mag) {
  118. width = globalKey.currentContext!.size!.width;
  119. setState(
  120. () {
  121. _isEnd = width >= measureData.remedicalList.length * itemWidth;
  122. _itemsPerPage = (width / itemWidth).toInt();
  123. var currentIndex = measureController.examInfo.selectedImageIndex;
  124. if (currentIndex * itemWidth >
  125. scrollController.position.maxScrollExtent) {
  126. currentIndex =
  127. scrollController.position.maxScrollExtent ~/ itemWidth;
  128. }
  129. scrollController.animateTo(
  130. (itemWidth * currentIndex).toDouble(),
  131. duration: const Duration(milliseconds: 300),
  132. curve: Curves.linear,
  133. );
  134. },
  135. );
  136. },
  137. );
  138. }
  139. @override
  140. void dispose() {
  141. super.dispose();
  142. }
  143. FWidget _buildImageListIcon(
  144. IconData iconsData, bool isCanClick, Function onIconTap) {
  145. return FInkWell(
  146. onTap: () => onIconTap.call(),
  147. child: FContainer(
  148. width: 100,
  149. child: FIcon(
  150. iconsData,
  151. color: isCanClick ? Colors.grey : Colors.white,
  152. size: 30,
  153. ),
  154. ),
  155. );
  156. }
  157. }
  158. /// 可滑动的图片组,显示当前测量组的所有图片
  159. class ScrollableImageList extends StatefulWidget implements FWidget {
  160. const ScrollableImageList({
  161. required this.scrollController,
  162. required this.globalKey,
  163. required this.remedicalList,
  164. Key? key,
  165. this.description = '',
  166. }) : super(key: key);
  167. /// 图片滑动控制器
  168. final ScrollController scrollController;
  169. final GlobalKey globalKey;
  170. final List<RemedicalInfoDTO> remedicalList;
  171. final String? description;
  172. @override
  173. State<ScrollableImageList> createState() => _ScrollableImageListState();
  174. }
  175. class _ScrollableImageListState extends State<ScrollableImageList> {
  176. /// 当前测量的图片
  177. // final measureCurrentImage = Get.put(MeasureGetCurrentImage());
  178. /// 测量AI数据
  179. final measureData = Get.find<MeasureDataController>();
  180. MeasureController measureController = Get.find<MeasureController>();
  181. late final measureHandler = Get.put(MeasureHandler());
  182. /// 测量语言包
  183. final measureLanguage = MeasureLanguage();
  184. /// 图像数据列表
  185. List<RemedicalInfoDTO> remedicalList = [];
  186. /// 当前选中的图像下标
  187. int selectedImageIndex = -1;
  188. /// 获取图片地址
  189. void onChangeImage(
  190. String imageUrl,
  191. String remedicalCode,
  192. ) async {
  193. if (measureData.itemCurrentImage == imageUrl) {
  194. return;
  195. }
  196. measureHandler.changeImageLoaded = true;
  197. measureHandler.imageChanged = ChangeImageInfo(
  198. imageUrl,
  199. remedicalCode,
  200. );
  201. ExamImageInfo selectedImage = measureController.examInfo.images.firstWhere(
  202. (element) => element.url == imageUrl,
  203. );
  204. selectedImageIndex =
  205. measureController.examInfo.images.indexOf(selectedImage);
  206. measureData.itemCurrentImage = imageUrl;
  207. measureController.examInfo.selectedImageIndex = selectedImageIndex;
  208. setState(() {});
  209. }
  210. /// 获取图像Code来更新图像
  211. void onChangeImageByRemedicalCode(_, e) {
  212. onChangeImage(findImageUrlByRemedicalCode(e), e);
  213. }
  214. /// 更新图像集合
  215. void onChangeImageList(_, e) {
  216. measureController = Get.find<MeasureController>();
  217. setState(() {
  218. remedicalList = e;
  219. });
  220. }
  221. String findImageUrlByRemedicalCode(String remedicalCode) {
  222. String imageUrl = '';
  223. for (var i = 0; i < measureController.examInfo.images.length; i++) {
  224. if (remedicalList[i].remedicalCode! == remedicalCode) {
  225. imageUrl = remedicalList[i].terminalImages!.imageUrl!;
  226. break;
  227. }
  228. }
  229. return imageUrl;
  230. }
  231. @override
  232. void initState() {
  233. remedicalList = widget.remedicalList;
  234. measureHandler.changeImageByRemedicalCode
  235. .addListener(onChangeImageByRemedicalCode);
  236. measureHandler.changeImageList.addListener(onChangeImageList);
  237. super.initState();
  238. }
  239. @override
  240. void dispose() {
  241. measureHandler.changeImageByRemedicalCode
  242. .removeListener(onChangeImageByRemedicalCode);
  243. measureHandler.changeImageList.removeListener(onChangeImageList);
  244. super.dispose();
  245. }
  246. @override
  247. FWidget build(BuildContext context) {
  248. return FContainer(
  249. key: ValueKey(measureData.itemCurrentImage),
  250. alignment: Alignment.topCenter,
  251. child: _buildImageList(remedicalList),
  252. );
  253. }
  254. ///翻译图片描述
  255. String _translateDescription(RemedicalInfoDTO remedicalInfo) {
  256. String description = '';
  257. try {
  258. if (remedicalInfo.application != null) {
  259. //判断是否是老数据,老数据里面没有applicationCategory的字段
  260. if (remedicalInfo.applicationCategory != null) {
  261. //如果不是老数据
  262. description = _getDescription(
  263. remedicalInfo.application ?? '',
  264. remedicalInfo.applicationCategory ?? '',
  265. );
  266. } else {
  267. //如果是老数据
  268. description = "Old data";
  269. }
  270. }
  271. } on Exception catch (e) {
  272. logger.e("Picture translation exception" + e.toString());
  273. } catch (e) {
  274. logger.e("Picture translation exception" + e.toString());
  275. }
  276. return description;
  277. }
  278. /// 设置翻译值
  279. String _setLanguageValue(String code) {
  280. return measureLanguage.t('application', code);
  281. }
  282. String _getDescription(String application, String applicationCategory) {
  283. String description = '';
  284. if ([application, applicationCategory].contains('FromSonopost')) {
  285. description = _setLanguageValue('FromSonopost');
  286. } else {
  287. if (application.isNotEmpty || applicationCategory.isNotEmpty) {
  288. description = _setLanguageValue(applicationCategory) +
  289. "-" +
  290. _setLanguageValue(application);
  291. } else {
  292. description = '';
  293. }
  294. }
  295. return description;
  296. }
  297. FWidget _buildImageList(List<RemedicalInfoDTO> remedicalItemList) {
  298. return FContainer(
  299. key: widget.globalKey,
  300. child: FListView.builder(
  301. scrollDirection: Axis.horizontal,
  302. shrinkWrap: true,
  303. controller: widget.scrollController,
  304. itemCount: remedicalItemList.toList().length,
  305. itemBuilder: (BuildContext context, int index) {
  306. final FWidget image = FContentImage(
  307. remedicalInfo: remedicalItemList[index],
  308. isMeasure: true,
  309. onTap: () => onChangeImage(
  310. remedicalItemList[index].terminalImages!.imageUrl!,
  311. remedicalItemList[index].remedicalCode!,
  312. ),
  313. serialNo: index + 1,
  314. description: _translateDescription(remedicalItemList[index]),
  315. );
  316. return FContainer(
  317. key: ValueKey(measureData.itemCurrentImage),
  318. width: 160,
  319. alignment: Alignment.center,
  320. decoration: BoxDecoration(
  321. border: Border.all(
  322. width: 3,
  323. color: remedicalItemList[index].terminalImages!.imageUrl! !=
  324. measureData.itemCurrentImage
  325. ? Colors.grey
  326. : Colors.blue,
  327. ),
  328. ),
  329. child: image,
  330. );
  331. },
  332. ),
  333. );
  334. }
  335. }