实现类似参数Rap2接口文档参数管理功能
功能要点:
1.多个表格树结构 — 采用element table 树结构
2.拖拽,要求拖拽范围在同一层级内 ---- 采用sortable.js

先说明下,我之前没怎么完整写过vue,都是做简单的修修补补,这还是第一次实现完整的一个页面功能,所以有很多前端的知识我是不懂的,也没有花太多时间认真去看.所以代码应该会存在些繁琐和没有意义的内容.
然后里面还会有些无意义代码,但我没有删掉

本来觉得还挺简单的,但是过程遇到了很多感觉很琐碎的问题,弄了蛮久

一开始我是先实现了单个树结构拖拽还是很顺利的,但是后来加入其他三个表格之后就出现了很多问题,所以感觉我编写的顺序存在一定问题,应该一开始就按四个表格去写,当然也可以将查看和编辑分两个页面,就只有两个,但我感觉也差不太多.

我将查看和编辑的表格放在同一个页面,查看编辑加起来四个表格,公用两个参数,分别是请求参数和传入参数.

下面就是总结下做的过程遇到写问题:
1.首先加入其他表格后,发现需要至少两个参数才能满足四个表格公用,所以原本树结构拖拽的逻辑,要从针对单个表格改为通用方式.
这也是为什么一开始编写顺序存在问题,一开始写的时候也没想那么多,当然也有很快的方法直接复制原本单个的拖拽逻辑修改下参数名,但是我觉得这样代码很重复,所以还是改为通用方式

2.加入其他表格后,最大的问题就是拖拽功能刷新后异常,主要异常有两种
一,数据刷新了,但是视图刷新异常
1.第一种 主要体现在拖拽范围越级,可以随意拖拽,但是控制台显示数据却是对的,视图应该恢复原本数据,但是没有恢复,导致视图错乱
2.第二种 父节点拖拽,子节点没有跟着一起拖拽.(这个我稍微查了下没细看,好像好树表结构子节点刷新有关,官方好像没有提供要自己实现,所以我放弃这种刷新方式)
我还遇到很奇怪的异常就是,父节点往下拖拽子节点是会正常跟着拖拽下去,但是如果父节点往上拖拽,子节点却不过去,这期间控制台输出的数据都是正常的
二.针对问题一,采用刷新:key的方式虽然可以解决,但是会出现刷新后表格抖动的问题,找了网上很多试过都无法解决,最后是赋空值后再赋值才解决

说一下上面两个关键点实现原理
1.树结构
element -table 2.7以上
2.主要是拖拽
1.需要一个树结构的参数和一个非树结构的参数
2.树结构用于表格传参,非树结构用于拖拽后数据更新
3.拖拽后我们根据拖拽行和目标行,判断父节点和层级是否一致(这个自己在参数对象里加上,我还加了位置数据,用于子节点交换),如果一致,则遍历交换,如果不一致则刷新,显示原本数据

(先粗略写下吧,有空再来优化)

<template>
  <div>
    <!-- 查看接口参数 -->
    <div v-if="!isEditorInterfaceDetailVisible && !isImportParams">
      <el-row :gutter="20">
        <el-col :span="24" class="toolbar">
          <el-descriptions
            class="margin-top"
            :title="interfaceForm.row.interfaceName"
            :column="1"
          >
            <template slot="extra">
              <el-button
                type="primary"
                size="small"
                @click="showEditorDetail()"
                >编辑接口信息</el-button
              >

              <el-button
                type="warning"
                plain
                size="small"
                @click="showTestDialog()"
                >模拟请求</el-button
              >
            </template>

            <el-descriptions-item label="描述" content-class-name="my-content">
              {{ this.interfaceForm.row.interfaceDescription }}
            </el-descriptions-item>

            <el-descriptions-item label="备注">
              {{ this.interfaceForm.interfaceDetailParam.remark }}
            </el-descriptions-item>
          </el-descriptions>
        </el-col>
      </el-row>
      <!-- <el-table
        style="width: 100%;margin-bottom: 20px;"
        row-key="id"
        border
        default-expand-all
        :data="requestTableObj.tableData"
        :key="'t2'"
        :lazy="false"
        :tree-props="{ children: 'children' }"
      >
        <el-table-column
          v-if="true"
          prop="paramName"
          label="名称"
          min-width="150"
        >
        </el-table-column
      ></el-table> -->
      <h3>请求参数</h3>
      <!--
        :key="'t2' + resonseTableKey"
        :lazy="false"
        :tree-props="{ children: 'children' }"
      > -->
      <!-- :key="'t1' + tableKey" -->
      <!-- :key="1" -->
      <el-table
        class="interfaceDetailTable"
        style="width: 100%;margin-bottom: 20px;"
        row-key="id"
        border
        default-expand-all
        @row-click="selectMoveItem"
        :data="requestTableObj.tableData"
        :lazy="false"
        :tree-props="{ children: 'children' }"
      >
        <el-table-column prop="paramName" label="名称" min-width="150">
        </el-table-column>

        <el-table-column label="必选" width="50">
          <template v-slot="scope">
            <el-checkbox v-model="scope.row.isRequired" disabled></el-checkbox>
          </template>
        </el-table-column>
        <el-table-column prop="type" label="类型" width="100">
        </el-table-column>
        <el-table-column prop="lengthSize" label="数据长度" min-width="80">
        </el-table-column>
        <el-table-column prop="description" label="描述" min-width="180">
        </el-table-column>
        <el-table-column prop="example" label="示例" min-width="180">
        </el-table-column>
      </el-table>
      <!-- :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" -->
      <h3>响应参数</h3>
      <el-table
        class="interfaceDetailTableResponse"
        style="width: 100%;margin-bottom: 20px;"
        row-key="id"
        border
        default-expand-all
        @row-click="selectMoveItem"
        v-loading="listLoading"
        :data="responseTableObj.tableData"
        :key="'t2' + resonseTableKey"
        :lazy="false"
        :tree-props="{ children: 'children' }"
      >
        <el-table-column prop="paramName" label="名称" min-width="150">
        </el-table-column>

        <el-table-column label="必选" width="50">
          <template v-slot="scope">
            <el-checkbox v-model="scope.row.isRequired" disabled></el-checkbox>
          </template>
        </el-table-column>
        <el-table-column prop="type" label="类型" width="100">
        </el-table-column>
        <el-table-column prop="lengthSize" label="数据长度" min-width="80">
        </el-table-column>
        <el-table-column prop="description" label="描述" min-width="180">
        </el-table-column>
        <el-table-column prop="example" label="示例" min-width="180">
        </el-table-column>
      </el-table>
    </div>
    <!-- 编辑接口参数 -->
    <div v-if="isEditorInterfaceDetailVisible && !isImportParams">
      <el-row :gutter="20">
        <el-col :span="24" class="toolbar">
          <el-descriptions
            class="margin-top"
            :title="interfaceForm.row.interfaceName"
            :column="1"
          ></el-descriptions> </el-col
      ></el-row>
      <el-form :inline="true">
        <el-row>
          <el-form-item label="描述">
            <el-input
              v-model="interfaceForm.row.interfaceDescription"
              placeholder="描述"
              width="600"
            ></el-input>
          </el-form-item>
        </el-row>
        <el-row>
          <el-form-item label="备注">
            <el-input
              v-model="interfaceForm.interfaceDetailParam.remark"
              placeholder="备注"
              width="70%"
            ></el-input>
          </el-form-item>
        </el-row>
      </el-form>
      <!-- 编辑 -->
      <el-row :gutter="20">
        <el-col :span="2" class="toolbar"> <h3>请求参数</h3> </el-col>
        <el-col :span="7" class="toolbar">
          <div
            style="margin-top: 13px;
    height: 30px;"
          >
            <el-button type="primary" size="small" @click="importRequest()"
              >导入</el-button
            >
          </div></el-col
        ></el-row
      >
      <!-- :key="updRequestTableKey" -->
      <el-table
        class="interfaceDetailTable"
        style="width: 100%;margin-bottom: 20px;"
        row-key="id"
        border
        default-expand-all
        @row-click="selectMoveItem"
        v-loading="listLoading"
        :data="requestTableObj.tableData"
        :key="'t3' + updRequestTableKey"
        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      >
        <el-table-column min-width="100" scoped-slot>
          <template slot="header">
            <el-link @click="addRow(null, requestTableObj.tableData)">
              <i class="el-icon-plus"></i>
            </el-link>
          </template>
          <template v-slot="scope">
            <span
              width="30px"
              @click="delRow(scope.row, requestTableObj.tableData)"
            >
              <el-link :underline="false">
                <i class=" el-icon-delete-solid"></i
              ></el-link>
            </span>
            <span
              width="30px"
              @click="addRow(scope.row, requestTableObj.tableData)"
              v-if="scope.row.type == 'Object' || scope.row.type == 'Array'"
            >
              <el-link :underline="false">
                <i class="el-icon-plus"></i
              ></el-link>
            </span>
          </template>
        </el-table-column>

        <el-table-column label="名称" width="180">
          <template class="el-dropdown-link" v-slot="scope">
            <el-input
              v-model="scope.row.paramName"
              :disabled="scope.row.id.length > 1 ? false : true"
            >
            </el-input>
          </template>
        </el-table-column>
        <el-table-column label="必填" width="50">
          <template v-slot="scope">
            <el-checkbox
              v-model="scope.row.isRequired"
              :disabled="scope.row.id.length > 1 ? false : true"
            >
            </el-checkbox>
          </template>
        </el-table-column>

        <el-table-column label="类型" min-width="180">
          <template v-slot="scope">
            <el-select
              v-model="scope.row.type"
              slot="prepend"
              placeholder="请选择"
              :disabled="scope.row.id.length > 1 ? false : true"
            >
              <el-option label="String" value="String"></el-option>
              <el-option label="Char" value="Char"></el-option>
              <el-option label="Object" value="Object"></el-option>
              <el-option label="Array" value="Array"></el-option>
            </el-select>
          </template>
        </el-table-column>

        <el-table-column label="数据长度" min-width="80">
          <template v-slot="scope">
            <el-input
              v-model="scope.row.lengthSize"
              :disabled="scope.row.id.length > 1 ? false : true"
            ></el-input>
          </template>
        </el-table-column>

        <el-table-column label="描述" min-width="180">
          <template v-slot="scope">
            <el-input
              v-model="scope.row.description"
              :disabled="scope.row.id.length > 1 ? false : true"
            ></el-input>
          </template>
        </el-table-column>

        <el-table-column label="示例" width="180">
          <template v-slot="scope">
            <el-input
              v-model="scope.row.example"
              :disabled="scope.row.id.length > 1 ? false : true"
            ></el-input>
          </template>
        </el-table-column>
      </el-table>

      <el-row :gutter="20">
        <el-col :span="2" class="toolbar"> <h3>响应参数</h3></el-col>
        <el-col :span="7" class="toolbar">
          <div
            style="margin-top: 13px;
    height: 30px;"
          >
            <el-button type="primary" size="small" @click="importResponse()"
              >导入</el-button
            >
          </div></el-col
        ></el-row
      >
      <!-- :key="'t4'+updResponeTableKey" -->
      <el-table
        class="interfaceDetailTableResponse"
        style="width: 100%;margin-bottom: 20px;"
        row-key="id"
        border
        default-expand-all
        @row-click="selectMoveItem"
        v-loading="listLoading"
        :data="responseTableObj.tableData"
        :key="'t4'"
        :lazy="false"
        :tree-props="{ children: 'children' }"
      >
        <el-table-column min-width="100" scoped-slot>
          <template slot="header">
            <span
              width="30px"
              @click="delRow(null, responseTableObj.tableData)"
            >
              <el-link :underline="false">
                <i class=" el-icon-delete-solid"></i
              ></el-link>
            </span>

            <el-link @click="addRow(null, responseTableObj.tableData)">
              <i class="el-icon-plus"></i>
            </el-link>
          </template>
          <template v-slot="scope">
            <span
              width="30px"
              @click="delRow(scope.row, responseTableObj.tableData)"
            >
              <el-link :underline="false">
                <i class=" el-icon-delete-solid"></i
              ></el-link>
            </span>
            <span
              width="30px"
              @click="addRow(scope.row, responseTableObj.tableData)"
              v-if="scope.row.type == 'Object' || scope.row.type == 'Array'"
            >
              <el-link :underline="false">
                <i class="el-icon-plus"></i
              ></el-link>
            </span>
          </template>
        </el-table-column>
        <el-table-column label="名称" sortable width="180">
          <template class="el-dropdown-link" v-slot="scope">
            <el-input v-model="scope.row.paramName"> </el-input>
          </template>
        </el-table-column>
        <el-table-column label="必填" width="50">
          <template v-slot="scope">
            <el-checkbox v-model="scope.row.isRequired"> </el-checkbox>
          </template>
        </el-table-column>

        <el-table-column label="类型" min-width="180">
          <template v-slot="scope">
            <el-select
              v-model="scope.row.type"
              slot="prepend"
              placeholder="请选择"
            >
              <el-option label="String" value="String"></el-option>
              <el-option label="Char" value="Char"></el-option>
              <el-option label="Object" value="Object"></el-option>
              <el-option label="Array" value="Array"></el-option>
              <el-option label="Boolean" value="Boolean"></el-option>
            </el-select>
          </template>
        </el-table-column>

        <el-table-column label="数据长度" min-width="80">
          <template v-slot="scope">
            <el-input v-model="scope.row.lengthSize"></el-input>
          </template>
        </el-table-column>

        <el-table-column label="描述" min-width="180">
          <template v-slot="scope">
            <el-input v-model="scope.row.description"></el-input>
          </template>
        </el-table-column>

        <el-table-column label="示例" width="180">
          <template v-slot="scope">
            <el-input v-model="scope.row.example"></el-input>
          </template>
        </el-table-column>
      </el-table>

      <el-row>
        <div style="margin-left:45%">
          <el-button
            size="small"
            type="primary"
            plain
            @click="showEditorDetail()"
            >取消</el-button
          >
          <el-button type="primary" size="small" @click="save()"
            >保存</el-button
          >
        </div>
      </el-row>
    </div>
    <div v-if="isImportParams">
      <el-row :gutter="20">
        <el-col :span="24" class="toolbar">
          <el-descriptions class="margin-top" :title="importTitle" :column="1">
            <template slot="extra">
              <el-button
                type="primary"
                size="small"
                @click="updImportRapamsState()"
                >返回</el-button
              >
            </template>
          </el-descriptions>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24" class="toolbar">
          <textarea
            v-model="jsonText"
            style="height:300px;width:100%"
          ></textarea>
        </el-col>
      </el-row>
      <el-row :span="24">
        <el-button
          size="small"
          style="margin-left:48%;margin-top:5px"
          type="primary"
          plain
          @click="importJsonToTable()"
          >导入</el-button
        >
      </el-row>
    </div>
    <test-request-params
      ref="testRequestParams"
      :interfaceForm="interfaceForm"
      v-if="testDialogVisible"
      @destory="testDialogClose"
    />
  </div>
</template>

<script>
import testRequestParams from "./test_request_params";
import Sortable from "sortablejs";
import util from "@/common/util";

export default {
  name: "interfaceCheck",
  props: {
    interfaceForm: {
      type: Object,
      require: true
    }
  },
  components: {
    testRequestParams
  },
  data() {
    return {
      nullTable: [{ nullName: "1" }],
      importTitle: "导入参数",
      jsonText: "",
      isImportParams: false,
      isImportRequest: false,
      isEditorInterfaceDetailVisible: false,
      interfaceDetail: {
        interfaceId: this.interfaceForm.row.id,
        remark: this.interfaceForm.interfaceDetailParam.remark,
        requestDefinition: this.interfaceForm.interfaceDetailParam
          .requestDefinition,
        responseDefinition: this.interfaceForm.interfaceDetailParam
          .responseDefinition
      },
      remark: this.interfaceForm.interfaceDetailParam.remark,
      listLoading: false,
      tableKey: "1",
      resonseTableKey: "11",
      updRequestTableKey: "111",
      updResponeTableKey: "111",
      testDialogVisible: false,
      udpRequestTableDate: [],
      udpResponeTableDate: [],
      childrenDate: {
        id: "",
        paramName: "",
        isRequired: false,
        type: "String",
        lengthSize: "",
        description: "",
        example: "",
        level: "",
        parentNode: "",
        positon: [],
        children: []
      },
      responseTableData: [],
      tableData: [],
      tableArr: [],
      treeArr: [],
      treeNum: {},
      requestTableObj: {
        id: "request",
        tableArr: [],
        tableData: []
      },
      responseTableObj: {
        id: "response",
        tableArr: [],
        treeArr: [],
        tableData: []
      },
      tableDataTemplate: {
        id: "",
        interfaceId: "",
        remark: "",
        requestDefinition: [
          {
            id: 1,
            paramName: "reqPara",
            isRequired: true,
            type: "Object",
            lengthSize: "",
            description: "",
            example: "",
            level: 1,
            parentNode: "",
            positon: [],
            children: [
              {
                id: "2",
                paramName: "inInterfaceCode",
                isRequired: false,
                type: "String",
                lengthSize: "40",
                description: "接口唯一码",
                example: "interface001",
                level: "2",
                parentNode: "1",
                positon: [],
                children: []
              },
              {
                id: "3",
                paramName: "inInterfaceName",
                isRequired: false,
                type: "String",
                lengthSize: "40",
                description: "SAP接口",
                example: "interface",
                level: "2",
                parentNode: "1",
                positon: [],
                children: []
              }
            ]
          },
          {
            id: 4,
            paramName: "inInterfacePara",
            isRequired: false,
            type: "Array",
            lengthSize: "",
            description: "",
            example: "",
            level: 1,
            parentNode: "",
            positon: [],
            children: [
              {
                id: 5,
                paramName: " IV_PRUEFLOS",
                isRequired: false,
                type: "String",
                lengthSize: "12",
                description: "检验批号",
                example: "10000474793",
                level: 2,
                parentNode: "4",
                positon: [],
                children: []
              }
            ]
          }
        ],
        responseDefinition: [
          {
            id: 1,
            paramName: "code",
            isRequired: true,
            type: "String",
            lengthSize: "",
            description: "返回编码",
            example: "0",
            level: 1,
            parentNode: "",
            positon: [],
            children: []
          },
          {
            id: 2,
            paramName: "message",
            isRequired: true,
            type: "String",
            lengthSize: "",
            description: "返回提示",
            example: "请求成功",
            level: 1,
            parentNode: "",
            positon: [],
            children: []
          },
          {
            id: 3,
            paramName: "success",
            isRequired: true,
            type: "String",
            lengthSize: "",
            description: "是否成功",
            example: "true",
            level: 1,
            parentNode: "",
            positon: [],
            children: []
          },
          {
            id: 4,
            paramName: "respRara",
            isRequired: false,
            type: "Object",
            lengthSize: "",
            description: "返回数据(Json)",
            example: '{/"abc/":/"acb/"}',
            level: 1,
            parentNode: "",
            positon: [],
            children: [
              {
                id: 5,
                paramName: "outInterfaceCode",
                isRequired: false,
                type: "String",
                lengthSize: "",
                description: "接口编码(请求唯一编码)",
                example: "WMS-GetUserInfo-1",
                level: 2,
                parentNode: "4",
                positon: [],
                children: []
              },
              {
                id: 6,
                paramName: "outInterfaceName",
                isRequired: false,
                type: "String",
                lengthSize: "12",
                description: "接口名称",
                example: "GetUserInfo",
                level: 2,
                parentNode: "4",
                positon: [],
                children: []
              }
            ]
          }
        ]
      }
    };
  },
  created() {
    this.tableData = this.interfaceForm.interfaceDetailParam.requestDefinition;
    this.responseTableData = this.interfaceForm.interfaceDetailParam.responseDefinition;

    this.requestTableObj.tableData = this.tableData;
    this.responseTableObj.tableData = this.responseTableData;
  },
  mounted() {
 
  },
  methods: {
    importRequest() {
      this.isImportRequest = true;
      this.updImportRapamsState();
    },
    importResponse() {
      this.isImportRequest = false;
      this.updImportRapamsState();
    },
    updImportRapamsState() {
      this.isImportParams = !this.isImportParams;
    },
    save() {
      this.listLoading = true;
      let obj = {
        id: this.interfaceForm.interfaceDetailParam.id,
        interfaceId: this.interfaceForm.row.id,
        remark: this.interfaceForm.interfaceDetailParam.remark,
        requestDefinition: JSON.stringify(this.requestTableObj.tableData),
        responseDefinition: JSON.stringify(this.responseTableObj.tableData)
      };

      baseAjax({
        url: xxx保存接口,
        data: JSON.stringify(obj),
        type: "POST",
        success: function(data) {
          if (data.isSuccess) {
            this.responseTableData = this.responseTableObj.tableData;
            this.tableData = this.requestTableObj.tableData;
            // this.tableDate = this.udpRequestTableDate;
            this.$message({
              showClose: true,
              message: "保存成功",
              type: "success"
            });
          } else {
            this.$message({
              showClose: true,
              message: data.responseMsg,
              type: "error"
            });
          }
          this.listLoading = false;
          this.showEditorDetail();
        }.bind(this),
        error: function() {
          this.$message({
            showClose: true,
            message: data.responseMsg,
            type: "error"
          });
          this.listLoading = false;
        }.bind(this)
      });
    },

    //树结构展开和表格一致 -- 并添加当前位置序号
    treeToRow(tableObj) {
      let tableData = tableObj.tableData;
      tableObj.tableArr = [];
      let tableArr = tableObj.tableArr;
      if (tableData != undefined) {
        tableData.forEach((value, index) => {
          let pos = [];
          pos.push(index);
          value.positon = pos;
          tableArr.push(value);
          if (value.children.length > 0) {
            this.getChildData(value, tableArr);
          }
        });
      }
      console.log("=====tableObj=========", tableObj);
      this.rowToTree(tableObj);
    },

    // 获取当前元素的子对象---子对象更新当前位置
    getChildData(parent, Arr) {
      if (parent.children.length > 0) {
        parent.children.forEach((param, index) => {
          //给对象添加位置
          let pos = JSON.parse(JSON.stringify(parent.positon));
          pos.push(index);
          param.positon = pos;
          Arr.push(param);

          if (param.children.length > 0) {
            this.getChildData(param, Arr);
          }
        });
      }
    },
    //行结构变为树结构
    rowToTree(tableObj) {
      let treeArr = [];
      if (tableObj.tableArr != undefined) {
        tableObj.tableArr.forEach(value => {
          if (value.level == 1) {
            treeArr.push(value);
          }
        });
      }
      console.log("treeArr", treeArr);
      tableObj.treeArr = treeArr;

      console.log("=====tableObj====rowToTree=====", tableObj);
    },
    //选中对象进行移动
    selectMoveItem(row, column, event) {
      let that = this;
      this.treeToRow(this.responseTableObj);
      this.treeToRow(this.requestTableObj);
      console.log("====this.requestTableObj==", this.requestTableObj);
      if (this.sortable && this.sortable.el) this.sortable.destroy(); //摧毁拖拽
      console.log("当前行", row);
      this.$nextTick(() => {
        that.rowDrop(); //拖拽#moveList对象
      });
    },
    //行拖拽
    rowDrop() {
      const that = this;
      console.log("============3====32");
      const tbody = document.querySelector(
        ".interfaceDetailTable .el-table__body-wrapper tbody"
      );

      const tbody2 = document.querySelector(
        ".interfaceDetailTableResponse .el-table__body-wrapper tbody"
      );

      that.sortable = Sortable.create(tbody, {
        fallbackOnBody: true,

        onEnd({ newIndex, oldIndex }) {
          console.log("拖动了行" + oldIndex, "当前序号: " + newIndex);
          //更新数据

          if (
            that.requestTableObj.tableArr[newIndex].level !=
              that.requestTableObj.tableArr[oldIndex].level ||
            that.requestTableObj.tableArr[newIndex].parentNode !=
              that.requestTableObj.tableArr[oldIndex].parentNode
          ) {
            console.log("===越界");
            //越界
            that.flashTableData();
          } else {
            console.log("=33=that.requestTableObj==", that.requestTableObj);
            that.changeTableData(oldIndex, newIndex, that.requestTableObj);
          }
        }
      });

      // 响应参数拖拽
      that.sortable = Sortable.create(tbody2, {
        fallbackOnBody: true,

        onEnd({ newIndex, oldIndex }) {
          console.log("拖动了行" + oldIndex, "当前序号: " + newIndex);
          console.log(
            "===越界???",
            that.responseTableObj.tableArr[newIndex].level,
            that.responseTableObj.tableArr[oldIndex].level
          );
          //更新数据
          if (
            that.responseTableObj.tableArr[newIndex].level !=
              that.responseTableObj.tableArr[oldIndex].level ||
            that.responseTableObj.tableArr[newIndex].parentNode !=
              that.responseTableObj.tableArr[oldIndex].parentNode
          ) {
            console.log("===越界");
            //越界
            that.flashTableData();
          } else {
            console.log("=22===that.responseTableObj==", that.responseTableObj);
            that.changeTableData(oldIndex, newIndex, that.responseTableObj);
          }
        }
      });
    },
    // 取消拖拽顺序
    handleCancelSort() {
      // 使table先隐藏,再显示,table将恢复拖拽之前的样式
      this.isShowTable = false;
      setTimeout(() => {
        this.isShowTable = true;
        // 必须延时,否则重新初始化的sortable无法拖拽
        setTimeout(() => {
          this.isEditOrder = false;
          this.sortable.options.sort = false;
          this.initSortable();
        }, 100);
      }, 100);
    },
    flashTable() {
      this.tableKey = this.tableKey + 1;
      this.resonseTableKey = this.resonseTableKey + 1;
      this.updRequestTableKey = this.updRequestTableKey + 1;
      this.updResponeTableKey = this.updResponeTableKey + 1;
    },
    //刷新表格
    flashTableData() {
      this.requestTableObj.tableData.splice(1, 0);
      this.responseTableObj.tableData.splice(1, 0);

      // this.flashTable();
      let request = JSON.parse(JSON.stringify(this.requestTableObj.tableData));
      this.requestTableObj.tableData = [];

      let response = JSON.parse(
        JSON.stringify(this.responseTableObj.tableData)
      );
      this.responseTableObj.tableData = [];

      console.log("===刷新===");
      console.log("requestTableObj", this.requestTableObj.tableData);
      console.log("responseTableObj", this.responseTableObj.tableData);
      this.$nextTick(() => {
        //在数据加载完,重新渲染表格
        this.updTable(request, response);
      });
    },
    updTable(request, response) {
      this.requestTableObj.tableData = request;
      this.responseTableObj.tableData = response;
    },

    //拖拽后更新表格数据
    changeTableData(oldIndex, newIndex, tableObj) {
      console.log("-=----tableObj------", tableObj);
      const that = this;
      let table_ = JSON.parse(JSON.stringify(tableObj));
      let tempFirst = JSON.parse(JSON.stringify(tableObj.tableArr[oldIndex]));
      let tempSec = JSON.parse(JSON.stringify(tableObj.tableArr[newIndex]));

      console.log("tempFirst", tempFirst);
      console.log("tempSec", tempSec);
      //根节点
      if (tableObj.tableArr[oldIndex].level == 1) {
        tableObj.treeArr.forEach((value, index) => {
          console.log(index, "===value==", value);
          if (value.id == tempFirst.id) {
            table_.treeArr[index] = tempSec;
            table_.tableData[index] = tempSec;
            // tableObj.treeArr[index] = tempSec;
            // tableObj.tableData[index] = tempSec;
            // tableObj.treeArr.splice(index, 1, tempSec);
            // tableObj.tableData.splice(index, 1, tempSec);
          }
          if (value.id == tempSec.id) {
            table_.treeArr[index] = tempFirst;
            table_.tableData[index] = tempFirst;
            // tableObj.treeArr[index] = tempFirst;
            // tableObj.tableData[index] = tempFirst;
            // tableObj.treeArr.splice(index, 1, tempFirst);
            // tableObj.tableData.splice(index, 1, tempFirst);
          }
        });

        tableObj.treeArr = table_.treeArr;
        tableObj.tableData = table_.tableData;
        console.log(" tableObj.treeArr", tableObj);
        console.log(" table_", table_);
        // this.requestTableObj.tableData.splice(1, 0);
        // this.responseTableObj.tableData.splice(1, 0);
      } else {
        //非根节点
        let tableDataTemp = JSON.parse(JSON.stringify(tableObj.tableData));

        this.changeTableDataChild(
          tableDataTemp[tempFirst.positon[0]],
          tempFirst,
          tempSec
        );
        console.log(["===tableDataTemp=="], tableDataTemp);
        //更新列表
        tableObj.tableData = JSON.parse(JSON.stringify(tableDataTemp));
        console.log(["===tableObj.tableData=="], tableObj.tableData);
        // this.tableData = tableDataTemp;
      }

      this.treeToRow(this.responseTableObj);
      this.treeToRow(this.requestTableObj);
      this.flashTableData();
      // console.log("========update=======");
      // console.log("tableData", this.tableData);
    },

    // 非根节点对象拖拽交换
    changeTableDataChild(parent, oldVal, newVal) {
      if (oldVal.positon.length > parent.positon.length) {
        parent.children.forEach((param, index) => {
          //找到对应子对象 同一层级除了最后一层前面都是一样的
          if (
            index == oldVal.positon[parent.positon.length] ||
            index == newVal.positon[parent.positon.length]
          ) {
            //如果是最后一层 -->交换对象
            if (parent.positon.length == oldVal.positon.length - 1) {
              console.log(index, "最终层级:", param);

              if (index == oldVal.positon[parent.positon.length]) {
                param.id = newVal.id;
                param.paramName = newVal.paramName;
                param.isRequired = newVal.isRequired;
                param.example = newVal.example;
                param.description = newVal.description;
                param.lengthSize = newVal.lengthSize;
                param.type = newVal.type;
                param.children = newVal.children;
              }

              if (index == newVal.positon[parent.positon.length]) {
                param.id = oldVal.id;
                param.paramName = oldVal.paramName;
                param.isRequired = oldVal.isRequired;
                param.example = oldVal.example;
                param.description = oldVal.description;
                param.lengthSize = oldVal.lengthSize;
                param.type = oldVal.type;
                param.children = oldVal.children;
              }
              console.log("=== parent.children==", parent.children);
            } else {
              //找到子对象但是还没到最终层级,查看下一层子对象的
              this.changeTableDataChild(param, oldVal, newVal);
            }
          }
        });
      }
    },
    //查看和编辑模式切换
    showEditorDetail() {
      this.isEditorInterfaceDetailVisible = !this
        .isEditorInterfaceDetailVisible;

      //编辑
      if (this.isEditorInterfaceDetailVisible) {
        if (
          this.requestTableObj.tableData == null ||
          this.requestTableObj.tableData == ""
        ) {
          this.requestTableObj.tableData = this.tableDataTemplate.requestDefinition;
          console.log(
            "===nullRequ===",
            JSON.parse(JSON.stringify(this.tableDataTemplate.requestDefinition))
          );
        }
        if (
          this.responseTableObj.tableData == null ||
          this.responseTableObj.tableData == ""
        ) {
          this.responseTableObj.tableData = this.tableDataTemplate.responseDefinition;
          console.log(
            "===nullRequ===",
            JSON.parse(
              JSON.stringify(this.tableDataTemplate.responseDefinition)
            )
          );
        }
      } else {
        this.requestTableObj.tableData = this.tableData;
        this.responseTableObj.tableData = this.responseTableData;
      }

      console.log(
        "=== this.requestTableObj.tableData===",
        this.requestTableObj.tableData
      );
      this.flashTableData();
    },
    showTestDialog() {
      this.testDialogVisible = true;
    },
    testDialogClose() {
      this.testDialogVisible = false;
    },
    delTableDataChild(parent, delVal) {
      if (delVal.positon.length > parent.positon.length) {
        console.log("==========del========", parent);
        // 0,1,1
        // 0,1
        parent.children.forEach((param, index) => {
          //找到对应子对象 同一层级除了最后一层前面都是一样的
          if (index == delVal.positon[parent.positon.length]) {
            console.log(index);
            //如果是最后一层 -->交换对象
            if (parent.positon.length == delVal.positon.length - 1) {
              //删除子对象
              parent.children.splice(delVal.positon[parent.positon.length], 1);
            } else {
              this.delTableDataChild(param, delVal);
            }
          }
        });
      }
    },
    delRow(row, tableData) {
      // console.log("===row===", row);
      let msg = "确认删除该参数?";

      this.$confirm(msg, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          // console.log("del==================");
          if (row != undefined) {
            if (row.level == 1) {
              tableData.splice(row.positon, 1);
            } else {
              this.delTableDataChild(tableData[row.positon[0]], row);
            }
          } else {
            tableData.splice(0);
          }
        })
        .catch(() => {
          this.$message({
            showClose: true,
            type: "info",
            message: "已取消删除"
          });
        });
    },
    addRow(row, tableData) {
      let newObject = JSON.parse(JSON.stringify(this.childrenDate));
      newObject.id = this.createId();
      if (row != undefined) {
        newObject.level = row.level + 1;
        newObject.parentNode = row.id;
        row.children.push(newObject);
      } else {
        newObject.level = 1;
        tableData.push(newObject);
      }
      this.treeToRow(this.requestTableObj);
      this.treeToRow(this.responseTableObj);
      this.flashTableData();
    },
    createId() {
      var mydate = new Date();
      var uuid =
        mydate.getDay() +
        mydate.getHours() +
        mydate.getMinutes() +
        mydate.getSeconds() +
        mydate.getMilliseconds() +
        Math.round(Math.random() * 10000);
      var rid = (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
      return uuid + "_" + rid;
    },

    importJsonToTable() {
      // console.log("==", JSON.parse(this.jsonText));
      let jsonObj;
      try {
        jsonObj = JSON.parse(this.jsonText);
      } catch (ex) {
        this.$message({
          showClose: true,
          type: "error",
          message: "参数非标准JSON格式,请检查!!"
        });
        return;
      }

      let tableDataChange = [];

      for (var i in jsonObj) {
        let newObject = JSON.parse(JSON.stringify(this.childrenDate));
        newObject.id = this.createId();
        newObject.level = 1;
        newObject.paramName = i;
        tableDataChange.push(newObject);
        let type = Object.prototype.toString.call(jsonObj[i]);
        type = type.substring(8, type.length - 1);
        newObject.type = type;

        if (type == "Object") {
          //子对象
          console.log(i + ":=obj=" + jsonObj[i]);

          this.importJsonChildrenToTable(newObject, jsonObj[i]);
        } else if (type == "Array") {
          let childrenArrayObj = jsonObj[i][0];
          let childTypeCheck = Object.prototype.toString.call(childrenArrayObj);
          childTypeCheck = childTypeCheck.substring(
            8,
            childTypeCheck.length - 1
          );

          if (childTypeCheck == "Object") {
            this.importJsonChildrenToTable(newObject, childrenArrayObj);
          } else {
            newObject.example = JSON.stringify(jsonObj[i]);
          }
        } else {
          let ex = JSON.stringify(jsonObj[i]);
          ex = ex.replace(/\"/g, "");
          newObject.example = ex;
        }

        // console.log(i + ":" + jsonObj[i]);
      }
      console.log(":tableDataChange", tableDataChange);
      let newObj = [];
      if (this.isImportRequest) {
        newObj = this.requestTableObj.tableData.concat(tableDataChange);
        this.requestTableObj.tableData = newObj;
        this.treeToRow(this.requestTableObj);
      } else {
        newObj = this.responseTableObj.tableData.concat(tableDataChange);
        this.responseTableObj.tableData = newObj;
        this.treeToRow(this.responseTableObj);
      }

      this.flashTableData();
      this.updImportRapamsState();
    },
    importJsonChildrenToTable(parent, children) {
      for (const j in children) {
        //判断当前类型
        let childrenType = Object.prototype.toString.call(children[j]);
        childrenType = childrenType.substring(8, childrenType.length - 1);

        let newChildrenObject = JSON.parse(JSON.stringify(this.childrenDate));
        newChildrenObject.id = this.createId();

        newChildrenObject.parentNode = parent.id;
        newChildrenObject.level = parent.level + 1;
        newChildrenObject.paramName = j;

        newChildrenObject.type = childrenType;
        // console.log("childrenType====", childrenType);
        if (childrenType == "Object") {
          //子对象
          this.importJsonChildrenToTable(newChildrenObject, children[j]);
        } else if (childrenType == "Array") {
          // console.log("parent[j]", newChildrenObject);

          let childrenArrayObj = children[j][0];
          let childTypeCheck = Object.prototype.toString.call(childrenArrayObj);
          childTypeCheck = childTypeCheck.substring(
            8,
            childTypeCheck.length - 1
          );

          if (childTypeCheck == "Object") {
            this.importJsonChildrenToTable(newChildrenObject, childrenArrayObj);
          } else {
            newChildrenObject.example = JSON.stringify(children[j]);
          }

          // console.log("children[j]", childrenArrayObj);
        } else {
          let ex = JSON.stringify(children[j]);
          ex = ex.replace(/\"/g, "");
          newChildrenObject.example = ex;
        }

        parent.children.push(newChildrenObject);
      }
    }
  }
};
</script>

<style>

</style>

因为我这里是点击目录弹窗显示,目录页点击后传参内容
下面是目录页代码
自定义查看弹窗

<el-row>
        <check-form :interfaceForm="interfaceForm"></check-form>
  </el-row>
<script>
import checkForm from ".自定义弹窗内容的路径";
</script>

传入参数结构,传进去后赋值给table

this.interfaceForm = {
            interfaceDetailParam: this.detailData, //树结构数据
            row: row //选中行数据
          };