task.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. <template>
  2. <div class="h5mianList">
  3. <div class="header">
  4. <div @click="back" class="back">
  5. <van-icon size="1.3rem" name="arrow-left" />
  6. </div>
  7. <div class="title">任务中心</div>
  8. </div>
  9. <div class="search" style="border-bottom: 1px solid #f1f1f1">
  10. <van-dropdown-menu>
  11. <van-dropdown-item
  12. v-model="dataForm.isReceived"
  13. :options="option1"
  14. @change="changeisReceived"
  15. />
  16. <van-dropdown-item title="筛选" ref="itemRef">
  17. <van-form @submit="onSubmit">
  18. <van-field
  19. v-model="dataForm.lineName"
  20. label="航线名称"
  21. placeholder="请输入航线名称"
  22. />
  23. <van-field
  24. v-model="dataForm.lineUnitName"
  25. @keydown.enter="changeisReceived"
  26. label="单元名称"
  27. placeholder="请输入单元名称"
  28. />
  29. </van-form>
  30. <div style="padding: 5px 16px; display: flex">
  31. <van-button
  32. type="primary"
  33. block
  34. round
  35. @click="
  36. (dataForm.lineName = ''),
  37. (dataForm.lineUnitName = ''),
  38. (dataForm.page = 1),
  39. (more = false),
  40. (dataList = []),
  41. getList(),
  42. itemRef.toggle()
  43. "
  44. >
  45. 清空
  46. </van-button>
  47. <van-button
  48. type="primary"
  49. block
  50. round
  51. @click="
  52. (dataForm.page = 1),
  53. (more = false),
  54. (dataList = []),
  55. getList(),
  56. itemRef.toggle()
  57. "
  58. >
  59. 确认
  60. </van-button>
  61. </div>
  62. </van-dropdown-item>
  63. <van-dropdown-item
  64. :title="listTypeName"
  65. v-model="dataForm.lietType"
  66. :options="option2"
  67. @change="changelietType"
  68. />
  69. </van-dropdown-menu>
  70. </div>
  71. <div
  72. class="table-container"
  73. id="scroll-container"
  74. ref="scrollContainer"
  75. v-scroll="handleScroll"
  76. >
  77. <table>
  78. <thead>
  79. <tr>
  80. <th>管线及单元</th>
  81. <th v-if="listTypeName != '默认'">距离</th>
  82. <th>状态</th>
  83. <th>时间</th>
  84. <th>操作</th>
  85. </tr>
  86. </thead>
  87. <tbody>
  88. <tr v-for="(row, index) in dataList" :key="index">
  89. <td>{{ row.lineName }}({{ row.lineUnitName }})</td>
  90. <td style="width: 90px" v-if="listTypeName != '默认'">{{ (row.distance/1000).toFixed(2) }}km</td>
  91. <td style="width: 120px">
  92. <span :style="{ color: isReceivedColor[row.isReceived] }">
  93. {{ isReceived[row.isReceived] }}
  94. </span>
  95. </td>
  96. <td style="width: 90px">{{ row.updateDate.slice(0, -9) }}</td>
  97. <td>
  98. <div class="bts" style="width: 170px">
  99. <div
  100. v-if="row.isReceived === '0'"
  101. class="danger"
  102. style="margin-right: 0.3rem"
  103. @click.stop="refuseTaskArrange(row.id)"
  104. >
  105. 拒绝
  106. </div>
  107. <div
  108. v-if="row.isReceived === '0'"
  109. @click.stop="receiveTaskArrange(row)"
  110. >
  111. 接受
  112. </div>
  113. <div
  114. class="danger"
  115. v-if="row.isReceived === '1'"
  116. @click.stop="cancelTaskArrange(row)"
  117. >
  118. 取消任务
  119. </div>
  120. <div
  121. v-if="row.isReceived === '1'"
  122. @click.stop="todownFly(row.verificationCode)"
  123. >
  124. 下载航线文件
  125. </div>
  126. <div
  127. class="success"
  128. v-if="row.isReceived === '6'"
  129. @click.stop="completeTaskArrange(row.id)"
  130. >
  131. 完成
  132. </div>
  133. </div>
  134. </td>
  135. </tr>
  136. </tbody>
  137. </table>
  138. </div>
  139. <van-back-top target=".table-container" />
  140. </div>
  141. </template>
  142. <script setup>
  143. import { useRoute, useRouter } from "vue-router";
  144. import {
  145. ref,
  146. defineProps,
  147. watch,
  148. defineExpose,
  149. onMounted,
  150. getCurrentInstance,
  151. computed,
  152. } from "vue";
  153. import { showToast, showConfirmDialog } from "vant";
  154. const { proxy } = getCurrentInstance();
  155. const route = useRoute();
  156. const router = useRouter();
  157. const total = ref(0);
  158. const scrollContainer = ref();
  159. const dataList = ref([]);
  160. import { goBackToApp, saveCode, downFly } from "@/utils/bridge";
  161. const isLoading = ref(false);
  162. const more = ref(false);
  163. const top = ref(false);
  164. const listTypeName = computed(() => {
  165. if (!rectangle.value) {
  166. return "定位中...";
  167. }
  168. return option2.value[dataForm.value.lietType].text;
  169. });
  170. const rectangle = ref();
  171. const location = ref();
  172. const itemRef = ref();
  173. const option1 = [
  174. { text: "全部", value: "" },
  175. { text: "未接收", value: 0 },
  176. { text: "已接收", value: 1 },
  177. { text: "已结束", value: 2 },
  178. { text: "已拒绝", value: 3 },
  179. { text: "已经下载航线文件", value: 4 },
  180. { text: "已上传文件", value: 5 },
  181. { text: "已确认上传文件为最终巡检文件", value: 6 },
  182. ];
  183. const option2 = ref([
  184. { text: "默认", value: 0 },
  185. { text: "离我最近", value: 1 },
  186. ]);
  187. const isReceivedColor = {
  188. 0: "#CCCCCC", // 灰色 - 未接收
  189. 1: "#4CAF50", // 绿色 - 已接收
  190. 2: "#9E9E9E", // 深灰色 - 已结束
  191. 3: "#F44336", // 红色 - 已拒绝
  192. 4: "#FFEB3B", // 黄色 - 已经下载航线文件
  193. 5: "#2196F3", // 蓝色 - 已上传文件
  194. 6: "#009688", // 深青色 - 已确认上传文件为最终巡检文件
  195. };
  196. const isReceived = {
  197. 0: "未接收",
  198. 1: "已接收",
  199. 2: "已结束",
  200. 3: "已拒绝",
  201. 4: "已经下载航线文件",
  202. 5: "已上传文件",
  203. 6: "已确认上传文件为最终巡检文件",
  204. };
  205. const dataForm = ref({
  206. isReceived: "",
  207. lietType: 0,
  208. page: 1,
  209. limit: 15,
  210. });
  211. const getLocation = () => {
  212. AMap.plugin("AMap.Geolocation", function () {
  213. var geolocation = new AMap.Geolocation({
  214. enableHighAccuracy: true, // 开启高精度模式
  215. timeout: 1000, // 设置超时时间为 30 秒
  216. noIpLocate: 0, // 使用 IP 定位作为备用方案
  217. noGeoLocation: 0, // 允许浏览器获取地理位置
  218. });
  219. geolocation.getCurrentPosition(function (status, result) {
  220. if (status === "complete") {
  221. var lng = result.position.lng;
  222. var lat = result.position.lat;
  223. console.log(lng, lat);
  224. } else {
  225. console.error("定位失败", result);
  226. fetch(
  227. "https://restapi.amap.com/v3/ip?key=74d5aa7c4270effe9a18d9cfa6149abf"
  228. )
  229. .then((response) => response.json())
  230. .then((data) => {
  231. console.log("IP 定位:", data);
  232. console.log("当前位置:" + data.province + data.city);
  233. console.log("经纬度:" + data.rectangle.split(";")[1]);
  234. location.value = data.province + data.city;
  235. rectangle.value = data.rectangle.split(";")[1];
  236. option2.value[1].text = `离我最近(${location.value})`;
  237. })
  238. .catch((error) => {
  239. console.error("IP 定位失败:", error);
  240. option2.value[1].text = "定位失败,点击重新定位";
  241. showToast("定位失败");
  242. });
  243. }
  244. });
  245. });
  246. };
  247. //获取数据
  248. const getList = (e) => {
  249. if (more.value) {
  250. showToast("没有更多了");
  251. isLoading.value = false;
  252. return;
  253. }
  254. if (e == 2) {
  255. isLoading.value = true;
  256. }
  257. if (dataForm.value.lietType == 1) {
  258. dataForm.value.lon = rectangle.value.split(",")[0];
  259. dataForm.value.lat = rectangle.value.split(",")[1];
  260. } else {
  261. dataForm.value.lon = null;
  262. dataForm.value.lat = null;
  263. }
  264. proxy
  265. .$ajax({
  266. method: "GET",
  267. url: `/task/zhkjwurenjitaskarrange/getUserTaskArrange`,
  268. params: dataForm.value,
  269. })
  270. .then((res) => {
  271. isLoading.value = false;
  272. if (res.data.code != 0) {
  273. return showToast(res.data.msg);
  274. }
  275. dataList.value.push(...res.data.data.list);
  276. total.value = res.data.data.total;
  277. if (dataList.value.length == total.value) {
  278. more.value = true;
  279. showToast("没有更多了");
  280. }
  281. });
  282. };
  283. // 详情
  284. const todetails = (e) => {
  285. let ruters = {
  286. path: "/taskDetails",
  287. component: () => import("./taskDetails.vue"),
  288. };
  289. router.addRoute(ruters);
  290. router.options.routes.push(ruters);
  291. sessionStorage.setItem("details", true);
  292. router.push({
  293. path: "/taskDetails",
  294. query: {
  295. id: e,
  296. },
  297. });
  298. };
  299. // 回到顶部
  300. const toTop = () => {
  301. scrollContainer.value.scrollTop = 0;
  302. };
  303. const changeisReceived = (event) => {
  304. dataList.value = [];
  305. dataForm.value.page = 1;
  306. more.value = false;
  307. if (event.target) {
  308. event.target.blur();
  309. itemRef.value.toggle();
  310. }
  311. getList();
  312. };
  313. const changelietType = () => {
  314. if (!rectangle.value) {
  315. getLocation();
  316. return;
  317. }
  318. dataList.value = [];
  319. dataForm.value.page = 1;
  320. more.value = false;
  321. getList();
  322. };
  323. const back = () => {
  324. goBackToApp("home");
  325. };
  326. // 拒绝
  327. const refuseTaskArrange = (id) => {
  328. showConfirmDialog({
  329. title: "提示",
  330. message: "是否拒收该任务",
  331. })
  332. .then(() => {
  333. // on confirm
  334. proxy
  335. .$ajax({
  336. method: "get",
  337. url: `/task/zhkjwurenjitaskarrange/refuseTaskArrange/${id}`,
  338. })
  339. .then((res) => {
  340. if (res.data.code != 0) {
  341. return showToast(res.data.msg);
  342. }
  343. showToast("操作成功");
  344. dataForm.value.page = 1;
  345. more.value = false;
  346. dataList.value = [];
  347. getList();
  348. });
  349. })
  350. .catch(() => {
  351. // on cancel
  352. });
  353. };
  354. // 完成
  355. const completeTaskArrange = (id) => {
  356. showConfirmDialog({
  357. title: "提示",
  358. message: "是否完成任务",
  359. })
  360. .then(() => {
  361. // on confirm
  362. proxy
  363. .$ajax({
  364. method: "get",
  365. url: `/task/zhkjwurenjitaskarrange/completeTaskArrange/${id}`,
  366. })
  367. .then((res) => {
  368. if (res.data.code != 0) {
  369. return showToast(res.data.msg);
  370. }
  371. showToast("操作成功");
  372. dataList.value = [];
  373. dataForm.value.page = 1;
  374. more.value = false;
  375. getList();
  376. });
  377. })
  378. .catch(() => {
  379. // on cancel
  380. });
  381. };
  382. // 接受
  383. const receiveTaskArrange = (data) => {
  384. showConfirmDialog({
  385. title: "提示",
  386. message: "是否确认接受该任务",
  387. })
  388. .then(() => {
  389. let DeviceId = sessionStorage.getItem("DeviceId");
  390. let info = JSON.parse(sessionStorage.getItem("userInfo"));
  391. data.receivedUserId = info.id;
  392. data.receivedUserName = info.realName;
  393. data.deviceId = DeviceId;
  394. proxy
  395. .$ajax({
  396. method: "post",
  397. url: `/task/zhkjwurenjitaskarrange/receiveTaskArrange`,
  398. data: data,
  399. })
  400. .then((res) => {
  401. if (res.data.code != 0) {
  402. return showToast(res.data.msg);
  403. }
  404. saveCode(res.data.data);
  405. showToast("操作成功");
  406. dataList.value = [];
  407. dataForm.value.page = 1;
  408. more.value = false;
  409. getList();
  410. });
  411. })
  412. .catch(() => {
  413. // on cancel
  414. });
  415. };
  416. const cancelTaskArrange = (data) => {
  417. showConfirmDialog({
  418. title: "提示",
  419. message: "是否取消任务",
  420. })
  421. .then(() => {
  422. proxy
  423. .$ajax({
  424. method: "get",
  425. url: `/task/zhkjwurenjitaskarrange/completeTaskArrange/${
  426. data.id
  427. }/${0}`,
  428. })
  429. .then((res) => {
  430. if (res.data.code != 0) {
  431. return showToast(res.data.msg);
  432. }
  433. showToast("操作成功");
  434. dataList.value = [];
  435. dataForm.value.page = 1;
  436. more.value = false;
  437. getList();
  438. });
  439. })
  440. .catch(() => {
  441. // on cancel
  442. });
  443. };
  444. // 下载航行文件
  445. const todownFly = (code) => {
  446. showConfirmDialog({
  447. title: "提示",
  448. message: "是否下载飞行文件",
  449. })
  450. .then(() => {
  451. // on confirm
  452. downFly(code);
  453. })
  454. .catch(() => {
  455. // on cancel
  456. });
  457. };
  458. // 触底加载
  459. const handleScroll = () => {
  460. // console.log(
  461. // scrollContainer.value.scrollHeight,
  462. // scrollContainer.value.scrollTop,
  463. // scrollContainer.value.clientHeight
  464. // );
  465. // 判断滚动容器是否触底
  466. if (
  467. scrollContainer.value.scrollHeight <=
  468. scrollContainer.value.scrollTop + scrollContainer.value.clientHeight + 70
  469. ) {
  470. // 触底逻辑,可以在这里进行数据加载或其他操作
  471. dataForm.value.page++;
  472. getList(1);
  473. }
  474. };
  475. onMounted(() => {
  476. if (sessionStorage.getItem("information")) {
  477. //判断是否有流程
  478. let a = JSON.parse(sessionStorage.getItem("information"));
  479. // console.log(a);
  480. dataForm.value.activityId = a.id;
  481. }
  482. // 获取滚动容器元素
  483. const scrollContainer = document.getElementById("scroll-container");
  484. // 监听滚动事件
  485. scrollContainer.addEventListener("scroll", handleScroll);
  486. getList(1);
  487. getLocation();
  488. });
  489. </script>
  490. <style scoped lang="less">
  491. .content {
  492. height: calc(85vh - 2rem);
  493. }
  494. .table-container {
  495. height: 300px; /* 设置容器高度 */
  496. overflow-y: auto; /* 内容区域滚动 */
  497. }
  498. table {
  499. width: 100%;
  500. border-collapse: collapse;
  501. }
  502. thead {
  503. position: sticky;
  504. top: 0;
  505. background-color: #fff; /* 表头背景色 */
  506. }
  507. th,
  508. td {
  509. padding: 8px;
  510. border: 1px solid #ddd;
  511. }
  512. .bts {
  513. display: flex;
  514. justify-content: space-around;
  515. color: #3e8ef7;
  516. .danger {
  517. color: #f5686f;
  518. }
  519. }
  520. </style>