SourceTermAnalysisSystem_vue/src/components/Table/index.vue
2026-07-27 18:54:43 +08:00

412 lines
12 KiB
Vue

<script setup lang="ts" name="Table">
import { ElButton, ElCheckbox, ElInput, ElInputNumber, ElPagination, ElSwitch, ElTable, ElTableColumn } from 'element-plus';
import { PropType, ref } from 'vue';
import { useI18n } from 'vue-i18n';
const props = withDefaults(defineProps<TableProps>(), {
rowkey: '',
showIndex: false,
selection: false,
isOperate: false,
isRadio: false,
czWidth: 100,
tableData: () => [],
tableHeader: () => [],
height: 430,
maxHeight: 1000,
setSelectAllState: true,
selectOptions: () => ({}),
optionsList: () => [],
isDevShow: false,
checkSelect: () => (_row: TableRowData) => false,
page: 0,
limit: 0,
pageSizes: () => [10, 20, 30, 50],
total: 0,
});
const emit = defineEmits<{
(e: 'setCurrentRow', row: TableRowData, oldRow: TableRowData): void;
(e: 'selectionChange', selection: TableRowData[]): void;
(e: 'cellClick', row: TableRowData, column: TableColumn, cell: HTMLElement, event: Event): void;
(e: 'cellDblclick', row: TableRowData, column: TableColumn, cell: HTMLElement, event: Event): void;
(e: 'rowClick', row: TableRowData, column: TableColumn, event: Event): void;
(e: 'rowDblclick', row: TableRowData, column: TableColumn, event: Event): void;
(e: 'handleBlur', data: HandleBlurData): void;
(e: 'handleSwitch', row: TableRowData): void;
(e: 'pagination', data: any): void;
// (e: 'view', row: TableRowData): void;
// (e: 'edit', row: TableRowData): void;
// (e: 'delete', row: TableRowData): void;
}>();
// import { T } from 'vitest/dist/chunks/environment.LoooBwUu.js';
const { t, locale } = useI18n();
// 首先定义基础接口
interface SelectOption {
value: any;
label: string;
[key: string]: any;
}
interface SelectOptionsConfig {
list: SelectOption[];
valueKey?: string;
labelKey?: string;
}
// 定义表头列类型
interface TableColumn {
colorArr?: any;
prop?: string;
label: string;
width?: number | string;
minWidth?: number | string;
fixed?: boolean | 'left' | 'right';
type?: 'default' | 'selection' | 'index' | 'date' | 'checkBox' | 'input' | 'inputNumber' | 'select' | 'switch' | 'colorText';
formatDate?: string;
props?: string;
disabled?: boolean;
selectKey?: string;
align?: 'left' | 'center' | 'right';
}
// 定义表格行数据类型
interface TableRowData {
[key: string]: any;
id?: string | number;
disabled?: boolean;
}
interface TableProps {
// 数据行唯一标识
rowkey?: string;
// 是否展示序号
showIndex?: boolean;
// 是否多选
selection?: boolean;
// 是否带操作栏
isOperate?: boolean;
// 操作宽度
czWidth?: number;
// 是否单选
isRadio?: boolean;
// 表单数据
tableData?: TableRowData[];
// 表头
tableHeader?: TableColumn[];
// 高度
height?: any;
// 最大高度
maxHeight?: number;
// 选择行为
setSelectAllState?: boolean;
// 下拉框参数
selectOptions?: Record<string, SelectOptionsConfig>;
// 调试模式
isDevShow?: boolean;
// 禁用选择函数
checkSelect?: (row: TableRowData) => boolean;
page?: number;
limit?: number;
pageSizes?: number[];
total?: number;
optionsList?: any[];
}
// 定义事件类型
interface HandleBlurData {
prop: string;
scope: {
row: TableRowData;
$index: number;
column: TableColumn;
};
}
interface PaginationData {
page: number;
limit: number;
}
const tableRef = ref<InstanceType<typeof ElTable> | null>(null);
// 用于单选表格,设定某一行为选中行
function handleSetCurrentRow(row: TableRowData, oldRow: TableRowData) {
tableRef.value?.setCurrentRow(row);
emit('setCurrentRow', row, oldRow);
}
function selectionChange(selection: TableRowData[]) {
console.log(selection, '选中');
emit('selectionChange', selection);
}
function getCellReferInfo(row: TableRowData, column: TableColumn, cell: HTMLElement, event: Event) {
emit('cellClick', row, column, cell, event);
}
function getCellDbReferInfo(row: TableRowData, column: TableColumn, cell: HTMLElement, event: Event) {
emit('cellDblclick', row, column, cell, event);
}
function getCurReferInfo(row: TableRowData, column: TableColumn, event: Event) {
emit('rowClick', row, column, event);
}
function getCurDbReferInfo(row: TableRowData, column: TableColumn, event: Event) {
emit('rowDblclick', row, column, event);
}
// function handlePagination(data: PaginationData) {
// emit('pagination', data);
// }
// 分页大小改变
function handleSizeChange(size: number) {
emit('pagination', { page: 1, limit: size });
}
// 当前页改变
function handleCurrentChange(currentPage: number) {
emit('pagination', { page: currentPage, limit: props.limit });
}
function handleSwitch(row: TableRowData) {
emit('handleSwitch', row);
}
function getValueById<T extends SelectOption>(
arrList: T[] = [],
value: any,
type: keyof T = 'value',
label: keyof T = 'label',
): T[keyof T] | undefined {
const item = arrList.find(item => item[type] === value);
return item ? item[label] : undefined;
}
function render(row: TableRowData, column: TableColumn): string {
return column.prop ? String(row[column.prop] || '') : '';
}
function handleClick(scope: { row: TableRowData; $index: number; column: TableColumn }) {
console.log('handleClick', scope);
}
defineExpose({
handleSetCurrentRow,
tableRef,
tableData: props.tableData, // 暴露props中的表格数据
});
function getValueStyle(val: any, colorArr: string[]) {
console.log(val,colorArr,"2141414")
if (!colorArr || !Array.isArray(colorArr)) {
return {};
}
// 确保val是有效的索引
if (val === '-1') {
val = 2;
}
if (val === '0') {
val = 1;
}
const index = Number.parseInt(val);
if (Number.isNaN(index) || index < 0 || index >= colorArr.length) {
return {};
}
return {
color: colorArr[index],
};
}
</script>
<template>
<div class="table">
<ElTable
ref="tableRef" :data="tableData" :height="height" :max-height="maxHeight" class="custom-table" border
:row-key="rowkey" :highlight-current-row="isRadio" @current-change="handleSetCurrentRow"
@selection-change="selectionChange" @cell-click="getCellReferInfo" @cell-dblclick="getCellDbReferInfo"
@row-click="getCurReferInfo" @row-dblclick="getCurDbReferInfo"
>
<ElTableColumn v-if="selection" type="selection" width="60" fixed align="center" />
<ElTableColumn v-if="showIndex" :label="t('serialNumber')" width="80" fixed align="center">
<template #default="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</ElTableColumn>
<ElTableColumn
v-for="(item, index) in tableHeader" :key="index" :prop="item.prop"
:label="item.noI18 ? item.label : t(item.prop)" :width="item.width ? item.width : ''"
:min-width="item.minWidth || '120'" :fixed="item.fixed" :type="item.type"
:color-arr="item.colorArr ? item.width : ''" :align="item.align || 'center'"
>
<template #default="scope">
<div class="table-list">
<slot v-if="item.formatDate" :name="item.formatDate" :row="scope.row">
<!-- {{ formatDateTotext(scope.row[item.prop!]) }} -->
</slot>
<slot v-else-if="item.type === 'date'" :name="item.props" :row="scope.row">
<!-- {{ formatDateTotext(scope.row[item.prop!]) }} -->
</slot>
<slot v-else-if="item.type === 'checkBox'" :name="item.props" :row="scope.row">
<ElCheckbox :model-value="scope.row[item.prop!]" :disabled="item.disabled" @click="handleClick(scope)" />
</slot>
<slot v-else-if="item.type === 'input'" :name="item.props" :row="scope.row">
<ElInput v-model="scope.row[item.prop!]" :disabled="item.disabled" @click="handleClick(scope)" />
</slot>
<slot v-else-if="item.type === 'colorText'" :name="item.props" :row="scope.row">
<div :style="{ color: scope.row[item.prop!].color }">
{{ scope.row[item.prop!].text }}
</div>
</slot>
<slot v-else-if="item.type === 'select' && selectOptions[item.prop!]&&scope.row[item.prop!]==-1&&item.label=='任务状态'" :name="item.prop" :row="scope.row">
<div style="color:red">
{{
getValueById(
selectOptions[item.prop!].list,
scope.row[item.prop!],
selectOptions[item.prop!].valueKey || 'value',
selectOptions[item.prop!].labelKey || 'label',
)
}}
</div>
</slot>
<slot v-else-if="item.type === 'select' && selectOptions[item.prop!]" :name="item.prop" :row="scope.row">
<div :style="getValueStyle(scope.row[item.prop!], item.colorArr)">
{{
getValueById(
selectOptions[item.prop!].list,
scope.row[item.prop!],
selectOptions[item.prop!].valueKey || 'value',
selectOptions[item.prop!].labelKey || 'label',
)
}}
</div>
</slot>
<slot v-else-if="item.type === 'select2'" :name="item.prop" :row="scope.row">
<ElSelect v-model="scope.row[item.prop!]" style="width: 110px">
<ElOption
v-for="item in optionsList" :key="item.eventName" :label="item.eventName"
:value="item.eventName"
/>
</ElSelect>
</slot>
<slot v-else-if="item.type === 'popover'" :name="item.props" :row="scope.row">
<el-popover
title="说明"
:content="scope.row[item.prop!]"
placement="left-start"
width="300"
>
<template #reference>
{{scope.row[item.prop!] ? (scope.row[item.prop!].slice(0,8)+'...') : ''}}
</template>
</el-popover>
</slot>
<slot v-else-if="item.type === 'switch'" :name="item.props" :row="scope.row">
<ElSwitch
:model-value="scope.row[item.prop!]" :disabled="item.disabled" inline-prompt size="large"
@change="handleSwitch(scope.row)"
/>
</slot>
<slot v-else-if="item.type === 'getRow'" :name="item.props" :row="scope.row">
<div style="cursor: pointer;text-decoration: underline;">
{{ scope.row[item.prop!] }}
</div>
</slot>
<slot v-else :name="item.prop" :row="scope.row">
<!-- {{ render(scope.row, item) }} -->
<div v-if="item.list && item.list.length">
<div v-for="v in item.list">
<div v-if="v.code == scope.row[item.prop!]">
{{ v.label }}
</div>
</div>
</div>
<div v-else>
{{ scope.row[item.prop!] }}
</div>
</slot>
</div>
</template>
</ElTableColumn>
<ElTableColumn v-if="isOperate" :label="t('operation')" :width="czWidth" align="center">
<template #default="scope">
<slot :scope="scope.row" :index="scope.$index" name="operate" />
</template>
</ElTableColumn>
</ElTable>
<!-- 分页 -->
<ElPagination
v-show="total > 0" background class="pagination" :total="total" :current-page="page" :page-size="limit"
:page-sizes="pageSizes" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<style scoped lang="less">
.table {
width: auto;
.custom-table {
width: 100%;
background: #043338;
}
.custom-text-btn {
padding: 0 4px;
margin: 0 2px;
}
.table-list {
display: contents;
}
.pagination-container {
margin-top: 16px;
text-align: right;
}
//current选中颜色
:deep(.current-row > td.el-table__cell) {
background: #0c817b;
}
//选择框按钮
:deep(.el-checkbox__inner) {
background-color: #07869f;
border: solid 1px #247f96;
}
// :deep(.el-checkbox__inner:after){
// background-color: #17e6f8;
// }
}
.btn {
width: 128px;
height: 50px;
line-height: 50px;
margin: 0 10px;
}
.pagination {
justify-content: left;
margin-top: 10px;
}
</style>
<style>
.el-popover,.el-popover__title{
color: #fff!important;
}
.el-popper__arrow, .el-popper__arrow:before{
display: none!important;
}
</style>