Browse Source

update test tools

arthur.wu 2 năm trước cách đây
mục cha
commit
dec8fbf558

+ 212 - 149
Tools/TestTools/client/lib/ApplyConsultationScreen.dart

@@ -5,6 +5,8 @@ import 'package:ustest/Services/UserService.dart';
 import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
 import 'package:autocomplete_textfield/autocomplete_textfield.dart';
 
+import 'ConsultationList.dart';
+
 class CustomPicker extends CommonPickerModel {
   String digits(int value, int length) {
     return '$value'.padLeft(length, "0");
@@ -106,173 +108,225 @@ class ApplyConsultationForm extends StatefulWidget {
 }
 
 class _ApplyConsultationFormState extends State<ApplyConsultationForm> {
-  final expertCodeController = TextEditingController();
-  final deviceCodeController = TextEditingController();
-  final scanPositionController = TextEditingController();
-  final timeController = TextEditingController(text: DateTime.now().toString());
   final patientCodeController = TextEditingController();
 
-  GlobalKey<AutoCompleteTextFieldState<String>> exportKey = GlobalKey();
+  Expert? selectedExpert;
+  Device? selectedDevice;
+  String? selectedOrgan;
+  DateTime time = DateTime.now();
+  GlobalKey<AutoCompleteTextFieldState<Expert>> exportKey =
+      GlobalKey<AutoCompleteTextFieldState<Expert>>();
+  GlobalKey<AutoCompleteTextFieldState<Device>> deviceKey =
+      GlobalKey<AutoCompleteTextFieldState<Device>>();
+  GlobalKey<AutoCompleteTextFieldState<String>> organKey = GlobalKey();
+
   double _formProgress = 0;
 
+  _ApplyConsultationFormState() {}
+
   @override
   Widget build(BuildContext context) {
     return Form(
-      child: Column(
-        mainAxisSize: MainAxisSize.min,
-        children: [
-          LinearProgressIndicator(value: _formProgress),
-          Text('Apply', style: Theme.of(context).textTheme.headline4),
-          Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: FutureBuilder<List<String>>(
-                future: fetchExperts(),
-                builder: (context, snapshot) {
-                  if (snapshot.hasError) {
-                    return const Center(
-                      child: Text('An error has occurred!'),
-                    );
-                  } else if (snapshot.hasData) {
-                    return SimpleAutoCompleteTextField(
-                      key: exportKey,
-                      suggestions: snapshot.data!,
-                      controller: expertCodeController,
-                      decoration: const InputDecoration(hintText: 'export'),
-                    );
-                  } else {
-                    return const Center(
-                      child: CircularProgressIndicator(),
-                    );
-                  }
-                }),
-          ),
-          Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: TextFormField(
-              controller: deviceCodeController,
-              decoration: const InputDecoration(hintText: 'device'),
-            ),
-          ),
-          Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: TextFormField(
-              controller: scanPositionController,
-              decoration: const InputDecoration(hintText: 'scan position'),
-            ),
-          ),
-          Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: Row(
-              children: [
-                Expanded(
-                    child: TextFormField(
-                  controller: timeController,
-                  decoration: const InputDecoration(hintText: 'time'),
-                )),
-                TextButton(
-                    onPressed: () {
-                      DatePicker.showDatePicker(context,
-                          showTitleActions: true,
-                          minTime: DateTime(2022, 3, 5),
-                          maxTime: DateTime(2024, 6, 7),
-                          theme: DatePickerTheme(
-                              headerColor: Colors.orange,
-                              backgroundColor: Colors.blue,
-                              itemStyle: TextStyle(
-                                  color: Colors.white,
-                                  fontWeight: FontWeight.bold,
-                                  fontSize: 18),
-                              doneStyle:
-                                  TextStyle(color: Colors.white, fontSize: 16)),
-                          onChanged: (date) {
-                        print('change $date in time zone ' +
-                            date.timeZoneOffset.inHours.toString());
-                      }, onConfirm: (date) {
-                        print('confirm $date');
-                      }, currentTime: DateTime.now(), locale: LocaleType.en);
-                    },
-                    child: Text(
-                      'date',
-                      style: TextStyle(color: Colors.blue),
-                    )),
-                TextButton(
-                    onPressed: () {
-                      DatePicker.showTimePicker(context, showTitleActions: true,
-                          onChanged: (date) {
-                        print('change $date in time zone ' +
-                            date.timeZoneOffset.inHours.toString());
-                      }, onConfirm: (date) {
-                        print('confirm $date');
-                      }, currentTime: DateTime.now());
-                    },
-                    child: Text(
-                      'time',
-                      style: TextStyle(color: Colors.blue),
-                    )),
-              ],
-            ),
-          ),
-          Padding(
-              padding: const EdgeInsets.all(8.0),
-              child: Row(
-                mainAxisAlignment: MainAxisAlignment.center,
+      child: FutureBuilder<AppConsultationDataModel>(
+          future: lodaDataAsync(),
+          builder: (context, snapshot) {
+            if (snapshot.hasError) {
+              return const Center(
+                child: Text('An error has occurred!'),
+              );
+            } else if (snapshot.hasData) {
+              return Column(
+                mainAxisSize: MainAxisSize.min,
                 children: [
-                  TextButton(
-                    style: ButtonStyle(
-                      foregroundColor: MaterialStateProperty.resolveWith(
-                          (Set<MaterialState> states) {
-                        return states.contains(MaterialState.disabled)
-                            ? null
-                            : Colors.white;
-                      }),
-                      backgroundColor: MaterialStateProperty.resolveWith(
-                          (Set<MaterialState> states) {
-                        return states.contains(MaterialState.disabled)
-                            ? null
-                            : Colors.blue;
-                      }),
-                    ),
-                    onPressed: _showWelcomeScreen,
-                    child: const Text('Submit'),
-                  ),
+                  LinearProgressIndicator(value: _formProgress),
+                  Text('Apply', style: Theme.of(context).textTheme.headline4),
+                  Padding(
+                      padding: const EdgeInsets.all(24.0),
+                      child: DropdownButtonFormField<Expert>(
+                        value: selectedExpert,
+                        decoration: InputDecoration(
+                            hintText: "Select an expert",
+                            suffixIcon: Icon(Icons.search)),
+                        onChanged: (item) {
+                          setState(() => this.selectedExpert = item);
+                        },
+                        key: exportKey,
+                        items: snapshot.data!.experts
+                            .map((e) => DropdownMenuItem<Expert>(
+                                  child: Text(e.userName),
+                                  value: e,
+                                ))
+                            .toList(),
+                      )),
                   Padding(
                     padding: const EdgeInsets.all(8.0),
-                    child: TextButton(
-                      style: ButtonStyle(
-                        foregroundColor: MaterialStateProperty.resolveWith(
-                            (Set<MaterialState> states) {
-                          return states.contains(MaterialState.disabled)
-                              ? null
-                              : Colors.white;
-                        }),
-                        backgroundColor: MaterialStateProperty.resolveWith(
-                            (Set<MaterialState> states) {
-                          return states.contains(MaterialState.disabled)
-                              ? null
-                              : Colors.blue;
-                        }),
-                      ),
-                      onPressed: () => {Navigator.of(context).pop()},
-                      child: const Text('Cancel'),
+                    child: Padding(
+                        child: Container(
+                            child: DropdownButtonFormField<Device>(
+                          value: selectedDevice,
+                          decoration: InputDecoration(
+                              hintText: "Select a device",
+                              suffixIcon: Icon(Icons.search)),
+                          onChanged: (item) {
+                            setState(() => this.selectedDevice = item);
+                          },
+                          key: deviceKey,
+                          items: snapshot.data!.devices
+                              .map((e) => DropdownMenuItem<Device>(
+                                    child: Text(e.deviceName),
+                                    value: e,
+                                  ))
+                              .toList(),
+                        )),
+                        padding: EdgeInsets.all(16.0)),
+                  ),
+                  Padding(
+                      padding: const EdgeInsets.all(24.0),
+                      child: DropdownButtonFormField<String>(
+                        key: organKey,
+                        value: selectedOrgan,
+                        decoration:
+                            InputDecoration(hintText: "Select one organ"),
+                        items: snapshot.data!.organs
+                            .map((e) => DropdownMenuItem<String>(
+                                  child: Text(e),
+                                  value: e,
+                                ))
+                            .toList(),
+                        onChanged: (value) {
+                          selectedOrgan = value;
+                        },
+                      )),
+                  Padding(
+                    padding: const EdgeInsets.all(24.0),
+                    child: Row(
+                      children: [
+                        Expanded(
+                          child: Text(time.toString()),
+                        ),
+                        TextButton(
+                            onPressed: () {
+                              DatePicker.showDatePicker(context,
+                                  showTitleActions: true,
+                                  minTime: DateTime(2022, 3, 5),
+                                  maxTime: DateTime(2024, 6, 7),
+                                  theme: DatePickerTheme(
+                                      headerColor: Colors.orange,
+                                      backgroundColor: Colors.blue,
+                                      itemStyle: TextStyle(
+                                          color: Colors.white,
+                                          fontWeight: FontWeight.bold,
+                                          fontSize: 18),
+                                      doneStyle: TextStyle(
+                                          color: Colors.white,
+                                          fontSize: 16)), onChanged: (date) {
+                                print('change $date in time zone ' +
+                                    date.timeZoneOffset.inHours.toString());
+                              }, onConfirm: (date) {
+                                print('confirm $date');
+                                setState(() {
+                                  this.time = date;
+                                });
+                              },
+                                  currentTime: DateTime.now(),
+                                  locale: LocaleType.en);
+                            },
+                            child: Text(
+                              'date',
+                              style: TextStyle(color: Colors.blue),
+                            )),
+                        TextButton(
+                            onPressed: () {
+                              DatePicker.showTimePicker(context,
+                                  showTitleActions: true, onChanged: (date) {
+                                print('change $date in time zone ' +
+                                    date.timeZoneOffset.inHours.toString());
+                              }, onConfirm: (date) {
+                                print('confirm $date');
+                                setState(() {
+                                  this.time = date;
+                                });
+                              }, currentTime: DateTime.now());
+                            },
+                            child: Text(
+                              'time',
+                              style: TextStyle(color: Colors.blue),
+                            )),
+                      ],
                     ),
                   ),
+                  Padding(
+                      padding: const EdgeInsets.all(8.0),
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.center,
+                        children: [
+                          TextButton(
+                            style: ButtonStyle(
+                              foregroundColor:
+                                  MaterialStateProperty.resolveWith(
+                                      (Set<MaterialState> states) {
+                                return states.contains(MaterialState.disabled)
+                                    ? null
+                                    : Colors.white;
+                              }),
+                              backgroundColor:
+                                  MaterialStateProperty.resolveWith(
+                                      (Set<MaterialState> states) {
+                                return states.contains(MaterialState.disabled)
+                                    ? null
+                                    : Colors.blue;
+                              }),
+                            ),
+                            onPressed: onSubmit,
+                            child: const Text('Submit'),
+                          ),
+                          Padding(
+                            padding: const EdgeInsets.all(8.0),
+                            child: TextButton(
+                              style: ButtonStyle(
+                                foregroundColor:
+                                    MaterialStateProperty.resolveWith(
+                                        (Set<MaterialState> states) {
+                                  return states.contains(MaterialState.disabled)
+                                      ? null
+                                      : Colors.white;
+                                }),
+                                backgroundColor:
+                                    MaterialStateProperty.resolveWith(
+                                        (Set<MaterialState> states) {
+                                  return states.contains(MaterialState.disabled)
+                                      ? null
+                                      : Colors.blue;
+                                }),
+                              ),
+                              onPressed: () => {Navigator.of(context).pop()},
+                              child: const Text('Cancel'),
+                            ),
+                          ),
+                        ],
+                      )),
                 ],
-              )),
-        ],
-      ),
+              );
+            } else {
+              return const Center(
+                child: CircularProgressIndicator(),
+              );
+            }
+          }),
     );
   }
 
-  void _showWelcomeScreen() async {
+  void onSubmit() async {
     try {
       ApplyConsultationRequest _model = new ApplyConsultationRequest(
           "expertusercode", "d", "s", DateTime.now(), List.empty(), "", "");
-      var service = GetIt.instance.get<UserService>();
-      var userName = expertCodeController.text;
-      var password = deviceCodeController.text;
-      var host = scanPositionController.text;
-      var result = await service.signInAsync(host, userName, password);
-      if (result != null) {
+      var service = GetIt.instance.get<ConsultationService>();
+      var expertCode = selectedExpert?.code;
+      var deviceCode = selectedDevice?.code;
+      var organ = selectedOrgan;
+      var result = await service.ApplyConsultationAsync(
+          expertCode!, deviceCode!, selectedOrgan!, time);
+      if (result) {
         Navigator.of(context).pushNamed('/');
       }
     } catch (e) {
@@ -280,7 +334,16 @@ class _ApplyConsultationFormState extends State<ApplyConsultationForm> {
     }
   }
 
-  fetchExperts() {}
+  Future<AppConsultationDataModel> lodaDataAsync() async {
+    try {
+      var service = GetIt.instance.get<ConsultationService>();
+      var model = await service.LoadDataAsync();
+      return model;
+    } catch (ex) {
+      print('lodaDataAsync ex' + ex.toString());
+      return Future.error(ex);
+    }
+  }
 }
 
 class ExportInfo {

+ 21 - 12
Tools/TestTools/client/lib/ConsultationList.dart

@@ -7,10 +7,10 @@ import 'package:sprintf/sprintf.dart';
 import 'package:http/http.dart' as http;
 
 class ConsultationList extends StatefulWidget {
-  ConsultationList({Key? key, required this.token, required this.patients})
+  ConsultationList({Key? key, required this.token, required this.consultations})
       : super();
   final String token;
-  final List<Consultation> patients;
+  final List<Consultation> consultations;
 
   @override
   _ConsultationListState createState() => _ConsultationListState();
@@ -31,7 +31,9 @@ class _ConsultationListState extends State<ConsultationList> {
               restorationId: 'list_demo_list_view',
               padding: const EdgeInsets.symmetric(vertical: 0),
               children: [
-                for (int index = 0; index < widget.patients.length; index++)
+                for (int index = 0;
+                    index < widget.consultations.length;
+                    index++)
                   Row(
                     children: [
                       Expanded(
@@ -40,10 +42,11 @@ class _ConsultationListState extends State<ConsultationList> {
                           leading: ExcludeSemantics(
                             child: Icon(Icons.person),
                           ),
-                          title: Text(widget.patients[index].id),
-                          subtitle: Text("patients[index].subtitle"),
+                          title: Text(widget.consultations[index].id),
+                          subtitle:
+                              Text(widget.consultations[index].patientName),
                           onTap: (() =>
-                              onTabPatient(widget.patients[index].id)),
+                              onTabPatient(widget.consultations[index].id)),
                         ),
                       )),
                       Container(
@@ -68,7 +71,10 @@ class _ConsultationListState extends State<ConsultationList> {
                                                 fontSize: 9),
                                           ),
                                         ]))),
-                                Container(child: Text("a"))
+                                Container(
+                                    child: TextButton(
+                                        child: Text("Start"),
+                                        onPressed: OnStartLiveConsultation))
                               ],
                             ),
                           )),
@@ -104,18 +110,20 @@ class _ConsultationListState extends State<ConsultationList> {
       print('GetRecordInfoPagesAsync.to ex' + ex.toString());
     }
   }
+
+  void OnStartLiveConsultation() {}
 }
 
 class Consultation {
   final String id;
+  final String patientName;
 
-  Consultation({
-    required this.id,
-  });
+  Consultation({required this.id, required this.patientName});
 
   factory Consultation.fromJson(Map<String, dynamic> json) {
     var item = Consultation(
-      id: json['PatientCode'] as String,
+      id: json['ConsultationCode'] as String,
+      patientName: json['PatientName'] as String,
     );
 
     return item;
@@ -123,7 +131,8 @@ class Consultation {
 
   Map<String, dynamic> toMap() {
     return {
-      'PatientCode': id,
+      'ConsultationCode': id,
+      'PatientName': patientName,
     };
   }
 

+ 3 - 0
Tools/TestTools/client/lib/MainScreen.dart

@@ -32,6 +32,7 @@ class _MainScreenState extends State<MainScreen> with RestorationMixin {
 
   @override
   Widget build(BuildContext context) {
+    print("build MainScreen");
     final selectedItem = <Widget>[UserView(), TestCaseView()];
     return Scaffold(
       appBar: AppBar(
@@ -45,6 +46,8 @@ class _MainScreenState extends State<MainScreen> with RestorationMixin {
             selectedIndex: _selectedIndex.value,
             onDestinationSelected: (index) {
               setState(() {
+                var oldIndex = _selectedIndex.value;
+                print('oldIndex:$oldIndex =>index:$index');
                 _selectedIndex.value = index;
               });
             },

+ 3 - 0
Tools/TestTools/client/lib/Services/AppSettings.dart

@@ -0,0 +1,3 @@
+class AppSettings {
+  static late String host = 'http://192.168.6.80:8303';
+}

+ 183 - 18
Tools/TestTools/client/lib/Services/ConsultationService.dart

@@ -4,17 +4,18 @@ import 'package:get_it/get_it.dart';
 import 'package:http/http.dart' as http;
 import 'package:localstorage/localstorage.dart';
 import 'package:sprintf/sprintf.dart';
+import 'package:ustest/ConsultationList.dart';
 import 'package:ustest/Services/LocalStorageService.dart';
 import 'dart:typed_data';
 
 import 'package:web_socket_channel/web_socket_channel.dart';
 
-class ConsultationService {
-  late String _host;
+import 'AppSettings.dart';
+import 'UserService.dart';
+import 'package:intl/intl.dart';
 
-  Future<ConsultationRecord> apply(
-      String host, String userName, String password) async {
-    _host = host;
+class ConsultationService {
+  Future<Expert> apply(String host, String userName, String password) async {
     var client = http.Client();
     var now = DateTime.now();
     var date = DateTime.utc(
@@ -26,16 +27,141 @@ class ConsultationService {
     var body = sprintf(
         '{"jsonrpc": "2.0", "method": "CommonLoginAsync", "params": [{"AnyAccount": "%s", "AnyCode": "", "Password": "%s" }], "id": 1 }',
         [userName, password]);
-    final response =
-        await client.post(Uri.parse(_host + '/ILoginService'), body: body);
+    final response = await client
+        .post(Uri.parse(AppSettings.host + '/ILoginService'), body: body);
     print('response.body' + response.body);
     final parsed = jsonDecode(response.body);
 
-    var record =
-        new ConsultationRecord(code: "code", accessToken: "accessToken");
+    var record = new Expert(code: "code", userName: "accessToken");
 
     return record; //TODO
   }
+
+  Future<AppConsultationDataModel> LoadDataAsync() async {
+    var userService = GetIt.instance.get<UserService>();
+    final user = userService.getCurrentUser();
+    final token = user?.accessToken;
+    final orgCode = user?.organizationCode;
+
+    var client = http.Client();
+
+    var body =
+        '{"jsonrpc": "2.0", "method": "GetPersonDeviceDropdownListAsync", "params": [{"Token": "$token"}], "id": 1 }';
+    print('QueryExam http.Client()' + body);
+    var response = await client
+        .post(Uri.parse(AppSettings.host + '/IDeviceService'), body: body);
+
+    var parsed = decodeResponseBody(
+        'GetPersonDeviceDropdownListAsync', response.bodyBytes);
+    var datas = parsed['result'];
+    final devices = datas.map<Device>((json) => Device.fromJson(json)).toList();
+
+    body =
+        '{"jsonrpc": "2.0", "method": "FindOrganizationExpertsAsync", "params": [{"Token": "$token", "OrganizationCode": "$orgCode"}], "id": 1 }';
+    print('QueryExam http.Client()' + body);
+    response = await client.post(
+        Uri.parse(AppSettings.host + '/ILiveConsultationService'),
+        body: body);
+
+    //final response = await post(client, "ILiveConsultationService",
+    //    "FindOrganizationExpertsAsync", args);
+    print('FindOrganizationExpertsAsync response.body' + response.body);
+    parsed = jsonDecode(response.body);
+    datas = parsed['result'];
+    final experts = datas.map<Expert>((json) => Expert.fromJson(json)).toList()
+        as List<Expert>;
+
+    body =
+        '{"jsonrpc": "2.0", "method": "GetOrganizationSettingAsync", "params": [{"Token": "$token",  "SettingType": 2, "Version": "0.0"}], "id": 1 }';
+    print('GetOrganizationSettingAsync http.Client()' + body);
+    response = await client.post(
+        Uri.parse(AppSettings.host + '/IOrganizationService'),
+        body: body);
+    parsed =
+        decodeResponseBody('GetOrganizationSettingAsync', response.bodyBytes);
+    var data = jsonDecode(parsed['result']['SettingData']);
+    var organSource =
+        data['ConsultationInfo']['Booking']['ScanPosition']['Source'];
+
+    var organs = organSource.map<String>((json) => json.toString()).toList()
+        as List<String>;
+    var model = new AppConsultationDataModel(experts, devices, organs);
+    return model;
+  }
+
+  decodeResponseBody(String logTag, Uint8List bodyBytes) {
+    var utfString = utf8.decode(bodyBytes);
+    print('$logTag response.body' + utfString);
+    final parsed = jsonDecode(utfString);
+    return parsed;
+  }
+
+  Future<List<Consultation>> FindConsultationsByPageAsync(String id) async {
+    try {
+      var userService = GetIt.instance.get<UserService>();
+      var user = userService.getCurrentUser();
+      var token = user?.accessToken;
+      var client = http.Client();
+
+      var body =
+          '{"jsonrpc": "2.0", "method": "FindConsultationsByPageAsync", "params": [{"Token": "$token",  "PageIndex": 1, "PageSize": 10}], "id": 1 }';
+      print('GetRecordInfoPagesAsync http.Client()' + body);
+      final response = await client.post(
+          Uri.parse(AppSettings.host + '/ILiveConsultationService'),
+          body: body);
+      print('FindConsultationsByPageAsync response.body' + response.body);
+      final parsed = jsonDecode(response.body);
+      var datas = parsed['result']['PageData'];
+      var list = datas
+          .map<Consultation>((json) => Consultation.fromJson(json))
+          .toList();
+      return list;
+    } catch (ex) {
+      print('FindConsultationsByPageAsync.to ex' + ex.toString());
+    }
+
+    return List.empty();
+  }
+
+  dynamic post(
+      http.Client client, String interface, String method, String args) async {
+    final body = sprintf(
+        '{"jsonrpc": "2.0", "method": "$method", "params": %s, "id": 1 }',
+        args);
+    final response = await client
+        .post(Uri.parse(AppSettings.host + '/$interface'), body: body);
+    print('GetUserInfoAsync response.body' + response.body);
+    var parsed = jsonDecode(response.body);
+  }
+
+  Future<bool> ApplyConsultationAsync(
+      String expertCode, String deviceCode, String organ, DateTime time) async {
+    var userService = GetIt.instance.get<UserService>();
+    var user = userService.getCurrentUser();
+    var token = user?.accessToken;
+    var client = http.Client();
+    var patientCode = "2D6DA689ECC54F52A17F20A05BDF5C27"; //TODO should from UI
+    DateFormat inputFormat = DateFormat("yyyy-MM-ddTHH:mm:ss");
+    var utcTime = inputFormat.format(time.toUtc()).toString();
+    var body =
+        '{"jsonrpc": "2.0", "method": "ApplyConsultationAsync", "params": [{"Token": "$token", "PatientCode":"$patientCode", "ExpertUserCode": "$expertCode", "DeviceCode": "$deviceCode", "ScanPosition": "$organ", "ConsultationTime":"$utcTime"}], "id": 1 }';
+    print('ApplyConsultationAsync http.Client()' + body);
+    final response = await client.post(
+        Uri.parse(AppSettings.host + '/ILiveConsultationService'),
+        body: body);
+    print('ApplyConsultationAsync response.body' + response.body);
+    final parsed = jsonDecode(response.body);
+    var datas = parsed['result'];
+    return true;
+  }
+}
+
+class AppConsultationDataModel {
+  final List<Expert> experts;
+  final List<Device> devices;
+  final List<String> organs;
+
+  AppConsultationDataModel(this.experts, this.devices, this.organs);
 }
 
 class TokenRequest {
@@ -73,20 +199,59 @@ class ApplyConsultationRequest extends TokenRequest {
       : super(token);
 }
 
-class ConsultationRecord {
+class Expert {
+  final String code;
+  final String userName;
+
+  Expert({required this.code, required this.userName});
+  @override
+  bool operator ==(Object other) => other is Expert && other.code == code;
+  factory Expert.fromJson(Map<String, dynamic> json) {
+    return Expert(
+      code: json['UserCode'] as String,
+      userName: json['UserName'] as String,
+    );
+  }
+
+  Map<String, dynamic> toJson() => {
+        "UserCode": code,
+        "UserName": userName,
+      };
+}
+
+class Device {
+  final String code;
+  final String deviceName;
+
+  Device({required this.code, required this.deviceName});
+  bool operator ==(Object other) => other is Device && other.code == code;
+  factory Device.fromJson(Map<String, dynamic> json) {
+    return Device(
+      code: json['Key'] as String,
+      deviceName: json['Value'] as String,
+    );
+  }
+
+  Map<String, dynamic> toJson() => {
+        "Key": code,
+        "Value": deviceName,
+      };
+}
+
+class Organ {
   final String code;
-  final String accessToken;
+  final String orgName;
 
-  ConsultationRecord({required this.code, required this.accessToken});
-  factory ConsultationRecord.fromJson(Map<String, dynamic> json) {
-    return ConsultationRecord(
-      code: json['code'] as String,
-      accessToken: json['accessToken'] as String,
+  Organ({required this.code, required this.orgName});
+  factory Organ.fromJson(Map<String, dynamic> json) {
+    return Organ(
+      code: json['Key'] as String,
+      orgName: json['Value'] as String,
     );
   }
 
   Map<String, dynamic> toJson() => {
-        "code": code,
-        "accessToken": accessToken,
+        "Key": code,
+        "Value": orgName,
       };
 }

+ 21 - 11
Tools/TestTools/client/lib/Services/UserService.dart

@@ -9,25 +9,35 @@ import 'dart:typed_data';
 
 import 'package:web_socket_channel/web_socket_channel.dart';
 
+import 'AppSettings.dart';
+
 class UserService {
-  late String _host;
+  late User currentUser;
   final String UserStroageKey = "CurrentUser";
   final LocalStorage storage = new LocalStorage('UserStroage');
   final WebSocketChannel Channel = WebSocketChannel.connect(
     Uri.parse('ws://192.168.6.80:9301?token=F97952F53B7C428C8EFE0659F8CF38F6'),
   );
   User? getCurrentUser() {
+    //if (currentUser != null) //TODO workaround
+    //{
+    //  if (currentUser?.userName != 'notlogin') {
+    //    return currentUser;
+    //  }
+    //}
+
     // this.storage.deleteItem(UserStroageKey);
     var value = this.storage.getItem(UserStroageKey);
     if (value != null) {
       print('getCurrentUser value:' + value.toString());
-      var user = User.fromJson(value);
-      return user;
+      currentUser = User.fromJson(value);
     } else {
       print('getCurrentUser value: null');
+      currentUser =
+          new User(userName: 'notlogin', accessToken: '', organizationCode: '');
     }
 
-    return null;
+    return currentUser;
   }
 
   logout() {
@@ -36,13 +46,13 @@ class UserService {
 
   Future<bool> signInAsync(
       String host, String userName, String password) async {
-    _host = host;
+    AppSettings.host = host;
     var client = http.Client();
     var body = sprintf(
         '{"jsonrpc": "2.0", "method": "CommonLoginAsync", "params": [{"AnyAccount": "%s", "AnyCode": "", "Password": "%s" }], "id": 1 }',
         [userName, password]);
-    var response =
-        await client.post(Uri.parse(_host + '/ILoginService'), body: body);
+    var response = await client
+        .post(Uri.parse(AppSettings.host + '/ILoginService'), body: body);
     print('response.body' + response.body);
     var parsed = jsonDecode(response.body);
     var token = parsed['result']['Token'];
@@ -50,8 +60,8 @@ class UserService {
       body = sprintf(
           '{"jsonrpc": "2.0", "method": "GetUserInfoAsync", "params": [{"Token": "%s" }], "id": 1 }',
           [token]);
-      response =
-          await client.post(Uri.parse(_host + '/IUserService'), body: body);
+      response = await client
+          .post(Uri.parse(AppSettings.host + '/IUserService'), body: body);
       print('GetUserInfoAsync response.body' + response.body);
       var parsed = jsonDecode(response.body);
       if (parsed != null) {
@@ -77,8 +87,8 @@ class UserService {
     final body = sprintf(
         '{"jsonrpc": "2.0", "method": "GetUserInfoAsync", "params": %s, "id": 1 }',
         args);
-    final response =
-        await client.post(Uri.parse(_host + '/$interface'), body: body);
+    final response = await client
+        .post(Uri.parse(AppSettings.host + '/$interface'), body: body);
     print('GetUserInfoAsync response.body' + response.body);
     var parsed = jsonDecode(response.body);
   }

+ 1 - 0
Tools/TestTools/client/lib/SignInScreen.dart

@@ -46,6 +46,7 @@ class _SignInFormState extends State<SignInForm> {
 
   @override
   Widget build(BuildContext context) {
+    print("build Signin");
     return Form(
       child: Column(
         mainAxisSize: MainAxisSize.min,

+ 1 - 0
Tools/TestTools/client/lib/TestCaseView.dart

@@ -6,6 +6,7 @@ class TestCaseView extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
+    print("build TestCaseView");
     var tests = fetchTestCases();
     return Scaffold(
       body: Container(

+ 8 - 21
Tools/TestTools/client/lib/UserView.dart

@@ -9,11 +9,14 @@ import 'package:ustest/ConsultationList.dart';
 import 'package:ustest/Services/UserService.dart';
 import 'package:http/http.dart' as http;
 
+import 'Services/ConsultationService.dart';
+
 class UserView extends StatelessWidget {
   const UserView();
 
   @override
   Widget build(BuildContext context) {
+    print("build userView");
     var service = GetIt.instance.get<UserService>();
     var user = service.getCurrentUser();
     if (user == null) {
@@ -62,7 +65,7 @@ class UserView extends StatelessWidget {
                     );
                   } else if (snapshot.hasData) {
                     return ConsultationList(
-                        token: accessToken, patients: snapshot.data!);
+                        token: accessToken, consultations: snapshot.data!);
                   } else {
                     return const Center(
                       child: CircularProgressIndicator(),
@@ -130,30 +133,14 @@ class UserView extends StatelessWidget {
   }
 
   Future<List<Consultation>> fetchPatients() async {
-    var list = <Consultation>[];
     try {
-      var service = GetIt.instance.get<UserService>();
-      var user = service.getCurrentUser() as User;
-      var client = http.Client();
-
-      var body = sprintf(
-          '{"jsonrpc": "2.0", "method": "FindPatients", "params": [{"Token": "%s",  "PageIndex": 1, "PageSize": 10}], "id": 1 }',
-          [user.accessToken]);
-      print('QueryExam http.Client()' + body);
-      final response = await client.post(
-          Uri.parse('http://192.168.6.80:8303/IPatientService'),
-          body: body);
-      print('QueryExam response.body' + response.body);
-      final parsed = jsonDecode(response.body);
-      var datas = parsed['result']['PageData'];
-
-      var list = datas
-          .map<Consultation>((json) => Consultation.fromJson(json))
-          .toList();
+      var service = GetIt.instance.get<ConsultationService>();
+
+      var list = await service.FindConsultationsByPageAsync('id');
       return list;
     } catch (ex) {
       print('QueryExam.to ex' + ex.toString());
-      return list;
+      return List.empty();
     }
   }
 

+ 4 - 0
Tools/TestTools/client/lib/main.dart

@@ -8,6 +8,8 @@ import 'package:ustest/MainScreen.dart';
 import 'package:get_it/get_it.dart';
 import 'package:colorize_logger/colorize_logger.dart';
 
+import 'Services/ConsultationService.dart';
+
 void main() {
   setup();
   runApp(const MyApp());
@@ -20,6 +22,7 @@ void setup() {
   getIt.registerSingleton<LocalStorageService>(LocalStorageService());
   getIt.registerSingleton<ApiTestService>(ApiTestService());
   getIt.registerSingleton<UserService>(UserService());
+  getIt.registerSingleton<ConsultationService>(ConsultationService());
 
 // Alternatively you could write it if you don't like global variables
 }
@@ -29,6 +32,7 @@ class MyApp extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
+    print("build MyApp");
     return MaterialApp(
       routes: {
         '/': (context) => MainScreen(),

+ 14 - 0
Tools/TestTools/client/pubspec.lock

@@ -97,6 +97,13 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_combo_box:
+    dependency: "direct main"
+    description:
+      name: flutter_combo_box
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.0.2+5"
   flutter_datetime_picker:
     dependency: "direct main"
     description:
@@ -142,6 +149,13 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "4.0.2"
+  intl:
+    dependency: "direct main"
+    description:
+      name: intl
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.17.0"
   js:
     dependency: transitive
     description:

+ 2 - 0
Tools/TestTools/client/pubspec.yaml

@@ -36,6 +36,8 @@ dependencies:
   fluttertoast: ^8.0.9
   flutter_datetime_picker: ^1.5.1
   autocomplete_textfield: ^2.0.1
+  flutter_combo_box: ^0.0.2+5
+  intl: ^0.17.0
   
 
 dev_dependencies: