需求:横纵都需要表头,表头可以右击自定义添加行列。点击某一个非表头的单元格,可以左右样式多层定位,如:
结构数据解析:表头为一个二维数组,一个数组代表一行,表格为另一个二维数组。如果接口请求保存为一个扁平的一维数组,可以在获取和保存时候对数组进行升维和降维。
下面是代码部分:
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>