Pārlūkot izejas kodu

feat(cert): 新增证书办理功能

- 添加证书办理对话框和相关表单组件
- 实现证书有效期选择、图片上传、办理方式选择等功能
- 集成远程选择组件用于选择证书代办机构
- 优化文件上传组件布局
wzg 6 mēneši atpakaļ
vecāks
revīzija
226fa80a58

+ 8 - 0
src/apis/fetch.js

@@ -472,4 +472,12 @@ export default {
   getCertProcessDetail(data) {
     return $http("/cert/process/detail", data);
   },
+
+  saveShipProcess(data) {
+    return $http("/cert/process/ship", data);
+  },
+
+  saveShipOwnerProcess(data) {
+    return $http("/cert/process/crew", data);
+  },
 };

+ 15 - 12
src/components/RemoteSelect.vue

@@ -3,9 +3,7 @@
     filterable
     :multiple="multiple"
     :multiple-limit="multiple ? 0 : 1"
-    remote
     clearable
-    reserve-keyword
     :placeholder="placeholder"
     :loading="loading"
     @change="selectItem"
@@ -48,11 +46,14 @@ export default {
 
   emits: ["selectItem"],
   setup(props, { emit }) {
-    let loading = ref(true);
-    const getSelectList = _.debounce(
-      async (term) => {
-        if (options.value.length) return;
-        loading.value = true;
+    let loading = ref(false);
+    let options = ref([]);
+    const getSelectList = async () => {
+      if (options.value.length > 0) {
+        return;
+      }
+      loading.value = true;
+      try {
         let res = await api[props.api]({
           ...props.params,
           term: "",
@@ -62,12 +63,14 @@ export default {
         } else {
           options.value = [];
         }
+      } catch (error) {
+        console.error("Failed to fetch select list:", error);
+        options.value = [];
+      } finally {
         loading.value = false;
-      },
-      2000,
-      { leading: true }
-    );
-    let options = ref([]);
+      }
+    };
+
     const selectItem = (item) => {
       emit("selectItem", item);
     };

+ 8 - 2
src/components/Uploader.vue

@@ -1,7 +1,7 @@
 <template>
-  <div class="df aic">
+  <div class="df aic" style="flex-wrap: wrap">
     <div
-      class="df aic mr20"
+      class="df aic mr20 mb20"
       style="position: relative"
       v-for="(item, index) in fileList"
       :key="item.type"
@@ -163,6 +163,12 @@ onMounted(() => {
 :deep().el-upload-dragger {
   width: 148px !important;
   height: 148px !important;
+  margin-bottom: 20px !important;
+}
+
+:deep().el-upload.is-drag {
+  bottom: 10px;
+  position: relative;
 }
 
 .hide:deep() .el-upload--picture-card {

+ 173 - 2
src/views/workStation/certsManage.vue

@@ -158,6 +158,85 @@
           />
         </div>
       </div>
+      <el-dialog :title="dialogTypeName" v-model="ruleFormVisible" width="800">
+        <el-form
+          class="pt20"
+          ref="ruleFormRef"
+          :model="ruleForm"
+          label-width="120px"
+        >
+          <el-form-item :label="ruleForm.typeName" v-if="dialogType != 6">
+            <el-date-picker
+              style="width: 140px; font-size: 13px"
+              v-model="ruleForm.startValidTime"
+              type="date"
+              placeholder="有效期开始时间"
+              value-format="YYYY/MM/DD"
+              format="YYYY/MM/DD"
+            />
+            <div style="margin: 0 4px">-</div>
+            <el-date-picker
+              style="width: 140px; font-size: 13px"
+              v-model="ruleForm.endValidTime"
+              type="date"
+              placeholder="有效期结束时间"
+              value-format="YYYY/MM/DD"
+              format="YYYY/MM/DD"
+            />
+          </el-form-item>
+          <el-form-item label="证书图片">
+            <div class="df">
+              <Uploader
+                class="pb20"
+                :uploaderId="'certsId' + 'country'"
+                :params="dialogType === 6 ? shipOwnerParams : shipParams"
+                :actionUrl="
+                  dialogType === 6
+                    ? store.state.shipOwnerUpdateUrl
+                    : store.state.shipCertUpdateUrl
+                "
+                :fileList="dialogType === 6 ? certFiles : certs"
+                @onUploadFileList="uploadSuccess($event)"
+                @onRemoveFileList="removeSuccess($event)"
+              ></Uploader>
+            </div>
+          </el-form-item>
+          <el-form-item label="办理方式">
+            <el-radio-group
+              v-model="ruleForm.processMethod"
+              @change="handleProcessMethodChange"
+            >
+              <el-radio :label="1">自办</el-radio>
+              <el-radio :label="2">代办</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item
+            label="证书代办机构"
+            v-if="ruleForm.processMethod === 2"
+          >
+            <RemoteSelect
+              class="w200"
+              api="getCertServAuthSelect"
+              v-model="ruleForm.certServAuthName"
+              placeholder="请选择"
+              @selectItem="selectCertServer($event)"
+            ></RemoteSelect>
+          </el-form-item>
+          <el-form-item label="备注">
+            <el-input
+              class="w300"
+              type="textarea"
+              :rows="5"
+              v-model="ruleForm.processRemark"
+              placeholder="请填写"
+            ></el-input>
+          </el-form-item>
+        </el-form>
+        <div class="df aic jcc mt50 pb20">
+          <el-button type="primary" @click="submit">提交</el-button>
+          <el-button @click="ruleFormVisible = false">取消</el-button>
+        </div>
+      </el-dialog>
     </div>
   </div>
 </template>
@@ -264,19 +343,107 @@ function changeSelect(e) {
   validType.value = e;
   getCertList();
 }
-
+const ruleFormVisible = ref(false);
+const ruleFormRef = ref(null);
+const ruleForm = ref({});
+const certs = ref([]);
+const certFiles = ref([]);
+const dialogType = ref(0);
+const dialogTypeName = ref("");
+const shipParams = ref({});
+const shipOwnerParams = ref({ type: 1 });
 async function handleEdit(row) {
   const postData = {
     certType: certType.value,
   };
   if (certType.value == 6) {
     postData["shipOwnerId"] = row.id;
+    ruleForm.value.shipOwnerId = row.id;
+    shipOwnerParams.value.shipOwnerId = row.id;
   } else {
     postData["certValidityPeriodId"] = row.id;
+    ruleForm.value.certValidityPeriodId = row.id;
+    shipParams.value.shipCode = row.shipCode;
   }
+  ruleFormVisible.value = true;
   let { data } = await api.getCertProcessDetail(postData);
-  console.log(data);
+  dialogType.value = data.result.type;
+  dialogTypeName.value = data.result.typeName;
+  ruleForm.value.processMethod = 1;
+  ruleForm.value.certServAuthId = "";
+  ruleForm.value.certServAuthName = "";
+  ruleForm.value.processRemark = "";
+
+  if (data.result.type === 6) {
+    ruleForm.value = { ...ruleForm.value, ...data.result.certDetail };
+    certFiles.value = data.result.certFiles;
+  } else {
+    ruleForm.value = { ...ruleForm.value, ...data.result.certValids[0] };
+    certs.value = data.result.certs;
+    shipParams.value.type = data.result.type;
+  }
+}
+
+function uploadSuccess({ response, file, list }, index) {
+  if (response.status == 0) {
+    let { key, fileKey, viewUrl, downloadUrl, id } = response.result;
+    let data = {
+      fileKey: fileKey || key,
+      viewUrl,
+      downloadUrl,
+      id,
+      url: viewUrl,
+    };
+    if (dialogType.value === 6) {
+      certFiles.value.push(data);
+    } else {
+      certs.value.push(data);
+    }
+  }
+}
+async function removeSuccess({ file, fileIndex }) {
+  let { data } = await api[
+    dialogType.value === 6 ? "deleteShipOwnerCert" : "deleteShipCert"
+  ]({ [dialogType.value === 6 ? "docId" : "shipCertId"]: file.id });
+  if (data.status == 0) {
+    ElMessage({
+      message: "删除成功!",
+      type: "success",
+    });
+    if (dialogType.value === 6) {
+      certFiles.value.splice(fileIndex, 1);
+    } else {
+      certs.value.splice(fileIndex, 1);
+    }
+  }
 }
+
+function handleProcessMethodChange(value) {
+  if (value === 1) {
+    // 自办时清空代办机构
+    ruleForm.value.certServAuthId = "";
+    ruleForm.value.certServAuthName = "";
+  }
+}
+
+function selectCertServer(e) {
+  console.log(e);
+  if (e && e.value) {
+    ruleForm.value.certServAuthId = e.value;
+    ruleForm.value.certServAuthName = e.key;
+  } else {
+    ruleForm.value.certServAuthId = "";
+    ruleForm.value.certServAuthName = "";
+  }
+}
+
+async function submit() {
+  console.log(ruleForm.value);
+  let { data } = await api[
+    dialogType.value === 6 ? "saveShipOwnerProcess" : "saveShipProcess"
+  ](ruleForm.value);
+}
+
 onMounted(() => {
   getCertList();
   getCertListType();
@@ -289,4 +456,8 @@ onMounted(() => {
   width: 180px;
   border-radius: 0;
 }
+
+.w300 {
+  width: 300px;
+}
 </style>