<template>
  <div class="main">
    <el-tabs default-active-key="1" @tab-click="handleClick">
      <el-tab-pane key="1" label="节点设置">
        <el-form ref="nodeConfig" :model="nodeConfig" :rules="nodeRules">
          <el-form-item label="节点名称" prop="nodeName">
            <el-input placeholder="请输入节点名称" v-model="nodeConfig.nodeName" />
          </el-form-item>
          <el-form-item label="模块名称" prop="templateName">
            <el-input placeholder="请输入模块名称" v-model="nodeConfig.templateName" />
          </el-form-item>
          <el-form-item label="镜像名称" prop="templateImage">
            <el-input placeholder="请输入镜像名称" v-model="nodeConfig.templateImage" />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" class="form-button" @click="saveNodeConfig">保存</el-button>
          </el-form-item>
        </el-form>
      </el-tab-pane>
      <el-tab-pane key="2" label="参数设置">
        <el-form>
          <el-form-item>
            <span class="form-span">参数类型</span>
            <el-table :data="argumentsparameters" border style="width: 100%">
              <el-table-column prop="paraname" header-align="center" align="center" label="名称"></el-table-column>
              <el-table-column prop="paratype" header-align="center" align="center" label="参数类型"></el-table-column>
              <el-table-column prop="paradesc" header-align="center" align="center" label="描述"></el-table-column>
              <el-table-column prop="paravalue" header-align="center" align="center" width="200" label="输入">
                <template slot-scope="scope">
                  <el-input
                    v-model="scope.row.paravalue"
                    placeholder="请输入内容"
                    @change="inpurparachange(scope.row)"
                  />
                </template>
              </el-table-column>
              <el-table-column
                prop="quotevalue"
                header-align="center"
                align="center"
                width="200"
                label="引用其他算法节点"
              >
                <template slot-scope="scope">
                  <el-cascader
                    :props="props"
                    filterable
                    clearable
                    v-model="scope.row.quotevalue"
                    :options="cascadeoptionpara"
                    @change="cascadeparahandleChange(scope.row)"
                  ></el-cascader>
                </template>
              </el-table-column>
            </el-table>
          </el-form-item>
          <el-form-item>
            <span class="form-span">文件类型</span>
            <el-table :data="argumentsartifacts" border style="width: 100%">
              <el-table-column prop="paraname" header-align="center" align="center" label="名称"></el-table-column>
              <el-table-column prop="parapath" header-align="center" align="center" label="文件类型"></el-table-column>
              <el-table-column prop="paradesc" header-align="center" align="center" label="描述"></el-table-column>
              <el-table-column
                prop="inputnodefilevalue"
                header-align="center"
                align="center"
                width="200"
                label="引用输入节点"
              >
                <template slot-scope="scope">
                  <el-select
                    v-model="scope.row.inputnodefilevalue"
                    multiple
                    placeholder="请选择"
                    @change="inputnodefilechange(scope.row)"
                  >
                    <el-option
                      v-for="item in inputnodefilemap"
                      :key="item.name"
                      :label="item.name"
                      :value="item.fileurl"
                    ></el-option>
                  </el-select>
                </template>
              </el-table-column>
              <el-table-column
                prop="quotevalue"
                header-align="center"
                align="center"
                width="200"
                label="引用其他算法节点"
              >
                <template slot-scope="scope">
                  <el-cascader
                    filterable
                    clearable
                    v-model="scope.row.quotevalue"
                    :options="cascadeoption"
                    @change="cascadehandleChange(scope.row)"
                  ></el-cascader>
                </template>
              </el-table-column>
              <el-table-column header-align="center" align="center" width="200" label="上传">
                <template slot-scope="scope">
                  <el-upload
                    class="upload-demo"
                    action="#"
                    multiple
                    :limit="3"
                    :auto-upload="false"
                    :on-exceed="handleExceed"
                    :file-list="scope.row.filelist"
                    :on-change="
                      (file, fileList) => {
                        handleChange(file, fileList, scope.row);
                      }
                    "
                  >
                    <el-button size="small" type="primary">点击上传</el-button>
                  </el-upload>
                </template>
              </el-table-column>
            </el-table>
          </el-form-item>
          <el-form-item label-width="50%">
            <el-button type="primary" @click="saveArgsData">保存</el-button>
          </el-form-item>
        </el-form>
      </el-tab-pane>
      <el-tab-pane key="3" label="节点输出">
        <el-form>
          <el-form-item>
            <span class="form-span">参数型输出</span>
            <el-table :data="outputsparameters" border style="width: 100%">
              <el-table-column
                prop="paraname"
                header-align="center"
                align="center"
                label="输出参数名称"
              ></el-table-column>
              <el-table-column prop="paratype" header-align="center" align="center" label="参数类型"></el-table-column>
              <el-table-column prop="paradesc" header-align="center" align="center" label="描述"></el-table-column>
              <el-table-column prop="paravalue" header-align="center" align="center" label="结果"></el-table-column>
            </el-table>
          </el-form-item>
          <el-form-item>
            <span class="form-span">文件型输出</span>
            <el-table :data="outputsartifacts" border style="width: 100%">
              <el-table-column
                prop="paraname"
                header-align="center"
                align="center"
                label="输出文件名称"
              ></el-table-column>
              <el-table-column prop="paratype" header-align="center" align="center" label="参数类型"></el-table-column>
              <el-table-column prop="paradesc" header-align="center" align="center" label="描述"></el-table-column>
              <el-table-column fixed="right" header-align="center" align="center" width="150" label="操作">
                <template slot-scope="scope">
                  <el-button type="text" size="small" @click="previewfile(scope.row.paraname, scope.row.valuefrom)">
                    预览
                  </el-button>
                  <el-button
                    type="text"
                    size="small"
                    @click="downloadoutputresult(scope.row.paraname, scope.row.valuefrom)"
                  >
                    下载
                  </el-button>
                </template>
              </el-table-column>
            </el-table>
          </el-form-item>
        </el-form>
      </el-tab-pane>
      <el-tab-pane key="4" label="节点日志">
        <el-radio-group v-model="containertype" default-value="main" @change="podcontainerchange">
          <el-radio label="main" value="main">main</el-radio>
          <el-radio label="init" value="init">init</el-radio>
          <el-radio label="wait" value="wait">wait</el-radio>
        </el-radio-group>
        <div class="log-box">
          <div v-if="!['', null, undefined].includes(podcontentlog)">
            <p class="logList-item" v-for="(item, index) in podcontentlogsplit" :key="index">
              {{ item }}
            </p>
          </div>
          <div v-else>暂无数据</div>
        </div>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>
<script>
import { Message } from "element-ui";
export default {
  data() {
    return {
      // 节点数据
      nodeConfig: {
        nodeName: undefined,
        templateName: undefined,
        templateImage: undefined
      },
      // 节点
      cell: undefined,
      // nodeConfig验证规则
      nodeRules: {
        nodeName: [{ required: true, message: "请输入节点名称", trigger: "change" }],
        templateName: [{ required: true, message: "请输入模块名称", trigger: "change" }],
        templateImage: [{ required: true, message: "请输入镜像名称", trigger: "change" }]
      },
      // 参数设置
      argumentsparameters: [],
      // 文件类型
      argumentsartifacts: [],
      // 日志具体内容
      podcontent: { main: "", wait: "", init: "" },
      // 日志
      podcontentlog: "",
      // 日志类型
      containertype: "main",
      // 分割之后的日志
      podcontentlogsplit: [],
      // 输出参数设置
      outputsparameters: [],
      // 输出文件设置
      outputsartifacts: [],
      // 参数类型级联目录
      cascadeoptionpara: [],
      // 输入源
      algonodeSource: [],
      // 设置多选
      props: { multiple: true },
      // 引用输入节点的文件列表
      inputnodefilemap: [],
      // 文件类型级联目录
      cascadeoption: [],
      // 节点对应的 templateName
      wftemplateName: "",
      // 工作流运行状态
      workflowStatus: "",
      // 节点对应的 templateName
      wftemplateName: "",
      // 节点对应 podphase 状态
      podphase: "",
      // 定时任务
      interval: null,
      // 不知道干嘛的
      algoparaInput: null
    };
  },
  props: {
    isShow: {
      type: Boolean,
      required: true,
      default: false
    }
  },
  methods: {
    /**
     * 保存节点数据
     */
    saveNodeConfig() {
      this.$refs.nodeConfig.validate((valid) => {
        if (valid) {
          Message.success("保存节点信息成功");
          this.cell.setData({
            nodeName: this.nodeConfig.nodeName,
            templateName: this.nodeConfig.templateName,
            templateImage: this.nodeConfig.templateImage
          });
        } else {
          Message.error("节点配置校验不通过");
          const data = this.cell.getData();
          this.nodeConfig = {
            nodeName: data.nodeName,
            templateName: data.templateName,
            templateImage: data.templateImage
          };
        }
      });
    },
    /**
     * 初始化组件
     *
     * @param cell 传入的cell对象
     */
    init(cell, workflowName, workflowStatus, idTemplateNameMap) {
      this.cell = cell;
      this.workflowName = workflowName;
      this.workflowStatus = workflowStatus;
      const data = cell.getData();
      this.nodeConfig = {
        nodeName: data.nodeName,
        templateName: data.templateName,
        templateImage: data.templateImage
      };
      this.wftemplateName = data.wftempname || "";
      this.argumentsparameters = data.argumentsparameters || [];
      this.argumentsartifacts = data.argumentsartifacts || [];
      this.outputsparameters = data.outputsparameters || [];
      this.outputsartifacts = data.outputsartifacts || [];
      this.algonodeSource = data.algonodeSource || [];
      this.inputnodefilemap = data.inputnodefilemap || [];
      this.algoparaInput = data.algoparaInput;
      this.buildCascadeoption();
      // 获取输出
      this.getOutputparavalue();
      if (!["", null, undefined].includes(this.workflowName)) {
        if (!["", null, undefined].includes(this.idTemplateNameMap)) {
          this.interval = window.setInterval(() => {
            this.getnodepodContent(idTemplateNameMap);
          }, 5000);
        }
      }
    },
    loadTestData() {
      this.argumentsartifacts.push({
        paraname: "test"
      });
    },
    /**
     * 构建级联数据
     */
    buildCascadeoption() {
      this.cascadeoptionpara = this.algonodeSource.map((item) => {
        const data = item.hasOwnProperty("getData") && item.getData instanceof Function ? item.getData() : item.data;
        const obj = {
          value: "",
          label: "",
          children: []
        };
        obj.value = data.nodeName;
        obj.label = data.nodeName;
        obj.children = data.outputsparameters.map((item) => {
          const obj = {
            value: "",
            label: ""
          };
          obj.value = item.paraname;
          obj.label = item.paraname;
          return obj;
        });
        return obj;
      });

      this.cascadeoption = this.algonodeSource.map((item) => {
        const data = item.hasOwnProperty("getData") && item.getData instanceof Function ? item.getData() : item.data;
        const obj = {
          value: "",
          label: "",
          children: []
        };
        obj.value = data.nodeName;
        obj.label = data.nodeName;
        obj.children = data.outputsartifacts.map((item) => {
          const obj = {
            value: "",
            label: ""
          };
          obj.value = item.paraname;
          obj.label = item.paraname;
          return obj;
        });
        return obj;
      });
    },
    /**
     * 文件类型选择文件
     *
     * @param item 输入的元素
     */
    inputnodefilechange(item) {
      if ((item.quotevalue && item.quotevalue.length > 0) || (item.filelist && item.filelist.length > 0)) {
        item.inputnodefilevalue = [];
        Message.error("已通过其他方式这只输入文件，不能重复设置，如需输入，请先删除已选择的数据");
      }
    },
    /**
     * 处理输入数据变化
     *
     * @param item 输入的元素
     */
    inpurparachange(item) {
      if (item.quotevalue != null && item.quotevalue.length > 0) {
        item.paravalue = null;
        Message.error("已选择其他节点参数作为输入，不能重复设置，如需输入，请先删除已选择的数据");
      }
    },
    /**
     * 保存参数数据
     */
    async saveArgsData() {
      if (!this.primaryvalidate()) {
        Message.error("保存失败，请检查参数是否输入完整");
        return;
      }
      // 保存参数类型
      await this.saveArgsType();

      this.cell.setData({
        argumentsparameters: this.argumentsparameters,
        argumentsartifacts: this.argumentsartifacts,
        inputnodefilemap: this.inputnodefilemap,
        algonodeSource: this.algonodeSource,
        algoparaInput: this.algoparaInput
      });
    },
    /**
     * 保存参数类型
     */
    async saveArgsType() {
      for (const item of this.argumentsparameters) {
        if (item.hasOwnProperty("quotevalue")) {
          // 引用其他算法节点参数类型输入改为多选节点之后
          item.valuefrom = [];
          if (item.quotevalue && item.quotevalue.length > 0) {
            item.valuefrom = item.quotevalue.map((item) => {
              return `{{tasks.${item[0]}.outputs.parameters.${item[1]}}}`;
            });
          }
        }
      }

      // 保存文件类型
      const filedata = new FormData();
      for (const item of this.argumentsartifacts) {
        if (item.hasOwnProperty("quotevalue") && item.quotevalue && item.quotevalue.length === 2) {
          item.valuefrom = `{{tasks.${item.quotevalue[0]}.outputs.artifacts.${item.quotevalue[1]}}}`;
        }
        if (item.hasOwnProperty("filelist")) {
          item.filelist = item.filelist.map((item) => item.raw);
          filedata.append(item.paraname, item.filelist[0]);
        }
      }
      if (!filedata.entries().next().done) {
        const { data } = await this.$http({
          url: this.$http.adornUrl("/visi/visiworkflow/savefile"),
          method: "post",
          data: filedata
        });
        if (data && data.code === 0) {
          for (const item of this.argumentsartifacts) {
            if (data.jsonfileurl.hasOwnProperty(item.paraname)) {
              item.fileurls.push(data.jsonfileurl[item.paraname]);
            }
          }
        }
      }

      // 遍历algoparaInput中algoparaGetInput中的数据，添加文件地址，后保存到映射关系数据库中
      for (const item of this.algoparaInput.getInput) {
        for (const source of this.algonodeSource) {
          const data =
            source.hasOwnProperty("getData") && source.getData instanceof Function ? source.getData() : source.data;
          if (item.paravalue != null && item.paravalue[0] === data.nodeName) {
            item.paravalue.push(data.algoparaOutAddress);
          }
        }
      }
    },
    /**
     * 验证表单
     *
     * @returns 是否校验成功
     */
    primaryvalidate() {
      for (const item of argumentsparameters) {
        if (
          (item.paravalue == null || item.paravalue == "") &&
          (item.quotevalue == null || item.quotevalue.length == 0)
        ) {
          return false;
        }
      }
      for (const item of argumentsartifacts) {
        if (
          (item.inputnodefilevalue == null || item.inputnodefilevalue.length == 0) &&
          (item.quotevalue == null || item.quotevalue.length == 0) &&
          (item.filelist == null || item.filelist.length == 0)
        ) {
          return false;
        }
      }
      return true;
    },
    /**
     * 处理option变化
     *
     * @param item 输入的元素
     */
    cascadeparahandleChange(item) {
      if (item.paravalue && item.paravalue != "") {
        item.quotevalue = [];
        Message.error("已自定义设置参数，不能重复设置，如需选择，请先删除输入");
      }
    },
    /**
     * 处理option变化
     *
     * @param item 输入的元素
     */
    cascadehandleChange() {
      if (
        (item.inputnodefilevalue && item.inputnodefilevalue.length > 0) ||
        (item.filelist && item.filelist.length > 0)
      ) {
        currow.quotevalue = [];
        Message.error("已通过其他方式这只输入文件，不能重复设置，如需输入，请先删除已选择的数据");
      }
    },
    /**
     * 文件上传异常处理
     */
    handleExceed(files, fileList) {
      Message.warning(
        `当前限制选择 3 个文件，本次选择了 ${files.length} 个文件，共选择了 ${files.length + fileList.length} 个文件`
      );
    },
    /**
     * 文件上传改变处理
     */
    handleChange(file, fileList, item) {
      if (
        (item.quotevalue && item.quotevalue.length > 0) ||
        (item.inputnodefilevalue && item.inputnodefilevalue.length > 0)
      ) {
        item.filelist = [];
        Message.error("已通过其他方式这只输入文件，不能重复设置，如需输入，请先删除已选择的数据");
        return;
      }
      if (!item.hasOwnProperty("filelist")) {
        item.filelist = [];
      }
      item.filelist.push(file);
    },
    /**
     * 切换日志格式
     */
    podcontainerchange() {
      this.podcontentlog = this.podcontent[this.containertype];
      this.podcontentlogsplit = this.podcontent[this.containertype].split(/[(\r\n)\r\n]+/);
    },
    /**
     * 输出参数页面tab 选中时，获取参数类型输出值
     */
    async getOutputparavalue() {
      if (this.outputsparameters && this.outputsparameters.length != 0 && this.workflowStatus == "Succeeded") {
        const { data } = await this.$http({
          url: this.$http.adornUrl("/visi/visinodeidtemplatemap/getoutputparavalue"),
          method: "get",
          params: this.$http.adornParams({
            workflowName: this.workflowName,
            wftemplateName: this.wftemplateName
          })
        });
        if (data && data.code === 0) {
          for (const item of data.outparavalueJson) {
            for (const parameter of outputsparameters) {
              if (item.name == parameter.paraname) {
                parameter.paravalue = item.value;
              }
            }
          }
        }
      }
    },
    /**
     * tabs切换
     */
    handleClick(tab, event) {
      if (tab.index === "2") {
        this.getOutputparavalue();
      }
    },
    /**
     * 预览 output 数据
     */
    async previewfile(paraname, valuefrom) {
      const { data } = await this.$http({
        url: this.$http.adornUrl("/visi/visinodeidtemplatemap/downloadoutput"),
        method: "get",
        params: this.$http.adornParams({
          workflowName: this.workflowName,
          wftemplateName: this.wftemplateName,
          outputartiparaName: paraname,
          outputartiparapath: valuefrom
        })
      });
      if (data && data.code === 0) {
        if (data.artifiletype == "csv") {
          const routeData = this.$router.resolve({
            path: "/visi-previewcsv",
            query: {
              csvurl: data.outputfileUrl
            }
          });
          window.open(routeData.href, "_blank");
        } else {
          window.open(data.outputfileUrl, "_blank");
        }
      } else {
        Message.error("下载失败");
      }
    },
    /**
     * 下载 output 数据
     */
    async downloadoutputresult(paraname, valuefrom) {
      const { data } = await this.$http({
        url: this.$http.adornUrl("/visi/visinodeidtemplatemap/downloadoutput"),
        method: "get",
        params: this.$http.adornParams({
          workflowName: this.workflowName,
          wftemplateName: this.wftemplateName,
          outputartiparaName: paraname,
          outputartiparapath: valuefrom
        })
      });
      if (data && data.code === 0) {
        window.open(data.outputfileUrl, "_blank");
      } else {
        Message.error("下载失败");
      }
    },
    /**
     * 查询日志
     */
    async getnodepodContent(idTemplateNameMap) {
      const { data } = await this.$http({
        url: this.$http.adornUrl("/visi/visiworkflow/getpodlog2"),
        method: "get",
        params: this.$http.adornParams({
          workflowName: this.workflowName,
          idTemplateNameMap: idTemplateNameMap,
          nodeId: this.cell.id
        })
      });
      if (data && data.code === 0) {
        this.workflowContentlog = data.workflowContent;
        this.podcontent = data.podcontent;
        this.podphase = data.podphase;
      }

      if (["Succeeded", "Error", "Failed"].includes(this.podphase)) {
        window.clearInterval(this.interval);
      }
    },
    /**
     * 新建边时，源节点为输入节点，算法节点内部获取输入节点对应的文件 name及url
     */
    changeinputnodemap(celldata, cell, sallfilemap) {
      cell.setData({ inputnodefilemap: sallfilemap });
      this.inputnodefilemap = sallfilemap;
    },
    /**
     * 新建边时，边源节点及目的节点均为 算法节点，目的节点获取源节点  相关输出参数
     *
     */
    changeSourcedata(celldata, cell) {
      this.algonodeSource = celldata.algonodeSource;
      this.buildCascadeoption();
    }
  },
  watch: {
    isShow: {
      handler(newValue) {
        if (newValue === false && this.interval) {
          window.clearInterval(this.interval);
        }
      },
      immediate: true
    }
  }
};
</script>
<style scope>
.form-button {
  display: block;
  margin: 0 auto;
}
.form-span {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 15px;
  font-weight: bold;
}
.main {
  background: #fff;
  padding: 5px;
  width: 100%;
  height: 100%;
}
.ant-tabs-tab {
  flex: 1 1 50px;
  padding: 7px 16px;
  display: flex;
  justify-content: center;
  width: 100%;
  height: 100%;
}
.el-select .el-input {
  /* width: 130px; */
  width: 100%;
  /* width: 0px; */
}
.input-with-select .el-input-group__prepend {
  background-color: #fff;
}
.el-form-item.el-input {
  width: 150px;
}
.logList-item {
  padding: 8px 0;
  margin: 0;
  font: normal 13px/1.2 "Courier", sans-serif;
}
.log-box {
  height: 60vh;
  width: 100%;
  padding: 10px;
  margin: 10px;
  background-color: #fff;
  position: relative;
  overflow: auto;
}
</style>
