|
|
|
|
<template>
|
|
|
|
|
<div class="list-table-v2" :style="containerStyle">
|
|
|
|
|
<!-- Mini hidden table for measuring row height (only when using dynamic height mode) -->
|
|
|
|
|
<div v-if="shouldUseProbeRow" ref="miniTableRef" class="mini-table" aria-hidden="true">
|
|
|
|
|
<div v-if="miniTableData.length > 0" class="mini-table-inner">
|
|
|
|
|
<div v-for="(row, idx) in miniTableData" :key="idx" class="mini-row">
|
|
|
|
|
<div v-for="item in prop.columns || []" :key="item.key" class="mini-cell">
|
|
|
|
|
<span class="mini-cell-content">
|
|
|
|
|
{{ getProbeCellText(row, item) }}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div ref="myTableRef" class="my-table">
|
|
|
|
|
<el-auto-resizer>
|
|
|
|
|
<template #default="{ height, width }">
|
|
|
|
|
<el-table-v2
|
|
|
|
|
ref="table"
|
|
|
|
|
:columns="tableColumns"
|
|
|
|
|
:data="pageData"
|
|
|
|
|
:width="width"
|
|
|
|
|
:height="resolvedHeight(height)"
|
|
|
|
|
:row-height="prop.rowHeight"
|
|
|
|
|
:header-height="prop.headerHeight"
|
|
|
|
|
:estimated-row-height="estimatedRowHeightToUse"
|
|
|
|
|
:border="border"
|
|
|
|
|
:row-key="rowKey"
|
|
|
|
|
:class="border ? 'has-border' : ''"
|
|
|
|
|
@scroll="onScroll"
|
|
|
|
|
@row-click="onRowClick"
|
|
|
|
|
@cell-click="onCellClick"
|
|
|
|
|
/>
|
|
|
|
|
</template>
|
|
|
|
|
</el-auto-resizer>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="page" class="my-pagination">
|
|
|
|
|
<el-pagination
|
|
|
|
|
:small="state.size.size == 'small'"
|
|
|
|
|
@size-change="handleSizeChange"
|
|
|
|
|
@current-change="handleCurrentChange"
|
|
|
|
|
:current-page="example.page"
|
|
|
|
|
:page-sizes="[10, 20, 50, 100, 200]"
|
|
|
|
|
:page-size="example.size"
|
|
|
|
|
layout="total, sizes, prev, pager, next, jumper"
|
|
|
|
|
:total="data.total"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="tsx" setup>
|
|
|
|
|
import { useStore } from "vuex";
|
|
|
|
|
import { ref, computed, watch, h, onMounted, onUpdated, onUnmounted, useSlots, renderSlot, nextTick } from "vue";
|
|
|
|
|
import { useI18n } from "vue3-i18n";
|
|
|
|
|
import { ElAutoResizer, ElTableV2 } from "element-plus";
|
|
|
|
|
import * as lodash from "lodash-es";
|
|
|
|
|
import TzDateTime from "../item/tzDateTime.vue";
|
|
|
|
|
|
|
|
|
|
const slots = useSlots();
|
|
|
|
|
|
|
|
|
|
const { t } = useI18n();
|
|
|
|
|
const { state } = useStore();
|
|
|
|
|
const table = ref();
|
|
|
|
|
const miniTableRef = ref();
|
|
|
|
|
const myTableRef = ref(); // Reference to .my-table for ResizeObserver
|
|
|
|
|
const miniTableData = ref<any[]>([]);
|
|
|
|
|
const estimatedRowHeight = ref<number | undefined>(undefined);
|
|
|
|
|
let miniTableResizeObserver: ResizeObserver | null = null;
|
|
|
|
|
|
|
|
|
|
// Header height constant
|
|
|
|
|
|
|
|
|
|
type TimestampValue =
|
|
|
|
|
| undefined
|
|
|
|
|
| boolean
|
|
|
|
|
| string
|
|
|
|
|
| {
|
|
|
|
|
valueFormat?: string;
|
|
|
|
|
valueTz?: string;
|
|
|
|
|
displayFormat?: string;
|
|
|
|
|
locale?: string;
|
|
|
|
|
type?: "iso8601" | "unix" | "unixMillis";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
interface TzDateTimeProps {
|
|
|
|
|
value: string | number;
|
|
|
|
|
valueFormat?: string;
|
|
|
|
|
valueTz?: string;
|
|
|
|
|
displayFormat?: string;
|
|
|
|
|
locale?: string;
|
|
|
|
|
type?: "iso8601" | "unix" | "unixMillis";
|
|
|
|
|
slot?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface TzDateTimeConfig {
|
|
|
|
|
valueFormat?: string;
|
|
|
|
|
valueTz?: string;
|
|
|
|
|
displayFormat?: string;
|
|
|
|
|
locale?: string;
|
|
|
|
|
type?: "iso8601" | "unix" | "unixMillis";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface TableColumn {
|
|
|
|
|
key: string;
|
|
|
|
|
dataKey?: string;
|
|
|
|
|
name?: string;
|
|
|
|
|
i18n?: string;
|
|
|
|
|
type?: string;
|
|
|
|
|
width?: string | number;
|
|
|
|
|
minWidth?: string | number;
|
|
|
|
|
fixed?: boolean | "left" | "right";
|
|
|
|
|
align?: "left" | "center" | "right";
|
|
|
|
|
slot?: boolean;
|
|
|
|
|
dict?: string;
|
|
|
|
|
timestamp?: TimestampValue;
|
|
|
|
|
filesize?: boolean;
|
|
|
|
|
|
|
|
|
|
[others: string]: any;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
|
data?: any;
|
|
|
|
|
columns?: TableColumn[];
|
|
|
|
|
page?: boolean;
|
|
|
|
|
height?: number | string;
|
|
|
|
|
maxHeight?: number | string;
|
|
|
|
|
example?: any;
|
|
|
|
|
rowKey?: string;
|
|
|
|
|
selectKey?: string;
|
|
|
|
|
treeProps?: any;
|
|
|
|
|
lazy?: boolean;
|
|
|
|
|
border?: boolean;
|
|
|
|
|
timestampFormat?: string;
|
|
|
|
|
rowHeight?: number;
|
|
|
|
|
estimatedRowHeight?: number;
|
|
|
|
|
headerHeight?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const prop = withDefaults(defineProps<Props>(), {
|
|
|
|
|
data: () => [],
|
|
|
|
|
columns: () => [],
|
|
|
|
|
page: false,
|
|
|
|
|
height: undefined,
|
|
|
|
|
maxHeight: undefined,
|
|
|
|
|
example: () => ({}),
|
|
|
|
|
rowKey: "id",
|
|
|
|
|
selectKey: undefined,
|
|
|
|
|
treeProps: undefined,
|
|
|
|
|
lazy: false,
|
|
|
|
|
border: false,
|
|
|
|
|
timestampFormat: "YYYY-MM-DD HH:mm:ss",
|
|
|
|
|
rowHeight: undefined,
|
|
|
|
|
estimatedRowHeight: undefined,
|
|
|
|
|
headerHeight: undefined,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits(["query", "selection-change", "row-click", "cell-click"]);
|
|
|
|
|
|
|
|
|
|
// Pagination data - use data.data if page response, otherwise data array
|
|
|
|
|
const pageData = computed(() => {
|
|
|
|
|
if (!prop.data) return [];
|
|
|
|
|
if (prop.page && prop.data.data) {
|
|
|
|
|
return prop.data.data;
|
|
|
|
|
}
|
|
|
|
|
if (Array.isArray(prop.data)) {
|
|
|
|
|
return prop.data;
|
|
|
|
|
}
|
|
|
|
|
return [];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Probe row text extraction (same logic as cellRenderer but returns text only)
|
|
|
|
|
const getProbeCellText = (rowData: any, item: TableColumn): string => {
|
|
|
|
|
const value = lodash.get(rowData, item.dataKey || item.key);
|
|
|
|
|
|
|
|
|
|
if (item.dict) return formatterByDist(item.dict, value);
|
|
|
|
|
if (item.timestamp) return formatStamp(value);
|
|
|
|
|
if (item.filesize) return formatFileSize(value);
|
|
|
|
|
if (rowData.scheme) return formatterByDist(rowData.scheme + "_" + (item.dataKey || item.key), value);
|
|
|
|
|
return getValue(value);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Whether to use probe row for dynamic height measurement
|
|
|
|
|
// Only use probe row when rowHeight is NOT explicitly specified
|
|
|
|
|
const shouldUseProbeRow = computed(() => {
|
|
|
|
|
return prop.rowHeight === undefined;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// The estimated row height to pass to el-table-v2
|
|
|
|
|
// Only used when rowHeight is NOT set (dynamic height mode)
|
|
|
|
|
const estimatedRowHeightToUse = computed(() => {
|
|
|
|
|
if (prop.rowHeight !== undefined) return undefined; // fixed height mode, don't use estimated
|
|
|
|
|
if (prop.estimatedRowHeight !== undefined) return prop.estimatedRowHeight; // user provided estimate
|
|
|
|
|
return estimatedRowHeight.value; // use probe-measured value
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Measure mini table row height when data changes (only when using probe row)
|
|
|
|
|
// We use TWO frames delay to let el-table-v2 fully settle before measuring
|
|
|
|
|
watch(
|
|
|
|
|
() => pageData.value,
|
|
|
|
|
async (data) => {
|
|
|
|
|
// Skip if rowHeight is set (fixed height mode) or no data
|
|
|
|
|
if (!shouldUseProbeRow.value || !data || data.length === 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Use up to 5 rows for mini table
|
|
|
|
|
miniTableData.value = data.slice(0, 5);
|
|
|
|
|
// Wait for mini table to render
|
|
|
|
|
await nextTick();
|
|
|
|
|
// Wait TWO frames for layout to settle
|
|
|
|
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
|
|
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
|
|
|
// Measure first row height
|
|
|
|
|
const firstRow = miniTableRef.value?.querySelector(".mini-row");
|
|
|
|
|
const height = firstRow?.offsetHeight;
|
|
|
|
|
if (height && height > 0) {
|
|
|
|
|
estimatedRowHeight.value = height;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{ immediate: true }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Setup ResizeObserver on mount (not window resize - that causes flickering)
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
// Create debounced resize handler for mini table width changes
|
|
|
|
|
const debouncedMeasure = lodash.debounce(async () => {
|
|
|
|
|
if (!shouldUseProbeRow.value || miniTableData.value.length === 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Clear previous measurement so el-table-v2 recalculates
|
|
|
|
|
estimatedRowHeight.value = undefined;
|
|
|
|
|
await nextTick();
|
|
|
|
|
// Wait TWO frames for layout to settle
|
|
|
|
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
|
|
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
|
|
|
// Measure first row height
|
|
|
|
|
const firstRow = miniTableRef.value?.querySelector(".mini-row");
|
|
|
|
|
const height = firstRow?.offsetHeight;
|
|
|
|
|
if (height && height > 0) {
|
|
|
|
|
estimatedRowHeight.value = height;
|
|
|
|
|
}
|
|
|
|
|
}, 100);
|
|
|
|
|
|
|
|
|
|
// Use ResizeObserver on .my-table to detect width changes
|
|
|
|
|
// This is better than window resize because it only fires when OUR container changes
|
|
|
|
|
miniTableResizeObserver = new ResizeObserver(() => {
|
|
|
|
|
debouncedMeasure();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (myTableRef.value) {
|
|
|
|
|
miniTableResizeObserver.observe(myTableRef.value);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Cleanup on unmount
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
if (miniTableResizeObserver) {
|
|
|
|
|
miniTableResizeObserver.disconnect();
|
|
|
|
|
miniTableResizeObserver = null;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const containerStyle = computed(() => {
|
|
|
|
|
const style: Record<string, string> = {};
|
|
|
|
|
if (prop.height !== undefined) {
|
|
|
|
|
style.height = typeof prop.height === "number" ? `${prop.height}px` : String(prop.height);
|
|
|
|
|
} else {
|
|
|
|
|
style.height = "100%";
|
|
|
|
|
}
|
|
|
|
|
if (prop.maxHeight !== undefined) {
|
|
|
|
|
style.maxHeight = typeof prop.maxHeight === "number" ? `${prop.maxHeight}px` : String(prop.maxHeight);
|
|
|
|
|
}
|
|
|
|
|
return style;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Use explicit height if provided, otherwise use auto from auto-resizer
|
|
|
|
|
const resolvedHeight = (autoHeight: number) => {
|
|
|
|
|
if (prop.height !== undefined) {
|
|
|
|
|
return typeof prop.height === "number" ? prop.height : parseInt(String(prop.height));
|
|
|
|
|
}
|
|
|
|
|
return autoHeight;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getValue = (value: any) => {
|
|
|
|
|
if ((typeof value === "undefined" || value === null || value === "") && value !== 0) {
|
|
|
|
|
return "--";
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const formatStamp = (value: any) => {
|
|
|
|
|
const date = new Date(value * 1000);
|
|
|
|
|
const month = date.getMonth() < 9 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
|
|
|
|
|
const day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
|
|
|
|
|
const hour = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
|
|
|
|
|
const minute = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
|
|
|
|
|
const second = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
|
|
|
|
|
return date.getFullYear() + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const formatFileSize = (value: any) => {
|
|
|
|
|
const k = value / 1024;
|
|
|
|
|
if (k < 1) {
|
|
|
|
|
return value + "B";
|
|
|
|
|
}
|
|
|
|
|
const m = k / 1024;
|
|
|
|
|
if (m < 1) {
|
|
|
|
|
return k.toFixed(2) + "K";
|
|
|
|
|
}
|
|
|
|
|
const g = m / 1024;
|
|
|
|
|
if (g < 1) {
|
|
|
|
|
return m.toFixed(2) + "M";
|
|
|
|
|
}
|
|
|
|
|
return g.toFixed(2) + "G";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Helper to resolve timestamp column config to TzDateTime props
|
|
|
|
|
const resolveTimestampProps = (ts: TimestampValue): TzDateTimeConfig | null => {
|
|
|
|
|
if (!ts) return null;
|
|
|
|
|
if (ts === true) return { type: "unixMillis", displayFormat: prop.timestampFormat };
|
|
|
|
|
if (typeof ts === "string") {
|
|
|
|
|
// If it's 'unix', 'iso8601', or 'unixMillis' treat as type
|
|
|
|
|
if (["unix", "iso8601", "unixMillis"].includes(ts)) {
|
|
|
|
|
return { type: ts as TzDateTimeConfig["type"], displayFormat: prop.timestampFormat };
|
|
|
|
|
}
|
|
|
|
|
// Otherwise treat as valueFormat
|
|
|
|
|
return { valueFormat: ts, displayFormat: prop.timestampFormat };
|
|
|
|
|
}
|
|
|
|
|
// For object config, apply default displayFormat if not specified
|
|
|
|
|
const config = ts as TzDateTimeConfig;
|
|
|
|
|
if (!config.displayFormat) {
|
|
|
|
|
config.displayFormat = prop.timestampFormat;
|
|
|
|
|
}
|
|
|
|
|
return config;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const formatterByDist = (dictKey: string, value: any) => {
|
|
|
|
|
if (!dictKey) {
|
|
|
|
|
return getValue(value);
|
|
|
|
|
}
|
|
|
|
|
const mapping = state.dict[dictKey];
|
|
|
|
|
if (mapping == null) {
|
|
|
|
|
return getValue(value);
|
|
|
|
|
}
|
|
|
|
|
return mapping[value] == null ? value : mapping[value];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const formatCellValue = (value: any, item: TableColumn, row: any) => {
|
|
|
|
|
if (item.dict) return formatterByDist(item.dict, value);
|
|
|
|
|
if (item.timestamp) return formatStamp(value);
|
|
|
|
|
if (item.filesize) return formatFileSize(value);
|
|
|
|
|
if (row.scheme) return formatterByDist(row.scheme + "_" + (item.dataKey || item.key), value);
|
|
|
|
|
return getValue(value);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSizeChange = (val: number) => {
|
|
|
|
|
prop.example.size = val;
|
|
|
|
|
emit("query");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleCurrentChange = (val: number) => {
|
|
|
|
|
prop.example.page = val;
|
|
|
|
|
emit("query");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onScroll = ({
|
|
|
|
|
scrollTop,
|
|
|
|
|
}: {
|
|
|
|
|
scrollTop: number;
|
|
|
|
|
scrollLeft?: number;
|
|
|
|
|
horizontal?: boolean;
|
|
|
|
|
vertical?: boolean;
|
|
|
|
|
}) => {
|
|
|
|
|
// Can be used for lazy loading or other scroll-based features
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onRowClick = (row: any) => {
|
|
|
|
|
emit("row-click", row);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onCellClick = ({ row, column }: { row: any; column: any }) => {
|
|
|
|
|
emit("cell-click", row, column, null, null);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Build columns for el-table-v2
|
|
|
|
|
const tableColumns = computed(() => {
|
|
|
|
|
return prop.columns.map((item: TableColumn) => {
|
|
|
|
|
const col: any = {
|
|
|
|
|
key: item.key,
|
|
|
|
|
title: item.name || (item.i18n ? t(item.i18n) : item.key),
|
|
|
|
|
dataKey: item.dataKey || item.key,
|
|
|
|
|
align: item.align || "center",
|
|
|
|
|
fixed: item.fixed,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// If width is explicitly provided, use it; otherwise use flexGrow to auto-distribute
|
|
|
|
|
if (item.width !== undefined) {
|
|
|
|
|
col.width = typeof item.width === "number" ? item.width : parseInt(String(item.width)) || 120;
|
|
|
|
|
} else {
|
|
|
|
|
// Use flexGrow: 1 to auto-expand columns to fill available width
|
|
|
|
|
col.flexGrow = 1;
|
|
|
|
|
col.width = 120; // minimum width
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (item.minWidth !== undefined) {
|
|
|
|
|
col.minWidth = typeof item.minWidth === "number" ? item.minWidth : parseInt(String(item.minWidth)) || 120;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cell renderer - el-table-v2 uses cellRenderer function
|
|
|
|
|
col.cellRenderer = ({ cellData, rowData }: { cellData: any; rowData: any }) => {
|
|
|
|
|
const slotName = item.key;
|
|
|
|
|
|
|
|
|
|
// If column has slot=true, render the parent's slot content
|
|
|
|
|
if (item.slot && slots[slotName]) {
|
|
|
|
|
return renderSlot(slots, slotName, { row: rowData });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const value = lodash.get(rowData, item.dataKey || item.key);
|
|
|
|
|
|
|
|
|
|
// Handle timestamp display using TzDateTime component
|
|
|
|
|
if (item.timestamp) {
|
|
|
|
|
const tzProps = resolveTimestampProps(item.timestamp);
|
|
|
|
|
if (tzProps) {
|
|
|
|
|
const { valueFormat, valueTz, displayFormat, locale, type } = tzProps;
|
|
|
|
|
return (
|
|
|
|
|
<TzDateTime
|
|
|
|
|
value={value}
|
|
|
|
|
valueFormat={valueFormat}
|
|
|
|
|
valueTz={valueTz}
|
|
|
|
|
displayFormat={displayFormat}
|
|
|
|
|
locale={locale}
|
|
|
|
|
type={type}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle dict display
|
|
|
|
|
if (item.dict) {
|
|
|
|
|
return <span>{formatterByDist(item.dict, value)}</span>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle formatting
|
|
|
|
|
const formatted = formatCellValue(value, item, rowData);
|
|
|
|
|
return <span>{formatted}</span>;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return col;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.list-table-v2 {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
flex: 1;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mini hidden table for measuring row height (flex boxes, not el-table-v2)
|
|
|
|
|
.mini-table {
|
|
|
|
|
position: absolute;
|
|
|
|
|
visibility: hidden;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
left: -9999px;
|
|
|
|
|
top: 0;
|
|
|
|
|
width: 100%; // Width responds to parent container
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.mini-table-inner {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.mini-row {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding: v-bind("state.size.tablePad");
|
|
|
|
|
border-right: var(--el-table-border);
|
|
|
|
|
border-bottom: var(--el-table-border);
|
|
|
|
|
background: v-bind("state.style.tableBg");
|
|
|
|
|
color: v-bind("state.style.tableColor");
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.mini-cell {
|
|
|
|
|
flex: 1;
|
|
|
|
|
min-width: 120px;
|
|
|
|
|
padding-right: 8px;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Flex grow columns match the real table's flex distribution
|
|
|
|
|
.mini-cell:nth-child(1) { flex: 1; min-width: 120px; }
|
|
|
|
|
.mini-cell:nth-child(2) { flex: 1; min-width: 120px; }
|
|
|
|
|
.mini-cell:nth-child(3) { flex: 1; min-width: 120px; }
|
|
|
|
|
.mini-cell:nth-child(4) { flex: 1; min-width: 120px; }
|
|
|
|
|
.mini-cell:nth-child(5) { flex: 1; min-width: 120px; }
|
|
|
|
|
.mini-cell:nth-child(6) { flex: 1; min-width: 120px; }
|
|
|
|
|
.mini-cell:nth-child(7) { flex: 1; min-width: 120px; }
|
|
|
|
|
.mini-cell:nth-child(8) { flex: 1; min-width: 120px; }
|
|
|
|
|
|
|
|
|
|
.mini-cell-content {
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.my-table {
|
|
|
|
|
flex: 1;
|
|
|
|
|
width: 100%;
|
|
|
|
|
min-height: 0; // Important for flex child to shrink properly
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
position: relative; // For mini-table's containing block
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.my-table :deep(.el-table-v2) {
|
|
|
|
|
--el-table-bg-color: v-bind("state.style.tableBg") !important;
|
|
|
|
|
--el-table-tr-bg-color: v-bind("state.style.tableBg") !important;
|
|
|
|
|
--el-table-expanded-cell-bg-color: v-bind("state.style.tableBg") !important;
|
|
|
|
|
--el-table-border-color: v-bind("state.style.tableBorderColor");
|
|
|
|
|
--el-table-text-color: v-bind("state.style.tableColor");
|
|
|
|
|
--el-table-header-text-color: v-bind("state.style.tableColor");
|
|
|
|
|
--el-table-row-hover-bg-color: v-bind("state.style.tableCurBg");
|
|
|
|
|
--el-table-current-row-bg-color: v-bind("state.style.tableCurBg");
|
|
|
|
|
--el-table-header-bg-color: v-bind("state.style.tableHeadBg");
|
|
|
|
|
--el-bg-color: v-bind("state.style.tableBg") !important;
|
|
|
|
|
|
|
|
|
|
// Border - el-table-v2 uses --el-table-border
|
|
|
|
|
--el-table-border: 1px solid var(--el-table-border-color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.my-table :deep(.el-table-v2__row) {
|
|
|
|
|
background: v-bind("state.style.tableBg") !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.my-table :deep(.el-table-v2__row:hover) {
|
|
|
|
|
background: v-bind("state.style.tableCurBg") !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.my-table :deep(.el-table-v2__header-cell) {
|
|
|
|
|
padding: v-bind("state.size.tablePad");
|
|
|
|
|
border-right: var(--el-table-border);
|
|
|
|
|
color: v-bind("state.style.tableColor");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.my-table :deep(.el-table-v2__row-cell) {
|
|
|
|
|
padding: v-bind("state.size.tablePad");
|
|
|
|
|
border-right: var(--el-table-border);
|
|
|
|
|
color: v-bind("state.style.tableColor");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Child row background for tree data
|
|
|
|
|
.my-table :deep(.el-table-v2__row[data-level="1"]),
|
|
|
|
|
.my-table :deep(.el-table-v2__row[data-level="3"]) {
|
|
|
|
|
background: v-bind("state.style.tableChildBg") !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.my-pagination {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
padding-top: 5px;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.my-pagination * {
|
|
|
|
|
--el-pagination-bg-color: v-bind("state.style.bodyBg") !important;
|
|
|
|
|
--el-pagination-disabled-bg-color: v-bind("state.style.bodyBg") !important;
|
|
|
|
|
--el-pagination-text-color: v-bind("state.style.color") !important;
|
|
|
|
|
--el-pagination-button-color: v-bind("state.style.color") !important;
|
|
|
|
|
--el-pagination-button-disabled-bg-color: v-bind("state.style.bodyBg") !important;
|
|
|
|
|
}
|
|
|
|
|
</style>
|