question_detail.dart 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. import 'dart:math';
  2. import 'package:flustars/flustars.dart' as FlutterStars;
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_screenutil/flutter_screenutil.dart';
  5. import 'package:liftmanager/common/common.dart';
  6. import 'package:liftmanager/internal/account/account_router.dart';
  7. import 'package:liftmanager/internal/bbs/model/question_detail.dart';
  8. import 'package:liftmanager/internal/bbs/page/tab/question/question_pay.dart';
  9. import 'package:liftmanager/internal/wode/wode_router.dart';
  10. import 'package:liftmanager/net/api_service.dart';
  11. import 'package:liftmanager/res/iconfont.dart';
  12. import 'package:liftmanager/res/resources.dart';
  13. import 'package:liftmanager/routers/fluro_navigator.dart';
  14. import 'package:liftmanager/utils/fast_notification.dart';
  15. import 'package:liftmanager/utils/theme_utils.dart';
  16. import 'package:liftmanager/utils/time_format.dart';
  17. import 'package:liftmanager/utils/toast.dart';
  18. import 'package:liftmanager/utils/utils.dart';
  19. import 'package:liftmanager/widgets/app_bar.dart';
  20. import 'package:liftmanager/widgets/bbs_content.dart';
  21. import 'package:liftmanager/widgets/load_image.dart';
  22. import 'package:liftmanager/widgets/preview_images.dart';
  23. class QuestionDetail extends StatefulWidget {
  24. QuestionDetail(this.id);
  25. final String id;
  26. @override
  27. State<StatefulWidget> createState() {
  28. return QuestionDetailState();
  29. }
  30. }
  31. class QuestionDetailState extends State<QuestionDetail> {
  32. bool _hasData = false;
  33. QuestionDetailModel detailObj;
  34. List<String> listPreview = [];
  35. double vipPrice;
  36. @override
  37. void initState() {
  38. super.initState();
  39. getQuestionDetail();
  40. getVipPrice();
  41. FastNotification.addListener("initIsPay", (initThisUserMoney) {
  42. if (mounted) {
  43. getQuestionDetail();
  44. setState(() {});
  45. }
  46. });
  47. }
  48. Future getQuestionDetail() async {
  49. await NewApiService().getQuestionDetail(int.parse(widget.id),
  50. onSuccess: (res) {
  51. if (res != null) {
  52. _hasData = true;
  53. detailObj = res;
  54. listPreview = [];
  55. setState(() {});
  56. detailObj.imgs?.split(",")?.forEach((element) {
  57. listPreview.add(Utils.getImagePath(element, isWater: true));
  58. });
  59. }
  60. }, onError: (code, msg) {
  61. toasts(msg);
  62. });
  63. }
  64. void getVipPrice() {
  65. NewApiService().getVipFeeList('1', onSuccess: (res) {
  66. setState(() {
  67. vipPrice = res.records[0].price;
  68. });
  69. }, onError: (code, msg) {
  70. toasts(msg);
  71. });
  72. }
  73. showAlertEvent() {
  74. showAlert(
  75. context,
  76. "提示",
  77. "确定登录?",
  78. "确定",
  79. () {
  80. NavigatorUtils.push(context, AccountRouter.loginPage, clearStack: true);
  81. },
  82. txt2: "取消",
  83. onPre2: () {
  84. NavigatorUtils.goBack(context);
  85. },
  86. );
  87. }
  88. Future changeLike() async {
  89. await NewApiService().questionLike(detailObj.id, 1, onSuccess: (res) {
  90. toasts("点赞成功");
  91. getQuestionDetail();
  92. }, onError: (code, msg) {
  93. toasts(msg);
  94. });
  95. }
  96. Future changeFav() async {
  97. await NewApiService().questionFav(detailObj.id, 1, onSuccess: (res) {
  98. toasts("收藏成功");
  99. initCollect();
  100. getQuestionDetail();
  101. }, onError: (code, msg) {
  102. toasts(msg);
  103. });
  104. }
  105. Future cancelLike() async {
  106. await NewApiService().questionLikeCancel(detailObj.id, 1, onSuccess: (res) {
  107. toasts("取消点赞成功");
  108. getQuestionDetail();
  109. }, onError: (code, msg) {
  110. toasts(msg);
  111. });
  112. }
  113. Future cancelFav() async {
  114. await NewApiService().questionFavCancel(detailObj.id, 1, onSuccess: (res) {
  115. toasts("取消收藏成功");
  116. initCollect();
  117. getQuestionDetail();
  118. }, onError: (code, msg) {
  119. toasts(msg);
  120. });
  121. }
  122. initCollect() {
  123. String collectInit = randomInt(1111, 9999).toString() +
  124. DateTime.now().millisecondsSinceEpoch.toString();
  125. FastNotification.push("collectAction", collectInit);
  126. }
  127. randomInt(int min, int max) {
  128. return new Random().nextInt(max) % (max - min + 1) + min;
  129. }
  130. @override
  131. Widget build(BuildContext context) {
  132. double width = MediaQuery.of(context).size.width;
  133. _clipText({title, bgcolor, textcolor}) {
  134. return ClipRRect(
  135. borderRadius: BorderRadius.all(Radius.circular(3)),
  136. child: Container(
  137. padding: EdgeInsets.only(left: 5, right: 5, top: 2, bottom: 2),
  138. color: bgcolor,
  139. alignment: Alignment.center,
  140. // color: Color(0xFD5D61),
  141. child: Text(
  142. title,
  143. style: TextStyle(fontSize: 11, color: textcolor),
  144. ),
  145. ),
  146. );
  147. }
  148. return Scaffold(
  149. resizeToAvoidBottomPadding: false, //不让键盘弹上去
  150. appBar: MyAppBar(
  151. centerTitle: "案例详情",
  152. ),
  153. body: _hasData
  154. ? Stack(
  155. children: <Widget>[
  156. Container(
  157. child: ListView(
  158. physics: detailObj.isTip != 1
  159. ? const NeverScrollableScrollPhysics()
  160. : null,
  161. children: <Widget>[
  162. Column(
  163. mainAxisAlignment: MainAxisAlignment.start,
  164. crossAxisAlignment: CrossAxisAlignment.start,
  165. children: <Widget>[
  166. Container(
  167. width: width,
  168. padding: EdgeInsets.symmetric(
  169. horizontal: 10, vertical: 10),
  170. decoration: BoxDecoration(
  171. border: Border(
  172. bottom:
  173. BorderSide(width: 0.5, color: Colours.line),
  174. ),
  175. ),
  176. child: Column(
  177. mainAxisAlignment: MainAxisAlignment.start,
  178. crossAxisAlignment: CrossAxisAlignment.start,
  179. children: <Widget>[
  180. Text(
  181. detailObj.title ?? "",
  182. style: TextStyle(
  183. fontSize: 16,
  184. fontWeight: FontWeight.w500,
  185. color: Color(0xff333333),
  186. ),
  187. textAlign: TextAlign.start,
  188. maxLines: 1,
  189. overflow: TextOverflow.ellipsis,
  190. ),
  191. SizedBox(
  192. height: 10,
  193. ),
  194. Row(
  195. children: [
  196. _clipText(
  197. title: detailObj.brandName ?? "",
  198. bgcolor:
  199. Color.fromRGBO(67, 141, 250, .16),
  200. textcolor: Color(0xFF5887FF)),
  201. Expanded(child: Container()),
  202. Text(
  203. "${detailObj.browseNum ?? "0"}浏览·${detailObj.likeNum ?? "0"}赞",
  204. textAlign: TextAlign.right,
  205. style: TextStyle(
  206. color: Color(0xFFCCCCCC),
  207. fontSize: 11,
  208. ),
  209. )
  210. ],
  211. ),
  212. ]),
  213. ),
  214. Container(
  215. padding: EdgeInsets.symmetric(
  216. horizontal: 10, vertical: 10),
  217. child: Row(
  218. children: <Widget>[
  219. Container(
  220. child: ClipRRect(
  221. borderRadius: BorderRadius.circular(16),
  222. child: LoadNetworkImage(
  223. detailObj.avatarUrl,
  224. // fit: BoxFit.cover,
  225. width: 32,
  226. height: 32,
  227. ),
  228. )),
  229. Container(
  230. padding: EdgeInsets.only(left: 5),
  231. child: Row(
  232. // crossAxisAlignment: CrossAxisAlignment.start,
  233. children: <Widget>[
  234. Text(
  235. detailObj.userName ?? "",
  236. style: TextStyle(
  237. fontSize: 14,
  238. color: Color(0xff555A64),
  239. ),
  240. ),
  241. SizedBox(
  242. width: 5,
  243. ),
  244. _clipText(
  245. title: 'lv1',
  246. bgcolor:
  247. Color.fromRGBO(253, 93, 97, 1),
  248. textcolor: Colors.white),
  249. ],
  250. ),
  251. )
  252. ],
  253. ),
  254. ),
  255. Container(
  256. padding: EdgeInsets.symmetric(horizontal: 10),
  257. child: Text(
  258. '${DateUtils().getFormartData(timeSamp: detailObj.createTime, format: 'yyyy-MM-dd HH:mm:ss')} 发布',
  259. style: TextStyle(
  260. fontSize: 12, color: Color(0xff989898)),
  261. ),
  262. ),
  263. SizedBox(
  264. height: 10,
  265. ),
  266. Divider(
  267. thickness: 0.5,
  268. ),
  269. Column(
  270. crossAxisAlignment: CrossAxisAlignment.start,
  271. mainAxisAlignment: MainAxisAlignment.start,
  272. children: <Widget>[
  273. Row(
  274. children: [
  275. Container(
  276. width: ScreenUtil().setWidth(2),
  277. height: ScreenUtil().setHeight(13),
  278. color: Color(0xFF568AFF),
  279. ),
  280. Container(
  281. padding: EdgeInsets.only(
  282. left: ScreenUtil().setWidth(10),
  283. top: ScreenUtil().setHeight(6),
  284. bottom: ScreenUtil().setWidth(5)),
  285. child: Text(
  286. "问题描述",
  287. style: TextStyle(
  288. fontSize: 15,
  289. color: Color(0xff333333),
  290. ),
  291. textAlign: TextAlign.left,
  292. ),
  293. ),
  294. ],
  295. ),
  296. Container(
  297. padding: EdgeInsets.symmetric(
  298. horizontal: 10, vertical: 10),
  299. child: Text(
  300. detailObj.expression ?? "",
  301. style: TextStyle(
  302. fontSize: 13,
  303. color: Color(0xff333333),
  304. ),
  305. textAlign: TextAlign.left,
  306. ),
  307. ),
  308. ],
  309. ),
  310. SizedBox(
  311. height: 6,
  312. child: Container(
  313. color: ThemeUtils.getDialogTextFieldColor(
  314. context)),
  315. ),
  316. Column(
  317. crossAxisAlignment: CrossAxisAlignment.start,
  318. mainAxisAlignment: MainAxisAlignment.start,
  319. children: <Widget>[
  320. Row(
  321. children: [
  322. Container(
  323. // margin: EdgeInsets.only(
  324. // top: ScreenUtil().setHeight(10)),
  325. width: ScreenUtil().setWidth(2),
  326. height: ScreenUtil().setHeight(13),
  327. color: Color(0xFF568AFF),
  328. ),
  329. Container(
  330. padding: EdgeInsets.only(
  331. left: ScreenUtil().setWidth(10),
  332. top: ScreenUtil().setHeight(6),
  333. bottom: ScreenUtil().setWidth(5)),
  334. child: Text(
  335. "解决方法",
  336. style: TextStyle(
  337. fontSize: 15,
  338. color: Color(0xff333333),
  339. ),
  340. textAlign: TextAlign.left,
  341. ),
  342. ),
  343. ],
  344. ),
  345. Container(
  346. padding: EdgeInsets.symmetric(
  347. horizontal: 10, vertical: 10),
  348. child: Text(
  349. detailObj.solution ?? "",
  350. style: TextStyle(
  351. fontSize: 13,
  352. color: Color(detailObj.isTip != 1
  353. ? 0x0c333333
  354. : 0xff333333),
  355. ),
  356. textAlign: TextAlign.left,
  357. ),
  358. )
  359. ],
  360. ),
  361. if (detailObj.isTip == 1)
  362. Container(
  363. padding: EdgeInsets.only(
  364. top: ScreenUtil().setWidth(5),
  365. left: ScreenUtil().setWidth(15),
  366. right: ScreenUtil().setWidth(15)),
  367. child: Wrap(
  368. spacing: 6,
  369. alignment: WrapAlignment.spaceBetween,
  370. crossAxisAlignment:
  371. WrapCrossAlignment.center,
  372. children: detailObj.imgs != null &&
  373. detailObj.imgs.isNotEmpty
  374. ? List<Widget>.from(detailObj.imgs
  375. .split(",")
  376. .asMap()
  377. .keys
  378. .map((subindex) {
  379. // print(item);
  380. return Container(
  381. padding: subindex <
  382. detailObj.imgs
  383. .split(",")
  384. .length -
  385. 1
  386. ? EdgeInsets.only(right: 6)
  387. : EdgeInsets.only(right: 0),
  388. // color:Colors.red,
  389. // decoration: BoxDecoration(
  390. // borderRadius: BorderRadius.circular(20.0),
  391. // ),
  392. child: GestureDetector(
  393. onTap: () {
  394. Navigator.of(context).push(
  395. new FadeRoute(
  396. page:
  397. PhotoViewGalleryScreen(
  398. images:
  399. listPreview, //传入图片list
  400. index:
  401. subindex, //传入当前点击的图片的index
  402. // heroTag: img,//传入当前点击的图片的hero tag (可选)
  403. ),
  404. ),
  405. );
  406. },
  407. child: ClipRRect(
  408. borderRadius:
  409. BorderRadius.circular(10),
  410. child: LoadNetworkImage(
  411. detailObj.imgs
  412. .split(",")[subindex],
  413. // height: width/375*75,
  414. height: ScreenUtil()
  415. .setWidth(80),
  416. width: ScreenUtil()
  417. .setWidth(80),
  418. isWater: true,
  419. ),
  420. ),
  421. ),
  422. );
  423. }).toList())
  424. : <Widget>[])),
  425. SizedBox(
  426. height: 70,
  427. ),
  428. ],
  429. ),
  430. ])),
  431. if (detailObj.isTip != 1)
  432. Positioned(
  433. bottom: ScreenUtil().setHeight(50),
  434. left: 0,
  435. height: ScreenUtil().setHeight(260),
  436. width: width,
  437. child: InkWell(
  438. child: Container(
  439. // color: Colors.red,
  440. decoration: BoxDecoration(
  441. gradient: LinearGradient(
  442. colors: [
  443. Color(0x66FFFFFF),
  444. Color(0xFFFFFFFF),
  445. ],
  446. begin: Alignment.topCenter,
  447. end: Alignment.bottomCenter),
  448. ),
  449. child: Column(
  450. mainAxisAlignment: MainAxisAlignment.center,
  451. children: [
  452. Stack(
  453. overflow: Overflow.visible,
  454. children: [
  455. GestureDetector(
  456. onTap: () {
  457. NavigatorUtils.push(
  458. context, '${WodeRouter.vip}?id=');
  459. },
  460. child: Container(
  461. width: 50,
  462. height: 50,
  463. decoration: BoxDecoration(
  464. gradient: LinearGradient(colors: [
  465. Color(0xffE6C8A0),
  466. Color(0xffDCB885)
  467. ]),
  468. borderRadius: BorderRadius.circular(25),
  469. ),
  470. child: Icon(
  471. Iconfont.huiyuan101,
  472. color: Colors.white,
  473. ),
  474. ),
  475. ),
  476. Positioned(
  477. top: 0,
  478. left: 30,
  479. child: Container(
  480. padding: EdgeInsets.all(2),
  481. color: Color(0xffF95046),
  482. child: Text(
  483. '最低仅需${vipPrice}元/月',
  484. style: TextStyle(
  485. color: Colors.white, fontSize: 9),
  486. ),
  487. ),
  488. ),
  489. ],
  490. ),
  491. Text(
  492. '立即成为会员,查看更多内容',
  493. style: TextStyle(
  494. fontSize: 13,
  495. color: Color(0xff333333),
  496. ),
  497. )
  498. ],
  499. )),
  500. ),
  501. ),
  502. Positioned(
  503. bottom: 0,
  504. left: 0,
  505. child: Container(
  506. height: ScreenUtil().setHeight(50),
  507. color: Colors.white,
  508. width: width,
  509. child: Row(children: <Widget>[
  510. Container(
  511. width: 60,
  512. child: GestureDetector(
  513. onTap: () {
  514. if (FlutterStars.SpUtil.getString(
  515. Constant.userId) ==
  516. "-1") {
  517. showAlertEvent();
  518. } else {
  519. if (detailObj.isLike == 1) {
  520. // cancelLike(2);
  521. cancelLike();
  522. } else {
  523. // changeLike(2);
  524. changeLike();
  525. }
  526. }
  527. },
  528. child: Column(
  529. mainAxisAlignment: MainAxisAlignment.center,
  530. children: <Widget>[
  531. Icon(
  532. // &#xe610;
  533. // : 0xe608,
  534. // &#xe6f8;
  535. detailObj.isLike == 1
  536. ? const IconData(0xe610,
  537. fontFamily: "Iconfont")
  538. : const IconData(0xe6f8,
  539. fontFamily: "Iconfont"),
  540. size: 20,
  541. color: Color(detailObj.isLike == 1
  542. ? 0xff5589FF
  543. : 0xff555A64),
  544. ),
  545. Text(
  546. detailObj.isLike == 1 ? "已点赞" : "点赞",
  547. style: TextStyle(
  548. color: Color(detailObj.isLike == 1
  549. ? 0xff5589FF
  550. : 0xff555A64),
  551. fontSize: 12),
  552. textAlign: TextAlign.start,
  553. ),
  554. ])),
  555. ),
  556. Container(
  557. width: 60,
  558. child: GestureDetector(
  559. onTap: () {
  560. if (FlutterStars.SpUtil.getString(
  561. Constant.userId) ==
  562. "-1") {
  563. showAlertEvent();
  564. } else {
  565. if (detailObj.isFavorite == 1) {
  566. // cancelLike(3);
  567. cancelFav();
  568. } else {
  569. // changeLike(3);
  570. changeFav();
  571. }
  572. }
  573. },
  574. child: Container(
  575. child: Column(
  576. mainAxisAlignment:
  577. MainAxisAlignment.center,
  578. children: <Widget>[
  579. Icon(
  580. // : 0xe604,
  581. detailObj.isFavorite == 1
  582. ? const IconData(0xe62a,
  583. fontFamily: "Iconfont")
  584. : const IconData(0xe6b7,
  585. fontFamily: "Iconfont"),
  586. size: 20,
  587. color: Color(detailObj.isFavorite == 1
  588. ? 0xff5589FF
  589. : 0xff555a64),
  590. ),
  591. Text(
  592. detailObj.isFavorite == 1 ? "已收藏" : "收藏",
  593. style: TextStyle(
  594. color: Color(detailObj.isFavorite == 1
  595. ? 0xff5589FF
  596. : 0xff555A64),
  597. fontSize: 12,
  598. ),
  599. textAlign: TextAlign.start,
  600. ),
  601. ])),
  602. ),
  603. ),
  604. Expanded(
  605. child: ClipRRect(
  606. borderRadius: BorderRadius.circular(22),
  607. child: Container(
  608. height: 44,
  609. // width: width / 2,
  610. color: Color(0xff5589FF),
  611. child: FlatButton(
  612. // padding: EdgeInsets.all(15.0),
  613. child: RichText(
  614. text: TextSpan(
  615. text: '打赏',
  616. style: TextStyle(
  617. fontSize: 16.0,
  618. fontWeight: FontWeight.w500),
  619. children: <TextSpan>[
  620. TextSpan(
  621. text: '(可查看全部内容)',
  622. style: TextStyle(
  623. fontSize: 11.0,
  624. )),
  625. ]),
  626. ),
  627. textColor: Colors.white,
  628. onPressed: () {
  629. if (FlutterStars.SpUtil.getString(
  630. Constant.userId) ==
  631. "-1") {
  632. showAlertEvent();
  633. } else {
  634. Navigator.push(
  635. context,
  636. MaterialPageRoute(
  637. builder: (context) => QuestionPay(
  638. detailObj.id.toString(),
  639. "question",
  640. detailObj.userName,
  641. detailObj.avatarUrl,
  642. expert: detailObj.expert
  643. .toString(),
  644. )));
  645. // NavigatorUtils.push(context,
  646. // "${BbsRouter.questionPay}?id=${detailObj.id}&userModel=${[detailObj.avatarUrl]}&type=question&name=${Uri.encodeComponent(detailObj.userName)}");
  647. }
  648. },
  649. ),
  650. ),
  651. )),
  652. SizedBox(
  653. width: 10,
  654. )
  655. ])))
  656. ],
  657. )
  658. : Center(
  659. child: Text("正在加载..."),
  660. ),
  661. );
  662. }
  663. }
  664. class FadeRoute extends PageRouteBuilder {
  665. final Widget page;
  666. FadeRoute({this.page})
  667. : super(
  668. pageBuilder: (
  669. BuildContext context,
  670. Animation<double> animation,
  671. Animation<double> secondaryAnimation,
  672. ) =>
  673. page,
  674. transitionsBuilder: (
  675. BuildContext context,
  676. Animation<double> animation,
  677. Animation<double> secondaryAnimation,
  678. Widget child,
  679. ) =>
  680. FadeTransition(
  681. opacity: animation,
  682. child: child,
  683. ),
  684. );
  685. }