index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. <template>
  2. <view class="task-page">
  3. <u-loading-page loading-text="加载中..." :loading="loading" font-size="16"></u-loading-page>
  4. <view class="task__header">
  5. <view class="task__header-container">
  6. <view class="search-form">
  7. <u-search placeholder="请输入任务处理人" v-model="searchKey" :showAction="false" @input="search"></u-search>
  8. </view>
  9. <view class="task__tabs">
  10. <view class="task__tab-item" v-for="item in tabList" :key="item.id"
  11. :class="{active:item.id===currentIndex}" @click="handleTabClick(item)">
  12. {{item.name}}
  13. </view>
  14. </view>
  15. </view>
  16. </view>
  17. <view class="task__body">
  18. <task-card @click="handleCardClick" @btntap="handleBtnClick" v-for="item in taskList" :key="item.task_id"
  19. :dataSource="item" @confirm="handleTaskConfirm"></task-card>
  20. </view>
  21. <u-modal :show="confirmModalVisible" :content="content" :showCancelButton="true" :closeOnClickOverlay="false"
  22. @confirm="handleModalConfirm" @cancel="handleModalCancel" :asyncClose="true">
  23. </u-modal>
  24. <u-notify ref="uNotify" message=""></u-notify>
  25. <u-popup :show="show" @close="close" @open="open" :closeOnClickOverlay="true" :safeAreaInsetTop="true">
  26. <view class="task-finished__area">
  27. <u--textarea :focus="true" v-model="report_msg" placeholder="" :maxlength="200" autoHeight border="none"
  28. style="margin-bottom: 24rpx;">
  29. </u--textarea>
  30. <u-button text="提交" type="primary" size="small" @click="handleSubmit" :disabled="loading"></u-button>
  31. </view>
  32. </u-popup>
  33. </view>
  34. </template>
  35. <script>
  36. import HeartBeat from '@/util/HeartBeat.js'
  37. import * as taskService from '@/service/task.js';
  38. import {
  39. TASK_ACTION_TYPE,
  40. TASK_WALK_TYPE
  41. } from '@/util/constants.js';
  42. import {
  43. assign,
  44. concat,
  45. } from 'lodash-es';
  46. import {
  47. mapState,
  48. mapActions
  49. } from 'vuex'
  50. export default {
  51. data() {
  52. return {
  53. loading: false,
  54. page: 1,
  55. total: 0,
  56. pageSize: 10,
  57. start_time: "",
  58. end_time: "",
  59. name: '',
  60. searchKey: '',
  61. currentIndex: 1,
  62. currentName: '待处理',
  63. tabList: [{
  64. id: 1,
  65. name: '待处理',
  66. value: '待处理',
  67. }, {
  68. id: 2,
  69. name: '处理中',
  70. value: '处理中',
  71. }, {
  72. id: 3,
  73. name: '已完成',
  74. value: '已完成'
  75. }],
  76. taskList: [],
  77. confirmModalVisible: false,
  78. content: '确认接收次任务?',
  79. currentTaskID: '',
  80. _heartBeat: null,
  81. isUpdateLocation: false,
  82. logs: [],
  83. show: false,
  84. report_msg: ''
  85. }
  86. },
  87. onShow() {
  88. },
  89. onReady() {
  90. this._heartBeat = HeartBeat.getInstance(this.recordRatio);
  91. },
  92. onLoad() {},
  93. onReachBottom() {
  94. const hasMore = this.total > 0 && this.toal > this.page * this.pageSize
  95. if (hasMore) {
  96. this.page++;
  97. this.getTaskList();
  98. }
  99. },
  100. onPullDownRefresh() {
  101. this.tasklist = [];
  102. this.page = 1;
  103. this.start_time = "";
  104. this.end_time = "";
  105. this.total = 0;
  106. this.getTaskList();
  107. setTimeout(() => {
  108. uni.stopPullDownRefresh();
  109. }, 1000)
  110. },
  111. onNavigationBarButtonTap(e) {
  112. },
  113. watch: {
  114. },
  115. computed: {
  116. ...mapState({
  117. recordRatio: state => state.task.ratio
  118. }),
  119. offsetLeft() {
  120. return
  121. },
  122. },
  123. onShow() {
  124. this.page = 1;
  125. this.tasklist = [];
  126. this.getTaskList();
  127. },
  128. methods: {
  129. ...mapActions(['addLocationData']),
  130. click(item) {
  131. console.log('item', item);
  132. },
  133. search() {
  134. this.page = 1;
  135. this.total = 0;
  136. this.getTaskList();
  137. },
  138. handleTabClick(tabItem) {
  139. if (!tabItem.id) {
  140. return
  141. }
  142. if (this.currentIndex !== tabItem.id) {
  143. this.currentIndex = tabItem.id;
  144. this.currentName = tabItem.value;
  145. this.resetTaskList();
  146. }
  147. },
  148. handleCardClick(taskID) {
  149. uni.navigateTo({
  150. url: "/pages/index/details?taskID=" + taskID
  151. })
  152. },
  153. handleBtnClick(type, taskID) {
  154. switch (type) {
  155. case TASK_ACTION_TYPE.START:
  156. case TASK_ACTION_TYPE.PAUSE:
  157. case TASK_ACTION_TYPE.RESTART:
  158. this.updateWalkStatus(type, taskID);
  159. break;
  160. case TASK_ACTION_TYPE.CLOCK:
  161. uni.navigateTo({
  162. url: '/pages/index/clockDetail?taskID=' + taskID
  163. })
  164. break;
  165. case TASK_ACTION_TYPE.FINISHED:
  166. this.currentTaskID = taskID;
  167. this.show = true;
  168. break;
  169. }
  170. },
  171. updateWalkStatus(type, taskID) {
  172. console.log(type, 'update walk status 2222', taskID)
  173. let message = '操作成功';
  174. switch (type) {
  175. case TASK_ACTION_TYPE.START:
  176. message = '任务已经开始';
  177. break;
  178. case TASK_ACTION_TYPE.RESTART:
  179. message = '继续记录';
  180. break;
  181. case TASK_ACTION_TYPE.PAUSE:
  182. message = '任务暂停成功';
  183. break;
  184. case TASK_ACTION_TYPE.FINISHED:
  185. message = '任务已完成';
  186. break;
  187. }
  188. const payload = {
  189. task_id: taskID,
  190. action: type
  191. }
  192. console.warn('update status', payload)
  193. this.loading = true;
  194. taskService.updateTaskWalkStatus(payload).then(() => {
  195. this.$refs.uNotify.show({
  196. top: 10,
  197. type: 'success',
  198. message,
  199. duration: 1000 * 3,
  200. fontSize: 16,
  201. safeAreaInsetTop: true
  202. })
  203. this.getTaskList();
  204. // 处理轨迹坐标点
  205. this.updateRecordLocation(type, taskID);
  206. }).finally(() => {
  207. this.loading = false;
  208. })
  209. },
  210. updateRecordLocation(type, taskID) {
  211. switch (type) {
  212. case TASK_ACTION_TYPE.START:
  213. case TASK_ACTION_TYPE.RESTART:
  214. this.isUpdateLocation = true;
  215. this._heartBeat.handle({
  216. type: 'record_' + taskID,
  217. data: {
  218. taskID
  219. },
  220. handler: this.getLocation
  221. })
  222. break;
  223. case TASK_ACTION_TYPE.PAUSE:
  224. case TASK_ACTION_TYPE.FINISHED:
  225. this.isUpdateLocation = false;
  226. this._heartBeat.clearByType('record_' + taskID)
  227. break;
  228. }
  229. },
  230. getLocation({
  231. taskID
  232. }) {
  233. return new Promise((resolve, reject) => {
  234. console.log('getlocation start', this.isUpdateLocation)
  235. if (!this.isUpdateLocation) {
  236. console.log('getlocation start 1 close')
  237. resolve(true)
  238. return
  239. }
  240. console.log('getlocation start 2 exec')
  241. uni.getLocation({
  242. type: 'gcj02',
  243. success: (res) => {
  244. console.log('当前位置的经度:' + res.longitude);
  245. console.log('当前位置的纬度:' + res.latitude);
  246. this.logs.push(`记录中:当前位置的经度${res.longitude};当前位置的纬度${res.latitude}`)
  247. this.addLocationData({
  248. id: Date.now(),
  249. taskID,
  250. latitude: res.latitude,
  251. longitude: res.longitude
  252. })
  253. resolve(false)
  254. },
  255. fail(err) {
  256. console.warn(err, 'get location error')
  257. }
  258. });
  259. })
  260. },
  261. resetTaskList() {
  262. this.page = 1;
  263. this.total = 0;
  264. this.getTaskList();
  265. },
  266. getTaskList() {
  267. this.loading = true;
  268. let payload = {
  269. page: this.page, // 否 页码, 默认1
  270. page_item: this.pageSize, //
  271. status: this.currentName,
  272. start_time: this
  273. .start_time, // 非必填 开始时间
  274. end_time: this.end_time,
  275. operator_user_name: this.searchKey
  276. };
  277. taskService.getTaskList(payload).then(res => {
  278. console.log(res, 'get task list')
  279. this.taskList = this.page === 1 ? res.page_list : concat(this.taskList, res.page_list);
  280. this.total = this.total_item;
  281. res.page_list.forEach(item => {
  282. if (item.walk_status === TASK_WALK_TYPE.IS_RECORDING) {
  283. this.isUpdateLocation = true;
  284. if (!this._heartBeat.hasType('record_' + item.task_id)) {
  285. this._heartBeat.handle({
  286. type: 'record_' + item.task_id,
  287. data: {
  288. taskID: item.task_id
  289. },
  290. handler: this.getLocation
  291. })
  292. }
  293. }
  294. })
  295. console.warn(this.taskList, 'task list 1345555')
  296. }).finally(() => {
  297. this.loading = false;
  298. })
  299. },
  300. handleTaskConfirm(taskID) {
  301. if (!taskID) {
  302. return
  303. }
  304. this.currentTaskID = taskID;
  305. this.confirmModalVisible = true;
  306. },
  307. handleModalConfirm() {
  308. const payload = {
  309. task_id: this.currentTaskID
  310. }
  311. console.log(this.currentTaskID, 'modal confirm', payload)
  312. taskService.confirmTaskWithTaskID(payload).then(res => {
  313. this.getTaskList();
  314. }).finally(() => {
  315. this.confirmModalVisible = false
  316. })
  317. },
  318. handleModalCancel() {
  319. this.currentTaskID = '';
  320. this.confirmModalVisible = false;
  321. },
  322. open() {
  323. console.log('open');
  324. },
  325. close() {
  326. this.show = false
  327. console.log('close');
  328. },
  329. handleSubmit() {
  330. if (!this.report_msg) {
  331. uni.$u.toast('请输入描述');
  332. return
  333. }
  334. this.loading = true;
  335. taskService.taskSubmit({
  336. task_id: this.currentTaskID,
  337. report_msg: this.report_msg
  338. }).then(res=>{
  339. uni.$u.toast('提交成功');
  340. // this.updateWalkStatus(TASK_ACTION_TYPE.FINISHED,this.currentTaskID);
  341. this.getTaskList();
  342. this.currentTaskID = '';
  343. }).finally(()=>{
  344. this.show = false;
  345. this.loading = false
  346. })
  347. }
  348. }
  349. }
  350. </script>
  351. <style lang="scss" scoped>
  352. .task-page {
  353. padding: 212rpx 0 24rpx;
  354. .task {
  355. &__header {
  356. position: fixed;
  357. left: 0;
  358. right: 0;
  359. top: 0;
  360. // #ifdef APP-PLUS
  361. padding-top: 24rpx;
  362. // #endif
  363. // #ifndef APP-PLUS
  364. padding-top: 112rpx;
  365. // #endif
  366. background-color: #F7F8FB;
  367. box-shadow: 0px 0px 16rpx 0px rgba(153, 153, 153, 0.2);
  368. border-radius: 4rpx;
  369. z-index: 1;
  370. .search-form {
  371. padding: 24rpx;
  372. }
  373. &-container {
  374. background-color: #fff;
  375. }
  376. }
  377. &__tabs {
  378. position: relative;
  379. padding: 0 74rpx;
  380. display: flex;
  381. ::v-deep .u-tabs__wrapper__nav {
  382. justify-content: space-between;
  383. }
  384. }
  385. &__tab-item {
  386. position: relative;
  387. flex: 1 1 0%;
  388. display: flex;
  389. align-items: center;
  390. justify-content: center;
  391. padding: 20rpx;
  392. font-size: 28rpx;
  393. color: #7489A9;
  394. transition: all 1s;
  395. &::before {
  396. content: '';
  397. position: absolute;
  398. bottom: 0;
  399. left: 50%;
  400. width: 0rpx;
  401. height: 4rpx;
  402. transform: translateX(-50%);
  403. background-color: #1B76FF;
  404. transition: all 1s;
  405. }
  406. &.active {
  407. color: #1B76FF;
  408. font-weight: 500;
  409. &::before {
  410. width: 120rpx;
  411. }
  412. }
  413. }
  414. &__tab-line {
  415. position: absolute;
  416. bottom: 0;
  417. width: 120rpx;
  418. height: 4rpx;
  419. background-color: #1B76FF;
  420. transform: translateX(50rpx);
  421. }
  422. &__body {
  423. padding: 40rpx 24rpx;
  424. }
  425. }
  426. }
  427. .task-finished {
  428. &__area {
  429. padding: 24rpx;
  430. }
  431. }
  432. </style>
  433. <style>
  434. page {
  435. background-color: #F7F8FB;
  436. }
  437. </style>