412 lines
12 KiB
Vue
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>
|