123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- import 'package:fis_i18n/i18n.dart';
- import 'package:fis_jsonrpc/rpc.dart';
- import 'package:fis_measure/interfaces/enums/annotation.dart';
- import 'package:fis_measure/interfaces/process/player/play_controller.dart';
- import 'package:fis_measure/interfaces/process/workspace/application.dart';
- import 'package:fis_measure/interfaces/process/workspace/exam_info.dart';
- import 'package:fis_measure/interfaces/process/workspace/measure_3d_view_controller.dart';
- import 'package:fis_measure/process/language/measure_language.dart';
- import 'package:fis_measure/process/layout/configuration.dart';
- import 'package:fis_measure/process/workspace/measure_controller.dart';
- import 'package:fis_measure/process/workspace/measure_data_controller.dart';
- import 'package:fis_measure/process/workspace/measure_handler.dart';
- import 'package:fis_measure/process/workspace/measure_3d_view_controller.dart';
- import 'package:fis_measure/view/gesture/positioned_cursor.dart';
- import 'package:fis_measure/view/measure/arrow_annotation_button.dart';
- import 'package:fis_measure/view/measure/drag_delete_area.dart';
- import 'package:fis_measure/view/measure/measure_config/widgets/measure_configuration_style.dart';
- import 'package:fis_measure/view/measure/measure_images_bar.dart';
- import 'package:fis_measure/view/measure/measure_left_annotation.dart';
- import 'package:fis_measure/view/measure/measure_player.dart';
- import 'package:fis_measure/view/measure/measure_search_input.dart';
- import 'package:fis_measure/view/measure/measure_tool.dart';
- import 'package:fis_measure/view/measure/carotid_measure_tool.dart';
- import 'package:fis_measure/view/measure/measure_tools_title.dart';
- import 'package:fis_measure/view/measure/measure_view_controller.dart';
- import 'package:fis_measure/view/measure/tool_chest_title.dart';
- import 'package:fis_measure/view/player/control_board/operate_bar.dart';
- import 'package:fis_ui/index.dart';
- import 'package:fis_ui/interface/interactive_container.dart';
- import 'package:fis_ui/widgets/layout/offstage.dart';
- import 'package:flutter/material.dart';
- import 'package:get/get.dart';
- /// 测量主页面
- class MeasureMainPage extends StatefulWidget implements FWidget {
- const MeasureMainPage(
- this.token, this.recordCode, this.patientCode, this.remedicalCode,
- {this.needRouterBack, Key? key})
- : super(key: key);
- final String token;
- final String patientCode;
- final String remedicalCode;
- final String recordCode;
- final bool? needRouterBack; // 需要返回按钮【一版用于返回到报告编辑】
- @override
- State<StatefulWidget> createState() => _MeasureMainPageState();
- }
- class _MeasureMainPageState extends State<MeasureMainPage> {
- /// 病人及图像信息
- String _curToken = '';
- String _curPatientCode = '';
- String _curRemedicalCode = '';
- String _curRecordCode = '';
- bool? _curNeedRouterBack;
- /// 数据
- final measureData = Get.find<MeasureDataController>();
- /// webview 控制器
- final measure3DViewController = Get.find<Measure3DViewController>();
- /// 测量项控制器
- final measureMetaController = Get.put(MeasureMetaController());
- /// 隐藏全屏loadding
- bool _hideFullScreenLoading = false;
- /// 图片loadding
- late bool imageLoaded = false;
- late final measureHandler = Get.find<MeasureHandler>();
- /// 测量控制器
- late MeasureController measureController;
- /// 响应图片切换事件通知
- void _onChangeImage(sender, e) {
- imageLoaded = e;
- setState(() {});
- }
- /// 响应全屏状态切换事件
- void _onChangeFullScreenState(sender, e) {
- setState(() {});
- }
- /// 在此处动态刷新测量窗口,而不是重置窗口
- void _onUpdateState(sender, Map<String, String> parameters) async {
- _curNeedRouterBack = false;
- bool needUpdate = false;
- if (_curPatientCode == (parameters['patientCode'] ?? '')) {
- if (_curRemedicalCode == (parameters['remedicalCode'] ?? '')) {
- } else {
- measureHandler.changeImageByRemedicalCode
- .emit(this, parameters['remedicalCode'] ?? '');
- }
- } else {
- needUpdate = true;
- }
- _curToken = parameters['token'] ?? '';
- _curPatientCode = parameters['patientCode'] ?? '';
- _curRemedicalCode = parameters['remedicalCode'] ?? '';
- _curRecordCode = parameters['recordCode'] ?? '';
- if (needUpdate) {
- await LayoutConfiguration.ins.loadData();
- List<RemedicalInfoDTO> remedicals = await _getCurRemedicals();
- _initMouseModuel();
- _initCarotidModuel(remedicals);
- measureData.remedicalList = remedicals;
- var remedicalInfo =
- await measureData.getImageInfo.call(_curRemedicalCode, _curToken);
- if (remedicalInfo != null) {
- measureData.aiResults = remedicalInfo.diagnosisResult ?? '';
- if (remedicalInfo.terminalImages != null) {
- _hideFullScreenLoading = true;
- measureData.itemCurrentImage =
- remedicalInfo.terminalImages!.imageUrl ?? '';
- getExamImageInfoList(remedicals);
- measureHandler.changeImageList.emit(this, remedicals);
- }
- }
- measureController.imageLoaded.removeListener(_onImageLoaded);
- measureController.imageLoaded.addListener(_onImageLoaded);
- }
- _setCurImageData();
- }
- /// 将当前的图像信息同步到 measureData 中
- void _setCurImageData() {
- measureData.measureImageData = MeasureImageData(
- patientCode: _curPatientCode,
- recordCode: _curRecordCode,
- remedicalCode: _curRemedicalCode,
- );
- }
- /// 先加载图像布局配置,然后加载全局数据
- void _loadLayoutConfig() async {
- await LayoutConfiguration.ins.loadData();
- setState(() {
- _initData();
- });
- }
- @override
- void initState() {
- _curToken = widget.token;
- _curPatientCode = widget.patientCode;
- _curRemedicalCode = widget.remedicalCode;
- _curRecordCode = widget.recordCode;
- _curNeedRouterBack = widget.needRouterBack;
- _hideFullScreenLoading = false;
- _loadLayoutConfig();
- _setCurImageData();
- measureData.curMeasureDataChanged.addListener(_onUpdateState);
- measureHandler.onChangeImageLoaded.addListener(_onChangeImage);
- measureHandler.onChangeFullScreenState
- .addListener(_onChangeFullScreenState);
- super.initState();
- }
- @override
- void dispose() {
- measureData.curMeasureDataChanged.removeListener(_onUpdateState);
- measureHandler.onChangeImageLoaded.removeListener(_onChangeImage);
- measureHandler.onChangeFullScreenState
- .removeListener(_onChangeFullScreenState);
- super.dispose();
- }
- @override
- FWidget build(BuildContext context) {
- FWidget body;
- if (!_hideFullScreenLoading) {
- const loadingWidget = FCenter(child: FCircularProgressIndicator());
- body = FRow(
- children: const [
- FExpanded(
- child: loadingWidget,
- ),
- ],
- );
- } else {
- body = FRow(
- children: [
- FOffstage(
- child: _MeasureLeftBoard(
- needRouterBack: _curNeedRouterBack,
- ),
- offstage: measureHandler.fullScreenState),
- const FVerticalDivider(),
- FExpanded(
- child: FColumn(
- mainAxisSize: MainAxisSize.max,
- children: [
- FExpanded(
- child: FStack(
- children: [
- if (!imageLoaded)
- MeasureRightBoard(
- key: ValueKey(measureData.itemCurrentImage),
- ),
- if (imageLoaded)
- FContainer(
- color: Colors.black,
- child: const FCenter(
- child: FCircularProgressIndicator(),
- ),
- ),
- ],
- )),
- FOffstage(
- child: const MeasureImagesBar(),
- offstage: measureHandler.fullScreenState),
- // if (!measureHandler.fullScreenState) const MeasureImagesBar(),
- ],
- ),
- ),
- ],
- );
- }
- return FCenter(
- child: FContainer(
- color: _hideFullScreenLoading
- ? const Color.fromRGBO(70, 70, 70, 1)
- : Colors.black,
- child: body,
- ),
- );
- }
- /// 获取当前状态下的图像集
- Future<List<RemedicalInfoDTO>> _getCurRemedicals() async {
- List<RemedicalInfoDTO> remedicals = [];
- var value = await measureData.getRemedicalList.call(
- _curPatientCode,
- _curRecordCode,
- _curToken,
- );
- for (var remedicalItemList in value) {
- remedicals.addAll(remedicalItemList.remedicalList ?? []);
- }
- return remedicals;
- }
- /// 初始化颈动脉模块
- /// [Carotid] ✅遍历出颈动脉信息列表,传给壳子
- void _initCarotidModuel(List<RemedicalInfoDTO> remedicals) {
- List<Ultra3DResourceInfo> ultra3DResourceInfos = [];
- for (var remedical in remedicals) {
- if (remedical.carotidResult != null) {
- ultra3DResourceInfos.add(Ultra3DResourceInfo(remedical.carotidResult!));
- }
- }
- measure3DViewController.ultra3DResourceInfoList = ultra3DResourceInfos;
- measure3DViewController.recordId = _curRecordCode;
- measure3DViewController.notifyShellLoadAllModel();
- }
- /// 初始化卡尺样式部分
- Future<void> _initMouseModuel() async {
- final mouseState = Get.put<IMouseState>(MouseState());
- final result = await measureData.getMeasureSystemSettingAsync()
- as MeasureSystemSettingDTO;
- measureData.measureSystemSetting = result;
- mouseState.cursorType =
- getMeasureSystemSettingCursorType(result.cursorType);
- mouseState.cursorSize = result.cursorSize.toDouble();
- }
- /// 测量页全局数据首次初始化
- void _initData() async {
- List<RemedicalInfoDTO> remedicals = await _getCurRemedicals();
- _initMouseModuel();
- _initCarotidModuel(remedicals);
- measureData.remedicalList = remedicals;
- var remedicalInfo =
- await measureData.getImageInfo.call(_curRemedicalCode, _curToken);
- if (remedicalInfo != null) {
- measureData.aiResults = remedicalInfo.diagnosisResult ?? '';
- if (remedicalInfo.terminalImages != null) {
- _hideFullScreenLoading = true;
- measureData.itemCurrentImage =
- remedicalInfo.terminalImages!.imageUrl ?? '';
- getExamImageInfoList(remedicals);
- }
- }
- measureController.imageLoaded.removeListener(_onImageLoaded);
- measureController.imageLoaded.addListener(_onImageLoaded);
- }
- /// 获取测量图片所需的图片组 并且写入控制器中 加载
- void getExamImageInfoList(List<RemedicalInfoDTO> remedicals) async {
- /// 检查中图片信息表
- List<ExamImageInfo> examImageInfoList = [];
- for (var element in remedicals) {
- examImageInfoList.add(
- ExamImageInfo(
- element.terminalImages!.imageUrl!,
- element.terminalImages!.previewUrl!,
- ),
- );
- }
- Get.delete<MeasureController>();
- measureController = Get.put(MeasureController(
- "",
- imagesFetchFunc: (code) async {
- return examImageInfoList;
- },
- ));
- await measureController.load();
- int selectedImageIndex = -1;
- if (examImageInfoList
- .any((element) => element.url == measureData.itemCurrentImage)) {
- ExamImageInfo selectedImage = examImageInfoList.firstWhere(
- (element) => element.url == measureData.itemCurrentImage,
- );
- selectedImageIndex = examImageInfoList.indexOf(selectedImage);
- measureController.examInfo.selectedImageIndex = selectedImageIndex;
- }
- MeasureLanguage.load(measureData.measureLanguage);
- }
- /// vid 切换时会触发到这里
- void _onImageLoaded(Object sender, ExamImageInfo? e) async {
- // measureHandler.changeImageLoaded = true;
- if (!mounted) return;
- final currentImage = measureData.remedicalList.firstWhereOrNull(
- (element) => element.terminalImages!.imageUrl == e!.url,
- );
- if (currentImage != null) {
- /// 获取图片详细信息
- var remedicalInfo = await measureData.getImageInfo(
- currentImage.remedicalCode ?? '',
- _curToken,
- );
- if (remedicalInfo != null) {
- measureData.aiResults = remedicalInfo.diagnosisResult ?? '';
- measure3DViewController.initParams();
- /// ai 良恶性 判断是否有ai
- measureData.diagnosisConclusion = remedicalInfo.diagnosisConclusion;
- if (remedicalInfo.carotidResult != null) {
- /// [Carotid] ✅详情传入测量信息
- measure3DViewController.carotidResult = remedicalInfo.carotidResult!;
- /// [Carotid] ✅需要在此通知 controller 存在颈动脉信息
- measure3DViewController.exist3DData = true;
- measure3DViewController
- .handleChangeCarotid2DImage(remedicalInfo.recordCode!);
- } else {
- measure3DViewController.exist3DData = false;
- }
- // [Carotid] ✅只要更换图片都要切换到Vid 2D模式
- if (measure3DViewController.curMeasureMode != MeasureMode.vidMode) {
- measure3DViewController.backToVidMode();
- }
- try {
- if (e != null) {
- Future.delayed(const Duration(milliseconds: 100), () {
- measureController.playerController.play();
- });
- setState(() {
- _hideFullScreenLoading = true;
- measureHandler.changeImageLoaded = false;
- });
- }
- } catch (error) {
- setState(() {
- _hideFullScreenLoading = true;
- measureHandler.changeImageLoaded = false;
- });
- }
- }
- }
- }
- }
- /// 测量左边操作页面
- class _MeasureLeftBoard extends StatefulWidget
- implements FInteractiveContainer {
- const _MeasureLeftBoard({Key? key, this.needRouterBack}) : super(key: key);
- @override
- final String pageName = 'MeasureLeftBoard';
- final bool? needRouterBack;
- @override
- State<_MeasureLeftBoard> createState() => _MeasureLeftBoardState();
- }
- class _MeasureLeftBoardState extends State<_MeasureLeftBoard> {
- final measureHandler = Get.find<MeasureHandler>();
- final playerController = Get.find<IPlayerController>();
- final measure3DViewController = Get.find<Measure3DViewController>();
- /// 数据
- late final measureData = Get.find<MeasureDataController>();
- /// 测量项控制器
- final measureMetaController = Get.find<MeasureMetaController>();
- /// 是否显示颈动脉2D指定的测量项
- bool showCarotid2DSelectMeasure = false;
- /// 是否为魔盒的Vid
- bool isThirdPart = Get.find<IApplication>().isThirdPart;
- /// 是否显示测量项
- bool hideMeasureItems = false;
- /// 是否正在拖拽
- bool isDragging = false;
- bool isMeasureTool = true;
- bool get isArrowMeasureAnnotationType =>
- measureHandler.changedAnnotationType == AnnotationType.arrow;
- TabEnum curSelectedTab = TabEnum.tabMeasureTool;
- void _onChangedTab(
- Object sender,
- TabEnum e,
- ) {
- setState(() {
- curSelectedTab = e;
- });
- }
- void _onCurItemMetaListChanged(sender, e) {
- if (mounted) {
- setState(() {});
- }
- }
- ///图像发生变化
- void _onChangeImage(sender, e) {
- final application = Get.find<IApplication>();
- setState(() {
- isThirdPart = application.isThirdPart;
- });
- }
- /// 拖拽状态发生改变
- _onDragStateChanged(Object sender, bool e) {
- setState(() {
- isDragging = e;
- });
- }
- @override
- void initState() {
- measureHandler.onChangedTab.addListener(_onChangedTab);
- measure3DViewController.updatePlayerMode.addListener(_onModeChanged);
- measureData.curItemMetaListChanged.addListener(_onCurItemMetaListChanged);
- measureHandler.onChangeImageLoaded.addListener(_onChangeImage);
- measureHandler.onDragStateChanged.addListener(_onDragStateChanged);
- super.initState();
- }
- @override
- void dispose() {
- measureHandler.onChangedTab.removeListener(_onChangedTab);
- measure3DViewController.updatePlayerMode.removeListener(_onModeChanged);
- measureData.curItemMetaListChanged
- .removeListener(_onCurItemMetaListChanged);
- measureHandler.onChangeImageLoaded.removeListener(_onChangeImage);
- measureHandler.onDragStateChanged.removeListener(_onDragStateChanged);
- super.dispose();
- }
- /// 模式改变触发更新
- void _onModeChanged(Object s, MeasureMode mode) {
- switch (mode) {
- case MeasureMode.vidMode:
- final playerController = Get.find<IPlayerController>();
- // 通过帧加载完成事件通知,去更新测量项
- if (playerController.currentFrame != null) {
- playerController.firstFrameLoaded
- .emit(this, playerController.currentFrame!);
- }
- setState(() {
- showCarotid2DSelectMeasure = false;
- hideMeasureItems = false;
- });
- break;
- case MeasureMode.carotid2DMode:
- setState(() {
- showCarotid2DSelectMeasure = true;
- hideMeasureItems = false;
- });
- break;
- case MeasureMode.carotid3DMode:
- setState(() {
- showCarotid2DSelectMeasure = true;
- hideMeasureItems = true;
- });
- break;
- }
- }
- bool get hideMeasureTab => (curSelectedTab == TabEnum.tabNodesTool);
- bool get hideCommentTab => !hideMeasureTab;
- @override
- FWidget build(BuildContext context) {
- final newPlayerController = Get.find<IPlayerController>();
- return FColumn(
- mainAxisSize: MainAxisSize.max,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- FOffstage(
- offstage: hideMeasureItems,
- child: LeftSiderHold(
- ifHideConfig: showCarotid2DSelectMeasure || isThirdPart),
- ),
- FOffstage(
- offstage: hideMeasureItems || hideCommentTab,
- child: FContainer(
- width: 300,
- key: UniqueKey(),
- child: const LeftSelectInput(),
- ),
- ),
- FOffstage(
- offstage: hideMeasureItems || hideMeasureTab,
- child: const LeftMeasureTools(),
- ),
- FExpanded(
- child: FStack(
- fit: StackFit.passthrough,
- children: [
- FOffstage(
- offstage: hideMeasureItems || hideMeasureTab,
- child: FContainer(
- width: 300,
- child: showCarotid2DSelectMeasure
- ? const CarotidLeftSiderSelectMeasure()
- : FContainer(
- key: Key(newPlayerController.url),
- child: const LeftSiderSelectMeasure()),
- ),
- ),
- FOffstage(
- offstage: hideMeasureItems || hideCommentTab,
- child: FContainer(
- width: 300,
- key: UniqueKey(),
- child: const MeasureLeftAnnotation(),
- ),
- ),
- ],
- ),
- ),
- FOffstage(
- offstage: hideMeasureItems || hideCommentTab || !isDragging,
- child: const DragDeleteArea(),
- ),
- FOffstage(
- offstage: hideMeasureItems || hideCommentTab || isDragging,
- child: const ArrowAnnotationButton()),
- FOffstage(
- offstage: !hideMeasureItems,
- child: FContainer(
- width: 300,
- child: FCenter(
- child: FElevatedButton(
- name: "backToVidMode",
- businessParent: widget,
- onPressed: () => measure3DViewController.backToVidMode(),
- child: FText(
- i18nBook.measure.vidMode.t,
- style: const TextStyle(color: Colors.white),
- ),
- ),
- ),
- ),
- ),
- const OperateBar(),
- widget.needRouterBack ?? false
- ? FContainer(
- width: 300,
- padding: const EdgeInsets.only(bottom: 20),
- child: FIconButton(
- businessParent: widget,
- name: "back",
- onPressed: () {
- Get.back();
- },
- icon: const FIcon(
- Icons.arrow_back,
- color: Colors.white,
- size: 36,
- ),
- ),
- )
- : const FSizedBox()
- ],
- );
- }
- }
|