repair_detail_page.dart 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. import 'dart:async';
  2. import 'dart:convert' as convert;
  3. import 'package:amap_location_flutter_plugin/amap_location_flutter_plugin.dart';
  4. import 'package:amap_location_flutter_plugin/amap_location_option.dart';
  5. import 'package:amap_map_fluttify/amap_map_fluttify.dart';
  6. import 'package:flutter/cupertino.dart';
  7. import 'package:flutter/foundation.dart';
  8. import 'package:flutter/material.dart';
  9. import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
  10. import 'package:keyboard_actions/keyboard_actions.dart';
  11. import 'package:liftmanager/common/common.dart';
  12. import 'package:liftmanager/common/user_db.dart';
  13. import 'package:liftmanager/internal/repair/model/repair_list_entity.dart';
  14. import 'package:liftmanager/internal/repair/repair_router.dart';
  15. import 'package:liftmanager/internal/repair/widgets/time_axis.dart';
  16. import 'package:liftmanager/net/api_service.dart';
  17. import 'package:liftmanager/res/resources.dart';
  18. import 'package:liftmanager/routers/fluro_navigator.dart';
  19. import 'package:liftmanager/utils/theme_utils.dart';
  20. import 'package:liftmanager/utils/toast.dart';
  21. import 'package:liftmanager/widgets/app_bar.dart';
  22. import 'package:liftmanager/widgets/click_item.dart';
  23. import 'package:liftmanager/widgets/click_tel_item.dart';
  24. import 'package:liftmanager/widgets/my_button.dart';
  25. import 'package:oktoast/oktoast.dart';
  26. import 'package:permission_handler/permission_handler.dart';
  27. import 'package:url_launcher/url_launcher.dart';
  28. class RepairDetailPage extends StatefulWidget {
  29. RepairDetailPage(this.repairItem);
  30. RepairItem repairItem;
  31. @override
  32. State<StatefulWidget> createState() {
  33. return RepairDetailPageState();
  34. }
  35. }
  36. class RepairDetailPageState extends State<RepairDetailPage> {
  37. Map<String, Object> _locationResult;
  38. StreamSubscription<Map<String, Object>> _locationListener;
  39. AmapLocationFlutterPlugin _locationPlugin = new AmapLocationFlutterPlugin();
  40. int _currentStatus = -1;
  41. LatLng latLng = LatLng(0, 0);
  42. String currentAddress = "";
  43. @override
  44. void initState() {
  45. super.initState();
  46. _locationListener = _locationPlugin
  47. .onLocationChanged()
  48. .listen((Map<String, Object> result) {
  49. setState(() {
  50. _locationPlugin.stopLocation();
  51. _locationResult = result;
  52. // address latitude longitude
  53. _locationResult.forEach((key, value) {
  54. if(key == 'address'){
  55. currentAddress = '$value';
  56. setState(() {});
  57. }else if(key == 'latitude'){
  58. latLng.latitude = double.parse('$value');
  59. setState(() {});
  60. }else if(key == 'longitude'){
  61. latLng.longitude = double.parse('$value');
  62. setState(() {});
  63. }
  64. print('key:$key :');
  65. print('value:$value :');
  66. });
  67. });
  68. });
  69. getLocation();
  70. getRepairDetail();
  71. getHasRole();
  72. }
  73. bool noRole = true;
  74. getHasRole() async {
  75. var role = await User().getCompanyRole();
  76. if(role == Constant.RoleAdmin || role == Constant.RoleRegion || role == Constant.RoleWork){
  77. noRole = false;
  78. setState(() {
  79. });
  80. }
  81. }
  82. getLocation() async{
  83. if (await requestPermission()) {
  84. if (null != _locationPlugin) {
  85. ///开始定位之前设置定位参数
  86. _setLocationOption();
  87. _locationPlugin.startLocation();
  88. }
  89. }
  90. }
  91. void _setLocationOption() {
  92. if (null != _locationPlugin) {
  93. AMapLocationOption locationOption = new AMapLocationOption();
  94. ///是否单次定位
  95. locationOption.onceLocation = true;
  96. ///是否需要返回逆地理信息
  97. locationOption.needAddress = true;
  98. ///逆地理信息的语言类型
  99. locationOption.geoLanguage = GeoLanguage.DEFAULT;
  100. ///设置Android端连续定位的定位间隔
  101. locationOption.locationInterval = 20000;
  102. ///设置Android端的定位模式<br>
  103. ///可选值:<br>
  104. ///<li>[AMapLocationMode.Battery_Saving]</li>
  105. ///<li>[AMapLocationMode.Device_Sensors]</li>
  106. ///<li>[AMapLocationMode.Hight_Accuracy]</li>
  107. locationOption.locationMode = AMapLocationMode.Hight_Accuracy;
  108. ///设置iOS端的定位最小更新距离<br>
  109. locationOption.distanceFilter = -1;
  110. ///设置iOS端期望的定位精度
  111. /// 可选值:<br>
  112. /// <li>[DesiredAccuracy.Best] 最高精度</li>
  113. /// <li>[DesiredAccuracy.BestForNavigation] 适用于导航场景的高精度 </li>
  114. /// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
  115. /// <li>[DesiredAccuracy.Kilometer] 1000米</li>
  116. /// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
  117. locationOption.desiredAccuracy = DesiredAccuracy.NearestTenMeters;
  118. ///设置iOS端是否允许系统暂停定位
  119. locationOption.pausesLocationUpdatesAutomatically = false;
  120. ///将定位参数设置给定位插件
  121. _locationPlugin.setLocationOption(locationOption);
  122. }
  123. }
  124. ///获取定位权限
  125. Future<bool> requestPermission() async {
  126. final permissions = await PermissionHandler()
  127. .requestPermissions([PermissionGroup.location]);
  128. if (permissions[PermissionGroup.location] == PermissionStatus.granted) {
  129. return true;
  130. } else {
  131. toasts('需要定位权限!');
  132. return false;
  133. }
  134. }
  135. void _callCallerTel(telNum) async {
  136. var url = 'tel:${telNum}';
  137. if (await canLaunch(url)) {
  138. await launch(url);
  139. } else {
  140. throw 'Could not launch $url';
  141. }
  142. }
  143. ///获取急修详情
  144. void getRepairDetail() {
  145. ApiService(context: context).repairDetail(widget.repairItem.id, onSuccess: (data) {
  146. if (data != null) {
  147. widget.repairItem = data;
  148. setState(() {});
  149. }
  150. }, onError: (code, msg) {
  151. showToast(msg);
  152. });
  153. }
  154. /// 选择时间
  155. Future<void> _selectTime() async {
  156. DatePicker.showDateTimePicker(context,
  157. showTitleActions: true, onChanged: (date) {}, onConfirm: (date) {
  158. if (_currentStatus == 1) {
  159. sendTaking("${date.toString().split(".")[0]}");
  160. } else if (_currentStatus == 2) {
  161. sendArrive("${date.toString().split(".")[0]}");
  162. }
  163. }, currentTime: DateTime.now(), locale: LocaleType.zh);
  164. }
  165. ///接单时间
  166. void sendTaking(String time) {
  167. showLoading(context, "正在执行...");
  168. ApiService(context: context).repairTaking(widget.repairItem.id, time, onSuccess: (data) {
  169. dismissLoading(context);
  170. if (data != null && data) {
  171. widget.repairItem.takingTime = time;
  172. setState(() {});
  173. } else {}
  174. }, onError: (code, msg) {
  175. dismissLoading(context);
  176. toasts(msg);
  177. });
  178. }
  179. ///到达时间
  180. void sendArrive(String time) {
  181. if(currentAddress.length == 0){
  182. showToast("位置获取失败");
  183. return;
  184. }
  185. showLoading(context, "正在执行...");
  186. ApiService(context: context).repairArrive(widget.repairItem.id, time, currentAddress,
  187. onSuccess: (data) {
  188. dismissLoading(context);
  189. if (data != null && data) {
  190. widget.repairItem.arriveTime = time;
  191. setState(() {});
  192. } else {}
  193. }, onError: (code, msg) {
  194. dismissLoading(context);
  195. toasts(msg);
  196. });
  197. }
  198. @override
  199. Widget build(BuildContext context) {
  200. return Scaffold(
  201. //resizeToAvoidBottomPadding: false,
  202. appBar: const MyAppBar(
  203. centerTitle: "急修详情",
  204. ),
  205. body: SafeArea(
  206. child: Column(
  207. children: <Widget>[
  208. Expanded(
  209. flex: 1,
  210. child: defaultTargetPlatform == TargetPlatform.iOS
  211. ? FormKeyboardActions(child: _buildBody())
  212. : SingleChildScrollView(child: _buildBody()),
  213. )
  214. ],
  215. ),
  216. ),
  217. );
  218. }
  219. _buildBody() {
  220. return Padding(
  221. padding: EdgeInsets.only(bottom: 30),
  222. child: Container(
  223. color: ThemeUtils.getBackgroundColor(context),
  224. child: Column(
  225. crossAxisAlignment: CrossAxisAlignment.start,
  226. children: <Widget>[
  227. Offstage(
  228. offstage: _currentStatus != 0,
  229. child: Column(
  230. crossAxisAlignment: CrossAxisAlignment.start,
  231. children: <Widget>[
  232. Container(
  233. padding: EdgeInsets.fromLTRB(15, 20, 15, 0),
  234. color: ThemeUtils.getTabsBg(context),
  235. child: Row(
  236. children: <Widget>[
  237. Text(
  238. "急修单已完成",
  239. style: TextStyle(fontSize: 24),
  240. )
  241. ],
  242. ),
  243. ),
  244. Container(
  245. margin: EdgeInsets.only(bottom: 8),
  246. padding: EdgeInsets.fromLTRB(15, 10, 15, 10),
  247. decoration: BoxDecoration(
  248. color: ThemeUtils.getTabsBg(context),
  249. ),
  250. child: Row(
  251. mainAxisAlignment: MainAxisAlignment.start,
  252. children: <Widget>[
  253. Offstage(
  254. offstage:noRole || widget.repairItem.status == 2 &&
  255. widget.repairItem.hasEvaluate == 1,
  256. child: FlatButton(
  257. color: const Color(0xFFE1EAFA),
  258. textColor: Colours.app_main,
  259. child: const Text(
  260. "评价",
  261. style: TextStyle(fontSize: Dimens.font_sp14),
  262. ),
  263. onPressed: () {
  264. NavigatorUtils.pushResult(context,
  265. "${RepairRouter.repairEvaluatePage}?islook=0&id=${widget.repairItem.id}",
  266. (res) {
  267. if (res != null && res) {
  268. widget.repairItem.hasEvaluate = 1;
  269. getRepairDetail();
  270. }
  271. });
  272. },
  273. ),
  274. ),
  275. Gaps.hGap16,
  276. FlatButton(
  277. color: Colours.app_main,
  278. textColor: Colors.white,
  279. child: const Text(
  280. "急修单",
  281. style: TextStyle(fontSize: Dimens.font_sp14),
  282. ),
  283. onPressed: () {
  284. RepairItem item = widget.repairItem;
  285. String jsonString = convert.jsonEncode(item);
  286. NavigatorUtils.push(context,
  287. "${RepairRouter.repairOrderPage}?item=${Uri.encodeComponent(jsonString)}");
  288. },
  289. ),
  290. ],
  291. ),
  292. )
  293. ],
  294. )),
  295. Offstage(
  296. offstage: widget.repairItem.hasEvaluate == 0,
  297. child: ClickItem(
  298. title: "评价信息",
  299. content: "",
  300. onTap: () {
  301. NavigatorUtils.pushResult(context,
  302. "${RepairRouter.repairEvaluatePage}?islook=1&id=${widget.repairItem.id}&service=${widget.repairItem.evaluation.serviceLevel}&star=${widget.repairItem.evaluation.starLevel}&advice=${Uri.encodeComponent(widget.repairItem.evaluation.advice)}&imgurl=${Uri.encodeComponent(widget.repairItem.evaluation.imgUrl)}",
  303. (res) {
  304. if (res != null && res) {
  305. widget.repairItem.hasEvaluate = 1;
  306. getRepairDetail();
  307. }
  308. });
  309. },
  310. )),
  311. Gaps.vGap8,
  312. ClickItem(
  313. title: "项目名称", content: "${widget.repairItem.projectName}"),
  314. ClickItem(
  315. title: "电梯注册代码",
  316. content: "${widget.repairItem.registrationCode}"),
  317. Offstage(
  318. offstage: widget.repairItem.callerName.length == 0,
  319. child: ClickTelItem(
  320. title: "召修人",
  321. content: "${widget.repairItem.callerName}",
  322. onTap: () {
  323. _callCallerTel("${widget.repairItem.callerTel}");
  324. },
  325. ),
  326. ),
  327. ClickItem(
  328. title: "故障原因",
  329. content:
  330. "${widget.repairItem.repairReason == 1 ? "停电" : widget.repairItem.repairReason == 2 ? "故障" : "其他"}"),
  331. ClickItem(
  332. title: "是否关人",
  333. content: "${widget.repairItem.isTrapped == 1 ? "是" : "否"}"),
  334. ClickItem(
  335. title: "是否紧急",
  336. content: "${widget.repairItem.isCritical == 1 ? "是" : "否"}"),
  337. ClickItem(
  338. title: "故障描述",
  339. content: "${widget.repairItem.callerFaultDescription}"),
  340. ClickTelItem(
  341. title: "急修负责人",
  342. content: "${widget.repairItem.workerName}",
  343. onTap: () {
  344. _callCallerTel("${widget.repairItem.workerTel}");
  345. },
  346. ),
  347. Gaps.vGap8,
  348. ClickItem(title: "最新动态", content: ""),
  349. Column(
  350. children: timeAxis(),
  351. ),
  352. Offstage(
  353. offstage: _currentStatus == 0||widget.repairItem.status>=2,
  354. child: Container(
  355. color: ThemeUtils.getTabsBg(context),
  356. child: Padding(
  357. padding: const EdgeInsets.all(16),
  358. child: MyButton(
  359. fontSize: 14,
  360. onPressed: () {
  361. if (_currentStatus == 3) {
  362. RepairItem item = widget.repairItem;
  363. String jsonString = convert.jsonEncode(item);
  364. NavigatorUtils.pushResult(context,
  365. "${RepairRouter.repairSafePage}?item=${Uri.encodeComponent(jsonString)}",
  366. (res) {
  367. if (res != null && res) {
  368. getRepairDetail();
  369. }
  370. });
  371. } else if (_currentStatus == 4) {
  372. RepairItem item = widget.repairItem;
  373. String jsonString = convert.jsonEncode(item);
  374. NavigatorUtils.pushResult(context,
  375. "${RepairRouter.repairSubmitPage}?item=${Uri.encodeComponent(jsonString)}",
  376. (res) {
  377. if (res != null && res) {
  378. getRepairDetail();
  379. }
  380. });
  381. } else {
  382. _selectTime();
  383. }
  384. },
  385. text:
  386. "${_currentStatus == 1 ? "接单" : _currentStatus == 2 ? "到达" : _currentStatus == 3 ? "安全确认并停梯" : "填写急修单"}",
  387. ),
  388. )))
  389. ],
  390. )),
  391. );
  392. }
  393. List<Widget> timeAxis() {
  394. List<Widget> list = [];
  395. _currentStatus = 0;
  396. list.add(LogisticsInformationItem(
  397. topColor: Colors.transparent,
  398. title: "报修时间",
  399. text: "${widget.repairItem.callerDate}"));
  400. list.add(LogisticsInformationItem(
  401. title: "派工时间", text: "${widget.repairItem.assignTime}"));
  402. if (widget.repairItem.takingTime.length == 0) {
  403. _currentStatus = 1;
  404. return list;
  405. }
  406. list.add(LogisticsInformationItem(
  407. title: "接单时间", text: "${widget.repairItem.takingTime}"));
  408. if (widget.repairItem.arriveTime.length == 0) {
  409. _currentStatus = 2;
  410. return list;
  411. }
  412. list.add(LogisticsInformationItem(
  413. title: "到达时间", text: "${widget.repairItem.arriveTime}"));
  414. if (widget.repairItem.stopDate.length == 0) {
  415. _currentStatus = 3;
  416. return list;
  417. }
  418. list.add(LogisticsInformationItem(
  419. title: "停梯时间", text: "${widget.repairItem.stopDate}"));
  420. if (widget.repairItem.recoveryDate.length == 0) {
  421. _currentStatus = 4;
  422. return list;
  423. }
  424. list.add(LogisticsInformationItem(
  425. bottomColor: Colors.transparent,
  426. title: "恢复时间",
  427. text: "${widget.repairItem.recoveryDate}"));
  428. return list;
  429. }
  430. }