JS默认参数传递额外参数(多文件上传, uploading)

发布时间 2023-06-09 18:42:53作者: Felix_Openmind
<!--
  module name: 应用介绍
-->
<template>
  <div
    class="main-intro"
    :style="{
      padding: props.type === 'serviceType' ? '0' : '0 16px',
      margin: props.type === 'serviceType' ? '0 0' : '0  auto',
    }"
  >
    <div class="main-intro-form">
      <a-form :model="formState" :label-col="labelCol" >
        <a-form-item :label="props.appName" :rules="[{ required: true }]">
          <a-textarea
            v-model:value="formState.appIntro"
            style="width: 100%"
            :disabled="props.disabledType"
          />
        </a-form-item>
        <a-form-item label="功能介绍" name="funcIntros">
          <div
            v-for="(intro, index) in formState.funcIntros"
            :key="index"
            style="margin-top: 5px; display: flex"
          >
            <a-input
              v-model:value="intro.name"
              placeholder="输入功能名称"
              style="width: 45%; border-radius: 5px"
              autoclear
              :disabled="props.disabledType"
            >
            </a-input>
            <a-input
              v-model:value="intro.desc"
              style="width: 45%; margin-left: 20px; border-radius: 5px"
              placeholder="功能描述"
              autoclear
              :disabled="props.disabledType"
            >
            </a-input>
            <PlusOutlined
              style="font-size: 20px; margin-left: 10px; color: #cccccc"
              v-show="index === 0"
              type="plus"
              @click="addDomain"
            />
            <MinusOutlined
              v-show="index !== 0 && index >= state.initIntrosSize"
              :disabled="index === 1"
              style="font-size: 20px; margin-left: 10px; color: #cccccc"
              @click="removeDomain(intro)"
            />
          </div>
        </a-form-item>
        <a-form-item label="系统截图" name="osScreenshots">
          <div class="snapshot-container">
            <div class="img-box" v-for="(item, index) in formState.osFiles">
              <div v-if="item.response === undefined">
                <a-spin style="position: relative; top: 80px; left: 60px" />
              </div>
              <div v-if="item.response !== undefined">
                <div>
                  <img
                    alt="系统截图"
                    class="img"
                    :src="item.response.data.address"
                  />
                  <CloseCircleFilled
                    class="close-circle"
                    @click="delOsImg(index)"
                  />
                </div>
                <a-input
                  placeholder="截图名称"
                  v-model:value="item.response.data.name"
                  style="
                    width: 150px;
                    border: 1px solid #e9e9e9;
                    margin-top: 15px;
                  "
                  :disabled="props.disabledType"
                />
              </div>
            </div>
            <div class="upload-container">
              <a-upload
                v-model:file-list="formState.osFiles"
                action="/empower/attachment/upload"
                list-type="picture-card"
                :show-upload-list="false"
                :disabled="props.disabledType"
              >
                <plus-outlined />
                <div class="ant-upload-text">图片上传</div>
              </a-upload>
            </div>
          </div>
        </a-form-item>
        <a-form-item label="学习视频" name="learningVideos">
          <div class="videos-container">
            <div
              v-for="(item, index) in formState.learningVideos"
              class="video-box"
            >
              <div v-if="item.response === undefined">
                <a-spin style="position: relative; top: 80px; left: 60px" />
              </div>
              <div
                v-if="item.response !== undefined"
                style="margin-right: 20px"
              >
                <video
                  :src="item.response.data.address"
                  controls
                  class="video"
                />
                <CloseCircleFilled
                  class="close-circle"
                  @click="delVideo(index)"
                />
              </div>
              <a-input
                v-model:value="item.response.data.name"
                style="width: 285px"
                v-if="item.response !== undefined"
                placeholder="视频名称"
                :disabled="props.disabledType"
              />
            </div>
            <div class="upload-video">
              <a-upload
                v-model:file-list="formState.learningVideos"
                action="/empower/attachment/upload"
                list-type="picture-card"
                :show-upload-list="false"
                :disabled="props.disabledType"
              >
                <div v-if="formState.learningVideos.length < 8">
                  <plus-outlined />
                  <div class="ant-upload-text">视频上传</div>
                </div>
              </a-upload>
            </div>
          </div>
        </a-form-item>
        <a-form-item label="学习文档">
          <a-upload
            v-model:file-list="formState.learningFiles"
            name="file"
            :multiple="true"
            action="/empower/attachment/upload"
            @change="learningFilesChange"
            :disabled="props.disabledType"
            style="width: 350px"
          >
            <a-button
              style="background-color: #eaf2ff; border: none"
              :loading="fileLoading"
            >
              <upload-outlined />
              <span style="color: #2c79ff">上传</span>
            </a-button>
          </a-upload>
        </a-form-item>
      </a-form>
    </div>
  </div>
</template>

<script setup>
import {
  defineComponent,
  ref,
  reactive,
  watch,
  watchEffect,
  defineExpose,
  defineEmits,
  toRaw,
  onBeforeUnmount,
  onMounted,
} from "vue";
import { useRoute, useRouter } from "vue-router";
import { message } from "ant-design-vue";
import { nanoid } from "nanoid";
import mitt from "@/utils/mitt";
import {
  MinusOutlined,
  PlusOutlined,
  UploadOutlined,
  CloseCircleFilled,
} from "@ant-design/icons-vue";

const router = useRouter();
const route = useRoute();
const labelCol = { style: { width: "75px" } };
const state = reactive({
  fileLoading: false,
  initIntrosSize: 1,
});
const previewVisible = ref(false);
const previewImage = ref("");
const props = defineProps(["type", "disabledType", "appName"]);

const formState = reactive({
  appIntro: "", // 应用简介
  funcIntros: [
    {
      name: "",
      desc: "",
    },
  ], // 功能介绍
  osFiles: [], // 系统截图文件对象
  osScreenshots: [], // 系统截图
  learningVideos: [], // 学习视频
  learningFiles: [], // 学习文档
  fileList: [],
});

// ======================= 功能介绍 start ====================
const removeDomain = (intro) => {
  let index = formState.funcIntros.indexOf(intro);
  if (index !== -1) {
    formState.funcIntros.splice(index, 1);
  }
};
const addDomain = () => {
  formState.funcIntros.push({
    name: "", // 功能名称
    desc: "", // 功能描述
  });
};
// ======================= 功能介绍 end ====================

// ====================== 系统截图 start ===================
const handleCancel = () => {
  previewVisible.value = false;
};
const handlePreview = async (file) => {
  console.log("file 预览", file);
  if (!file.url && !file.preview) {
    file.preview = await getBase64(file.originFileObj);
  }
  previewImage.value = file.url || file.preview;
  previewVisible.value = true;
};
const handleChange = ({ fileList: newFileList }) => {
  fileList.value = newFileList;
};

const getBase64 = (file) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = (error) => reject(error);
  });
};
// ====================== 系统截图 end   ===================
const osFileChange = (e) => {
  console.log("e:::: ", e);
  let fileList = [...e.fileList];
  let formFiles = fileList.map((file) => {
    let resArr = [];
    if (file.response !== undefined) {
      resArr.push({
        snapshotName: "",
        ...file,
        address: file.response.data.address,
        id: file.response.data.id,
      });
    }
    return resArr;
  });
  if (formFiles.length > 0) {
    formState.osScreenshots = formFiles.map((formFile) => {
      return formFile;
    });
  }
};

const delOsImg = (index) => {
  formState.osFiles.splice(index, 1);
};
// ====================== 学习视频 start ===================
const delVideo = (index) => {
  formState.learningVideos.splice(index, 1);
};
// TODO videosChange
const videosChange = (e) => {
  let fileList = [...e.fileList];
  let formFiles = fileList.map((file) => {
    let resArr = [];
    if (file.response !== undefined) {
      resArr.push({
        name: "",
        ...file,
        address: file.response.data.address,
        id: file.response.data.id,
      });
    }
    return resArr;
  });
  if (formFiles.length > 0) {
    formState.osScreenshots = formFiles.map((formFile) => {
      return formFile;
    });
  }
};
// ====================== 学习视频 end   ===================

// ====================== 学习文档 start ===================
const learningFilesChange = (e) => {
  let fileList = [...e.fileList];
  console.log("fileList::: ", fileList);
  //read from response and show file link
  fileList = fileList.map((file) => {
    if (file.response) {
      // Component will show file.url as link
      file.url = file.response.address;
    }
    return file;
  });

  formState.fileList = fileList;
};

const delFiles = (index) => {
  formState.learningFiles.splice(index, 1);
};
// ====================== 学习文档 end   ===================
defineExpose({
  formState,
});
</script>

<style lang="scss" scoped>
.ant-upload-select-picture-card i {
  font-size: 32px;
  color: #999;
}

.ant-upload-select-picture-card .ant-upload-text {
  margin-top: 8px;
  color: #666;
}

.main-intro {
  padding: 0 16px;
  width: 600px;
  text-align: left;
  margin: 0 auto;

  &-form {
    border-radius: 8px;
    padding: 0 24px;
    background-color: #fff;

    .snapshot-container {
      display: flex;
      flex-wrap: wrap;

      .img-box {
        width: 150px;
        margin-right: 15px;
        position: relative;

        .img {
          width: 100%;
          height: 150px;

          &:hover {
            border: 4px solid #4688f1;
          }
        }
        &:hover .close-circle {
          display: inline-block;
        }
        .close-circle {
          font-size: 20px;
          color: #4688f1;
          position: absolute;
          right: -13px;
          top: -10px;
          cursor: pointer;
          display: none;
        }
      }
    }

    .videos-container {
      display: flex;
      flex-wrap: wrap;

      .video-box {
        position: relative;
        width: 305px;
        margin-right: 8px;
        .video {
          width: 100%;
          height: 170px;
          border-radius: 5px;

          &:hover {
            border: 4px solid #4688f1;
          }
        }

        &:hover .close-circle {
          display: inline-block;
        }

        .close-circle {
          font-size: 20px;
          color: #4688f1;
          position: absolute;
          right: 6px;
          top: -7px;
          cursor: pointer;
          display: none;
        }
      }
    }

    .upload-video {
      height: 222px;
    }

    :deep(.ant-upload.ant-upload-select-picture-card) {
      width: 150px;
      height: 171px;
      border: 1px solid #d0d4da;
      background-color: #fff;
    }

    :deep(.anticon-plus) {
      color: #d7d7d7;
      font-size: 30px;
      font-weight: 900;
    }

    :deep(.ant-btn .anticon) {
      color: #2c79ff;
    }

    :deep(.ant-upload-list) {
      width: 40% !important;
    }
  }
}
:deep(.ant-upload-list-item) {
  width: 450px;
}
</style>