Files
new_wms_admin/src/components/ProTable/index.vue
2025-09-24 17:27:03 +08:00

218 lines
8.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<!-- 表格内容 card -->
<div :class="!isBoxClass ? '' : 'card table-main'">
<!-- 查询表单 card -->
<!-- <SearchForm
v-show="isShowSearch"
:search="search"
:reset="reset"
:formData="formData"
:search-param="searchParam"
:search-col="searchCol"
/> -->
<slot name="search"></slot>
<!-- 表格头部 操作按钮 -->
<div class="table-header">
<div class="header-button-lf">
<slot
name="tableHeader"
:selected-list-ids="selectedListIds"
:selected-list="selectedList"
:is-selected="isSelected"
/>
</div>
</div>
<!-- 表格主体 -->
<el-table
ref="tableRef"
v-bind="$attrs"
:data="data ?? tableData"
:border="border"
:row-key="
row => {
return routeName === 'boxCode' || routeName === 'boxMarkIndex' ? row.detailId + '' + row.id : row.id;
}
"
@selection-change="selectionChange"
:style="!isBoxClass ? 'height: 400px; overflow-y: auto' : ''"
>
<!-- 默认插槽 -->
<slot></slot>
<template v-for="item in tableColumns" :key="item">
<!-- selection || index || expand -->
<el-table-column
v-if="item.type && ['selection', 'index', 'expand'].includes(item.type)"
v-bind="item"
:align="item.align ?? 'center'"
:reserve-selection="item.type == 'selection'"
>
<template v-if="item.type == 'expand'" #default="scope">
<component :is="item.render" v-bind="scope" v-if="item.render"> </component>
<slot v-else :name="item.type" v-bind="scope"></slot>
</template>
</el-table-column>
<!-- other -->
<TableColumn v-if="!item.type && item.prop && item.isShow" :column="item">
<template v-for="slot in Object.keys($slots)" #[slot]="scope">
<slot :name="slot" v-bind="scope"></slot>
</template>
</TableColumn>
</template>
<!-- 插入表格最后一行之后的插槽 -->
<template #append>
<slot name="append"> </slot>
</template>
<!-- 无数据 -->
<template #empty>
<div class="table-empty">
<slot name="empty">
<img src="@/assets/images/notData.png" alt="notData" />
<div>暂无数据</div>
</slot>
</div>
</template>
</el-table>
<!-- 分页组件 -->
<slot name="pagination">
<Pagination
v-if="pagination"
:pageable="pageable"
:handle-size-change="handleSizeChange"
:handle-current-change="handleCurrentChange"
:length="selectedList.length"
:sizes="sizes"
/>
</slot>
</div>
<!-- 列设置 -->
<ColSetting v-if="toolButton" ref="colRef" v-model:col-setting="colSetting" />
</template>
<script setup lang="ts" name="ProTable">
// import SearchForm from "@/components/SearchForm/index.vue";
// /watch
import { ref, provide, onMounted, toRef } from "vue";
import { ElTable } from "element-plus";
import { useTable } from "@/hooks/useTable";
import { useSelection } from "@/hooks/useSelection";
// import { BreakPoint } from "@/components/Grid/interface";
import { ColumnProps } from "@/components/ProTable/interface";
// import SearchForm from "@/components/SearchForm/index.vue";
import Pagination from "./components/Pagination.vue";
import ColSetting from "./components/ColSetting.vue";
import TableColumn from "./components/TableColumn.vue";
const $router = useRouter();
const routeName: any = ref($router.currentRoute.value.name);
export interface ProTableProps {
columns: ColumnProps[]; // 列配置项 ==> 必传
// formData?: any[];
isBoxClass?: boolean;
data?: any[]; // 静态 table data 数据,若存在则不会使用 requestApi 返回的 data ==> 非必传
requestApi?: (params: any) => Promise<any>; // Promise<any>; // 请求表格数据的 api ==> 非必传
requestAuto?: boolean; // 是否自动执行请求 api ==> 非必传默认为true
requestError?: (params: any) => void; // 表格 api 请求错误监听 ==> 非必传
dataCallback?: (data: any) => any; // 返回数据的回调函数,可以对数据进行处理 ==> 非必传
title?: string; // 表格标题,目前只在打印的时候用到 ==> 非必传
pagination?: boolean; // 是否需要分页组件 ==> 非必传默认为true
initParam?: any; // 初始化请求参数 ==> 非必传(默认为{}
orgCode?: any; //组织ID,组织id改变时重新请求数据
border?: boolean; // 是否带有纵向边框 ==> 非必传默认为true
toolButton?: boolean; // 是否显示表格功能按钮 ==> 非必传默认为true
rowKey?: string; // 行数据的 Key用来优化 Table 的渲染,当表格数据多选时,所指定的 id ==> 非必传(默认为 id
// searchCol?: number | Record<BreakPoint, number>; // 表格搜索项 每列占比配置 ==> 非必传 { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }
sizes?: any;
}
// 接受父组件参数,配置默认值
const props = withDefaults(defineProps<ProTableProps>(), {
formData: () => [],
columns: () => [],
requestAuto: true,
pagination: true,
initParam: {},
isBoxClass: true,
border: true,
toolButton: true,
// rowKey: `id${index}`,
// searchCol: () => ({ xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }),
sizes: [50, 100, 150, 200]
});
// 是否显示搜索模块
// const isShowSearch = ref(true);
// 表格 DOM 元素
const tableRef = ref<InstanceType<typeof ElTable>>();
const newValInitParams = toRef(props, "initParam");
// 表格多选 Hooks
const { selectionChange, selectedList, selectedListIds, isSelected } = useSelection(props.rowKey);
// 清空选中数据列表
const clearSelection = () => tableRef.value!.clearSelection();
// 表格操作 Hooks
const { tableData, pageable, getTableList, handleSizeChange, handleCurrentChange } = useTable(
routeName.value,
props.requestApi,
newValInitParams,
props.pagination,
props.requestError,
clearSelection
);
// 初始化请求
onMounted(() => props.requestAuto && getTableList());
// 接收 columns 并设置为响应式
const tableColumns = ref<ColumnProps[]>(props.columns);
// 定义 enumMap 存储 enum 值(避免异步请求无法格式化单元格内容 || 无法填充搜索下拉选择)
const enumMap = ref(new Map<string, { [key: string]: any }[]>());
provide("enumMap", enumMap);
const setEnumMap = async (col: ColumnProps) => {
if (!col.enum) return;
// 如果当前 enum 为后台数据需要请求数据,则调用该请求接口,并存储到 enumMap
if (typeof col.enum !== "function") return enumMap.value.set(col.prop!, col.enum!);
const { data } = await col.enum();
enumMap.value.set(col.prop!, data);
};
// 扁平化 columns
const flatColumnsFunc = (columns: ColumnProps[], flatArr: ColumnProps[] = []) => {
columns.forEach(async col => {
if (col._children?.length) flatArr.push(...flatColumnsFunc(col._children));
flatArr.push(col);
// 给每一项 column 添加 isShow && isFilterEnum 默认属性
col.isShow = col.isShow ?? true;
col.isFilterEnum = col.isFilterEnum ?? true;
// 设置 enumMap
setEnumMap(col);
});
return flatArr.filter(item => !item._children?.length);
};
// flatColumns
const flatColumns = ref<ColumnProps[]>();
flatColumns.value = flatColumnsFunc(tableColumns.value);
// 列设置 ==> 过滤掉不需要设置的列
const colRef = ref();
const colSetting = tableColumns.value!.filter(
item => !["selection", "index", "expand"].includes(item.type!) && item.prop !== "operation" && item.isShow
);
// 暴露给父组件的参数和方法(外部需要什么,都可以从这里暴露出去)
defineExpose({
element: tableRef,
tableData,
pageable,
getTableList,
handleSizeChange,
handleCurrentChange,
clearSelection,
enumMap,
isSelected,
selectedList,
selectedListIds
});
</script>