
<template>
  <el-dialog
    :title="'创建镜像构建器'"
    :close-on-click-modal="false"
    :visible.sync="visible"
    @close="cancel"
    width="70%"
  >
    <el-steps :active="active" finish-status="success">
      <el-step title="选择语言"></el-step>
      <el-step title="构建设置"></el-step>
    </el-steps>
    <el-form
      ref="imagesForm"
      :model="imagesForm"
      :rules="dataRule"
      label-width="80px"
    >
      <el-form-item v-show="active == 1">
        <el-form-item prop="imageType" labelWidth="15%">
          <h4 style="width: 400px; line-height: 0.5">通过制品构建新的镜像</h4>
          <p style="width: 400px; line-height: 0.2">
            您可以将已有制品构建成新的镜像
          </p>
          <el-radio-group v-model="imagesForm.imageType">
            <el-radio label="jar" border></el-radio>
            <el-radio label="war" border></el-radio>
            <el-radio label="binary" border></el-radio>
          </el-radio-group>
        </el-form-item>
        <br />
        <el-form-item label="镜像类型" prop="type" labelWidth="15%">
          <el-select v-model="imagesForm.type" placeholder="请选择">
            <el-option label="基础镜像" value="基础镜像"></el-option>
            <el-option label="应用镜像" value="应用镜像"></el-option>
          </el-select>
        </el-form-item>
      </el-form-item>
      <el-form-item v-show="active == 2">
        <el-form-item label="上传制品" prop="goods" labelWidth="15%">
          <el-upload
            ref="Upload"
            class="upload-demo"
            drag
            name="s2ibinary"
            accept=".jar, .war"
            action=""
            :on-success="handleAvatarSuccess"
            :before-remove="beforeRemove"
            :http-request="uploadFile"
            :before-upload="beforeUpload"
            :limit="1"
            :on-exceed="handleExceed"
          >
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">
              将文件拖到此处，或<em>点击上传</em>
            </div>
          </el-upload> </el-form-item
        ><br />
        <el-form-item label="构建环境" prop="buildEnvironment" labelWidth="15%">
          <el-select
            v-model="imagesForm.buildEnvironment"
            style="width: 400px"
            placeholder="请选择"
          >
            <el-option
              v-for="item in options"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        </el-form-item>
        <br />
        <el-form-item label="镜像名称" prop="imageName" labelWidth="15%">
          <el-input
            v-model="imagesForm.imageName"
            placeholder="镜像名称及 Tag，默认为代码仓库的项目名称"
            style="width: 400px"
            clearable
          ></el-input>
        </el-form-item>
        <br />
        <el-form-item label="tag" prop="imageTag" labelWidth="15%">
          <el-input
            v-model="imagesForm.imageTag"
            style="width: 400px"
            placeholder="latest"
            clearable
          ></el-input>
        </el-form-item>
        <br />
        <el-form-item label="目标镜像仓库" prop="warehouse" labelWidth="15%">
          <el-select
            v-model="imagesForm.warehouse"
            style="width: 400px"
            placeholder="请选择"
          >
            <el-option
              v-for="item in warehouse"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        </el-form-item>
        <br />
        <!-- <el-form-item label="描述信息" prop="imageDescription" labelWidth="15%">
          <el-input
            v-model="imagesForm.imageDescription"
            style="width: 400px"
            maxlength="256"
            show-word-limit
            type="textarea"
            placeholder="描述信息不超过 256 个字符"
            :rows="4"
          ></el-input>
        </el-form-item>
        <br /> -->
        <h5 style="margin-left: 20px">
          应用程序开发人员可以使用以下环境变量来配置此镜像的运行时行为；详细的配置说明请查看<a
            href="https://gitee.com/sun1040084806/s2i-java-container/tree/master/java/images"
            target="_blank"
            >编译模板</a
          >
        </h5>
        <el-form-item
          v-for="(item, index) in imagesForm.environment"
          :key="index"
        >
          <el-form-item prop="environment">
            <el-select
              v-model="item.name"
              style="width: 270px"
              clearable
              placeholder="键"
            >
              <el-option
                v-for="item in environment"
                v-model="item.key"
                :key="item.key"
                :label="item.key"
                :value="item.key"
              >
              </el-option>
            </el-select>
            <el-input
              v-model="item.value"
              style="width: 270px"
              clearable
              placeholder="值"
            >
            </el-input>
            <el-button
              type="danger"
              icon="el-icon-delete"
              circle
              @click="deleteEnvironment(index)"
            ></el-button>
          </el-form-item>
        </el-form-item>
        <el-button
          type="primary"
          round
          style="margin-left: 490px"
          v-show="active == 2"
          @click="addEnvironment"
          >添加环境参数</el-button
        >
      </el-form-item>
      <div style="text-align: right; margin: 0">
        <el-button style="margin-top: 12px" @click="cancel">取消</el-button>
        <el-button style="margin-top: 12px" @click="pre" v-if="active == 2"
          >上一步</el-button
        >
        <el-button style="margin-top: 12px" @click="next" v-if="active == 1"
          >下一步</el-button
        >
        <el-button style="margin-top: 12px" @click="submit" v-if="active == 2"
          >创建</el-button
        >
      </div>
    </el-form>
  </el-dialog>
</template>

<script>
/* eslint-disable */
export default {
  data() {
    // 自定义规则
    const checkGoods = (rule, value, callback) => {
      console.log("checkGoods value", value);
      if (this.file.fileName) {
        return callback();
      } else {
        return callback(new Error("附件不能为空"));
      }
    };

    const checkEnvironment = (rule, value, callback) => {
      console.log("checkEnvironment value", value);
      var hash = {}; //定义一个hash表
      let resdata = JSON.parse(JSON.stringify(value));
      for (var i = 0; i < resdata.length; i++) {
        if (!hash[resdata[i].name]) {
          hash[resdata[i].name] = true;
        } else {
          callback(new Error("键值不能重复"));
        }
      }
      return callback();
    };
    return {
      visible: false,
      active: 1,
      file: {
        fileName: "",
        binaryName: "",
        fileRes: "",
        fileSize: 0,
      },
      options: [],
      jar: [],
      war: [],
      binary: [],
      warehouse: [],
      environment: [
        {
          defaultValue: "",
          description:
            "Arguments to use when calling Maven, replacing the default package hawt-app:build -DskipTests -e. Please be sure to run the hawt-app:build goal (when not already bound to the package execution phase), otherwise the startup scripts won't work.",
          key: "MAVEN_ARGS",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "Additional Maven arguments, useful for temporary adding arguments like -X or -am -pl .",
          key: "MAVEN_ARGS_APPEND",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "Path to target/ where the jar files are created for multi module builds. These are added to ${MAVEN_ARGS}",
          key: "ARTIFACT_DIR",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "Arguments to use when copying artifacts from the output dir to the application dir. Useful to specify which artifacts will be part of the image. It defaults to -r hawt-app/* when a hawt-app dir is found on the build directory, otherwise jar files only will be included (*.jar).",
          key: "ARTIFACT_COPY_ARGS",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "If set then the Maven repository is removed after the artifact is built. This is useful for keeping the created application image small, but prevents incremental builds. The default is false",
          key: "MAVEN_CLEAR_REPO",
          required: false,
          type: "boolean",
        },
        {
          defaultValue: "",
          description:
            "the directory where the application resides. All paths in your application are relative to this directory. By default it is the same directory where this startup script resides.",
          key: "JAVA_APP_DIR",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "directory holding the Java jar files as well an optional classpath file which holds the classpath. Either as a single line classpath (colon separated) or with jar files listed line-by-line. If not set JAVA_LIB_DIR is the same as JAVA_APP_DIR.",
          key: "JAVA_LIB_DIR",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description: "options to add when calling java",
          key: "JAVA_OPTIONS",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "a number \u003e= 7. If the version is set then only options suitable for this version are used. When set to 7 options known only to Java \u003e 8 will be removed. For versions \u003e= 10 no explicit memory limit is calculated since Java \u003e= 10 has support for container limits.",
          key: "JAVA_MAJOR_VERSION",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "is used when no -Xmx option is given in JAVA_OPTIONS. This is used to calculate a default maximal Heap Memory based on a containers restriction. If used in a Docker container without any memory constraints for the container then this option has no effect. If there is a memory constraint then -Xmx is set to a ratio of the container available memory as set here. The default is 25 when the maximum amount of memory available to the container is below 300M, 50 otherwise, which means in that case that 50% of the available memory is used as an upper boundary. You can skip this mechanism by setting this value to 0 in which case no -Xmx option is added.",
          key: "JAVA_MAX_MEM_RATIO",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "is used when no -Xms option is given in JAVA_OPTIONS. This is used to calculate a default initial Heap Memory based on a containers restriction. If used in a Docker container without any memory constraints for the container then this option has no effect. If there is a memory constraint then -Xms is set to a ratio of the container available memory as set here. By default this value is not set.",
          key: "JAVA_INIT_MEM_RATIO",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "restrict manually the number of cores available which is used for calculating certain defaults like the number of garbage collector threads. If set to 0 no base JVM tuning based on the number of cores is performed.",
          key: "JAVA_MAX_CORE",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "set this to get some diagnostics information to standard out when things are happening",
          key: "JAVA_DIAGNOSTICS",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "main class to use as argument for java. When this environment variable is given, all jar files in $JAVA_APP_DIR are added to the classpath as well as $JAVA_LIB_DIR.",
          key: "JAVA_MAIN_CLASS",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "A jar file with an appropriate manifest so that it can be started with java -jar if no $JAVA_MAIN_CLASS is set. In all cases this jar file is added to the classpath, too.",
          key: "JAVA_APP_JAR",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description: "Name to use for the process",
          key: "JAVA_APP_NAME",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "the classpath to use. If not given, the startup script checks for a file ${JAVA_APP_DIR}/classpath and use its content literally as classpath. If this file doesn't exists all jars in the app dir are added (classes:${JAVA_APP_DIR}/*).",
          key: "JAVA_CLASSPATH",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description: "If set remote debugging will be switched on",
          key: "JAVA_DEBUG",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description: "If set enables suspend mode in remote debugging",
          key: "JAVA_DEBUG_SUSPEND",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description: "Port used for remote debugging. Default: 5005",
          key: "JAVA_DEBUG_PORT",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "The URL of the proxy server that translates into the http.proxyHost and http.proxyPort system properties.",
          key: "HTTP_PROXY",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "The URL of the proxy server that translates into the https.proxyHost and https.proxyPort system properties.",
          key: "HTTPS_PROXY",
          required: false,
          type: "string",
        },
        {
          defaultValue: "",
          description:
            "The list of hosts that should be reached directly, bypassing the proxy, that translates into the http.nonProxyHosts system property.",
          key: "NO_PROXY",
          required: false,
          type: "string",
        },
      ],
      imagesForm: {
        imageName: "",
        imageAlias: "",
        imageId: 0,
        imageTag: "",
        type: "",
        imageType: "",
        buildEnvironment: "",
        imageSize: "",
        imageDescription: "",
        warehouse: "",
        environment: [],
      },
      dataRule: {
        imageName: [
          { required: true, message: "镜像名称不能为空", trigger: "blur" },
        ],
        imageTag: [
          { required: true, message: "版本不能为空", trigger: "blur" },
        ],
        imageType: [{ required: true, message: "请选择制品", trigger: "blur" }],
        buildEnvironment: [
          { required: true, message: "请选择构建环境", trigger: "change" },
        ],
        warehouse: [
          { required: true, message: "请选择目标镜像仓库", trigger: "change" },
        ],
        goods: [{ validator: checkGoods, trigger: "change" }],
        environment: [{ validator: checkEnvironment, trigger: "change" }],
        imageDescription: [],
        type: [
          { required: true, message: "镜像类型不能为空", trigger: "blur" },
        ],
      },
    };
  },
  methods: {
    init(id) {
      this.imagesForm.imageId = id || 0;
      this.imagesForm.environment = [];
      this.visible = true;
      this.active = 1;
      this.options = [];
      this.warehouse = [];
      this.jar = [];
      this.war = [];
      this.binary = [];
      this.file = {
        fileName: "",
        binaryName: "",
        fileRes: "",
        fileSize: 0,
      };
      this.$nextTick(() => {
        this.$refs["imagesForm"].resetFields();
        this.$refs.Upload.clearFiles();
        // 获取构建环境
        this.$http({
          url: "/kubesphereApi/apis/devops.kubesphere.io/v1alpha1/s2ibuildertemplates",
          method: "get",
        })
          .then(({ data }) => {
            // console.log("data", data);
            data.items[0].spec.containerInfo.forEach((element) => {
              var value = element.builderImage;
              var label = value.substring(value.lastIndexOf("/") + 1);
              this.binary.push({ value, label });
            });
            data.items[1].spec.containerInfo.forEach((element) => {
              var value = element.builderImage;
              var label = value.substring(value.lastIndexOf("/") + 1);
              var runtimeImage = element.runtimeImage;
              this.jar.push({ value, label, runtimeImage });
            });
            data.items[4].spec.containerInfo.forEach((element) => {
              var value = element.builderImage;
              var label = value.substring(value.lastIndexOf("/") + 1);
              var runtimeImage = element.runtimeImage;
              this.war.push({ value, label, runtimeImage });
            });
          })
          .catch((error) => {
            this.$message.error("获取构建环境错误");
            console.log("获取构建环境错误", error);
          });

        // 获取目标镜像仓库
        //把目标项目的名称需要修改
        this.$http({
          url: "/kubesphereApi/api/v1/namespaces/mkcloud/secrets",
          method: "get",
          //
          params: {
            fieldSelector: "type=kubernetes.io/dockerconfigjson",
          },
        })
          .then(({ data }) => {
            data.items.forEach((element) => {
              var value = element.metadata.name;
              var label = element.metadata.name;
              this.warehouse.push({ value, label });
            });
          })
          .catch((error) => {
            this.$message.error("获取目标镜像仓库错误");
            console.log("获取目标镜像仓库错误", error);
          });
      });
    },
    // 表单提交
    submit() {
      this.$refs["imagesForm"].validate((valid) => {
        if (valid) {
          this.$http({
            url: this.$http.adornUrl("/kubeSphereApi/s2iBuilder"),
            method: "post",
            data: {
              languageType: this.imagesForm.imageType,
              fileName: this.file.fileName,
              fileSize: this.file.fileSize,
              creator: this.$store.state.user.name,
              namespace: this.file.fileRes.metadata.namespace,
              tag: this.imagesForm.imageTag,
              builderImage: this.imagesForm.buildEnvironment,
              runtimeImage:
                this.imagesForm.imageType == "binary"
                  ? ""
                  : this.options[0].value === this.imagesForm.buildEnvironment
                  ? this.options[0].runtimeImage
                  : this.options[1].runtimeImage,
              type: this.imagesForm.imageType == "binary" ? "binary" : "java",
              imageName: this.imagesForm.imageName,
              warehouse: this.imagesForm.warehouse,
              sourceUrl: this.file.fileRes.spec.downloadURL,
              environment: this.imagesForm.environment,
            },
          })
            .then((res) => {
              console.log("Res", res);
              this.$http({
                url: this.$http.adornUrl("/generator/images/save"),
                method: "post",
                data: this.$http.adornData({
                  imageName: this.imagesForm.imageName,
                  imageAlias: res.data.spec.builderName,
                  imageTag: this.imagesForm.imageTag,
                  creatorName: this.$store.state.user.name,
                  createTime: new Date().getTime(),
                  imageType: this.imagesForm.imageTag,
                  imageSize: this.file.fileRes.spec.size,
                  buildEnvironment: this.imagesForm.buildEnvironment.substring(
                    this.imagesForm.buildEnvironment.lastIndexOf("/") + 1
                  ),
                  imageDescription: "未发布",
                  type: this.imagesForm.type,
                }),
              }).then(({ data }) => {
                if (data && data.code === 0) {
                  this.$message({
                    message: "操作成功",
                    type: "success",
                    duration: 1500,
                    onClose: () => {
                      this.visible = false;
                      this.$emit("refreshDataList");
                    },
                  });
                } else {
                  this.$message.error(data.msg);
                }
              });
            })
            .catch((error) => {
              this.$message.warning("创建镜像错误");
              console.log("创建镜像错误", error);
            });
        }
      });
    },
    // 前进
    next() {
      if (this.imagesForm.imageType === "jar") this.options = this.jar;
      else if (this.imagesForm.imageType === "war") this.options = this.war;
      else if (this.imagesForm.imageType === "binary")
        this.options = this.binary;
      this.active++;
    },
    // 后退
    pre() {
      this.active--;
    },
    // 取消
    cancel() {
      this.visible = false;
    },
    // 上传成功
    handleAvatarSuccess() {
      this.$message({
        message: "上传成功",
        type: "success",
        duration: 1500,
      });
    },
    // 移除之前
    beforeRemove(file) {
      if (file && file.status === "success")
        return this.$confirm(`确定移除 ${file.name}？`);
    },
    // 上传之前
    beforeUpload(file) {
      console.log("file", file);
      // 没有后缀，直接返回true
      if (file.name.indexOf(".") === -1) return true;
      let suffix = file.name.substring(file.name.lastIndexOf(".") + 1); //获取文件后缀名
      let suffixArray = ["jar", "war"]; //限制的文件类型，根据情况自己定义
      if (suffixArray.indexOf(suffix) === -1) {
        this.$message.error("文件格式错误");
        return false;
      }
    },
    // 文件数量限制
    handleExceed(files, fileList) {
      this.$message.warning("只允许上传一个文件");
    },
    // 格式化文件名字
    formatFileName(name) {
      var binaryName =
        name.toLowerCase().replace(/([^a-zA-Z0-9])/g, "-") +
        Math.random().toString(36).slice(-4);
      return binaryName;
    },
    // 自定义的上传函数
    uploadFile(param) {
      //file就是当前添加的文件
      var file = param.file;
      this.file.fileName = file.name;
      this.file.fileSize = file.size.toString();
      this.file.binaryName = this.formatFileName(file.name);
      console.log("file", file);
      // 创建上传文件的类型
      var form = new FormData();
      form.append(param.filename, file);
      // 创建文件链接
      this.$http({
        url: "/kubesphereApi/apis/devops.kubesphere.io/v1alpha1/namespaces/mkcloud/s2ibinaries",
        method: "post",
        data: {
          apiVersion: "devops.kubesphere.io/v1alpha1",
          kind: "S2iBinary",
          metadata: {
            annotations: {
              "kubesphere.io/creator": this.$store.state.user.name,
            },
            labels: {
              "controller-tools.k8s.io": "1.0",
            },
            name: this.file.binaryName,
            namespace: "mkcloud-test",
          },
        },
        headers: {
          Authorization: this.$store.state.connect.Authentation,
        },
      })
        .then((res) => {
          console.log("res", res);
          // 上传文件
          this.$http({
            url: `/kubesphereApi/kapis/devops.kubesphere.io/v1alpha2/namespaces/mkcloud/s2ibinaries/${this.file.binaryName}/file`,
            method: "put",
            data: form,
            onUploadProgress: (progressEvent) => {
              const complete =
                ((progressEvent.loaded / progressEvent.total) * 100) | 0;
              param.onProgress({ percent: complete }); //调用upload组件的 onProgress
            },
            headers: {
              "Content-Type": "multipart/form-data",
            },
            timeout: undefined,
          })
            .then(({ data }) => {
              param.onSuccess();
              this.file.fileRes = data;
            })
            .catch((error) => {
              console.log("上传文件错误", error);
              this.$message.error("上传文件错误");
            });
        })
        .catch((error) => {
          console.log("创建文件链接错误", error);
          this.$message.error("创建文件链接错误");
        });
    },
    // 添加环境变量
    addEnvironment() {
      const length = this.imagesForm.environment.length;
      if (length == 0) {
        this.imagesForm.environment.push({
          name: "",
          value: "",
        });
        return;
      }
      if (
        this.imagesForm.environment[length - 1].name == "" ||
        this.imagesForm.environment[length - 1].name == undefined ||
        this.imagesForm.environment[length - 1].name == null
      ) {
        this.$message.warning("键值不能为空");
      } else {
        this.imagesForm.environment.push({
          name: "",
          value: "",
        });
      }
    },
    // 删除环境变量
    deleteEnvironment(index) {
      console.log("index", index);
      this.imagesForm.environment.splice(index, 1);
    },
  },
};
</script>
