maintenance_detail_page.dart 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. import 'dart:io';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:liftmanager/internal/maintenance/maintenance_router.dart';
  5. import 'package:liftmanager/internal/maintenance/model/maintenance_detail_item.dart';
  6. import 'package:liftmanager/internal/maintenance/model/maintenance_list_entity.dart';
  7. import 'package:liftmanager/internal/maintenance/model/maintenance_options_item.dart';
  8. import 'package:liftmanager/internal/maintenance/provider/maintenance_detail_page_provider.dart';
  9. import 'package:liftmanager/internal/maintenance/widgets/maintenance_options.dart';
  10. import 'package:liftmanager/net/api_service.dart';
  11. import 'package:liftmanager/res/resources.dart';
  12. import 'package:liftmanager/routers/fluro_navigator.dart';
  13. import 'package:liftmanager/utils/theme_utils.dart';
  14. import 'package:liftmanager/widgets/app_bar.dart';
  15. import 'package:liftmanager/widgets/click_item.dart';
  16. import 'package:liftmanager/widgets/selected_image.dart';
  17. import 'package:liftmanager/widgets/star_item.dart';
  18. import 'package:oktoast/oktoast.dart';
  19. import 'package:provider/provider.dart' as p;
  20. class MaintenanceDetailPage extends StatefulWidget {
  21. MaintenanceDetailPage(this.item);
  22. final MaintenanceListItem item;
  23. @override
  24. State<StatefulWidget> createState() {
  25. return MaintenanceDetailPageState();
  26. }
  27. }
  28. class MaintenanceDetailPageState extends State<MaintenanceDetailPage>
  29. with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
  30. List<Map> tabs = [
  31. {"id": 0, "name": "机房"},
  32. {"id": 1, "name": "轿顶"},
  33. {"id": 2, "name": "轿厢"},
  34. {"id": 3, "name": "层门"},
  35. {"id": 4, "name": "底坑井道"},
  36. // {"id": 5, "name": "评价"}
  37. ];
  38. MaintenanceDetailPageProvider provider = MaintenanceDetailPageProvider();
  39. TabController _tabController;
  40. PageController _pageController = PageController(initialPage: 0);
  41. TextEditingController _controller = TextEditingController();
  42. TextEditingController _controller2 = TextEditingController();
  43. MaintenanceDetailEntity item = MaintenanceDetailEntity();
  44. List<File> images = [];
  45. var mainSignImgByte;
  46. var mainSignImgByte2;
  47. Image mainSignImg = Image.asset(
  48. "assets/images/img_sign.png",
  49. width: 80,
  50. height: 80,
  51. );
  52. Image secondSign = Image.asset(
  53. "assets/images/img_sign.png",
  54. width: 80,
  55. height: 80,
  56. );
  57. @override
  58. void initState() {
  59. super.initState();
  60. tabs = [
  61. {"id": 0, "name": widget.item.category > 3 ? "第一页" : "机房"},
  62. {"id": 1, "name": widget.item.category > 3 ? "第二页" : "轿顶"},
  63. {"id": 2, "name": widget.item.category > 3 ? "第三页" : "轿厢"},
  64. {"id": 3, "name": widget.item.category > 3 ? "第四页" : "层门"},
  65. {"id": 4, "name": widget.item.category > 3 ? "第五页" : "底坑井道"}
  66. ];
  67. if (widget.item.hasEvaluate == "1") {
  68. tabs.add({"id": 5, "name": "评价"});
  69. }
  70. _tabController = new TabController(vsync: this, length: tabs.length);
  71. _getDetail();
  72. }
  73. @override
  74. void dispose() {
  75. _tabController.dispose();
  76. super.dispose();
  77. }
  78. _onPageChange(int index) {
  79. _tabController.animateTo(index);
  80. provider.setIndex(index);
  81. }
  82. Future _getDetail() async {
  83. ApiService(context: context).maintenanceRecordDetail(widget.item.recordId,
  84. onSuccess: (data) {
  85. item = data;
  86. _getOptions();
  87. setState(() {});
  88. }, onError: (code, msg) {
  89. showToast(msg);
  90. });
  91. }
  92. Future _getOptions() async {
  93. ApiService(context: context)
  94. .maintenanceOptions(widget.item.maintenanceType, item.category,
  95. onSuccess: (List<MaintenanceOptionsItem> datas) {
  96. initOptions(datas);
  97. setState(() {});
  98. }, onError: (code, msg) {
  99. showToast(msg);
  100. });
  101. }
  102. ///初始化维保项
  103. void initOptions(List<MaintenanceOptionsItem> datas) {
  104. Map<String, int> map = item.getMaintenanceOptionArr();
  105. Map<int, List<MaintenanceOptionsItem>> _optionsMap = {
  106. 1: [],
  107. 2: [],
  108. 3: [],
  109. 4: [],
  110. 5: []
  111. };
  112. if (widget.item.category < 4) {
  113. for (var i = 0; i < datas.length; ++i) {
  114. var item = datas[i];
  115. item.status = map[item.id] ?? 0;
  116. if ([1, 2, 3, 4, 5].contains(item.sort)) {
  117. if (datas[item.sort] == null) _optionsMap[item.sort] = [];
  118. _optionsMap[item.sort].add(item);
  119. provider.setOptions(_optionsMap);
  120. }
  121. }
  122. } else {
  123. for (var i = 0; i < datas.length; ++i) {
  124. var item = datas[i];
  125. item.status = map[item.id] ?? 0;
  126. int length = datas.length ~/ 5 + 1;
  127. if (i < length) {
  128. _optionsMap[1].add(item);
  129. provider.setOptions(_optionsMap);
  130. } else if (i < length * 2) {
  131. _optionsMap[2].add(item);
  132. provider.setOptions(_optionsMap);
  133. } else if (i < length * 3) {
  134. _optionsMap[3].add(item);
  135. provider.setOptions(_optionsMap);
  136. } else if (i < length * 4) {
  137. _optionsMap[4].add(item);
  138. provider.setOptions(_optionsMap);
  139. } else if (i < length * 5) {
  140. _optionsMap[5].add(item);
  141. provider.setOptions(_optionsMap);
  142. }
  143. }
  144. }
  145. }
  146. @override
  147. Widget build(BuildContext context) {
  148. return p.ChangeNotifierProvider<MaintenanceDetailPageProvider>(
  149. create: (_) => provider,
  150. child: Scaffold(
  151. appBar: MyAppBar(
  152. centerTitle: "日常保养",
  153. // actions: <Widget>[
  154. // FlatButton(
  155. // child: Text("保存", key: const Key('actionName')),
  156. // textColor: Colours.dark_text,
  157. // highlightColor: Colors.transparent,
  158. // onPressed: () {},
  159. // )
  160. // ],
  161. ),
  162. body: Column(
  163. crossAxisAlignment: CrossAxisAlignment.start,
  164. children: <Widget>[
  165. Row(
  166. children: <Widget>[
  167. Expanded(
  168. flex: 1,
  169. child: Container(
  170. // 隐藏点击效果
  171. color: ThemeUtils.getTabsBg(context),
  172. child: TabBar(
  173. onTap: (index) {
  174. if (!mounted) {
  175. return;
  176. }
  177. _pageController.jumpToPage(index);
  178. },
  179. isScrollable: true,
  180. controller: _tabController,
  181. labelStyle: TextStyles.textBold18,
  182. indicatorSize: TabBarIndicatorSize.label,
  183. // labelPadding: const EdgeInsets.only(left: 16.0),
  184. unselectedLabelColor: Colours.text_gray,
  185. labelColor: Theme.of(context).primaryColor,
  186. indicatorPadding:
  187. const EdgeInsets.only(left: 5.0, right: 5.0),
  188. tabs: tabs.map((map) {
  189. return _TabView("${map["name"]}", "", map["id"]);
  190. }).toList()),
  191. )),
  192. ],
  193. ),
  194. Gaps.line,
  195. Expanded(
  196. child: PageView.builder(
  197. key: const Key('pageView'),
  198. itemCount: tabs.length,
  199. onPageChanged: _onPageChange,
  200. controller: _pageController,
  201. itemBuilder: (BuildContext context, int index) {
  202. if (index == 5) {
  203. _controller2.text = item.evaluation.advice;
  204. return Container(
  205. color: ThemeUtils.getBackgroundColor(context),
  206. child: ListView(
  207. // crossAxisAlignment: CrossAxisAlignment.start,
  208. children: <Widget>[
  209. StarItem(
  210. title: "服务态度",
  211. starRating:
  212. item.evaluation.serviceLevel.toDouble(),
  213. ),
  214. StarItem(
  215. title: "急修满意度",
  216. starRating:
  217. item.evaluation.starLevel.toDouble(),
  218. ),
  219. Gaps.vGap8,
  220. ClickItem(title: "客户评价"),
  221. Container(
  222. color: ThemeUtils.getTabsBg(context),
  223. child: Padding(
  224. padding: const EdgeInsets.only(
  225. top: 5,
  226. left: 15.0,
  227. right: 15.0,
  228. bottom: 8.0),
  229. child: TextField(
  230. enabled: false,
  231. maxLength: 100,
  232. maxLines: 8,
  233. autofocus: false,
  234. controller: _controller2,
  235. decoration: InputDecoration(
  236. hintText: "填写现场情况描述",
  237. border: InputBorder.none,
  238. hintStyle: TextStyles.textGray14)),
  239. ),
  240. ),
  241. SizedBox(
  242. height: 8,
  243. ),
  244. ClickItem(title: "客户手写签名", content: ""),
  245. Container(
  246. height: 200,
  247. color: ThemeUtils.getTabsBg(context),
  248. alignment: Alignment.center,
  249. child: Stack(
  250. alignment: Alignment.center,
  251. children: <Widget>[
  252. Positioned(
  253. child: Text(
  254. "手写签名",
  255. style: TextStyle(
  256. fontSize: 12,
  257. color: Colours.text_gray_c),
  258. ),
  259. ),
  260. Image.network(
  261. "${item.evaluation.imgUrl}",
  262. width: 150,
  263. height: 150,
  264. fit: BoxFit.fill,
  265. ),
  266. ],
  267. ),
  268. ),
  269. ]));
  270. } else if (index == 4) {
  271. _controller.text = item.maintenanceAdvice;
  272. return ListView(
  273. children: <Widget>[
  274. Container(
  275. color: ThemeUtils.getBackgroundColor(context),
  276. child: MaintenanceOptions(
  277. index: index,
  278. items: provider.optionsMap[index + 1],
  279. type: widget.item.maintenanceType,
  280. liftType: widget.item.liftType,
  281. )),
  282. Container(
  283. color: ThemeUtils.getBackgroundColor(context),
  284. child: uploadView()),
  285. // child: MaintenanceOptions(index: index,items:_optionsMap[index+1],type: widget.type, liftType: widget.liftType,));
  286. ],
  287. );
  288. } else {
  289. return Container(
  290. color: ThemeUtils.getBackgroundColor(context),
  291. child: MaintenanceOptions(
  292. index: index,
  293. items: provider.optionsMap[index + 1],
  294. type: widget.item.maintenanceType,
  295. liftType: widget.item.liftType,
  296. ));
  297. }
  298. },
  299. ),
  300. )
  301. ],
  302. ),
  303. ));
  304. }
  305. ///第五页底部
  306. Widget uploadView() {
  307. bool isDark = ThemeUtils.isDark(context);
  308. return Container(
  309. padding: EdgeInsets.fromLTRB(15, 5, 15, 5),
  310. decoration: BoxDecoration(
  311. borderRadius: BorderRadius.circular(6),
  312. ),
  313. child: Column(
  314. crossAxisAlignment: CrossAxisAlignment.start,
  315. children: <Widget>[
  316. ClickItem(
  317. title: "计划日期",
  318. content: "${item.planDate}",
  319. ),
  320. ClickItem(
  321. title: "停梯时间",
  322. content: "${item.stopDate}",
  323. ),
  324. ClickItem(
  325. title: "恢复时间",
  326. content: "${item.recoveryDate}",
  327. ),
  328. ClickItem(
  329. title: "保养建议",
  330. hintText: "",
  331. ),
  332. Container(
  333. color: isDark ? Colours.dark_bg_gray : Colors.white,
  334. child: Padding(
  335. padding: const EdgeInsets.only(
  336. top: 5, left: 15.0, right: 15.0, bottom: 8.0),
  337. child: TextField(
  338. maxLength: 30,
  339. maxLines: 3,
  340. // autofocus: false,
  341. enabled: false,
  342. controller: _controller,
  343. // keyboardType: widget.keyboardType,
  344. //style: TextStyles.textDark14,
  345. decoration: InputDecoration(
  346. hintText: "${item.maintenanceAdvice}",
  347. border: InputBorder.none,
  348. hintStyle: TextStyles.textGray14)),
  349. ),
  350. ),
  351. ClickItem(
  352. title: "保养图片",
  353. hintText: "",
  354. ),
  355. Container(
  356. color: isDark ? Colours.dark_bg_gray : Colors.white,
  357. child: GridView.builder(
  358. shrinkWrap: true,
  359. padding: const EdgeInsets.fromLTRB(8.0, 12, 8.0, 12.0),
  360. physics: NeverScrollableScrollPhysics(),
  361. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  362. crossAxisCount: 3, childAspectRatio: 1.18),
  363. itemCount: item.status == "2"
  364. ? item.mtRecordImgs.length
  365. : (images.length >= 9 ? 9 : images.length + 1),
  366. itemBuilder: (_, index) {
  367. return Stack(
  368. children: <Widget>[
  369. Center(
  370. child: item.status == "2"
  371. ? GestureDetector(
  372. onTap: () {
  373. NavigatorUtils.push(
  374. context,
  375. "${MaintenanceRouter.viewImage}?edit=0&img=" +
  376. Uri.encodeComponent(
  377. item.mtRecordImgs[index].imgUrl));
  378. },
  379. child: Image.network(
  380. "${item.mtRecordImgs[index].imgUrl}",
  381. width: 80,
  382. height: 80,
  383. fit: BoxFit.fill,
  384. ))
  385. : SelectedImage(
  386. image: index < images.length
  387. ? images[index]
  388. : null,
  389. onTap: () {}),
  390. )
  391. ],
  392. );
  393. },
  394. )),
  395. SizedBox(
  396. height: 8,
  397. ),
  398. ClickItem(
  399. title: "负责人签名",
  400. hintText: "",
  401. ),
  402. Container(
  403. padding: EdgeInsets.all(15),
  404. color: isDark ? Colours.dark_bg_gray : Colors.white,
  405. child: Row(
  406. mainAxisAlignment: MainAxisAlignment.start,
  407. children: <Widget>[
  408. GestureDetector(
  409. onTap: () {},
  410. child: Container(
  411. color: Colors.white,
  412. alignment: Alignment.center,
  413. child: Stack(
  414. alignment: Alignment.center,
  415. children: <Widget>[
  416. Positioned(
  417. child: Text(
  418. "主要维保人员",
  419. style: TextStyle(
  420. fontSize: 12, color: Colours.text_gray_c),
  421. )),
  422. Image.network(
  423. "${item.signatureImg1}",
  424. width: 150,
  425. height: 150,
  426. fit: BoxFit.fill,
  427. ),
  428. ],
  429. ),
  430. )),
  431. SizedBox(
  432. width: 15,
  433. ),
  434. Offstage(
  435. offstage: item.signatureImg2?.length == 0,
  436. child: GestureDetector(
  437. onTap: () {},
  438. child: Container(
  439. color: Colors.white,
  440. alignment: Alignment.center,
  441. child: Stack(
  442. alignment: Alignment.center,
  443. children: <Widget>[
  444. Positioned(
  445. child: Text(
  446. "次要维保人员",
  447. style: TextStyle(
  448. fontSize: 12, color: Colours.text_gray_c),
  449. )),
  450. Image.network(
  451. "${item.signatureImg2}",
  452. width: 150,
  453. height: 150,
  454. fit: BoxFit.fill,
  455. ),
  456. ],
  457. ),
  458. )))
  459. ],
  460. ))
  461. ],
  462. ),
  463. );
  464. }
  465. @override
  466. bool get wantKeepAlive => true;
  467. }
  468. class _TabView extends StatelessWidget {
  469. const _TabView(this.tabName, this.tabSub, this.index);
  470. final String tabName;
  471. final String tabSub;
  472. final int index;
  473. @override
  474. Widget build(BuildContext context) {
  475. return p.Consumer<MaintenanceDetailPageProvider>(
  476. builder: (_, provider, child) {
  477. return Tab(
  478. child: SizedBox(
  479. child: Row(
  480. crossAxisAlignment: CrossAxisAlignment.center,
  481. mainAxisAlignment: MainAxisAlignment.center,
  482. children: <Widget>[
  483. Text(
  484. tabName,
  485. style: TextStyle(fontSize: 15),
  486. ),
  487. Offstage(
  488. offstage: provider.index != index,
  489. child: Padding(
  490. padding: const EdgeInsets.only(top: 1.0),
  491. child: Text(tabSub,
  492. style: TextStyle(fontSize: Dimens.font_sp12)),
  493. )),
  494. ],
  495. ),
  496. ));
  497. },
  498. );
  499. }
  500. }