table原生表格,横纵表头右击添加删除行列

需求:横纵都需要表头,表头可以右击自定义添加行列。点击某一个非表头的单元格,可以左右样式多层定位,如:

结构数据解析:表头为一个二维数组,一个数组代表一行,表格为另一个二维数组。如果接口请求保存为一个扁平的一维数组,可以在获取和保存时候对数组进行升维和降维。

下面是代码部分:
html部分:
 

    <table>
      <template v-for="(item, index) in columns.conditionCellList" :key="item.id">
        <tr>
          <template v-for="(i, iIndex) in item" :key="i">
            <td
              :rowspan="i.rowSpan"
              :colspan="i.colSpan"
              :class="selectedStyle(i.valueVariable.id)"
              :style="{
                border:
                  selectItem?.valueVariable?.id === i.valueVariable.id ? '2px solid #5292f7' : '',
              }"
              @click="leftClick(i)"
              @contextmenu.prevent="togglePopover(i)"
            >
              <!-- 左上角 -->
              <template v-if="index === 0 && iIndex === 0">
                <template v-if="!editBoxVisible">
                  <span>
                    {{ i.valueVariable.title }}
                  </span>
                  <p>
                    <i
                      class="iconfont icon-bianji"
                      style="cursor: pointer"
                      @click="editContent"
                    ></i>
                  </p>
                </template>
                <a-textarea
                  v-else
                  id="textarea"
                  v-model:value="i.valueVariable.title"
                  :rows="4"
                  placeholder="请输入"
                  @blur="handleBlur"
                />
              </template>
              <!-- 其他表格的头部 -->
              <template v-else>
                <a-popover
                  v-if="i.valueVariable?.id"
                  v-model:visible="popovers[i.valueVariable?.id]"
                  placement="rightTop"
                  trigger="click"
                >
                  <template #content>
                    <template v-for="operate in projectDateList" :key="operate.type">
                      <p class="specific_details" @click="changeOver(operate, index, iIndex, i)">
                        {{ operate.name }}
                      </p>
                      <a-divider style="margin: 5px 0"
                    /></template>
                  </template>
                  <div>
                    <LibValueComp
                      :dictCode="DictConst.LIBRARY_TYPE"
                      :value="undefined"
                      @change="(data) => leftValueChangeClick(item, data)"
                    />
                    <p>
                      <span>
                        {{ i.valueVariable.title }}
                        <!-- ---{{ i.row }} --{{ i.col }} -->
                      </span>
                    </p>
                  </div>
                </a-popover>
              </template>
            </td>
          </template>
          <template v-for="(cell, cellIndex) in valueCellList" :key="cellIndex">
            <td
              v-if="index === cell.row"
              @click="cellClick(cell)"
              :style="{
                border:
                  selectItem?.row === cell.row && selectItem?.col === cell.col
                    ? '2px solid #5292f7'
                    : '',
              }"
            >
              <ValueTypeComp
                :value="cell.value"
                @change="(data) => valueTypeChangeClick(item, data)"
              />
              <ValueComp
                :value="cell.value"
                @change="(data: any) => rightValueChangeClick(cell, data)"
              />
              <!-- {{ cell.row }}-- {{ cell.col }} -->
            </td>
          </template>
        </tr>
      </template>
    </table>

下面是js部分(包含初始化数据格式,可以根据自己的格式进行调节):
  插件说明:uuidv4  为生成默认id的三方插件。

RuleTypeEnum:为自己书写的ts类型,可以自己写死。

其他组件都可以自行删除,这里不做处理,自己弄:

<script setup lang="ts">
import { ref, onMounted, computed, nextTick, watch } from "vue";
import selectAttributeData from "./SelectAttributeData.vue";
import DictConst from "srule-front-common/src/enums/DictConst";
import { RuleTypeEnum } from "srule-front-common/src/enums";
// import { Util } from "@msa/msa-core";
import LibValueComp from "../../../components/LibValueComp.vue";
import ValueComp from "../../../components/ValueComp.vue";
import ValueTypeComp from "../../../components/ValueTypeComp.vue";
import { ComplexScoreCard, ConditionCol, valueCellList } from "srule-front-common/src/types";
import { sruleRuleStore } from "../../../stores/srule/rule";
import { Modal, message } from "ant-design-vue";
import { DataTypeEnum } from "srule-front-common/src/enums/srule/library/DataTypeEnum";
import { ValueTypeEnum } from "srule-front-common/src/enums/srule/rule/ValueTypeEnum";
// import type { CascaderProps } from "ant-design-vue";
import { v4 as uuidv4 } from "uuid";

const ruleStore = sruleRuleStore();

const props = defineProps({
  contentId: {
    type: String,
    default: () => undefined,
  },
});
const columns = ref<any>({});

onMounted(() => {
  // initData();
});
watch(
  () => props.contentId,
  (_val) => {
    nextTick(() => {
      search();
    });
  },
  {
    immediate: true,
  },
);

const selectItem = ref<any>({}); //当前点击项
const popovers = ref<any>({}); // 获取当前打开值
const editBoxVisible = ref<boolean>(false);

const search = () => {
  if (!props.contentId) return message.error("评分卡id不存在!");
  const callback = (data: string) => {
    processingData(data);
  };
  ruleStore.getContent(props.contentId, callback);
};
// 获取到数据后转json格式
const processingData = (data: string) => {
  const content = data ? JSON.parse(data) : {};
  if (content.conditionCellList && content.valueCellList) {
    // 根据row,把数据处理成为二维数组
    columns.value["conditionCellList"] = transformTwoDimensionalArray(content.conditionCellList);
    columns.value["valueCellList"] = transformTwoDimensionalArray(content.valueCellList);
  } else {
    columns.value = {
      conditionRowList: [],
      conditionColList: [],
      conditionCellList: [
        [
          {
            row: 0,
            col: 0,
            rowSpan: 1,
            colSpan: 1,
            valueVariable: {
              id: "2-1",
              name: "LEFT && TOP",
              title: "LEFT && TOP",
              children: [
                {
                  id: "",
                  name: "string",
                  title: "string",
                  dataType: DataTypeEnum.String,
                  value: {},
                },
              ],
            },
          },
          {
            row: 0,
            col: 1,
            rowSpan: 1,
            colSpan: 1,
            valueVariable: {
              id: "0-3",
              name: "无",
              title: "无",
              children: [
                {
                  id: "",
                  name: "string",
                  title: "string",
                  dataType: DataTypeEnum.String,
                  value: {},
                },
              ],
            },
          },
        ],
        [
          {
            row: 1,
            col: 0,
            rowSpan: 1,
            colSpan: 1,
            valueVariable: {
              id: "3-0",
              name: "无",
              title: "无",
              children: [
                {
                  id: "",
                  name: "string",
                  title: "string",
                  dataType: DataTypeEnum.String,
                  value: {},
                },
              ],
            },
          },
        ],
      ],
      valueCellList: [
        [
          {
            row: 1,
            col: 1,
            getValue: {
              valueType: ValueTypeEnum.Input,
            },
          },
        ],
      ],
    };
  }
};
// 将json数据转为二维数组
const transformTwoDimensionalArray = (data: any) => {
  const groupedArray = data.reduce((acc: any, obj: any) => {
    // 查找是否已经存在 row 对应的数组
    const existingArray = acc.find((arr: any) => arr[0]?.row === obj.row);
    if (existingArray) {
      existingArray.push(obj);
    } else {
      // 如果不存在,则创建一个新的数组并放入大的数组中
      acc.push([obj]);
    }
    return acc;
  }, []);
  return groupedArray;
};

// 表头鼠标右击事件
// 表头鼠标左击事件
const leftClick = (record: any) => {
  if (record.valueVariable.id === columns.value.conditionCellList[0][0]?.valueVariable.id) {
    return;
  }
  selectItem.value = record;
  belongingHeaderIdList.value = [];
  updateValue("");
};
const togglePopover = (record: any) => {
  if (record.valueVariable?.id != columns.value.conditionCellList[0][0].valueVariable?.id) {
    const sign =
      columns.value.conditionCellList[0][0].rowSpan > record.row ? "crosswise" : "vertical";
    headerRightClickCalculation(sign);
    selectItem.value = record;
    updateValue(record.valueVariable?.id);
  }
};
// // 排他:关闭其他点击标签的右击弹框,展开当前右击项
const updateValue = (name: string) => {
  // 将所有属性设置为 false
  for (const key in popovers.value) {
    popovers.value[key] = false;
  }
  if (!name) return;
  // 将指定属性设置为 true
  popovers.value[name] = true;
};
// 右击选择
const changeOver = (record: any, index: number, iIndex: number, content: any) => {
  switch (record.type) {
    case "addLine":
      addTableLinw(index, iIndex, content); // 调用添加列的函数
      break;
    case "addRow":
      addTableRow(index, iIndex, content);
      break;
    case "deleteLine":
      promptModelComponent("line", index, iIndex, content);
      break;
    case "deleteRow":
      promptModelComponent("row", index, iIndex, content);
      break;
  }

  updateValue("");
};
// 单元格点击事件
const cellClick = (record: any) => {
  selectItem.value = record;
  belongingHeaderIdList.value = [];
  selectedTable(record);
};
// 添加行
const addTableRow = (index: number, iIndex: number, record: any) => {
  // 横向table添加行事件
  if (columns.value.conditionCellList[0][0].rowSpan > index) {
    let arr = columns.value.conditionCellList[0].filter((item: any, c: number) => c != 0);
    const totalColSpan = arr.reduce((acc: any, obj: any) => acc + (obj.colSpan || 0), 0);
    let insertArray = [];
    for (let i = 0; i < totalColSpan; i++) {
      const newContent = {
        row: columns.value.conditionCellList[0][0].rowSpan,
        col: columns.value.conditionCellList[0][0].colSpan + i,
        rowSpan: 1, //包含以自己  后面的总和加上自己表示自己可以有多少个子集-也就是横坐标的总个数
        colSpan: 1, // 多少行-第一个永远只占一列
        valueVariable: {
          id: uuidv4(),
          name: "无-111",
          title: "无-11",
          children: [
            { id: "", name: "string", title: "string", dataType: DataTypeEnum.String, value: {} },
          ],
        },
      };
      insertArray.push(newContent);
    }

    columns.value.conditionCellList.splice(
      columns.value.conditionCellList[0][0].rowSpan,
      0,
      insertArray,
    );
    // 给第一列最大的左侧增加数值
    columns.value.conditionCellList[0][0].rowSpan++;
    columns.value.conditionCellList[0][0].row++;
    // 如果横向标题增加行数-给纵向标题的row序号加1
    for (
      let i = columns.value.conditionCellList[0][0].rowSpan;
      i < columns.value.conditionCellList.length;
      i++
    ) {
      columns.value.conditionCellList[i].forEach((c: any) => {
        c.row += 1;
      });
    }
    // 如果横向表头点击添加表头,所有单元格原有行数加1
    for (let i = 0; i < columns.value.valueCellList.length; i++) {
      columns.value.valueCellList[i].forEach((item: any) => {
        item.row++;
      });
    }
  } else {
    // 纵向头部添加的事件
    if (record.col === 0) {
      let insertArray = [];
      for (let i = 0; i < columns.value.conditionCellList[0][0].colSpan; i++) {
        const newContent = {
          row: columns.value.conditionCellList[index][0].row + 1,
          col: record.col + i,
          rowSpan: 1, //包含以自己  后面的总和加上自己表示自己可以有多少个子集-也就是横坐标的总个数
          colSpan: 1, // 多少行-第一个永远只占一列
          valueVariable: {
            id: uuidv4(),
            name: "无",
            title: "无",
            children: [
              { id: "", name: "string", title: "string", dataType: DataTypeEnum.String, value: {} },
            ],
          },
        };
        insertArray.push(newContent);
      }
      columns.value.conditionCellList.splice(record.row + 1, 0, insertArray);
      for (let i = index + 2; i < columns.value.conditionCellList.length; i++) {
        columns.value.conditionCellList[i].forEach((item: any) => {
          item.row = i;
        });
      }
      // 纵向第一行表头添加表格事件
      const addTableNumber =
        columns.value.conditionCellList[0].reduce(
          (acc: any, obj: any) => acc + (obj.colSpan || 0),
          0,
        ) - columns.value.conditionCellList[0][0].colSpan;
      const addCellList = ref<any>([]);
      if (
        columns.value.conditionCellList[index][iIndex].row !=
        columns.value.conditionCellList[index - 1][0].row
      ) {
        for (let index = 0; index < addTableNumber; index++) {
          addCellList.value.push({
            row: record.row + 1,
            col: index + columns.value.conditionCellList[0][0].colSpan,
            getValue: {
              valueType: ValueTypeEnum.Input,
            },
          });
        }
        columns.value.valueCellList.splice(record.row + 1, 0, addCellList.value);
      }
    } else {
      // 计算需要添加子列的话,需要添加几个
      let totaleNumber =
        columns.value.conditionCellList[columns.value.conditionCellList[0][0].rowSpan].length;
      let arr = [];
      for (let i = 0; i < totaleNumber - record.col; i++) {
        const newContent = {
          row: 1,
          col: record.col + i,
          rowSpan: 1, //包含以自己  后面的总和加上自己表示自己可以有多少个子集-也就是横坐标的总个数
          colSpan: 1, // 多少行-第一个永远只占一列
          valueVariable: {
            id: uuidv4(),
            name: "无",
            title: "无",
            children: [
              { id: "", name: "string", title: "string", dataType: DataTypeEnum.String, value: {} },
            ],
          },
        };
        arr.push(newContent);
      }
      columns.value.conditionCellList.splice(record.row + 1, 0, arr);
      // 往下处理row的编号变化
      for (let i = index + 1; i < columns.value.conditionCellList.length; i++) {
        columns.value.conditionCellList[i].forEach((item: any) => {
          item.row = i + item.rowSpan - 1;
        });
      }
      // 往上找row小于或者等于新增行的row值,就给找到的加上rowSpan加1
      for (let i = columns.value.conditionCellList[0][0].rowSpan; i < record.row + 1; i++) {
        columns.value.conditionCellList[i].forEach((item: any, iiiiccc: number) => {
          if (
            item.row + 1 >= columns.value.conditionCellList[index + 1][0].row &&
            item.valueVariable.id != record.valueVariable.id &&
            iiiiccc < record.col &&
            columns.value.conditionCellList[index + 1][0].col != item.col &&
            item.col < record.col
          ) {
            item.rowSpan++;
            item.row++;
          }
        });
      }
      const addTableNumber =
        columns.value.conditionCellList[0].reduce(
          (acc: any, obj: any) => acc + (obj.colSpan || 0),
          0,
        ) - columns.value.conditionCellList[0][0].colSpan;
      const addCellList = ref<any>([]);
      for (let index = 0; index < addTableNumber; index++) {
        addCellList.value.push({
          row: record.row + 1,
          col: index + columns.value.conditionCellList[0][0].colSpan,
          getValue: {
            valueType: ValueTypeEnum.Input,
          },
        });
      }
      columns.value.valueCellList.splice(record.row + 1, 0, addCellList.value);
    }
    // 重新排序单元格的row
    for (let index = 0; index < columns.value.valueCellList.length; index++) {
      columns.value.valueCellList[index].forEach((item: any) => {
        item.row = columns.value.conditionCellList[0][0].rowSpan + index;
      });
    }
  }
};
// 添加列
const addTableLinw = (index: number, iIndex: number, record: any) => {
  // 判断是否为横坐标表头
  if (columns.value.conditionCellList[0][0].rowSpan > index) {
    if (index === 0) {
      // 横坐标第一行添加表头
      for (let i = index; i < columns.value.conditionCellList[0][0].rowSpan; i++) {
        const newContent = {
          row: columns.value.conditionCellList[i][1]
            ? columns.value.conditionCellList[i][1].row
            : columns.value.conditionCellList[i][0].row,
          col: 0,
          rowSpan: 1, //包含以自己  后面的总和加上自己表示自己可以有多少个子集-也就是横坐标的总个数
          colSpan: 1, // 多少行-第一个永远只占一列
          valueVariable: {
            id: uuidv4(),
            name: "无",
            title: "无",
            children: [
              { id: "", name: "string", title: "string", dataType: DataTypeEnum.String, value: {} },
            ],
          },
        };
        columns.value.conditionCellList[i].splice(iIndex + 1, 0, newContent);
      }
      // 处理横向标题的col列号
      for (let i = index; i < columns.value.conditionCellList[0][0].rowSpan; i++) {
        columns.value.conditionCellList[i].forEach((sign: any, signIndex: number) => {
          if (
            sign.row === 0 &&
            sign.valueVariable.id != columns.value.conditionCellList[0][0].valueVariable.id
          ) {
            sign.col = columns.value.conditionCellList[i][signIndex - 1].col + 1 + sign.colSpan - 1;
          } else if (
            sign.valueVariable.id != columns.value.conditionCellList[0][0].valueVariable.id
          ) {
            sign.col = signIndex + columns.value.conditionCellList[0][0].colSpan;
            sign.row = columns.value.conditionCellList[i][0].row;
          }
        });
      }

      // 横坐标第一行添加表格列,进行按规律插入
      for (let i = 0; i < columns.value.valueCellList.length; i++) {
        columns.value.valueCellList[i].splice(record.col, 0, {
          row: columns.value.valueCellList[i][0].row,
          col: 0,
          getValue: {
            valueType: ValueTypeEnum.Input,
          },
        });
        // 给插入的表格列号进行排序
        columns.value.valueCellList[i].forEach((item: any, itemIndex: number) => {
          item.col = columns.value.conditionCellList[0][0].colSpan + itemIndex;
        });
      }
    } else {
      // 添加列,给上层的所有父列colSpan加1
      const totalColSpan = columns.value.conditionCellList[index]
        .slice(0, iIndex)
        .reduce((acc: any, obj: any) => acc + (obj.colSpan || 0), 1);
      let sumColspan = 0;
      for (let i = 0; i < index; i++) {
        let currentArray = columns.value.conditionCellList[i];
        for (let j = 0; j < currentArray.length; j++) {
          let currentObject = currentArray[j];
          // 把第一个格子排除
          if (
            currentObject.valueVariable.id != columns.value.conditionCellList[0][0].valueVariable.id
          ) {
            sumColspan += currentObject.colSpan;
          }
          if (sumColspan >= totalColSpan) {
            // 给他的上面几个对象colSpan加1
            columns.value.conditionCellList[i][j].colSpan++;
            columns.value.conditionCellList[i][j].col++;
            sumColspan = 0;
            // 给上面父级的列号加1
            for (let p = j + 1; p < currentArray.length; p++) {
              columns.value.conditionCellList[i][p].col += 1;
            }
            break; // 退出内层循环
          }
        }
      }
      // 添加列
      for (let i = index; i < columns.value.conditionCellList.length - 1; i++) {
        //  对行进行过滤避免加错到表格
        if (
          columns.value.conditionCellList[0][0].rowSpan > columns.value.conditionCellList[i][0].row
        ) {
          const newContent = {
            row: columns.value.conditionCellList[index][0].row + 1,
            col: i,
            rowSpan: 1, //包含以自己  后面的总和加上自己表示自己可以有多少个子集-也就是横坐标的总个数
            colSpan: 1, // 多少行-第一个永远只占一列
            valueVariable: {
              id: uuidv4(),
              name: "无",
              title: "无",
              children: [
                {
                  id: "",
                  name: "string",
                  title: "string",
                  dataType: DataTypeEnum.String,
                  value: {},
                },
              ],
            },
          };
          columns.value.conditionCellList[i].splice(iIndex + 1, 0, newContent);
          // 处理后续的row和col
          columns.value.conditionCellList[i].forEach((sign: any, signIndex: number) => {
            if (sign.row === 0) {
              sign.col = signIndex + 1;
              sign.row = 0;
            } else {
              sign.col = signIndex + columns.value.conditionCellList[0][0].colSpan;
              sign.row = columns.value.conditionCellList[i][0].row;
            }
          });
          // 处理计算col错误逻辑
          columns.value.conditionCellList[i].forEach((content: any, contentIndex: number) => {
            if (
              columns.value.conditionCellList[i][contentIndex - 1] &&
              columns.value.conditionCellList[i][contentIndex - 1].col +
                columns.value.conditionCellList[i][contentIndex].colSpan !=
                content.col
            ) {
              content.col =
                columns.value.conditionCellList[i][contentIndex - 1].col +
                columns.value.conditionCellList[i][contentIndex].colSpan;
            }
          });
        }
      }
      for (let i = 0; i < columns.value.valueCellList.length; i++) {
        columns.value.valueCellList[i].splice(record.col, 0, {
          row: columns.value.valueCellList[i][0].row,
          col: record.col + 1,
          getValue: {
            valueType: ValueTypeEnum.Input,
          },
        });
        // columns.value.valueCellList[i].forEach((item: any, itemIndex: number) => {
        //   item.col = itemIndex + 1;
        // });
        // 给插入的表格列号进行排序
        columns.value.valueCellList[i].forEach((item: any, itemIndex: number) => {
          item.col = columns.value.conditionCellList[0][0].colSpan + itemIndex;
        });
      }
    }
  } else {
    columns.value.valueCellList.forEach((item: any) => {
      item.forEach((i: any) => {
        i.col++;
      });
    });
    for (
      let i = columns.value.conditionCellList[0][0].rowSpan;
      i < columns.value.conditionCellList.length;
      i++
    ) {
      const newContent = {
        row: i,
        col: columns.value.conditionCellList[0][0].colSpan,
        rowSpan: 1, //包含以自己  后面的总和加上自己表示自己可以有多少个子集-也就是横坐标的总个数
        colSpan: 1, // 多少行-第一个永远只占一列
        valueVariable: {
          id: uuidv4(),
          name: "无",
          title: "无",
          children: [
            { id: "", name: "string", title: "string", dataType: DataTypeEnum.String, value: {} },
          ],
        },
      };
      columns.value.conditionCellList[i].push(newContent);
    }
    // columns.value.conditionCellList[0][0].col++;
    columns.value.conditionCellList[0][0].colSpan++;
    // 给横坐标所有的列号加1
    for (let i = 0; i < columns.value.conditionCellList[0][0].rowSpan; i++) {
      columns.value.conditionCellList[i].forEach((item: any) => {
        item.col++;
      });
    }
  }
};
// 删除行
const deleteTableRow = (index: number, iIndex: number, record: any) => {
  // 横坐标-表头-删除行
  if (columns.value.conditionCellList[0][0].rowSpan > index) {
    if (index === 0) {
      // 第一行右击删除行
      columns.value.conditionCellList[0].splice(1);
      columns.value.conditionCellList[0] = [
        ...columns.value.conditionCellList[0],
        ...columns.value.conditionCellList[1],
      ];
      columns.value.conditionCellList.splice(1, 1);
    } else {
      // 其他行
      columns.value.conditionCellList.splice(index, 1);
    }
    columns.value.conditionCellList[0][0].rowSpan--;
    columns.value.conditionCellList[0][0].row = columns.value.conditionCellList[0][0].rowSpan - 1;
    // 给所有非表头的单元格-的行减一
    for (let i = 0; i < columns.value.valueCellList.length; i++) {
      columns.value.valueCellList[i].forEach((c: any) => {
        c.row--;
      });
    }
  } else {
    // 删除具有子项和当前项的-表头
    for (let i = columns.value.conditionCellList.length - 1; i >= index; i--) {
      // 删除某一个只有单行的
      if (
        columns.value.conditionCellList[i] &&
        record.row === columns.value.conditionCellList[i][0].row &&
        record.rowSpan === 1
      ) {
        columns.value.conditionCellList.splice(i, 1); // 使用splice删除元素
      }
      // 删除具有多个子集,但是只有一个父级的
      if (
        columns.value.conditionCellList[i] &&
        record.row >= columns.value.conditionCellList[i][0].row &&
        record.rowSpan > 1
      ) {
        columns.value.conditionCellList.splice(i, 1); // 使用splice删除元素
      }
      // 如果删除纵向具有子级某一个,进行截取,并替换数组
      if (
        columns.value.conditionCellList[index] &&
        columns.value.conditionCellList[index][0].valueVariable.id != record.valueVariable.id &&
        iIndex != 0 &&
        columns.value.conditionCellList[i] &&
        columns.value.conditionCellList[index][0].valueVariable.id ===
          columns.value.conditionCellList[i][0].valueVariable.id &&
        columns.value.conditionCellList[index][0].row != record.row
      ) {
        columns.value.conditionCellList[index].splice(iIndex > 1 ? iIndex : 0);
        if (columns.value.conditionCellList[index + 1]) {
          columns.value.conditionCellList[index] = [
            ...columns.value.conditionCellList[index],
            ...columns.value.conditionCellList[index + 1],
          ];
          columns.value.conditionCellList.splice(index + 1, 1);
        }
      }
    }

    // 删除单元格
    for (let i = columns.value.valueCellList.length - 1; i >= index; i--) {
      if (record.row >= columns.value.valueCellList[i][0].row) {
        columns.value.valueCellList.splice(i, 1); // 使用splice删除元素
      }
    }
    // 往上找row当大于或者等于当前点击的row值,就给找到的加上rowSpan加减1
    for (let i = columns.value.conditionCellList[0][0].rowSpan; i < record.row; i++) {
      if (columns.value.conditionCellList[i]) {
        columns.value.conditionCellList[i].forEach((item: any) => {
          if (item.row >= record.row && item.rowSpan > 1) {
            item.rowSpan -= record.rowSpan > 1 ? record.rowSpan : 1;
            item.row -= record.rowSpan > 1 ? record.rowSpan : 1;
          }
        });
      }
    }
  }
  // 更新当前表格所有的行号-row的值
  for (let i = 0; i < columns.value.conditionCellList.length; i++) {
    columns.value.conditionCellList[i].forEach((c: any) => {
      c.row = i + c.rowSpan - 1;
    });
  }
};
// 删除列
const deleteTableLine = (index: number, iIndex: number, record: any) => {
  if (columns.value.conditionCellList[0][0].rowSpan > index) {
    // 过滤从前一项到点击这一项的区间范围,删除区间内所有子列
    for (let o = columns.value.conditionCellList[index][iIndex - 1].col + 1; o <= record.col; o++) {
      for (let i = 0; i < columns.value.conditionCellList[0][0].rowSpan; i++) {
        // 过滤点击项上层的同列表头
        if (index >= i && iIndex != 0 && iIndex != 0) {
          columns.value.conditionCellList[i].forEach((item: any, itemIndex: number) => {
            if (record.col === item.col && item.colSpan === 1) {
              columns.value.conditionCellList[i].splice(itemIndex, 1);
            }
          });
        }
        // 过滤点击项下层的所有子列表头
        if (index <= i) {
          columns.value.conditionCellList[i] = columns.value.conditionCellList[i].filter(
            (item: any) => item.col != o,
          );
        }
      }
      for (let i = 0; i < columns.value.valueCellList.length; i++) {
        columns.value.valueCellList[i] = columns.value.valueCellList[i].filter(
          (item: any) => item.col != o,
        );
      }
    }
    // 更新单元格col
    for (let i = 0; i < columns.value.valueCellList.length; i++) {
      columns.value.valueCellList[i].forEach((cell: any, cellIndex: number) => {
        cell.col = cellIndex + columns.value.conditionCellList[0][0].colSpan;
      });
    }

    // 给上层的所有父列colSpan减一
    const totalColSpan = columns.value.conditionCellList[index]
      .slice(0, iIndex)
      .reduce((acc: any, obj: any) => acc + (obj.colSpan || 0), 1);
    for (let i = 0; i < index; i++) {
      let currentArray = columns.value.conditionCellList[i];
      let sumColspan = 0;
      for (let j = 0; j < currentArray.length; j++) {
        let currentObject = currentArray[j];
        //   // 把第一个格子排除
        if (
          currentObject.valueVariable.id != columns.value.conditionCellList[0][0].valueVariable.id
        ) {
          sumColspan += currentObject.colSpan;
        }
        if (sumColspan >= totalColSpan && columns.value.conditionCellList[i][j].colSpan > 1) {
          columns.value.conditionCellList[i][j].colSpan -= record.colSpan;
          columns.value.conditionCellList[i][j].col -= record.colSpan;
          sumColspan = 0;
        }
      }
    }
    // 处理横向标题的col列号
    for (let i = 0; i < columns.value.conditionCellList[0][0].rowSpan; i++) {
      columns.value.conditionCellList[i].forEach((sign: any, signIndex: number) => {
        if (
          sign.row === 0 &&
          sign.valueVariable.id != columns.value.conditionCellList[0][0].valueVariable.id
        ) {
          sign.col = sign.colSpan + columns.value.conditionCellList[i][signIndex - 1].col;
        } else if (
          sign.valueVariable.id != columns.value.conditionCellList[0][0].valueVariable.id
        ) {
          sign.col = columns.value.conditionCellList[i][signIndex - 1]
            ? columns.value.conditionCellList[i][signIndex - 1].col +
              (sign.colSpan != 0 ? sign.colSpan : 1)
            : sign.colSpan + columns.value.conditionCellList[0][0].colSpan - 1;
          sign.row = columns.value.conditionCellList[i][0].row;
        }
      });
    }
  } else {
    //给左上角的单个格子进行减colSpan
    columns.value.conditionCellList[0][0].colSpan--;
    columns.value.conditionCellList[0][0].col--;
    for (
      let i = columns.value.conditionCellList[0][0].rowSpan;
      i < columns.value.conditionCellList.length;
      i++
    ) {
      columns.value.conditionCellList[i] = columns.value.conditionCellList[i].filter(
        (item: any) => item.col != record.col,
      );
    }

    // 更新表头列
    for (let i = 0; i < columns.value.conditionCellList[0][0].rowSpan; i++) {
      columns.value.conditionCellList[i].forEach((item: any) => {
        item.col--;
      });
    }
    // 更新单元格列
    for (let i = 0; i < columns.value.valueCellList.length; i++) {
      columns.value.valueCellList[i].forEach((cell: any, cellIndex: number) => {
        cell.col = cellIndex + columns.value.conditionCellList[0][0].colSpan;
      });
    }
  }
};
// 删除的提示modal组件
const promptModelComponent = (type: string, index: number, iIndex: number, record: any) => {
  const promptContent = ref<string>("确定删除?");
  switch (type) {
    case "row":
      promptContent.value = "确定删除所在行?";
      break;
    case "line":
      promptContent.value = "确定删除所在列?";
      break;
  }
  Modal.confirm({
    title: "提示",
    content: promptContent.value,
    okText: "确认",
    cancelText: "取消",
    onOk: () => {
      if (type === "row") {
        deleteTableRow(index, iIndex, record);
      } else {
        deleteTableLine(index, iIndex, record);
      }
    },
    onCancel() {},
  });
};
// 计算展示的表格
const valueCellList = computed(() => computedValueCellList());
const computedValueCellList = () => {
  const arr = ref<any>([]);
  columns.value.valueCellList.forEach((item: any) => {
    arr.value.push(...item);
  });
  return arr.value;
};
// 表头右击-左击样式
const belongingHeaderIdList = ref<string[]>([]);
const selectedTable = (record: any) => {
  if (record.col && record.row) {
    // 点击单元格,找到所属子列的横向表头的id
    for (let i = 0; i < columns.value.conditionCellList[0][0].rowSpan; i++) {
      let currentArray = columns.value.conditionCellList[i];
      for (let j = 0; j < currentArray.length; j++) {
        let currentObject = currentArray[j];
        if (
          currentObject.col >= record.col &&
          columns.value.conditionCellList[i][j].valueVariable?.id !=
            columns.value.conditionCellList[0][0].valueVariable?.id
        ) {
          belongingHeaderIdList.value.push(columns.value.conditionCellList[i][j].valueVariable?.id);
          break;
        }
      }
    }
    // 点击单元格,找到侧轴所属行
    for (let i = columns.value.conditionCellList[0][0].rowSpan; i < record.row + 1; i++) {
      if (columns.value.conditionCellList[i]) {
        columns.value.conditionCellList[i].forEach((item: any) => {
          if (item.row >= record.row) {
            belongingHeaderIdList.value.push(item.valueVariable?.id);
          }
        });
      }
    }
  }
};
const selectedStyle = (id: string) => {
  return belongingHeaderIdList.value.includes(id) ? "includingColumn" : "nonExistent";
};
// 点击左上角单元格的编辑按钮
const editContent = () => {
  editBoxVisible.value = true;
  nextTick(() => {
    const input = document.getElementById("textarea");
    if (input) input.focus();
  });
};
const handleBlur = () => {
  editBoxVisible.value = false;
};
const leftValueChangeClick = (_item: any, _data: any) => {
  // item.leftValue = RuleCommonUtil.variableValue(data);
};
const valueTypeChangeClick = (_item: any, _valueType: any) => {
  // item.rightValue = { valueType: valueType.value };
};
const rightValueChangeClick = (_item: any, _data: any) => {
  // item.rightValue = RuleCommonUtil.convertValue(item.rightValue?.valueType, data);
};
// 表头右击计算展示的操作数据
const projectDateList = ref<any>([]);
const headerRightClickCalculation = (type: string) => {
  const list = ref<any>([
    {
      name: "配置条件",
      type: "deploy",
    },
    {
      name: "清空条件",
      type: "empty",
    },
    {
      name: "复制",
      type: "copy",
    },
    {
      name: "粘贴",
      type: "paste",
    },
    {
      name: "添加条件列",
      type: "addLine",
    },
    {
      name: "添加条件行",
      type: "addRow",
    },
    {
      name: "删除行",
      type: "deleteRow",
    },
    {
      name: "删除列",
      type: "deleteLine",
    },
  ]);
  // 计算横坐标-表头的行列数据
  const subArray = columns.value.conditionCellList.slice(
    0,
    columns.value.conditionCellList[0][0].rowSpan,
  );
  // 计算纵坐标-表头的行列数据
  const subArray2 = columns.value.conditionCellList.slice(
    columns.value.conditionCellList[0][0].rowSpan,
    columns.value.conditionCellList.length,
  );
  if (type === "crosswise") {
    if (subArray.length === 1) {
      list.value = list.value.filter((item: any) => item.type != "deleteRow");
    }
    if (subArray[0].length === 2) {
      list.value = list.value.filter((item: any) => item.type != "deleteLine");
    }
  } else {
    if (subArray2.length === 1) {
      list.value = list.value.filter((item: any) => item.type != "deleteRow");
    }
    if (subArray2[0].length === 1) {
      list.value = list.value.filter((item: any) => item.type != "deleteLine");
    }
  }

  return (projectDateList.value = list.value);
};
// 保存
const saveClick = () => {
  const sss = ref<any>({ ...columns.value });
  sss.value["conditionCellList"] = sss.value.conditionCellList.flat();
  sss.value["valueCellList"] = sss.value.valueCellList.flat();
  const params = {
    id: props.contentId,
    contentType: RuleTypeEnum.ComplexScoreCard,
    content: JSON.stringify(sss.value),
  };
  const callback = () => {
    search();
  };
  ruleStore.postSaveContent(params, callback);
};
</script>

下面是css部分:

<style lang="less" scoped>
.native-table {
  padding: 10px;

  table {
    border-collapse: collapse;
    width: 100%;
  }

  th,
  td {
    border: 1px solid #ccc;
    padding: 8px;
    text-align: center;
  }

  th {
    background-color: #f2f2f2;
  }

  .nested-table {
    border-collapse: collapse;
    width: 100%;
    margin: 0; /* Remove default margin */
    border: none; /* Remove border from nested table */
  }

  .nested-table th,
  .nested-table td {
    border: 1px solid black;
    padding: 8px;
    text-align: center;
  }
}

.specific_details {
  color: initial; /* 恢复默认文字颜色 */
  background-color: initial; /* 恢复默认背景颜色 */
  font-size: 13px;

  &:hover {
    color: white;
    background-color: #348afc;
    cursor: pointer; /* 小手指示器 */
  }
}
// 给表头添加添加背景色
.nonExistent {
  background: #ececec;
}

.includingColumn {
  background: #fff;
}
// 表头的选择属性默认样式
.operation-container {
  color: #a3a3a3;
  font-weight: 500;
  font-size: 14px;
  border: 1px dashed transparent;

  &:hover {
    border: 1px dashed gray;
    cursor: pointer;
  }
}
</style>

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值