voyageDetail.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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. </el-dialog>
  269. </div>
  270. </div>
  271. </template>
  272. <script>
  273. import { onMounted, reactive, ref, toRefs } from "_vue@3.2.20@vue";
  274. import api from "../../apis/fetch";
  275. import { useRoute } from "vue-router";
  276. import _ from "lodash";
  277. import { ElNotification } from "element-plus";
  278. export default {
  279. setup() {
  280. const route = useRoute();
  281. let map = ref();
  282. let voyage = ref({});
  283. let medias = ref();
  284. let coordinates = ref();
  285. let previewSrcList = ref([]);
  286. async function getVoyageDetail() {
  287. let res = await api.getVoyageDetail({
  288. type: 2,
  289. voyageId: route.query.id,
  290. });
  291. coordinates.value = res.data.result.coordinates;
  292. voyage.value = res.data.result.voyage;
  293. medias.value = res.data.result.medias;
  294. for (let i of medias.value) {
  295. previewSrcList.value.push(i.downloadUrl);
  296. }
  297. setShipMarker();
  298. }
  299. function initMap() {
  300. var center = new TMap.LatLng(31.228721, 121.524761);
  301. //初始化地图
  302. map.value = new TMap.Map("map-container", {
  303. zoom: 12, //设置地图缩放级别
  304. center: center, //设置地图中心点坐标
  305. });
  306. }
  307. function setShipMarker(longitude, latitude) {
  308. var marker = new TMap.MultiMarker({
  309. id: "marker-layer", //图层id
  310. map: map.value,
  311. styles: {
  312. //点标注的相关样式
  313. marker: new TMap.MarkerStyle({
  314. width: 25,
  315. height: 35,
  316. anchor: { x: 16, y: 32 },
  317. src: "https://hhd-pat-1255802371.cos.ap-shanghai.myqcloud.com/frontend/ship-red-icon.png",
  318. }),
  319. },
  320. geometries: [
  321. {
  322. //点标注数据数组
  323. id: "demo",
  324. styleId: "marker",
  325. position: new TMap.LatLng(31.228721, 121.524761),
  326. properties: {
  327. title: "marker",
  328. },
  329. },
  330. ],
  331. });
  332. }
  333. let disabledStatus = ref(true);
  334. let updateCache = {};
  335. function changeVoyageInfo() {
  336. updateCache = _.cloneDeep(voyage.value);
  337. disabledStatus.value = false;
  338. }
  339. function cancelVoyageChange() {
  340. voyage.value = updateCache;
  341. disabledStatus.value = true;
  342. }
  343. async function submitVoyageChange() {
  344. let {
  345. id,
  346. transStatus,
  347. loadStartTime,
  348. loadEndTime,
  349. dischargeStartTime,
  350. dischargeEndTime,
  351. actualDischargeTons,
  352. remark,
  353. } = voyage.value;
  354. let res = await api.updateVoyage({
  355. id,
  356. transStatus,
  357. loadStartTime,
  358. loadEndTime,
  359. dischargeStartTime,
  360. dischargeEndTime,
  361. actualDischargeTons,
  362. remark,
  363. });
  364. if (res.data.status == 0) {
  365. ElNotification({
  366. type: "success",
  367. title: res.data.msg,
  368. });
  369. disabledStatus.value = true;
  370. } else {
  371. ElNotification({
  372. type: "error",
  373. title: res.data.msg,
  374. });
  375. console.log(res);
  376. }
  377. }
  378. let options = ref([
  379. {
  380. value: 1,
  381. label: "航行",
  382. },
  383. {
  384. value: 2,
  385. label: "停泊",
  386. },
  387. {
  388. value: 3,
  389. label: "装货",
  390. },
  391. {
  392. value: 4,
  393. label: "运输中",
  394. },
  395. {
  396. value: 5,
  397. label: "卸货",
  398. },
  399. ]);
  400. async function finishVoyage() {
  401. if (!voyage.value.dischargeEndTime) return;
  402. let res = await api.finishVoyage({
  403. voyageId: route.query.id,
  404. });
  405. if (res.data.status == 0) {
  406. voyage.value.voyageStatus = 2;
  407. ElNotification({
  408. type: "success",
  409. title: res.data.msg,
  410. });
  411. } else {
  412. ElNotification({
  413. type: "error",
  414. title: res.data.msg,
  415. });
  416. console.log(res);
  417. }
  418. }
  419. let currentUrl = ref("");
  420. let videoModal = ref(false);
  421. function openVideoModal(url) {
  422. currentUrl.value = url;
  423. videoModal.value = true;
  424. }
  425. onMounted(() => {
  426. initMap();
  427. getVoyageDetail();
  428. });
  429. return {
  430. options,
  431. voyage,
  432. coordinates,
  433. medias,
  434. disabledStatus,
  435. changeVoyageInfo,
  436. cancelVoyageChange,
  437. submitVoyageChange,
  438. finishVoyage,
  439. currentUrl,
  440. videoModal,
  441. openVideoModal,
  442. previewSrcList,
  443. };
  444. },
  445. };
  446. </script>
  447. <style scoped>
  448. .map-container {
  449. width: 100%;
  450. height: 500px;
  451. }
  452. :deep().el-input__inner {
  453. color: #333 !important;
  454. }
  455. .card-note {
  456. height: 30px;
  457. font-size: 12px;
  458. font-family: PingFangSC-Regular, PingFang SC;
  459. font-weight: 400;
  460. color: #777777;
  461. }
  462. .media-box {
  463. width: 200px;
  464. height: 200px;
  465. margin-top: 20px;
  466. }
  467. </style>