123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- import 'dart:typed_data';
- import 'package:fis_jsonrpc/rpc.dart';
- import 'package:fis_measure/interfaces/enums/annotation.dart';
- import 'package:fis_measure/interfaces/process/items/item.dart';
- import 'package:fis_measure/interfaces/process/items/item_metas.dart';
- import 'package:fis_measure/interfaces/process/items/terms.dart';
- import 'package:fis_measure/interfaces/process/items/types.dart';
- import 'package:fis_measure/interfaces/process/player/play_controller.dart';
- import 'package:fis_measure/interfaces/process/standard_line/calibration.dart';
- import 'package:fis_measure/interfaces/process/visuals/visual_area.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_controller.dart';
- import 'package:fis_measure/process/items/item_meta_convert.dart';
- import 'package:fis_measure/process/workspace/measure_3d_view_controller.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/rpc_bridge.dart';
- import 'package:fis_measure/view/measure/measure_main_view.dart';
- import 'package:flutter/material.dart';
- import 'package:get/get.dart';
- import 'item_create_test.dart';
- import 'process/workspace/measure_handler.dart';
- class MeasureDataTester {
- static Future<List<RemedicalItemList>> getRemedicalList(
- String patientCode,
- String recordCode,
- String token,
- ) async {
- return [];
- }
- static Future<RemedicalInfoDTO?> getImageInfo(
- String remedicalCode,
- String token,
- String? remedicalAISelectedInfoCode,
- ) async {
- return null;
- }
- static Future<MeasureApplicationDTO?> getMeasureApplication(
- dynamic args) async {
- return null;
- }
- static Future<bool> saveUserDefinedMeasureApplicationAsync(
- dynamic args) async {
- return true;
- }
- static Future<bool?> saveImage(
- Uint8List imageBytes,
- String patientCode,
- String recordCode,
- String remedicalCode,
- String measuredData,
- VidImageSource source,
- ) async {
- return null;
- }
- static Future<void> saveMeasureSystemSettingAsync(
- MeasureSystemSettingDTO measureSystemSetting) async {
- return;
- }
- static Future<MeasureSystemSettingDTO?> getMeasureSystemSettingAsync() async {
- return null;
- }
- static Future<String> shareImage(String vid) async {
- return '';
- }
- static Future<CommentItemResultDTO?> getCommentsByApplicationAsync(
- String applicationName, String categoryName) async {
- return null;
- }
- static Future<PresetCommentItemResultDTO?> getPresetCommentsAsync() async {
- return null;
- }
- ///参数1:remedicalCode,参数2:token,参数3:patientCode,参数4:图像位置
- static Future<RemedicalInfoDTO?> getImageInfoByIndex(
- String remedicalCode, String token, String patientCode, int index) async {
- return null;
- }
- static Future<bool?> resetUserCommentsAsync(
- String applicationName, String categoryName) async {
- return null;
- }
- static Future<bool?> saveUserDefinedCommentsAsync(
- String applicationName,
- String categoryName,
- List<CommentItemDTO>? add,
- List<CommentItemDTO>? delete,
- List<UpdateCommentItemDTO>? update) async {
- return null;
- }
- }
- class MeasureTestPage extends StatefulWidget {
- const MeasureTestPage({Key? key}) : super(key: key);
- // ignore: non_constant_identifier_names
- static List<dynamic> MetaDTOList = [];
- @override
- State<StatefulWidget> createState() => _MeasureTestPageState();
- }
- class _MeasureTestPageState extends State<MeasureTestPage> {
- static const C_LINEAR_TISSUE =
- // "http://cdn-bj.fis.plus/9F066341FA874E21B48CDE247C13D495.vid"; //B TVI TD
- // "http://cdn-bj.fis.plus/974BABA5113640639FD749E06DD7DA5B.vid"; //B CF CW
- "http://cdn-bj.fis.plus/0B344F48BA574ECD82B7FEDB8848421A.vid"; //单幅TM
- // "http://cdn-bj.fis.plus/3379F38302884C2991D90FBDFB0DEA7E.dat"; //单幅TM(2)
- // "http://cdn-bj.fis.plus/6A99AD2530864616B64355A8EA9AE3EC.vid";
- // "http://cdn-bj.fis.plus/F26C6E5D57A7472A97E9EB543DF0D16C.vid"; // 单幅Convex
- // "http://cdn-bj.fis.plus/6B6E069659D14E7299EB9F6EFCDE9C8C.vid"; //双幅单TissueConvex
- // "http://cdn-bj.fis.plus/062643B82365437DB95F3811580AF3ED.vid"; //四幅单模式
- // "http://cdn-bj.fis.plus/EA90D146049D416E8E466B7446E00001.vid"; //四幅Doppler
- // "http://cdn-bj.fis.plus/3rd_linearTvTissue2.vid"; //魔盒
- // "http://cdn-bj.fis.plus/81FFF8E5E078473FA687FBE81C4869B1.vid"; // 魔盒TV
- // "http://cdn-bj.fis.plus/7B450708A2784B1490304C82787349BE.vid";// 胎儿Zoom
- static const C_CONVEX_TISSUE =
- "http://cdn-bj.fis.plus/FEB1AAE5D9C24839BEE31B16E8CB450A.vid";
- final _3dc = Get.put<Measure3DViewController>(Measure3DViewController());
- final datac = Get.put<MeasureDataController>(MeasureDataController(
- // MeasureDataTester.getRemedicalList,
- // MeasureDataTester.getImageInfo,
- // MeasureDataTester.getMeasureApplication,
- // MeasureDataTester.saveUserDefinedMeasureApplicationAsync,
- MeasureDataTester.saveImage,
- // MeasureDataTester.saveMeasureSystemSettingAsync,
- // MeasureDataTester.getMeasureSystemSettingAsync,
- // MeasureDataTester.shareImage,
- // MeasureDataTester.getCommentsByApplicationAsync,
- // MeasureDataTester.saveUserDefinedCommentsAsync,
- // MeasureDataTester.resetUserCommentsAsync,
- // MeasureDataTester.getPresetCommentsAsync,
- // MeasureDataTester.getImageInfoByIndex,
- ));
- final measureHandler = Get.put(MeasureHandler());
- final controller = Get.put<IMeasureController>(MeasureController(
- "12345",
- imagesFetchFunc: (code) async {
- return <ExamImageInfo>[
- ExamImageInfo(C_LINEAR_TISSUE, C_LINEAR_TISSUE),
- ExamImageInfo(C_CONVEX_TISSUE, C_CONVEX_TISSUE)
- ];
- },
- ));
- bool loaded = false;
- int opType = 0;
- bool useArrowAnnotation = false;
- @override
- void initState() {
- measureHandler.newImageLoading;
- controller.load().then((value) {
- // 加载指定图像
- controller.examInfo.selectedImageIndex = 0;
- });
- controller.imageLoaded.addListener(onImageLoaded);
- super.initState();
- }
- @override
- void dispose() {
- controller.imageLoaded.removeListener(onImageLoaded);
- controller.dispose();
- Get.delete<IMeasureController>();
- super.dispose();
- }
- void onImageLoaded(Object sender, ExamImageInfo? e) {
- if (!mounted) return;
- if (e != null) {
- Future.delayed(const Duration(milliseconds: 100), () {
- controller.playerController.play();
- });
- setState(() {
- loaded = true;
- });
- }
- }
- @override
- Widget build(BuildContext context) {
- Widget body;
- if (!loaded) {
- const loadingWidget = Center(child: CircularProgressIndicator());
- body = Row(
- children: const [
- SizedBox(
- width: 300,
- child: loadingWidget,
- ),
- VerticalDivider(),
- Expanded(child: loadingWidget),
- ],
- );
- } else {
- body = Row(
- key: ValueKey(controller.examInfo.selectedImageIndex),
- children: [
- opType == 1
- ? const _MeasureLeftAnnotation()
- : const _MeasureLeftBoard(),
- const VerticalDivider(),
- const Expanded(
- child: MeasureRightBoard(),
- ),
- ],
- );
- }
- return Scaffold(
- backgroundColor: const Color.fromARGB(255, 53, 55, 51),
- appBar: AppBar(
- actions: [
- TextButton(
- onPressed: () {
- Get.find<IApplication>().clearRecords();
- },
- child: const Text(
- "清空",
- style: TextStyle(
- color: Colors.white,
- ),
- ),
- ),
- TextButton(
- onPressed: () {
- Get.find<IApplication>().undoRecord();
- },
- child: const Text(
- "撤销",
- style: TextStyle(
- color: Colors.white,
- ),
- ),
- ),
- TextButton(
- onPressed: () {
- final c = Get.find<IStandardLineCalibrationController>();
- if (c.isEditing) {
- c.cancelEdit();
- } else {
- c.enterEditMode();
- }
- },
- child: const Text(
- "校准线",
- style: TextStyle(
- color: Colors.white,
- ),
- ),
- ),
- TextButton.icon(
- onPressed: () {
- setState(() {
- if (useArrowAnnotation) {
- useArrowAnnotation = false;
- controller.workingApplication.switchAnnotation();
- } else {
- useArrowAnnotation = true;
- controller.workingApplication
- .switchAnnotation(AnnotationType.arrow);
- }
- });
- },
- icon: const Icon(Icons.arrow_right_alt_sharp),
- label: Text(
- "箭头",
- style: TextStyle(
- color: useArrowAnnotation ? Colors.amber : Colors.white,
- ),
- ),
- ),
- TextButton(
- onPressed: () {
- setState(() {
- opType = opType == 1 ? 0 : 1;
- });
- },
- child: Text(
- opType == 1 ? "注释" : "测量",
- style: const TextStyle(
- color: Colors.white,
- ),
- ),
- ),
- TextButton(
- onPressed: () {
- if (controller.examInfo.selectedImageIndex == 0) return;
- controller.examInfo.selectedImageIndex = 0;
- },
- child: Text(
- '线阵',
- style: TextStyle(
- color: controller.examInfo.selectedImageIndex == 0
- ? Colors.amber
- : Colors.white,
- ),
- ),
- ),
- TextButton(
- onPressed: () {
- if (controller.examInfo.selectedImageIndex == 1) return;
- controller.examInfo.selectedImageIndex = 1;
- },
- child: Text(
- '扇阵',
- style: TextStyle(
- color: controller.examInfo.selectedImageIndex == 1
- ? Colors.amber
- : Colors.white,
- ),
- ),
- ),
- ],
- leading: IconButton(
- onPressed: () {
- Navigator.of(context).pop();
- },
- icon: const Icon(Icons.arrow_back),
- ),
- ),
- body: body,
- floatingActionButton: _ModeTips(),
- floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
- );
- }
- }
- class MeasureRightBoard extends StatefulWidget {
- const MeasureRightBoard({Key? key}) : super(key: key);
- @override
- State<StatefulWidget> createState() => _MeasureRightBoardState();
- }
- class _MeasureRightBoardState extends State<MeasureRightBoard> {
- final playerController = Get.find<IPlayerController>();
- @override
- Widget build(BuildContext context) {
- return Container(
- padding: const EdgeInsets.all(8).copyWith(left: 0),
- child: Stack(
- children: const [
- MeasureMainView(),
- _PlayerTips(),
- ],
- ),
- );
- }
- }
- class _PlayerTips extends StatefulWidget {
- const _PlayerTips({Key? key}) : super(key: key);
- @override
- State<StatefulWidget> createState() => _PlayerTipsState();
- }
- class _PlayerTipsState extends State<_PlayerTips> {
- final playerController = Get.find<IPlayerController>();
- bool loading = false;
- String content = 'xxxxxxxxxxxxxxxxxxxx';
- @override
- void initState() {
- playerController.frameLoadStateChanged.addListener(_onLoadStateChanged);
- super.initState();
- }
- @override
- void dispose() {
- playerController.frameLoadStateChanged.removeListener(_onLoadStateChanged);
- super.dispose();
- }
- void _onLoadStateChanged(sender, bool e) {
- loading = e;
- if (loading) {
- Future.delayed(
- const Duration(milliseconds: 100),
- () {
- setState(() {
- content = loading ? "Loading。。。" : "";
- });
- },
- );
- } else {
- setState(() {
- content = "";
- });
- }
- }
- @override
- Widget build(BuildContext context) {
- return Positioned(
- child: Center(
- child: Text(
- content,
- style: const TextStyle(
- color: Colors.white,
- fontSize: 28,
- ),
- ),
- ),
- top: Get.size.height * 0.44,
- left: 0,
- right: 0,
- );
- }
- }
- class _MeasureLeftBoard extends StatefulWidget {
- const _MeasureLeftBoard({Key? key}) : super(key: key);
- @override
- State<StatefulWidget> createState() => _MeasureLeftBoardState();
- }
- class _MeasureLeftBoardState extends State<_MeasureLeftBoard> {
- // ignore: non_constant_identifier_names
- static final C_SUPPORTED_ITEMS = <String>[
- MeasureTerms.Distance,
- MeasureTerms.Perimeter,
- MeasureTerms.Area,
- MeasureTerms.Angle,
- MeasureTerms.Depth,
- MeasureTerms.Volume,
- MeasureTerms.Stenosis,
- MeasureTerms.AbRatio,
- MeasureTerms.RUV,
- //
- MeasureTypes.AreaPerimeterEllipse,
- MeasureTypes.AreaPerimeterPolyline,
- MeasureTypes.AreaPerimeterSpline,
- ];
- // ignore: non_constant_identifier_names
- static final C_SUPPORTED_M_ITEMS = <String>[
- MeasureTerms.VerticalDistance,
- MeasureTerms.Timespan,
- MeasureTerms.Depth,
- MeasureTerms.Stenosis,
- MeasureTerms.AbRatio,
- MeasureTerms.Slope,
- MeasureTerms.TAMAX,
- MeasureTerms.Velocity,
- MeasureTerms.Acceleration,
- MeasureTerms.PSED,
- MeasureTerms.RI,
- MeasureTerms.MaxPG,
- "LV TEI Index",
- "AV Ratio",
- MeasureTerms.HeartRate,
- // MeasureTerms.PHT,
- "MV PHT",
- "Qp/Qs",
- ];
- late final List<String> passeItems;
- final scrollController = ScrollController();
- final application = Get.find<IApplication>();
- String modeType = 'Tissue';
- int activeIndex = 0;
- List<ItemMeta> workingItems = [];
- @override
- void initState() {
- // passeItems = C_SUPPORTED_ITEMS;
- // passeItems = TestItems.C_DISTANCE_ITEMS;
- passeItems = TestItems.C_TEST_ITEMS;
- loadItems();
- application.visualAreaChanged.addListener(_visualAreaChanged);
- super.initState();
- }
- @override
- dispose() {
- application.visualAreaChanged.removeListener(_visualAreaChanged);
- super.dispose();
- }
- void loadItems() {
- workingItems = [];
- var names = (modeType == "TissueTM" || modeType == "Doppler")
- ? C_SUPPORTED_M_ITEMS
- : passeItems;
- final workingItemDtos =
- MeasureTestPage.MetaDTOList.where((e) => names.contains(e['Name']));
- for (var map in workingItemDtos) {
- final dto = ItemMetaDTO.fromJson(map);
- final item = ItemMetaConverter(dto).output();
- workingItems.add(item);
- }
- }
- void _visualAreaChanged(sender, IVisualArea e) {
- if (mounted) {
- _setAvailableModes(e.mode.modeType.toString().split('.')[1]);
- // changeItemByMeta(0); //暂时不要自动切测量项
- setState(() {});
- }
- }
- void _setAvailableModes(String name) {
- modeType = name;
- loadItems();
- }
- @override
- Widget build(BuildContext context) {
- return Container(
- width: 300,
- padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
- child: Scrollbar(
- controller: scrollController,
- isAlwaysShown: true,
- child: ListView.separated(
- controller: scrollController,
- itemCount: workingItems.length,
- itemBuilder: (BuildContext context, int index) {
- final meta = workingItems[index];
- final active = index == activeIndex;
- return active
- ? ElevatedButton(
- onPressed: () {
- changeItemByMeta(index);
- },
- child: Text(meta.name),
- style: ElevatedButton.styleFrom(
- fixedSize: const Size.fromHeight(50),
- ),
- )
- : OutlinedButton(
- onPressed: () => changeItemByMeta(index),
- child: Text(meta.name),
- style: OutlinedButton.styleFrom(
- fixedSize: const Size.fromHeight(50),
- ),
- );
- },
- separatorBuilder: (BuildContext context, int index) {
- return const SizedBox(height: 8);
- },
- ),
- ),
- );
- }
- void changeItemByMeta(int index) {
- setState(() {
- activeIndex = index;
- });
- final meta = workingItems[index];
- application.switchItem(meta);
- print(application.activeMeasureItem?.meta.name);
- // handle combo item
- if (application.activeMeasureItem != null) {
- final item = application.activeMeasureItem!;
- if (item is ITopMeasureItem) {
- item.switchChild(0);
- }
- }
- }
- }
- class _MeasureLeftAnnotation extends StatefulWidget {
- const _MeasureLeftAnnotation({Key? key}) : super(key: key);
- @override
- State<StatefulWidget> createState() => _MeasureLeftAnnotationState();
- }
- class _MeasureLeftAnnotationState extends State<_MeasureLeftAnnotation> {
- // ignore: non_constant_identifier_names
- static final C_SUPPORTED_TEXTS = <String>[
- "肝左叶",
- "胆囊",
- "脾脏",
- "结石",
- "积液",
- ];
- final scrollController = ScrollController();
- final application = Get.find<IApplication>();
- @override
- void initState() {
- // application.switchAnnotation(AnnotationType.label, C_SUPPORTED_TEXTS[0]);
- // application.switchAnnotation(AnnotationType.arrow);
- application.switchAnnotation(AnnotationType.input);
- super.initState();
- }
- @override
- Widget build(BuildContext context) {
- return Container(
- width: 300,
- padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
- child: Scrollbar(
- controller: scrollController,
- isAlwaysShown: true,
- child: ListView.separated(
- controller: scrollController,
- itemCount: C_SUPPORTED_TEXTS.length,
- itemBuilder: (BuildContext context, int index) {
- final name = C_SUPPORTED_TEXTS[index];
- const style = TextStyle(color: Colors.white, fontSize: 16);
- const dragStyle = TextStyle(color: Colors.amber, fontSize: 18);
- // TODO: melon - set drag cursor after version updated up then 3.0
- // https://github.com/flutter/flutter/pull/100475
- return Draggable<String>(
- data: name,
- dragAnchorStrategy: (data, context, offset) {
- // return offset - Offset(120, 14);
- return Offset.zero;
- },
- child: OutlinedButton(
- child: Text(name, style: style),
- onPressed: () {
- application.switchAnnotation(AnnotationType.label, name);
- },
- style: OutlinedButton.styleFrom(
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(4),
- ),
- side: BorderSide(color: Colors.grey.shade100),
- fixedSize: const Size.fromHeight(44),
- ),
- ),
- feedback: Material(
- color: Colors.transparent,
- child: Text(name, style: dragStyle),
- ),
- onDragStarted: () {
- application.switchAnnotation(AnnotationType.label, name);
- },
- );
- },
- separatorBuilder: (BuildContext context, int index) {
- return const SizedBox(height: 8);
- },
- ),
- ),
- );
- }
- }
- class _ModeTips extends StatefulWidget {
- @override
- State<StatefulWidget> createState() => _ModeTipsState();
- }
- class _ModeTipsState extends State<_ModeTips> {
- IApplication? application;
- @override
- void initState() {
- Future.delayed(const Duration(milliseconds: 100), () {
- application = Get.find<IApplication>();
- application!.visualsLoaded.addListener(_onVisualsLoaded);
- });
- super.initState();
- }
- @override
- void dispose() {
- application!.visualsLoaded.removeListener(_onVisualsLoaded);
- super.dispose();
- }
- void _onVisualsLoaded(Object sender, void e) {
- setState(() {});
- }
- @override
- Widget build(BuildContext context) {
- if (application == null) return const Text("Wait");
- return Material(
- child: Text(application!.avaliableModes.map((e) => e.name).join('/')),
- );
- }
- }
|