repair_detail_page.dart 17 KB

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