Переглянути джерело

feat(shipOwnerManage): 添加船舶绑定功能

- 新增船舶信息绑定页面
- 实现船舶信息的搜索和绑定
- 优化船员信息保存逻辑
- 添加省份选择接口
wzg 9 місяців тому
батько
коміт
e5b810c6de
1 змінених файлів з 385 додано та 29 видалено
  1. 385 29
      src/views/shipOwnerManage/shipOwnerDetail.vue

+ 385 - 29
src/views/shipOwnerManage/shipOwnerDetail.vue

@@ -279,11 +279,200 @@
       upload-text="点击上传"
     />
   </div>
-  <div class="container-title df aic jcsb pr20">
-    船舶信息
-    <el-button type="primary">添加船舶</el-button>
+  <div v-if="route.query.shipOwnerId">
+    <div class="container-title df aic jcsb pr20">
+      船舶信息
+      <el-button
+        v-if="!shipOwnerForm?.shipInfo?.shipId && !isBindShipVisible"
+        type="primary"
+        @click="bindShip"
+      >
+        绑定船舶
+      </el-button>
+    </div>
+    <div
+      class="line-container-p24"
+      ref="shipInfoSection"
+      v-if="shipOwnerForm?.shipInfo.id || isBindShipVisible"
+    >
+      <div class="line">
+        <div class="info-line">
+          <div class="info-line-title">
+            <span class="red">*</span>
+            船名
+          </div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.shipname"
+            :disabled="shipInfoDisabled"
+          ></el-input>
+          <view class="unit"></view>
+        </div>
+        <div class="info-line">
+          <div class="info-line-title">
+            <span class="red">*</span>
+            MMSI
+          </div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.mmsi"
+            :disabled="
+              shipInfoDisabled ||
+              !!shipOwnerForm.shipInfo.code ||
+              !!shipOwnerForm.shipInfo.shipId
+            "
+            @blur="searchShip($event, currentIndex)"
+          ></el-input>
+        </div>
+      </div>
+      <div class="line">
+        <div class="info-line">
+          <div class="info-line-title">
+            <span class="red">*</span>
+            联系船员姓名
+          </div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.contentShipOwnerName"
+          ></el-input>
+          <view class="unit"></view>
+        </div>
+        <div class="info-line">
+          <div class="info-line-title">
+            <span class="red">*</span>
+            联系手机号
+          </div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.contentShipOwnerPhone"
+          ></el-input>
+          <view class="unit"></view>
+        </div>
+      </div>
+      <div class="line">
+        <div class="info-line">
+          <div class="info-line-title">船籍</div>
+          <el-select
+            style="width: 240px"
+            v-model="shipOwnerForm.shipInfo.registryProvince"
+            placeholder="请选择船籍"
+            :disabled="shipInfoDisabled"
+          >
+            <el-option
+              v-for="item in provinceOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </div>
+      </div>
+      <div class="line">
+        <div class="info-line">
+          <div class="info-line-title">船长</div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.length"
+            :disabled="shipInfoDisabled"
+          ></el-input>
+          <view class="unit">米</view>
+        </div>
+        <div class="info-line">
+          <div class="info-line-title">船宽</div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.breadth"
+            :disabled="shipInfoDisabled"
+          ></el-input>
+          <view class="unit">米</view>
+        </div>
+      </div>
+      <div class="line">
+        <div class="info-line">
+          <div class="info-line-title">载货吨位</div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.loadTons"
+            :disabled="shipInfoDisabled"
+          ></el-input>
+          <view class="unit">吨</view>
+        </div>
+        <div class="info-line">
+          <div class="info-line-title">船龄</div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.age"
+            :disabled="shipInfoDisabled"
+          ></el-input>
+          <view class="unit">年</view>
+        </div>
+      </div>
+      <div class="line">
+        <div class="info-line">
+          <div class="info-line-title">满载吃水</div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.draught"
+            :disabled="shipInfoDisabled"
+          ></el-input>
+          <view class="unit">米</view>
+        </div>
+        <div class="info-line">
+          <div class="info-line-title">吨位(总吨)</div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.tonnage"
+            :disabled="shipInfoDisabled"
+          ></el-input>
+          <view class="unit">吨</view>
+        </div>
+      </div>
+      <div class="line">
+        <div class="info-line">
+          <div class="info-line-title">主机功率</div>
+          <el-input
+            class="info-line-text"
+            v-model="shipOwnerForm.shipInfo.monitorRate"
+            :disabled="shipInfoDisabled"
+          ></el-input>
+          <view class="unit">千瓦</view>
+        </div>
+        <div class="info-line">
+          <div class="info-line-title">南京报备</div>
+          <el-switch
+            v-model="shipOwnerForm.shipInfo.nanjingReport"
+            size="large"
+            active-text="已报备"
+            :active-value="1"
+            inactive-text="未报备"
+            :inactive-value="0"
+            :disabled="shipInfoDisabled"
+          />
+        </div>
+      </div>
+      <div class="line">
+        <div class="info-line">
+          <div class="info-line-title">三峡报备</div>
+          <el-switch
+            v-model="shipOwnerForm.shipInfo.sanxiaReport"
+            size="large"
+            active-text="已报备"
+            :active-value="1"
+            inactive-text="未报备"
+            :inactive-value="0"
+            :disabled="shipInfoDisabled"
+          />
+        </div>
+      </div>
+    </div>
+    <div
+      class="df aic jcfe pr20 pb30"
+      v-if="!shipOwnerForm.shipInfo.id && isBindShipVisible"
+    >
+      <el-button @click="cancelBindShip">取消绑定</el-button>
+      <el-button type="primary" @click="addShip">绑定船舶</el-button>
+    </div>
   </div>
-  <div class="line-container-p24"></div>
 
   <div class="df jcc mt30 mb30" v-if="!route.query.shipOwnerId">
     <el-button @click="router.replace('/shipOwnerManage/shipOwnerList')">
@@ -390,30 +579,66 @@ const certificateRules = {
   certFile: [{ validator: validateCertFile, trigger: "change" }],
 };
 // 初始化船员表单数据结构
+// const shipOwnerForm = ref({
+//   shipOwnerId: 0, // 船员ID,匹配时返回,未匹配到为0,非0时下方内容无效
+//   userName: "", // 船员姓名(必填)
+//   userPhone: "", // 船员手机(必填)
+//   idcardNo: "", // 船员身份证号(非必填)
+//   idcardFrontFileKey: "key", // 船员身份证正面文件key(非必填)
+//   idcardFrontViewUrl: "", // 船员身份证正面文件预览地址(非必填)
+//   idcardFrontDownloadUrl: "", // 船员身份证正面文件下载地址(非必填)
+//   idcardBackFileKey: "", // 船员身份证反面文件key(非必填)
+//   idcardBackViewUrl: "", // 船员身份证反面文件预览地址(非必填)
+//   idcardBackDownloadUrl: "", // 船员身份证反面文件下载地址(非必填)
+//   certificate: {
+//     gender: "", // 性别(1-男;2-女)
+//     certNo: "", // 证书编号(必填)
+//     certType: "", // 证书类型(非必填)
+//     postRole: "", // 职务资格(必填)
+//     issuerAt: "", // 发证日期(必填)
+//     expiryAt: "", // 截止日期(必填)
+//     issuerAuthority: "", // 签发机构(必填)
+//     applicableRestrictions: "", // 适用限制(非必填)
+//   },
+//   documents: [], // 文件信息数组
+// shipInfo:{}
+// });
 const shipOwnerForm = ref({
-  shipOwnerId: 0, // 船员ID,匹配时返回,未匹配到为0,非0时下方内容无效
-  userName: "", // 船员姓名(必填)
-  userPhone: "", // 船员手机(必填)
-  idcardNo: "", // 船员身份证号(非必填)
-  idcardFrontFileKey: "key", // 船员身份证正面文件key(非必填)
-  idcardFrontViewUrl: "", // 船员身份证正面文件预览地址(非必填)
-  idcardFrontDownloadUrl: "", // 船员身份证正面文件下载地址(非必填)
-  idcardBackFileKey: "", // 船员身份证反面文件key(非必填)
-  idcardBackViewUrl: "", // 船员身份证反面文件预览地址(非必填)
-  idcardBackDownloadUrl: "", // 船员身份证反面文件下载地址(非必填)
+  shipOwnerId: 0,
+  userName: "测试船员18",
+  userPhone: "13989999918",
+  idcardNo: "",
+  idcardFrontFileKey: "key",
+  idcardFrontViewUrl: "",
+  idcardFrontDownloadUrl: "",
+  idcardBackFileKey: "",
+  idcardBackViewUrl: "",
+  idcardBackDownloadUrl: "",
   certificate: {
-    gender: "", // 性别(1-男;2-女)
-    certNo: "", // 证书编号(必填)
-    certType: "", // 证书类型(非必填)
-    postRole: "", // 职务资格(必填)
-    issuerAt: "", // 发证日期(必填)
-    expiryAt: "", // 截止日期(必填)
-    issuerAuthority: "", // 签发机构(必填)
-    applicableRestrictions: "", // 适用限制(非必填)
+    gender: 1,
+    certNo: "9",
+    certType: "",
+    postRole: "大副",
+    issuerAt: "2025-04-15T16:00:00.000Z",
+    expiryAt: "2025-04-29T16:00:00.000Z",
+    issuerAuthority: "99",
+    applicableRestrictions: "999",
   },
-  documents: [], // 文件信息数组
+  documents: [
+    {
+      docType: 1,
+      fileKey:
+        "new/ship_onwer_doc_temp/汇很多船务公司/976a8dc8-94d9-4d0a-ba82-5ddfafddcbc81744727290090.png",
+      viewUrl:
+        "https://hhd-shipping-formal-1255802371.cos.ap-shanghai.myqcloud.com/new/ship_onwer_doc_temp/%E6%B1%87%E5%BE%88%E5%A4%9A%E8%88%B9%E5%8A%A1%E5%85%AC%E5%8F%B8/976a8dc8-94d9-4d0a-ba82-5ddfafddcbc81744727290090.png?sign=q-sign-algorithm%3Dsha1%26q-ak%3DAKID4xb091cy4tRikV0EBrGOGsCF1WkhMlum%26q-sign-time%3D1744727290%3B93158697600%26q-key-time%3D1744727290%3B93158697600%26q-header-list%3Dhost%26q-url-param-list%3D%26q-signature%3D86b5d9af068ca7a19038b9c67a795cfde834a1d8",
+      downloadUrl:
+        "https://hhd-shipping-formal-1255802371.cos.ap-shanghai.myqcloud.com/new/ship_onwer_doc_temp/%E6%B1%87%E5%BE%88%E5%A4%9A%E8%88%B9%E5%8A%A1%E5%85%AC%E5%8F%B8/976a8dc8-94d9-4d0a-ba82-5ddfafddcbc81744727290090.png?sign=q-sign-algorithm%3Dsha1%26q-ak%3DAKID4xb091cy4tRikV0EBrGOGsCF1WkhMlum%26q-sign-time%3D1744727290%3B93156019200%26q-key-time%3D1744727290%3B93156019200%26q-header-list%3Dhost%26q-url-param-list%3Dresponse-cache-control%3Bresponse-content-disposition%3Bresponse-content-language%3Bresponse-content-type%3Bresponse-expires%26q-signature%3D3ebfed3521abe099246ad7cf1370606769ad89cc&response-cache-control=no-cache&response-content-disposition=filename%3D%2255.png%22&response-content-language=zh-CN&response-expires=Wed%2C%2016%20Apr%202025%2014%3A28%3A10%20GMT&response-content-type=application%2Foctet-stream",
+    },
+  ],
+  loginAccountId: "19",
+  shippingId: "15",
+  shipInfo: {},
 });
-
 // 计算属性 - 文件列表
 const idCardFrontFileList = computed(() => {
   if (
@@ -497,6 +722,7 @@ async function getShipOwnerDetail() {
       },
       // 处理文档信息
       documents: data.result.documents || [],
+      shipInfo: data.result.shipInfo || {},
     };
   } else {
     ElMessage.error(data.msg || "获取船员详情失败");
@@ -671,9 +897,9 @@ const cancelEditingBasicInfo = () => {
 
 // 保存基本信息
 const saveBasicInfo = () => {
-  shipOwnerFormRef.value.validate((valid) => {
+  shipOwnerFormRef.value.validate(async (valid) => {
     if (!valid) return;
-
+    if (!(await confirm("确定保存基本信息吗?"))) return;
     // 构建保存数据
     const saveData = {
       shipOwnerId: shipOwnerForm.value.shipOwnerId,
@@ -734,7 +960,7 @@ const cancelEditingCertificate = () => {
 
 // 保存证书信息
 const updateShipOwnerCert = () => {
-  certificateFormRef.value.validate((valid) => {
+  certificateFormRef.value.validate(async (valid) => {
     if (!valid) return;
 
     // 验证证书照片是否上传
@@ -742,6 +968,7 @@ const updateShipOwnerCert = () => {
       ElMessage.warning("请上传证书照片");
       return;
     }
+    if (!(await confirm("确定保存证书信息吗?"))) return;
 
     // 构建保存数据
     const saveData = {
@@ -778,15 +1005,17 @@ const saveShipOwner = () => {
   shipOwnerFormRef.value.validate((valid1) => {
     if (!valid1) return;
 
-    certificateFormRef.value.validate((valid2) => {
+    certificateFormRef.value.validate(async (valid2) => {
       if (!valid2) return;
 
-      验证证书照片是否上传;
+      // 验证证书照片是否上传;
       if (!certFileList.value.length) {
         ElMessage.warning("请上传证书照片");
         return;
       }
 
+      if (!(await confirm("确定保存船员信息吗?"))) return;
+
       // 如果有ID,则更新,否则新增
       const apiMethod = route.query.shipOwnerId
         ? api.updateShipOwner
@@ -813,6 +1042,14 @@ const saveShipOwner = () => {
                 JSON.stringify(shipOwnerForm.value)
               );
             }
+          } else if (res.data.status === 3) {
+            router
+              .replace(
+                `/shipOwnerManage/shipOwnerDetail?shipOwnerId=${res.data.result.id}&isAdd=true`
+              )
+              .then(() => {
+                window.location.reload();
+              });
           } else {
             ElMessage.error(res.data.msg || "保存失败");
           }
@@ -826,6 +1063,125 @@ const saveShipOwner = () => {
   });
 };
 
+const isBindShipVisible = ref(false);
+const shipInfoDisabled = ref(false);
+const shipInfoSection = ref(null);
+
+function bindShip() {
+  if (isBindShipVisible.value) return;
+  isBindShipVisible.value = true;
+  getProvinceSelect();
+  // 1秒后页面向下滚动
+  setTimeout(() => {
+    if (shipInfoSection.value) {
+      shipInfoSection.value.scrollIntoView({ behavior: "smooth" });
+    }
+  }, 50);
+}
+const provinceOptions = ref([]);
+async function getProvinceSelect() {
+  let { data } = await api.getProvinceSelect();
+  if (data.status === 0) {
+    provinceOptions.value = data.result;
+  } else {
+    provinceOptions.value = [];
+  }
+}
+
+async function searchShip(e) {
+  if (e.target.value.length != 9) return;
+  const loading = ElLoading.service({
+    lock: true,
+    text: "正在匹配船舶...",
+    background: "rgba(0, 0, 0, 0.7)",
+  });
+  let { data } = await api.searchShip({
+    mmsi: e.target.value,
+  });
+  loading.close();
+  console.log(data);
+  if (data.status == 0) {
+    shipOwnerForm.value.shipInfo = data.result;
+    shipInfoDisabled.value = true;
+  }
+}
+
+function cancelBindShip() {
+  isBindShipVisible.value = false;
+  shipInfoDisabled.value = false;
+  shipOwnerForm.value.shipInfo = {};
+}
+async function addShip() {
+  if (!shipOwnerForm.value.shipInfo.shipname) {
+    ElMessage({
+      type: "warning",
+      message: "请填写船舶名称",
+    });
+    return;
+  }
+  if (!shipOwnerForm.value.shipInfo.mmsi) {
+    ElMessage({
+      type: "warning",
+      message: "请填写船舶MMSI",
+    });
+    return;
+  }
+  if (!shipOwnerForm.value.shipInfo.contentShipOwnerName) {
+    ElMessage({
+      type: "warning",
+      message: "请填写船员姓名",
+    });
+    return;
+  }
+  if (!shipOwnerForm.value.shipInfo.contentShipOwnerPhone) {
+    ElMessage({
+      type: "warning",
+      message: "请填写船员手机号",
+    });
+    return;
+  }
+  if (!(await confirm("确认绑定船舶?"))) return;
+
+  let { data } = await api.addShip({
+    ...shipOwnerForm.value.shipInfo,
+    shipOwnerId: route.query.shipOwnerId,
+  });
+
+  if (data.status == 0) {
+    ElMessage({
+      type: "success",
+      message: "绑定成功",
+    });
+  } else {
+    ElMessage({
+      type: "error",
+      message: data.msg,
+    });
+  }
+}
+
+async function confirm(
+  text = "确定操作?",
+  title = "提示",
+  confirmButtonText = "确定",
+  cancelButtonText = "取消",
+  type = "warning"
+) {
+  return new Promise((resolve, reject) => {
+    ElMessageBox.confirm(text, title, {
+      confirmButtonText,
+      cancelButtonText,
+      type,
+    })
+      .then(() => {
+        resolve(true);
+      })
+      .catch(() => {
+        resolve(false);
+      });
+  });
+}
+
 // 初始化数据
 onMounted(() => {
   // 如果有ID参数,获取船员详情