Ver código fonte

更新 航次详情(修改航次

wangzhihui 4 anos atrás
pai
commit
f3ef65cfa7
4 arquivos alterados com 569 adições e 4 exclusões
  1. 50 1
      src/App.vue
  2. 15 0
      src/apis/fetch.js
  3. BIN
      src/assets/ship-red-icon.png
  4. 504 3
      src/views/voyage/voyageDetail.vue

+ 50 - 1
src/App.vue

@@ -72,7 +72,7 @@ export default {
 
 .main-section {
   margin: 24px 0 0 24px;
-  height: calc(100% - 140px);
+  height: calc(100% - 76px);
   overflow: scroll;
 }
 
@@ -102,6 +102,9 @@ export default {
 .jcsa {
   justify-content: space-around;
 }
+.jcsb {
+  justify-content: space-between;
+}
 
 .aic {
   align-items: center;
@@ -115,6 +118,14 @@ export default {
   margin-left: 8px;
 }
 
+.acfe {
+  justify-content: flex-end;
+}
+
+.mt20 {
+  margin-top: 20px;
+}
+
 .container-title {
   font-size: 18px;
   font-family: PingFangSC-Medium, PingFang SC;
@@ -122,4 +133,42 @@ export default {
   color: #0094fe;
   margin: 30px 0 15px 0;
 }
+
+.line {
+  display: flex;
+  align-items: center;
+  align-content: flex-start;
+  margin: 20px;
+}
+
+.info-line {
+  display: flex;
+  align-items: center;
+  align-content: flex-start;
+  margin-right: 20px;
+}
+
+.info-line-title {
+  width: 100px;
+  height: 100%;
+  font-size: 14px;
+  font-family: PingFangSC-Regular, PingFang SC;
+  font-weight: 400;
+  color: #353a42;
+  line-height: 100%;
+  text-align: right;
+  padding-right: 20px;
+}
+
+.info-line-text {
+  width: 240px !important;
+  height: 100%;
+  line-height: 100%;
+}
+
+.info-line-textarea {
+  width: 620px;
+  height: 100%;
+  line-height: 100%;
+}
 </style>

+ 15 - 0
src/apis/fetch.js

@@ -25,6 +25,21 @@ export default {
     return $http("post", "voyage/list", data);
   },
 
+  // 获取航次详情
+  getVoyageDetail(data) {
+    return $http("post", "/voyage/detail", data);
+  },
+
+  // 更新航次
+  updateVoyage(data) {
+    return $http("post", "/voyage/backstage/update", data);
+  },
+
+  // 完成航次
+  finishVoyage(data) {
+    return $http("post", "/voyage/backstage/finish", data);
+  },
+
   // 根据船名/MMSI/船东手机号获取船舶用户信息(员工端添加航次选择船)
   getUserInfoAndShipInfo(data) {
     return $http("post", "ship/backstage/userShipInfo", data);

BIN
src/assets/ship-red-icon.png


+ 504 - 3
src/views/voyage/voyageDetail.vue

@@ -1,9 +1,510 @@
-<template>voyageDetail</template>
+<template>
+  <div class="line-container-p18">
+    <i class="el-icon-arrow-left"></i>
+    <div class="dib go-back ml8">返回航次列表</div>
+    <div class="line">
+      <div class="info-line">
+        <div class="info-line-title">航次名称</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.voyageName"
+          disabled
+        ></el-input>
+      </div>
+      <div class="info-line">
+        <div class="info-line-title">货主</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.cargoOwnerName"
+          disabled
+        ></el-input>
+      </div>
+    </div>
+    <div class="line">
+      <div class="info-line">
+        <div class="info-line-title">船东</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.shipOwnerName"
+          disabled
+        ></el-input>
+      </div>
+      <div class="info-line">
+        <div class="info-line-title">船东手机号</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.shipOwnerPhone"
+          disabled
+        ></el-input>
+      </div>
+    </div>
+    <div class="line">
+      <div class="info-line">
+        <div class="info-line-title">船舶</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.shipName"
+          disabled
+        ></el-input>
+      </div>
+      <div class="info-line">
+        <div class="info-line-title">MMSI</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.shipMmsi"
+          disabled
+        ></el-input>
+      </div>
+    </div>
+    <div id="map-container" class="map-container"></div>
+    <div class="line" style="margin-top: 30px">
+      <div class="info-line">
+        <div class="info-line-title">开始时间</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.startTime"
+          disabled
+        ></el-input>
+      </div>
+      <div class="info-line">
+        <div class="info-line-title">结束时间</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.endTime"
+          disabled
+        ></el-input>
+      </div>
+    </div>
+    <div class="line">
+      <div class="info-line">
+        <div class="info-line-title">装货港</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.loadPort"
+          disabled
+        ></el-input>
+      </div>
+      <div class="info-line">
+        <div class="info-line-title">卸货港</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.dischargeProt"
+          disabled
+        ></el-input>
+      </div>
+    </div>
+    <div class="line">
+      <div class="info-line">
+        <div class="info-line-title">货种</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.cargo"
+          disabled
+        ></el-input>
+      </div>
+      <div class="info-line">
+        <div class="info-line-title">吨位</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.tons"
+          disabled
+        ></el-input>
+      </div>
+    </div>
+  </div>
+  <div class="container-title">航次信息</div>
+  <div class="line-container-p18">
+    <div class="line">
+      <div class="info-line">
+        <div class="info-line-title">运输状态</div>
+        <el-select
+          v-model="voyage.transStatus"
+          placeholder="Select"
+          class="info-line-text"
+          :disabled="disabledStatus"
+        >
+          <el-option
+            v-for="item in options"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          ></el-option>
+        </el-select>
+      </div>
+      <div class="info-line">
+        <div class="info-line-title">实际卸货吨位</div>
+        <el-input
+          class="info-line-text"
+          v-model="voyage.actualDischargeTons"
+          :disabled="disabledStatus"
+        ></el-input>
+      </div>
+    </div>
+    <div class="line">
+      <div class="info-line">
+        <div class="info-line-title">装货开始时间</div>
+        <el-date-picker
+          class="info-line-text"
+          v-model="voyage.loadStartTime"
+          type="datetime"
+          format="YYYY/MM/DD HH:mm:ss"
+          value-format="YYYY/MM/DD HH:mm:ss"
+          placeholder="装货开始时间"
+          :disabled="disabledStatus"
+        ></el-date-picker>
+      </div>
+      <div class="info-line">
+        <div class="info-line-title">装货结束时间</div>
+        <el-date-picker
+          class="info-line-text"
+          v-model="voyage.loadEndTime"
+          type="datetime"
+          format="YYYY/MM/DD HH:mm:ss"
+          value-format="YYYY/MM/DD HH:mm:ss"
+          placeholder="装货开始时间"
+          :disabled="disabledStatus"
+        ></el-date-picker>
+      </div>
+    </div>
+    <div class="line">
+      <div class="info-line">
+        <div class="info-line-title">卸货开始时间</div>
+        <el-date-picker
+          class="info-line-text"
+          v-model="voyage.dischargeStartTime"
+          type="datetime"
+          format="YYYY/MM/DD HH:mm:ss"
+          value-format="YYYY/MM/DD HH:mm:ss"
+          placeholder="装货开始时间"
+          :disabled="disabledStatus"
+        ></el-date-picker>
+      </div>
+      <div class="info-line">
+        <div class="info-line-title">卸货结束时间</div>
+        <el-date-picker
+          class="info-line-text"
+          v-model="voyage.dischargeEndTime"
+          type="datetime"
+          format="YYYY/MM/DD HH:mm:ss"
+          value-format="YYYY/MM/DD HH:mm:ss"
+          placeholder="装货开始时间"
+          :disabled="disabledStatus"
+        ></el-date-picker>
+      </div>
+    </div>
+    <div class="line">
+      <div class="info-line">
+        <div class="info-line-title">备注</div>
+        <el-input
+          class="info-line-textarea"
+          v-model="voyage.remark"
+          autosize
+          type="textarea"
+          :disabled="disabledStatus"
+        ></el-input>
+      </div>
+    </div>
+    <div
+      class="media-content df ffw"
+      style="
+        width: 100%;
+        height: 400px;
+        background: #f7f7f7;
+        border-radius: 2px;
+      "
+    >
+      <el-card
+        style="
+          width: 240px;
+          height: 360px;
+          margin-left: 20px;
+          margin-bottom: 15px;
+        "
+        v-for="item in medias"
+        :key="item"
+        shadow="hover"
+      >
+        <div class="card-note">
+          {{ item.note }}
+        </div>
+        <div class="media-box" style="position: relative">
+          <el-image
+            v-if="item.mediaType == 1"
+            style="width: 100%; height: 100%"
+            fit="contain"
+            :src="item.downloadUrl"
+            :preview-src-list="previewSrcList"
+          ></el-image>
+          <video
+            style="width: 100%; height: 100%"
+            v-else
+            :src="item.downloadUrl"
+          ></video>
+          <img
+            @click="openVideoModal(item.downloadUrl)"
+            v-if="item.mediaType == 2"
+            src="../../assets/icon-player.png"
+            style="
+              object-fit: contain;
+              width: 40px;
+              height: 40px;
+              position: absolute;
+              top: calc(50% - 20px);
+              left: calc(50% - 20px);
+              background: #fff;
+              border-radius: 50%;
+            "
+            alt=""
+          />
+        </div>
+      </el-card>
+
+      <el-dialog
+        v-model="videoModal"
+        title="视频审核"
+        width="30%"
+        :before-close="videoClose"
+      >
+        <video
+          autoplay
+          controls
+          style="width: 100%; height: 100%"
+          :src="currentUrl"
+        ></video>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button type="primary" @click="dialogAuditVideo(1)">
+              通过
+            </el-button>
+            <el-button type="warning" @click="dialogAuditVideo(2)">
+              未通过
+            </el-button>
+          </span>
+        </template>
+      </el-dialog>
+    </div>
+    <div class="df aic acfe mt20" v-if="voyage.voyageStatus == 1">
+      <el-button v-if="disabledStatus" type="primary" @click="changeVoyageInfo">
+        修改航次
+      </el-button>
+      <div v-else>
+        <div>
+          <el-button @click="cancelVoyageChange">取消修改</el-button>
+          <el-button type="primary" @click="submitVoyageChange">
+            提交修改
+          </el-button>
+        </div>
+      </div>
+      <el-button
+        v-if="voyage.dischargeEndTime && disabledStatus"
+        type="primary"
+        @click="finishVoyage"
+      >
+        完成航次
+      </el-button>
+    </div>
+  </div>
+</template>
 <script>
+import { onMounted, reactive, ref, toRefs } from "_vue@3.2.20@vue";
+import api from "../../apis/fetch";
+import { useRoute } from "vue-router";
+import _ from "lodash";
+import { ElNotification } from "element-plus";
+
 export default {
   setup() {
-    return {};
+    const route = useRoute();
+    let map = ref();
+    let voyage = ref({});
+    let medias = ref();
+    let coordinates = ref();
+    let previewSrcList = ref([]);
+
+    async function getVoyageDetail() {
+      let res = await api.getVoyageDetail({
+        type: 2,
+        voyageId: route.query.id,
+      });
+
+      coordinates.value = res.data.result.coordinates;
+      voyage.value = res.data.result.voyage;
+      medias.value = res.data.result.medias;
+      for (let i of medias.value) {
+        previewSrcList.value.push(i.downloadUrl);
+      }
+      setShipMarker();
+    }
+
+    function initMap() {
+      var center = new TMap.LatLng(31.228721, 121.524761);
+      //初始化地图
+      map.value = new TMap.Map("map-container", {
+        zoom: 12, //设置地图缩放级别
+        center: center, //设置地图中心点坐标
+      });
+    }
+
+    function setShipMarker(longitude, latitude) {
+      var marker = new TMap.MultiMarker({
+        id: "marker-layer", //图层id
+        map: map.value,
+        styles: {
+          //点标注的相关样式
+          marker: new TMap.MarkerStyle({
+            width: 25,
+            height: 35,
+            anchor: { x: 16, y: 32 },
+            src: "https://hhd-pat-1255802371.cos.ap-shanghai.myqcloud.com/frontend/ship-red-icon.png",
+          }),
+        },
+        geometries: [
+          {
+            //点标注数据数组
+            id: "demo",
+            styleId: "marker",
+            position: new TMap.LatLng(31.228721, 121.524761),
+            properties: {
+              title: "marker",
+            },
+          },
+        ],
+      });
+    }
+
+    let disabledStatus = ref(true);
+    let updateCache = {};
+    function changeVoyageInfo() {
+      updateCache = _.cloneDeep(voyage.value);
+      disabledStatus.value = false;
+    }
+    function cancelVoyageChange() {
+      voyage.value = updateCache;
+      disabledStatus.value = true;
+    }
+    async function submitVoyageChange() {
+      let {
+        id,
+        transStatus,
+        loadStartTime,
+        loadEndTime,
+        dischargeStartTime,
+        dischargeEndTime,
+        actualDischargeTons,
+        remark,
+      } = voyage.value;
+      let res = await api.updateVoyage({
+        id,
+        transStatus,
+        loadStartTime,
+        loadEndTime,
+        dischargeStartTime,
+        dischargeEndTime,
+        actualDischargeTons,
+        remark,
+      });
+      if (res.data.status == 0) {
+        ElNotification({
+          type: "success",
+          title: res.data.msg,
+        });
+        disabledStatus.value = true;
+      } else {
+        ElNotification({
+          type: "error",
+          title: res.data.msg,
+        });
+        console.log(res);
+      }
+    }
+    let options = ref([
+      {
+        value: 1,
+        label: "航行",
+      },
+      {
+        value: 2,
+        label: "停泊",
+      },
+      {
+        value: 3,
+        label: "装货",
+      },
+      {
+        value: 4,
+        label: "运输中",
+      },
+      {
+        value: 5,
+        label: "卸货",
+      },
+    ]);
+
+    async function finishVoyage() {
+      if (!voyage.value.dischargeEndTime) return;
+      let res = await api.finishVoyage({
+        voyageId: route.query.id,
+      });
+
+      if (res.data.status == 0) {
+        voyage.value.voyageStatus = 2;
+        ElNotification({
+          type: "success",
+          title: res.data.msg,
+        });
+      } else {
+        ElNotification({
+          type: "error",
+          title: res.data.msg,
+        });
+        console.log(res);
+      }
+    }
+
+    function openVideoModal(url) {
+      currentUrl.value = url;
+      videoModal.value = true;
+    }
+
+    onMounted(() => {
+      initMap();
+      getVoyageDetail();
+    });
+    return {
+      options,
+      voyage,
+      coordinates,
+      medias,
+      disabledStatus,
+      changeVoyageInfo,
+      cancelVoyageChange,
+      submitVoyageChange,
+      finishVoyage,
+      openVideoModal,
+      previewSrcList,
+    };
   },
 };
 </script>
-<style scoped></style>
+<style scoped>
+.map-container {
+  width: 100%;
+  height: 500px;
+}
+:deep().el-input__inner {
+  color: #333 !important;
+}
+.card-note {
+  height: 30px;
+  font-size: 12px;
+  font-family: PingFangSC-Regular, PingFang SC;
+  font-weight: 400;
+  color: #777777;
+}
+
+.media-box {
+  width: 200px;
+  height: 200px;
+  margin-top: 20px;
+}
+</style>