position_list.dart 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. import 'dart:async';
  2. import 'dart:io';
  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:city_pickers/city_pickers.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:flutter_picker/flutter_picker.dart';
  8. import 'package:flutter_screenutil/flutter_screenutil.dart';
  9. import 'package:liftmanager/internal/bbs/bbs_router.dart';
  10. import 'package:liftmanager/internal/bbs/model/mix_model.dart';
  11. import 'package:liftmanager/internal/bbs/presenter/position_list_presenter.dart';
  12. import 'package:liftmanager/internal/search/presenter/base_list_provider.dart';
  13. import 'package:liftmanager/internal/wode/model/table_dicts_model.dart';
  14. import 'package:liftmanager/mvp/base_page_state.dart';
  15. import 'package:liftmanager/net/api_service.dart';
  16. import 'package:liftmanager/res/resources.dart';
  17. import 'package:liftmanager/routers/fluro_navigator.dart';
  18. import 'package:liftmanager/utils/toast.dart';
  19. import 'package:liftmanager/widgets/app_search_bar.dart';
  20. import 'package:liftmanager/widgets/bbs_content.dart';
  21. import 'package:liftmanager/widgets/my_refresh_list.dart';
  22. import 'package:liftmanager/widgets/state_layout.dart';
  23. import 'package:permission_handler/permission_handler.dart';
  24. import 'package:provider/provider.dart';
  25. class PositionList extends StatefulWidget {
  26. String city;
  27. String provinceName;
  28. PositionList({this.city, this.provinceName});
  29. @override
  30. PositionListState createState() => PositionListState();
  31. }
  32. class PositionListState
  33. extends BasePageState<PositionList, PositionListPresenterSeconds> {
  34. // Map<String, Object> _locationResult;
  35. // StreamSubscription<Map<String, Object>> _locationListener;
  36. // AmapLocationFlutterPlugin _locationPlugin = new AmapLocationFlutterPlugin();
  37. BaseListProvider<Records> provider = BaseListProvider<Records>();
  38. int _page = 1;
  39. List<dynamic> categoryList = [
  40. {"title": "地址", "label": "地点"},
  41. {"title": "所属职位", "label": "所属职位"},
  42. {"title": "薪资范围", "label": "薪资范围"}
  43. ];
  44. ScrollController _scrollController = new ScrollController();
  45. @override
  46. void initState() {
  47. provider.setStateTypeNotNotify(StateType.loading);
  48. super.initState();
  49. cityName = widget.city;
  50. provinceName = widget.provinceName;
  51. categoryList[0]['label'] = widget.city;
  52. _onRefresh();
  53. ///移除定位监听
  54. // if (null != _locationListener) {
  55. // _locationListener.cancel();
  56. // }
  57. // ///销毁定位
  58. // if (null != _locationPlugin) {
  59. // _locationPlugin.destroy();
  60. // }
  61. // _locationListener = _locationPlugin
  62. // .onLocationChanged()
  63. // .listen((Map<String, Object> result) {
  64. // setState(() {
  65. // _locationPlugin.stopLocation();
  66. // _locationResult = result;
  67. // print(_locationResult["city"]);
  68. // print(_locationResult["province"]);
  69. // // address latitude longitude
  70. // provinceName = _locationResult["province"];
  71. // categoryList[0]['label'] = _locationResult["city"];
  72. // _onRefresh();
  73. // setState(() {});
  74. // });
  75. // });
  76. // getInitLocation();
  77. getJobClass();
  78. }
  79. // // 获取定位权限
  80. // Future<bool> requestPermission() async {
  81. // final permissions = await PermissionHandler()
  82. // .requestPermissions([PermissionGroup.location]);
  83. // if (permissions[PermissionGroup.location] == PermissionStatus.granted) {
  84. // return true;
  85. // } else {
  86. // toasts('需要定位权限!');
  87. // _onRefresh();
  88. // setState(() {});
  89. // return false;
  90. // }
  91. // }
  92. // getInitLocation() async {
  93. // if (await requestPermission()) {
  94. // if (null != _locationPlugin) {
  95. // ///开始定位之前设置定位参数
  96. // _setLocationOption();
  97. // // _locationPlugin.getSystemAccuracyAuthorization();
  98. // _locationPlugin.startLocation();
  99. // }
  100. // }
  101. // }
  102. // void _setLocationOption() {
  103. // if (null != _locationPlugin) {
  104. // AMapLocationOption locationOption = new AMapLocationOption();
  105. // ///是否单次定位
  106. // locationOption.onceLocation = true;
  107. // ///是否需要返回逆地理信息
  108. // locationOption.needAddress = true;
  109. // ///逆地理信息的语言类型
  110. // locationOption.geoLanguage = GeoLanguage.DEFAULT;
  111. // ///设置Android端连续定位的定位间隔
  112. // locationOption.locationInterval = 20000;
  113. // locationOption.desiredLocationAccuracyAuthorizationMode =
  114. // AMapLocationAccuracyAuthorizationMode.ReduceAccuracy;
  115. // ///设置Android端的定位模式<br>
  116. // ///可选值:<br>
  117. // ///<li>[AMapLocationMode.Battery_Saving]</li>
  118. // ///<li>[AMapLocationMode.Device_Sensors]</li>
  119. // ///<li>[AMapLocationMode.Hight_Accuracy]</li>
  120. // locationOption.locationMode = AMapLocationMode.Hight_Accuracy;
  121. // // locationOption.requestAccuracyAuthorization();
  122. // ///设置iOS端的定位最小更新距离<br>
  123. // locationOption.distanceFilter = -1;
  124. // ///设置iOS端期望的定位精度
  125. // /// 可选值:<br>
  126. // /// <li>[DesiredAccuracy.Best] 最高精度</li>
  127. // /// <li>[DesiredAccuracy.BestForNavigation] 适用于导航场景的高精度 </li>
  128. // /// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
  129. // /// <li>[DesiredAccuracy.Kilometer] 1000米</li>
  130. // /// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
  131. // locationOption.desiredAccuracy = DesiredAccuracy.Best;
  132. // ///设置iOS端是否允许系统暂停定位
  133. // locationOption.pausesLocationUpdatesAutomatically = false;
  134. // ///将定位参数设置给定位插件
  135. // _locationPlugin.setLocationOption(locationOption);
  136. // }
  137. // }
  138. @override
  139. void dispose() {
  140. _scrollController.dispose();
  141. // ///移除定位监听
  142. // if (null != _locationListener) {
  143. // _locationListener.cancel();
  144. // }
  145. // ///销毁定位
  146. // if (null != _locationPlugin) {
  147. // _locationPlugin.destroy();
  148. // }
  149. super.dispose();
  150. }
  151. List<TableDictsModel> jobClass = [];
  152. // 获取招聘职位分类
  153. Future getJobClass() async {
  154. NewApiService().queryConstant('recruitment_info', 'job', onSuccess: (res) {
  155. jobClass = res;
  156. setState(() {});
  157. }, onError: (code, msg) {
  158. toasts(msg);
  159. });
  160. }
  161. Result addressResult = new Result();
  162. String provinceName;
  163. String cityName;
  164. // 选择地址
  165. void _clickEventFunc() async {
  166. Result tempResult = await CityPickers.showCityPicker(
  167. theme: ThemeData.light(),
  168. context: context,
  169. showType: ShowType.pc,
  170. cancelWidget: GestureDetector(
  171. onTap: () {
  172. provinceName = null;
  173. cityName = null;
  174. categoryList[0]['label'] = "不限地区";
  175. Navigator.pop(context);
  176. _onRefresh();
  177. setState(() {});
  178. },
  179. child: Text(
  180. "不限地区",
  181. style: TextStyle(
  182. color: Color(0xffff0000),
  183. ),
  184. ),
  185. ),
  186. locationCode: addressResult != null
  187. ? addressResult.areaId ??
  188. addressResult.cityId ??
  189. addressResult.provinceId
  190. : null, // 初始化地址信息
  191. );
  192. if (tempResult != null) {
  193. print(tempResult);
  194. addressResult = tempResult;
  195. if (tempResult.cityName == "市辖区") {
  196. cityName = "重庆城区";
  197. } else {
  198. cityName = tempResult.cityName;
  199. }
  200. provinceName = tempResult.provinceName;
  201. if (cityName == "县") {
  202. categoryList[0]['label'] = "重庆市-县";
  203. } else {
  204. categoryList[0]['label'] = cityName;
  205. }
  206. _onRefresh();
  207. setState(() {});
  208. }
  209. }
  210. changTypeClass(item, index) {
  211. if (index == 0) {
  212. // 选择地址
  213. _clickEventFunc();
  214. } else if (index == 1) {
  215. // 所属职位
  216. showPositionModal(context);
  217. } else if (index == 2) {
  218. // 薪资范围
  219. showSalaryModal(context);
  220. }
  221. setState(() {});
  222. }
  223. // 所属职位
  224. List jobClassData = [];
  225. String jobSelected;
  226. showPositionModal(BuildContext context) {
  227. jobClassData.clear();
  228. jobClassData.add("不限");
  229. for (var i = 0; i < jobClass.length; i++) {
  230. jobClassData.add(jobClass[i].value);
  231. }
  232. new Picker(
  233. // selecteds:[0],
  234. cancelText: "取消",
  235. confirmText: "确认",
  236. adapter: PickerDataAdapter<String>(
  237. pickerdata: jobClassData,
  238. ),
  239. changeToFirst: true,
  240. hideHeader: false,
  241. onConfirm: (Picker picker, List value) {
  242. if (value[0] == 0) {
  243. jobSelected = null;
  244. } else {
  245. jobSelected = picker.getSelectedValues()[0];
  246. print(jobSelected);
  247. }
  248. categoryList[1]['label'] = picker.getSelectedValues()[0];
  249. _onRefresh();
  250. setState(() {});
  251. },
  252. ).showModal(this.context);
  253. }
  254. List salaryRange = [
  255. {
  256. "title": "不限",
  257. "min": null,
  258. "max": null,
  259. },
  260. {
  261. "title": "3K以下",
  262. "min": 0,
  263. "max": 3000,
  264. },
  265. {
  266. "title": "3-5k",
  267. "min": 3000,
  268. "max": 5000,
  269. },
  270. {
  271. "title": "5-10k",
  272. "min": 5000,
  273. "max": 10000,
  274. },
  275. {
  276. "title": "10-20k",
  277. "min": 10000,
  278. "max": 20000,
  279. },
  280. {
  281. "title": "20-50k",
  282. "min": 20000,
  283. "max": 50000,
  284. },
  285. {
  286. "title": "50K以上",
  287. "min": 50000,
  288. "max": null,
  289. }
  290. ];
  291. // 薪资范围
  292. List moneyList;
  293. List salaryRangeData = [];
  294. int minSalary;
  295. int maxSalary;
  296. showSalaryModal(BuildContext context) {
  297. salaryRangeData.clear();
  298. for (var i = 0; i < salaryRange.length; i++) {
  299. salaryRangeData.add(salaryRange[i]["title"]);
  300. }
  301. new Picker(
  302. selectedTextStyle: TextStyle(color: Colors.black),
  303. selecteds: moneyList,
  304. cancelText: "取消",
  305. confirmText: "确认",
  306. adapter: PickerDataAdapter<String>(
  307. pickerdata: salaryRangeData,
  308. ),
  309. changeToFirst: true,
  310. hideHeader: false,
  311. onConfirm: (Picker picker, List value) {
  312. print(12389);
  313. print(value);
  314. moneyList = value;
  315. int index = value[0];
  316. minSalary = salaryRange[index]['min'];
  317. maxSalary = salaryRange[index]['max'];
  318. categoryList[2]['label'] = salaryRange[index]["title"];
  319. _onRefresh();
  320. setState(() {});
  321. },
  322. ).showModal(this.context);
  323. }
  324. @override
  325. Widget build(BuildContext context) {
  326. double width = MediaQuery.of(context).size.width;
  327. return ChangeNotifierProvider<BaseListProvider<Records>>(
  328. create: (_) => provider,
  329. child: Scaffold(
  330. appBar: SearchAppBar2(
  331. onPressed: (text) {
  332. jobSelected = text;
  333. _onRefresh();
  334. },
  335. ),
  336. body: Container(
  337. child: Stack(
  338. children: <Widget>[
  339. Column(
  340. children: <Widget>[
  341. Container(
  342. width: width,
  343. height: ScreenUtil().setWidth(50),
  344. decoration: BoxDecoration(
  345. border: Border(
  346. bottom: BorderSide(
  347. width: 5,
  348. color: Color(0xffF9F9F9),
  349. ),
  350. ),
  351. ),
  352. child: TopTitle(
  353. categoryList: categoryList,
  354. fun: changTypeClass,
  355. )),
  356. SizedBox(
  357. height: 10,
  358. ),
  359. Expanded(
  360. flex: 1,
  361. child: Consumer<BaseListProvider<Records>>(
  362. builder: (_, provider, __) {
  363. return MyListView(
  364. key: Key('position_list'),
  365. itemCount: provider.list.length,
  366. stateType: provider.stateType,
  367. onRefresh: _onRefresh,
  368. loadMore: _loadMore,
  369. hasMore: provider.hasMore,
  370. showSeparator: false,
  371. itemBuilder: (_, index) {
  372. return GestureDetector(
  373. child: Container(
  374. padding: EdgeInsets.symmetric(horizontal: 10),
  375. child: PositionCell(
  376. provider.list[index],
  377. ),
  378. ),
  379. onTap: () {
  380. NavigatorUtils.push(context,
  381. "${BbsRouter.positionDetail}?id=${provider.list[index].id.toString()}");
  382. },
  383. );
  384. },
  385. );
  386. }))
  387. ],
  388. ),
  389. ],
  390. ),
  391. ),
  392. ),
  393. );
  394. }
  395. Future _onRefresh() async {
  396. _page = 1;
  397. await presenter.getPositionList(
  398. _page,
  399. provinceName: provinceName,
  400. cityName: cityName,
  401. minSalary: minSalary,
  402. maxSalary: maxSalary,
  403. job: jobSelected,
  404. );
  405. }
  406. Future _loadMore() async {
  407. _page++;
  408. await presenter.getPositionList(
  409. _page,
  410. provinceName: provinceName,
  411. cityName: cityName,
  412. minSalary: minSalary,
  413. maxSalary: maxSalary,
  414. job: jobSelected,
  415. );
  416. }
  417. @override
  418. PositionListPresenterSeconds createPresenter() {
  419. return PositionListPresenterSeconds();
  420. }
  421. }
  422. class TopTitle extends StatelessWidget {
  423. TopTitle({Key key, this.categoryList, this.fun}) : super(key: key);
  424. List<dynamic> categoryList;
  425. Function fun;
  426. List<Widget> listWidget(context) => categoryList.asMap().keys.map((index) {
  427. return index != 1
  428. ? GestureDetector(
  429. onTap: () {
  430. fun(categoryList[index], index);
  431. },
  432. child: Container(
  433. child: Row(children: <Widget>[
  434. Row(
  435. children: <Widget>[
  436. Text(
  437. categoryList[index]['label'] ?? '',
  438. style: TextStyle(
  439. fontSize: 14,
  440. color: Color(0xff333333),
  441. ),
  442. textAlign: TextAlign.start,
  443. ),
  444. Container(
  445. padding: EdgeInsets.only(top: 3),
  446. child: Icon(
  447. Icons.keyboard_arrow_down,
  448. size: 20.0,
  449. ),
  450. )
  451. ],
  452. ),
  453. SizedBox(width: ScreenUtil().setWidth(15)),
  454. ]),
  455. ),
  456. )
  457. : Container(child: null);
  458. }).toList();
  459. @override
  460. Widget build(BuildContext context) {
  461. return Container(
  462. child: Row(
  463. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  464. children: listWidget(context),
  465. ),
  466. );
  467. }
  468. }