voyageDetail.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. <template>
  2. <div class="line-container-p18">
  3. <i class="el-icon-arrow-left"></i>
  4. <div class="dib go-back ml8">返回航次列表</div>
  5. <div class="line">
  6. <div class="info-line">
  7. <div class="info-line-title">航次名称</div>
  8. <el-input
  9. class="info-line-text"
  10. v-model="voyage.voyageName"
  11. disabled
  12. ></el-input>
  13. </div>
  14. <div class="info-line">
  15. <div class="info-line-title">货主</div>
  16. <el-input
  17. class="info-line-text"
  18. v-model="voyage.cargoOwnerName"
  19. disabled
  20. ></el-input>
  21. </div>
  22. </div>
  23. <div class="line">
  24. <div class="info-line">
  25. <div class="info-line-title">船东</div>
  26. <el-input
  27. class="info-line-text"
  28. v-model="voyage.shipOwnerName"
  29. disabled
  30. ></el-input>
  31. </div>
  32. <div class="info-line">
  33. <div class="info-line-title">船东手机号</div>
  34. <el-input
  35. class="info-line-text"
  36. v-model="voyage.shipOwnerPhone"
  37. disabled
  38. ></el-input>
  39. </div>
  40. </div>
  41. <div class="line">
  42. <div class="info-line">
  43. <div class="info-line-title">船舶</div>
  44. <el-input
  45. class="info-line-text"
  46. v-model="voyage.shipName"
  47. disabled
  48. ></el-input>
  49. </div>
  50. <div class="info-line">
  51. <div class="info-line-title">MMSI</div>
  52. <el-input
  53. class="info-line-text"
  54. v-model="voyage.shipMmsi"
  55. disabled
  56. ></el-input>
  57. </div>
  58. </div>
  59. <div id="map-container" class="map-container"></div>
  60. <div class="line" style="margin-top: 30px">
  61. <div class="info-line">
  62. <div class="info-line-title">开始时间</div>
  63. <el-input
  64. class="info-line-text"
  65. v-model="voyage.startTime"
  66. disabled
  67. ></el-input>
  68. </div>
  69. <div class="info-line">
  70. <div class="info-line-title">结束时间</div>
  71. <el-input
  72. class="info-line-text"
  73. v-model="voyage.endTime"
  74. disabled
  75. ></el-input>
  76. </div>
  77. </div>
  78. <div class="line">
  79. <div class="info-line">
  80. <div class="info-line-title">装货港</div>
  81. <el-input
  82. class="info-line-text"
  83. v-model="voyage.loadPort"
  84. disabled
  85. ></el-input>
  86. </div>
  87. <div class="info-line">
  88. <div class="info-line-title">卸货港</div>
  89. <el-input
  90. class="info-line-text"
  91. v-model="voyage.dischargeProt"
  92. disabled
  93. ></el-input>
  94. </div>
  95. </div>
  96. <div class="line">
  97. <div class="info-line">
  98. <div class="info-line-title">货种</div>
  99. <el-input
  100. class="info-line-text"
  101. v-model="voyage.cargo"
  102. disabled
  103. ></el-input>
  104. </div>
  105. <div class="info-line">
  106. <div class="info-line-title">吨位</div>
  107. <el-input
  108. class="info-line-text"
  109. v-model="voyage.tons"
  110. disabled
  111. ></el-input>
  112. </div>
  113. </div>
  114. </div>
  115. <div class="container-title">航次信息</div>
  116. <div class="line-container-p18">
  117. <div class="line">
  118. <div class="info-line">
  119. <div class="info-line-title">运输状态</div>
  120. <el-select
  121. v-model="voyage.transStatus"
  122. placeholder="Select"
  123. class="info-line-text"
  124. :disabled="disabledStatus"
  125. >
  126. <el-option
  127. v-for="item in options"
  128. :key="item.value"
  129. :label="item.label"
  130. :value="item.value"
  131. ></el-option>
  132. </el-select>
  133. </div>
  134. <div class="info-line">
  135. <div class="info-line-title">实际卸货吨位</div>
  136. <el-input
  137. class="info-line-text"
  138. v-model="voyage.actualDischargeTons"
  139. :disabled="disabledStatus"
  140. ></el-input>
  141. </div>
  142. </div>
  143. <div class="line">
  144. <div class="info-line">
  145. <div class="info-line-title">装货开始时间</div>
  146. <el-date-picker
  147. class="info-line-text"
  148. v-model="voyage.loadStartTime"
  149. type="datetime"
  150. format="YYYY/MM/DD HH:mm:ss"
  151. value-format="YYYY/MM/DD HH:mm:ss"
  152. placeholder="装货开始时间"
  153. :disabled="disabledStatus"
  154. ></el-date-picker>
  155. </div>
  156. <div class="info-line">
  157. <div class="info-line-title">装货结束时间</div>
  158. <el-date-picker
  159. class="info-line-text"
  160. v-model="voyage.loadEndTime"
  161. type="datetime"
  162. format="YYYY/MM/DD HH:mm:ss"
  163. value-format="YYYY/MM/DD HH:mm:ss"
  164. placeholder="装货开始时间"
  165. :disabled="disabledStatus"
  166. ></el-date-picker>
  167. </div>
  168. </div>
  169. <div class="line">
  170. <div class="info-line">
  171. <div class="info-line-title">卸货开始时间</div>
  172. <el-date-picker
  173. class="info-line-text"
  174. v-model="voyage.dischargeStartTime"
  175. type="datetime"
  176. format="YYYY/MM/DD HH:mm:ss"
  177. value-format="YYYY/MM/DD HH:mm:ss"
  178. placeholder="装货开始时间"
  179. :disabled="disabledStatus"
  180. ></el-date-picker>
  181. </div>
  182. <div class="info-line">
  183. <div class="info-line-title">卸货结束时间</div>
  184. <el-date-picker
  185. class="info-line-text"
  186. v-model="voyage.dischargeEndTime"
  187. type="datetime"
  188. format="YYYY/MM/DD HH:mm:ss"
  189. value-format="YYYY/MM/DD HH:mm:ss"
  190. placeholder="装货开始时间"
  191. :disabled="disabledStatus"
  192. ></el-date-picker>
  193. </div>
  194. </div>
  195. <div class="line">
  196. <div class="info-line">
  197. <div class="info-line-title">备注</div>
  198. <el-input
  199. class="info-line-textarea"
  200. v-model="voyage.remark"
  201. autosize
  202. type="textarea"
  203. :disabled="disabledStatus"
  204. ></el-input>
  205. </div>
  206. </div>
  207. <div
  208. class="media-content df ffw"
  209. style="width: 100%; background: #f7f7f7; border-radius: 2px"
  210. >
  211. <el-card
  212. style="
  213. width: 240px;
  214. height: 360px;
  215. margin-left: 20px;
  216. margin-bottom: 15px;
  217. "
  218. v-for="item in medias"
  219. :key="item"
  220. shadow="hover"
  221. >
  222. <div class="card-note">
  223. {{ item.note }}
  224. </div>
  225. <div class="media-box" style="position: relative">
  226. <el-image
  227. v-if="item.mediaType == 1"
  228. style="width: 100%; height: 100%"
  229. fit="contain"
  230. :src="item.downloadUrl"
  231. :preview-src-list="previewSrcList"
  232. ></el-image>
  233. <video
  234. style="width: 100%; height: 100%"
  235. v-else
  236. :src="item.downloadUrl"
  237. ></video>
  238. <img
  239. @click="openVideoModal(item.downloadUrl)"
  240. v-if="item.mediaType == 2"
  241. src="../../assets/icon-player.png"
  242. style="
  243. object-fit: contain;
  244. width: 40px;
  245. height: 40px;
  246. position: absolute;
  247. top: calc(50% - 20px);
  248. left: calc(50% - 20px);
  249. background: #fff;
  250. border-radius: 50%;
  251. "
  252. alt=""
  253. />
  254. </div>
  255. </el-card>
  256. <el-dialog
  257. v-model="videoModal"
  258. title="视频审核"
  259. width="30%"
  260. :before-close="videoClose"
  261. >
  262. <video
  263. autoplay
  264. controls
  265. style="width: 100%; height: 100%"
  266. :src="currentUrl"
  267. ></video>
  268. <template #footer>
  269. <span class="dialog-footer">
  270. <el-button type="primary" @click="dialogAuditVideo(1)">
  271. 通过
  272. </el-button>
  273. <el-button type="warning" @click="dialogAuditVideo(2)">
  274. 未通过
  275. </el-button>
  276. </span>
  277. </template>
  278. </el-dialog>
  279. </div>
  280. <div class="df aic jcfe mt20" v-if="voyage.voyageStatus == 1">
  281. <el-button v-if="disabledStatus" type="primary" @click="changeVoyageInfo">
  282. 修改航次
  283. </el-button>
  284. <div v-else>
  285. <div>
  286. <el-button @click="cancelVoyageChange">取消修改</el-button>
  287. <el-button type="primary" @click="submitVoyageChange">
  288. 提交修改
  289. </el-button>
  290. </div>
  291. </div>
  292. <el-button
  293. v-if="voyage.dischargeEndTime && disabledStatus"
  294. type="primary"
  295. @click="finishVoyage"
  296. >
  297. 完成航次
  298. </el-button>
  299. </div>
  300. </div>
  301. </template>
  302. <script>
  303. import { onMounted, reactive, ref, toRefs } from "_vue@3.2.20@vue";
  304. import api from "../../apis/fetch";
  305. import { useRoute } from "vue-router";
  306. import _ from "lodash";
  307. import { ElNotification } from "element-plus";
  308. export default {
  309. setup() {
  310. const route = useRoute();
  311. let map = ref();
  312. let voyage = ref({});
  313. let medias = ref();
  314. let coordinates = ref();
  315. let previewSrcList = ref([]);
  316. async function getVoyageDetail() {
  317. let res = await api.getVoyageDetail({
  318. type: 2,
  319. voyageId: route.query.id,
  320. });
  321. coordinates.value = res.data.result.coordinates;
  322. voyage.value = res.data.result.voyage;
  323. medias.value = res.data.result.medias;
  324. for (let i of medias.value) {
  325. previewSrcList.value.push(i.downloadUrl);
  326. }
  327. setShipMarker();
  328. }
  329. function initMap() {
  330. var center = new TMap.LatLng(31.228721, 121.524761);
  331. //初始化地图
  332. map.value = new TMap.Map("map-container", {
  333. zoom: 12, //设置地图缩放级别
  334. center: center, //设置地图中心点坐标
  335. });
  336. }
  337. function setShipMarker(longitude, latitude) {
  338. var marker = new TMap.MultiMarker({
  339. id: "marker-layer", //图层id
  340. map: map.value,
  341. styles: {
  342. //点标注的相关样式
  343. marker: new TMap.MarkerStyle({
  344. width: 25,
  345. height: 35,
  346. anchor: { x: 16, y: 32 },
  347. src: "https://hhd-pat-1255802371.cos.ap-shanghai.myqcloud.com/frontend/ship-red-icon.png",
  348. }),
  349. },
  350. geometries: [
  351. {
  352. //点标注数据数组
  353. id: "demo",
  354. styleId: "marker",
  355. position: new TMap.LatLng(31.228721, 121.524761),
  356. properties: {
  357. title: "marker",
  358. },
  359. },
  360. ],
  361. });
  362. }
  363. let disabledStatus = ref(true);
  364. let updateCache = {};
  365. function changeVoyageInfo() {
  366. updateCache = _.cloneDeep(voyage.value);
  367. disabledStatus.value = false;
  368. }
  369. function cancelVoyageChange() {
  370. voyage.value = updateCache;
  371. disabledStatus.value = true;
  372. }
  373. async function submitVoyageChange() {
  374. let {
  375. id,
  376. transStatus,
  377. loadStartTime,
  378. loadEndTime,
  379. dischargeStartTime,
  380. dischargeEndTime,
  381. actualDischargeTons,
  382. remark,
  383. } = voyage.value;
  384. let res = await api.updateVoyage({
  385. id,
  386. transStatus,
  387. loadStartTime,
  388. loadEndTime,
  389. dischargeStartTime,
  390. dischargeEndTime,
  391. actualDischargeTons,
  392. remark,
  393. });
  394. if (res.data.status == 0) {
  395. ElNotification({
  396. type: "success",
  397. title: res.data.msg,
  398. });
  399. disabledStatus.value = true;
  400. } else {
  401. ElNotification({
  402. type: "error",
  403. title: res.data.msg,
  404. });
  405. console.log(res);
  406. }
  407. }
  408. let options = ref([
  409. {
  410. value: 1,
  411. label: "航行",
  412. },
  413. {
  414. value: 2,
  415. label: "停泊",
  416. },
  417. {
  418. value: 3,
  419. label: "装货",
  420. },
  421. {
  422. value: 4,
  423. label: "运输中",
  424. },
  425. {
  426. value: 5,
  427. label: "卸货",
  428. },
  429. ]);
  430. async function finishVoyage() {
  431. if (!voyage.value.dischargeEndTime) return;
  432. let res = await api.finishVoyage({
  433. voyageId: route.query.id,
  434. });
  435. if (res.data.status == 0) {
  436. voyage.value.voyageStatus = 2;
  437. ElNotification({
  438. type: "success",
  439. title: res.data.msg,
  440. });
  441. } else {
  442. ElNotification({
  443. type: "error",
  444. title: res.data.msg,
  445. });
  446. console.log(res);
  447. }
  448. }
  449. function openVideoModal(url) {
  450. currentUrl.value = url;
  451. videoModal.value = true;
  452. }
  453. onMounted(() => {
  454. initMap();
  455. getVoyageDetail();
  456. });
  457. return {
  458. options,
  459. voyage,
  460. coordinates,
  461. medias,
  462. disabledStatus,
  463. changeVoyageInfo,
  464. cancelVoyageChange,
  465. submitVoyageChange,
  466. finishVoyage,
  467. openVideoModal,
  468. previewSrcList,
  469. };
  470. },
  471. };
  472. </script>
  473. <style scoped>
  474. .map-container {
  475. width: 100%;
  476. height: 500px;
  477. }
  478. :deep().el-input__inner {
  479. color: #333 !important;
  480. }
  481. .card-note {
  482. height: 30px;
  483. font-size: 12px;
  484. font-family: PingFangSC-Regular, PingFang SC;
  485. font-weight: 400;
  486. color: #777777;
  487. }
  488. .media-box {
  489. width: 200px;
  490. height: 200px;
  491. margin-top: 20px;
  492. }
  493. </style>