662 lines
20 KiB
Plaintext
662 lines
20 KiB
Plaintext
<script lang="ts">
|
|
export default {
|
|
name: "TableRow",
|
|
};
|
|
</script>
|
|
|
|
<script lang="ts" setup>
|
|
import { Recordable } from "../../types";
|
|
import { LayIcon } from "@layui/icons-vue";
|
|
import { computed, ref, StyleValue, useSlots, WritableComputedRef } from "vue";
|
|
import LayCheckbox from "../checkbox/index.vue";
|
|
import LayTooltip from "../tooltip/index.vue";
|
|
import LayRadio from "../radio/index.vue";
|
|
|
|
export interface TableRowProps {
|
|
index: number;
|
|
indentSize: number;
|
|
currentIndentSize: number;
|
|
expandSpace: boolean;
|
|
expandIndex: number;
|
|
selectedKeys: Recordable[];
|
|
selectedKey: string;
|
|
tableColumnKeys: Recordable[];
|
|
childrenColumnName?: string;
|
|
columns: Recordable[];
|
|
checkbox?: boolean;
|
|
cellClassName: string | Function;
|
|
cellStyle: string | Function;
|
|
rowClassName: string | Function;
|
|
rowStyle: string | Function;
|
|
id: string;
|
|
data: any;
|
|
spanMethod: Function;
|
|
defaultExpandAll: boolean;
|
|
expandKeys: Recordable[];
|
|
getCheckboxProps: Function;
|
|
getRadioProps: Function;
|
|
}
|
|
|
|
const slot = useSlots();
|
|
|
|
const emit = defineEmits([
|
|
"row",
|
|
"row-double",
|
|
"row-contextmenu",
|
|
"update:expandKeys",
|
|
"update:selectedKeys",
|
|
"update:selectedKey",
|
|
]);
|
|
|
|
const props = withDefaults(defineProps<TableRowProps>(), {
|
|
checkbox: false,
|
|
childrenColumnName: "children",
|
|
cellStyle: "",
|
|
cellClassName: "",
|
|
});
|
|
|
|
const tableExpandAll = ref(props.defaultExpandAll);
|
|
|
|
const tableExpandKeys: WritableComputedRef<Recordable[]> = computed({
|
|
get() {
|
|
return [...props.expandKeys];
|
|
},
|
|
set(val) {
|
|
emit("update:expandKeys", val);
|
|
},
|
|
});
|
|
|
|
const tableSelectedKeys: WritableComputedRef<Recordable[]> = computed({
|
|
get() {
|
|
return [...props.selectedKeys];
|
|
},
|
|
set(val) {
|
|
emit("update:selectedKeys", val);
|
|
},
|
|
});
|
|
|
|
const tableSelectedKey: WritableComputedRef<string> = computed({
|
|
get() {
|
|
return props.selectedKey;
|
|
},
|
|
set(val) {
|
|
emit("update:selectedKey", val);
|
|
},
|
|
});
|
|
|
|
const isExpand: WritableComputedRef<any> = computed({
|
|
get() {
|
|
return tableExpandAll.value
|
|
? true
|
|
: tableExpandKeys.value.includes(props.data[props.id]);
|
|
},
|
|
set(val) {
|
|
let newTableExpandKeys = [...tableExpandKeys.value];
|
|
if (!val) {
|
|
newTableExpandKeys.splice(
|
|
newTableExpandKeys.indexOf(props.data[props.id]),
|
|
1
|
|
);
|
|
} else {
|
|
newTableExpandKeys.push(props.data[props.id]);
|
|
}
|
|
tableExpandAll.value = false;
|
|
tableExpandKeys.value = newTableExpandKeys;
|
|
},
|
|
});
|
|
|
|
const slotsData = ref<string[]>([]);
|
|
|
|
props.columns.map((value: any) => {
|
|
if (value.customSlot) {
|
|
slotsData.value.push(value.customSlot);
|
|
}
|
|
});
|
|
|
|
const rowClick = function (data: any, evt: MouseEvent) {
|
|
emit("row", data, evt);
|
|
};
|
|
|
|
const rowDoubleClick = function (data: any, evt: MouseEvent) {
|
|
emit("row-double", data, evt);
|
|
};
|
|
|
|
const rowContextmenu = function (data: any, evt: MouseEvent) {
|
|
emit("row-contextmenu", data, evt);
|
|
};
|
|
|
|
const expandIconType = computed(() => {
|
|
return isExpand.value ? "layui-icon-subtraction" : "layui-icon-addition";
|
|
});
|
|
|
|
const handleExpand = () => {
|
|
isExpand.value = !isExpand.value;
|
|
};
|
|
|
|
const renderCellStyle = (
|
|
row: any,
|
|
column: any,
|
|
rowIndex: number,
|
|
columnIndex: number
|
|
) => {
|
|
if (typeof props.cellStyle === "string") {
|
|
return props.cellStyle;
|
|
}
|
|
return props.cellStyle(row, column, rowIndex, columnIndex);
|
|
};
|
|
|
|
const renderCellClassName = (
|
|
row: any,
|
|
column: any,
|
|
rowIndex: number,
|
|
columnIndex: number
|
|
) => {
|
|
if (typeof props.cellClassName === "string") {
|
|
return props.cellClassName;
|
|
}
|
|
return props.cellClassName(row, column, rowIndex, columnIndex);
|
|
};
|
|
|
|
const renderRowStyle = (data: any, index: number) => {
|
|
if (typeof props.rowStyle === "string") {
|
|
return props.rowStyle;
|
|
}
|
|
return props.rowStyle(data, index);
|
|
};
|
|
|
|
const renderRowClassName = (data: any, index: number) => {
|
|
if (typeof props.rowClassName === "string") {
|
|
return props.rowClassName;
|
|
}
|
|
return props.rowClassName(data, index);
|
|
};
|
|
|
|
const childrenIndentSize = computed(
|
|
() => props.currentIndentSize + props.indentSize
|
|
);
|
|
|
|
const renderFixedStyle = (column: any, columnIndex: number) => {
|
|
if (column.fixed) {
|
|
if (column.fixed == "left") {
|
|
var left = 0;
|
|
for (var i = 0; i < columnIndex; i++) {
|
|
if (
|
|
props.columns[i].fixed &&
|
|
props.columns[i].fixed == "left" &&
|
|
props.tableColumnKeys.includes(props.columns[i].key)
|
|
) {
|
|
left = left + Number(props.columns[i]?.width?.replace("px", ""));
|
|
}
|
|
}
|
|
return { left: `${left}px` } as StyleValue;
|
|
} else {
|
|
var right = 0;
|
|
for (var i = columnIndex + 1; i < props.columns.length; i++) {
|
|
if (
|
|
props.columns[i].fixed &&
|
|
props.columns[i].fixed == "right" &&
|
|
props.tableColumnKeys.includes(props.columns[i].key)
|
|
) {
|
|
right = right + Number(props.columns[i]?.width?.replace("px", ""));
|
|
}
|
|
}
|
|
return { right: `${right}px` } as StyleValue;
|
|
}
|
|
} else {
|
|
var isLast = true;
|
|
for (var i = columnIndex + 1; i < props.columns.length; i++) {
|
|
if (
|
|
props.columns[i].fixed == undefined &&
|
|
props.tableColumnKeys.includes(props.columns[i].key)
|
|
) {
|
|
isLast = false;
|
|
}
|
|
}
|
|
return isLast ? ({ "border-right": "none" } as StyleValue) : {};
|
|
}
|
|
return {} as StyleValue;
|
|
};
|
|
|
|
const renderFixedClassName = (column: any, columnIndex: number) => {
|
|
if (column.fixed) {
|
|
if (column.fixed == "left") {
|
|
var left = true;
|
|
for (var i = columnIndex + 1; i < props.columns.length; i++) {
|
|
if (
|
|
props.columns[i].fixed &&
|
|
props.columns[i].fixed == "left" &&
|
|
props.tableColumnKeys.includes(props.columns[i].key)
|
|
) {
|
|
left = false;
|
|
}
|
|
}
|
|
return left ? `layui-table-fixed-left-last` : "";
|
|
} else {
|
|
var right = true;
|
|
for (var i = 0; i < columnIndex; i++) {
|
|
if (
|
|
props.columns[i].fixed &&
|
|
props.columns[i].fixed == "right" &&
|
|
props.tableColumnKeys.includes(props.columns[i].key)
|
|
) {
|
|
right = false;
|
|
}
|
|
}
|
|
return right ? `layui-table-fixed-right-first` : "";
|
|
}
|
|
}
|
|
};
|
|
|
|
const spanMethodAttr = (
|
|
row: any,
|
|
column: any,
|
|
rowIndex: number,
|
|
columnIndex: number
|
|
) => {
|
|
const attrs = props.spanMethod(row, column, rowIndex, columnIndex);
|
|
if (attrs instanceof Array) {
|
|
return { rowspan: attrs[0], colspan: attrs[1] };
|
|
} else if (attrs instanceof Object) {
|
|
return attrs;
|
|
} else {
|
|
return { rowspan: 1, colspan: 1 };
|
|
}
|
|
};
|
|
|
|
const isAutoShow = (
|
|
row: any,
|
|
column: any,
|
|
rowIndex: number,
|
|
columnIndex: number
|
|
) => {
|
|
const attrs = spanMethodAttr(row, column, rowIndex, columnIndex);
|
|
if (attrs.colspan == 0 && attrs.rowspan == 0) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
const checkboxProps = props.getCheckboxProps(props.data, props.index);
|
|
const radioProps = props.getRadioProps(props.data, props.index);
|
|
</script>
|
|
|
|
<template>
|
|
<tr
|
|
:style="[renderRowStyle(data, index)]"
|
|
:class="[renderRowClassName(data, index)]"
|
|
@click.stop="rowClick(data, $event)"
|
|
@dblclick.stop="rowDoubleClick(data, $event)"
|
|
@contextmenu.stop="rowContextmenu(data, $event)"
|
|
>
|
|
<template v-for="(column, columnIndex) in columns" :key="columnIndex">
|
|
<template v-if="tableColumnKeys.includes(column.key)">
|
|
<template v-if="column.type">
|
|
<template v-if="column.type == 'radio'">
|
|
<td
|
|
class="layui-table-cell layui-table-cell-radio"
|
|
v-if="isAutoShow(data, column, index, columnIndex)"
|
|
:colspan="
|
|
spanMethodAttr(data, column, index, columnIndex).colspan
|
|
"
|
|
:rowspan="
|
|
spanMethodAttr(data, column, index, columnIndex).rowspan
|
|
"
|
|
:style="[
|
|
{
|
|
textAlign: column.align,
|
|
whiteSpace: column.ellipsisTooltip ? 'nowrap' : 'normal',
|
|
},
|
|
renderFixedStyle(column, columnIndex),
|
|
renderCellStyle(data, column, index, columnIndex),
|
|
]"
|
|
:class="[
|
|
renderFixedClassName(column, columnIndex),
|
|
renderCellClassName(data, column, index, columnIndex),
|
|
column.fixed ? `layui-table-fixed-${column.fixed}` : '',
|
|
]"
|
|
>
|
|
<span
|
|
v-if="expandSpace && columnIndex === expandIndex"
|
|
:style="{ 'margin-right': currentIndentSize + 'px' }"
|
|
></span>
|
|
|
|
<span
|
|
v-if="
|
|
expandSpace &&
|
|
!data[childrenColumnName] &&
|
|
!slot.expand &&
|
|
columnIndex === expandIndex
|
|
"
|
|
class="layui-table-cell-expand-icon-spaced"
|
|
></span>
|
|
|
|
<lay-icon
|
|
v-if="
|
|
(slot.expand || data[childrenColumnName]) &&
|
|
columnIndex === expandIndex
|
|
"
|
|
class="layui-table-cell-expand-icon"
|
|
:type="expandIconType"
|
|
@click="handleExpand"
|
|
></lay-icon>
|
|
|
|
<lay-radio
|
|
v-model="tableSelectedKey"
|
|
v-bind="radioProps"
|
|
:value="data[id]"
|
|
/>
|
|
</td>
|
|
</template>
|
|
|
|
<template v-if="column.type == 'checkbox'">
|
|
<td
|
|
class="layui-table-cell layui-table-cell-checkbox"
|
|
v-if="isAutoShow(data, column, index, columnIndex)"
|
|
:colspan="
|
|
spanMethodAttr(data, column, index, columnIndex).colspan
|
|
"
|
|
:rowspan="
|
|
spanMethodAttr(data, column, index, columnIndex).rowspan
|
|
"
|
|
:style="[
|
|
{
|
|
textAlign: column.align,
|
|
whiteSpace: column.ellipsisTooltip ? 'nowrap' : 'normal',
|
|
},
|
|
renderFixedStyle(column, columnIndex),
|
|
renderCellStyle(data, column, index, columnIndex),
|
|
]"
|
|
:class="[
|
|
renderFixedClassName(column, columnIndex),
|
|
renderCellClassName(data, column, index, columnIndex),
|
|
column.fixed ? `layui-table-fixed-${column.fixed}` : '',
|
|
]"
|
|
>
|
|
<span
|
|
v-if="expandSpace && columnIndex === expandIndex"
|
|
:style="{ 'margin-right': currentIndentSize + 'px' }"
|
|
></span>
|
|
|
|
<span
|
|
v-if="
|
|
expandSpace &&
|
|
!data[childrenColumnName] &&
|
|
!slot.expand &&
|
|
columnIndex === expandIndex
|
|
"
|
|
class="layui-table-cell-expand-icon-spaced"
|
|
></span>
|
|
|
|
<lay-icon
|
|
v-if="
|
|
(slot.expand || data[childrenColumnName]) &&
|
|
columnIndex === expandIndex
|
|
"
|
|
class="layui-table-cell-expand-icon"
|
|
:type="expandIconType"
|
|
@click="handleExpand"
|
|
></lay-icon>
|
|
|
|
<lay-checkbox
|
|
v-model="tableSelectedKeys"
|
|
v-bind="checkboxProps"
|
|
:value="data[id]"
|
|
skin="primary"
|
|
/>
|
|
</td>
|
|
</template>
|
|
|
|
<template v-if="column.type == 'number'">
|
|
<td
|
|
class="layui-table-cell layui-table-cell-number"
|
|
v-if="isAutoShow(data, column, index, columnIndex)"
|
|
:colspan="
|
|
spanMethodAttr(data, column, index, columnIndex).colspan
|
|
"
|
|
:rowspan="
|
|
spanMethodAttr(data, column, index, columnIndex).rowspan
|
|
"
|
|
:style="[
|
|
{
|
|
textAlign: column.align,
|
|
whiteSpace: column.ellipsisTooltip ? 'nowrap' : 'normal',
|
|
},
|
|
renderFixedStyle(column, columnIndex),
|
|
renderCellStyle(data, column, index, columnIndex),
|
|
]"
|
|
:class="[
|
|
renderFixedClassName(column, columnIndex),
|
|
renderCellClassName(data, column, index, columnIndex),
|
|
column.fixed ? `layui-table-fixed-${column.fixed}` : '',
|
|
]"
|
|
>
|
|
<span
|
|
v-if="expandSpace && columnIndex === expandIndex"
|
|
:style="{ 'margin-right': currentIndentSize + 'px' }"
|
|
></span>
|
|
|
|
<span
|
|
v-if="
|
|
expandSpace &&
|
|
!data[childrenColumnName] &&
|
|
!slot.expand &&
|
|
columnIndex === expandIndex
|
|
"
|
|
class="layui-table-cell-expand-icon-spaced"
|
|
></span>
|
|
|
|
<lay-icon
|
|
v-if="
|
|
(slot.expand || data[childrenColumnName]) &&
|
|
columnIndex === expandIndex
|
|
"
|
|
class="layui-table-cell-expand-icon"
|
|
:type="expandIconType"
|
|
@click="handleExpand"
|
|
></lay-icon>
|
|
|
|
{{ index + 1 }}
|
|
</td>
|
|
</template>
|
|
</template>
|
|
|
|
<template v-else>
|
|
<template v-if="column.customSlot">
|
|
<td
|
|
class="layui-table-cell"
|
|
v-if="isAutoShow(data, column, index, columnIndex)"
|
|
:colspan="
|
|
spanMethodAttr(data, column, index, columnIndex).colspan
|
|
"
|
|
:rowspan="
|
|
spanMethodAttr(data, column, index, columnIndex).rowspan
|
|
"
|
|
:style="[
|
|
{
|
|
textAlign: column.align,
|
|
whiteSpace: column.ellipsisTooltip ? 'nowrap' : 'normal',
|
|
},
|
|
renderFixedStyle(column, columnIndex),
|
|
renderCellStyle(data, column, index, columnIndex),
|
|
]"
|
|
:class="[
|
|
renderFixedClassName(column, columnIndex),
|
|
renderCellClassName(data, column, index, columnIndex),
|
|
column.fixed ? `layui-table-fixed-${column.fixed}` : '',
|
|
]"
|
|
>
|
|
<span
|
|
v-if="expandSpace && columnIndex === expandIndex"
|
|
:style="{ 'margin-right': currentIndentSize + 'px' }"
|
|
></span>
|
|
|
|
<span
|
|
v-if="
|
|
expandSpace &&
|
|
!data[childrenColumnName] &&
|
|
!slot.expand &&
|
|
columnIndex === expandIndex
|
|
"
|
|
class="layui-table-cell-expand-icon-spaced"
|
|
></span>
|
|
|
|
<lay-icon
|
|
v-if="
|
|
(slot.expand || data[childrenColumnName]) &&
|
|
columnIndex === expandIndex
|
|
"
|
|
class="layui-table-cell-expand-icon"
|
|
:type="expandIconType"
|
|
@click="handleExpand"
|
|
></lay-icon>
|
|
|
|
<lay-tooltip v-if="column.ellipsisTooltip" :isAutoShow="true">
|
|
<slot
|
|
:name="column.customSlot"
|
|
:data="data"
|
|
:column="column"
|
|
></slot>
|
|
<template #content>
|
|
<slot
|
|
:name="column.customSlot"
|
|
:data="data"
|
|
:column="column"
|
|
></slot>
|
|
</template>
|
|
</lay-tooltip>
|
|
<slot
|
|
v-else
|
|
:name="column.customSlot"
|
|
:data="data"
|
|
:column="column"
|
|
></slot>
|
|
</td>
|
|
</template>
|
|
|
|
<template v-else>
|
|
<td
|
|
class="layui-table-cell"
|
|
v-if="isAutoShow(data, column, index, columnIndex)"
|
|
:colspan="
|
|
spanMethodAttr(data, column, index, columnIndex).colspan
|
|
"
|
|
:rowspan="
|
|
spanMethodAttr(data, column, index, columnIndex).rowspan
|
|
"
|
|
:style="[
|
|
{
|
|
textAlign: column.align,
|
|
whiteSpace: column.ellipsisTooltip ? 'nowrap' : 'normal',
|
|
},
|
|
renderFixedStyle(column, columnIndex),
|
|
renderCellStyle(data, column, index, columnIndex),
|
|
]"
|
|
:class="[
|
|
renderFixedClassName(column, columnIndex),
|
|
renderCellClassName(data, column, index, columnIndex),
|
|
column.fixed ? `layui-table-fixed-${column.fixed}` : '',
|
|
]"
|
|
>
|
|
<span
|
|
v-if="expandSpace && columnIndex === expandIndex"
|
|
:style="{ 'margin-right': currentIndentSize + 'px' }"
|
|
></span>
|
|
|
|
<span
|
|
v-if="
|
|
expandSpace &&
|
|
!data[childrenColumnName] &&
|
|
!slot.expand &&
|
|
columnIndex === expandIndex
|
|
"
|
|
class="layui-table-cell-expand-icon-spaced"
|
|
></span>
|
|
|
|
<lay-icon
|
|
v-if="
|
|
(slot.expand || data[childrenColumnName]) &&
|
|
columnIndex === expandIndex
|
|
"
|
|
class="layui-table-cell-expand-icon"
|
|
:type="expandIconType"
|
|
@click="handleExpand"
|
|
></lay-icon>
|
|
|
|
<lay-tooltip
|
|
v-if="column.ellipsisTooltip"
|
|
:content="data[column.key]"
|
|
:isAutoShow="true"
|
|
>
|
|
{{ data[column.key] }}
|
|
</lay-tooltip>
|
|
<span v-else> {{ data[column.key] }} </span>
|
|
</td>
|
|
</template>
|
|
</template>
|
|
</template>
|
|
</template>
|
|
</tr>
|
|
|
|
<tr class="layui-table-cell-expand" v-if="slot.expand && isExpand">
|
|
<td class="layui-table-cell" :colspan="columns.length">
|
|
<slot name="expand" :data="data"></slot>
|
|
</td>
|
|
</tr>
|
|
|
|
<template v-if="data[childrenColumnName] && isExpand">
|
|
<template
|
|
v-for="(children, childrenIndex) in data[childrenColumnName]"
|
|
:key="childrenIndex"
|
|
>
|
|
<table-row
|
|
:id="id"
|
|
:data="children"
|
|
:index="childrenIndex"
|
|
:columns="columns"
|
|
:indent-size="indentSize"
|
|
:current-indent-size="childrenIndentSize"
|
|
:checkbox="checkbox"
|
|
:tableColumnKeys="tableColumnKeys"
|
|
:expandSpace="expandSpace"
|
|
:expandIndex="expandIndex"
|
|
:cellStyle="cellStyle"
|
|
:cellClassName="cellClassName"
|
|
:rowStyle="rowStyle"
|
|
:rowClassName="rowClassName"
|
|
:spanMethod="spanMethod"
|
|
:defaultExpandAll="defaultExpandAll"
|
|
:getCheckboxProps="getCheckboxProps"
|
|
:getRadioProps="getRadioProps"
|
|
@row="rowClick"
|
|
@row-double="rowDoubleClick"
|
|
@row-contextmenu="rowContextmenu"
|
|
v-model:expandKeys="tableExpandKeys"
|
|
v-model:selectedKeys="tableSelectedKeys"
|
|
v-model:selectedKey="tableSelectedKey"
|
|
>
|
|
<template
|
|
v-for="name in slotsData"
|
|
#[name]="slotProp: { data: any, column: any }"
|
|
>
|
|
<slot
|
|
:name="name"
|
|
:data="slotProp.data"
|
|
:column="slotProp.column"
|
|
></slot>
|
|
</template>
|
|
<template
|
|
v-if="slot.expand"
|
|
#expand="slotProp: { data: any, column: any }"
|
|
>
|
|
<slot
|
|
name="expand"
|
|
:data="slotProp.data"
|
|
:column="slotProp.column"
|
|
></slot>
|
|
</template>
|
|
</table-row>
|
|
</template>
|
|
</template>
|
|
</template>
|