tableSearch.vue table公共组件
<template>
<div>
<el-form :inline="true" label-width="12rem" :model="searchform" v-if="searchList.length > 0">
<el-row>
<el-col :span="8" v-for="(item, index) in searchList" :key="'search' + index"
v-show="index < searchShowNum || (index >= searchShowNum && searchShow)">
<el-form-item :label="item.label">
<el-input v-if="item.type == 'input'" :placeholder="item.pl" v-model="searchform[item.prop]" clearable/>
<el-select v-else-if="item.type == 'select'" :placeholder="item.pl"
v-model="searchform[item.prop]">
<el-option v-for="(item2, index2) in item.options" :key="'search' + item.prop + index2"
:label="item2[item.optionSetting.label]" :value="item2[item.optionSetting.value]" />
</el-select>
<elSelectLoad v-if="item.type == 'selectload'" @getData="item.setting.getData" v-model:value="searchform[item.prop]" :obj="item.setting.obj" :loadmoreClass="item.setting.loadmoreClass" />
</el-form-item>
</el-col>
<el-col :span="7" :offset="1">
<el-button type="primary" @click="search">查询</el-button>
<el-button plain @click="clearAction">清空</el-button>
<span class="screen" @click="searchShow = !searchShow" v-if="searchList.length > searchShowNum">
{{ searchShow ? "收起查询条件" : "展开查询条件" }}
<el-icon v-show="!searchShow">
<ArrowDown />
</el-icon>
<el-icon v-show="searchShow">
<ArrowUp />
</el-icon>
</span>
</el-col>
</el-row>
</el-form>
<el-row :gutter="10" v-if="optionObj.topBtn && optionObj.topBtn.length > 0">
<el-col :span="24">
<slot v-for="(item) in optionObj.topBtn" :name="item"></slot>
</el-col>
</el-row>
<el-table v-loading="loading" :data="tableData" border
:header-cell-style="{ background: '#FAFAFA', borderRight: 'none' }" style="width: 100%">
<el-table-column v-for="(item, index) in tableList" :key="'table' + index" :prop="item.prop"
:label="item.label" :width="item.width" align="center" show-overflow-tooltip>
<template #default="scope">
<slot v-if="item.slot" :name="item.prop" :row="scope.row"></slot>
</template>
</el-table-column>
</el-table>
<el-pagination v-if="isPagination" v-model:currentPage="searchform.page" :page-size="searchform.size"
:page-sizes="[10, 30, 50, 100]" layout="total, prev, pager, next, sizes , jumper" :total="total"
@size-change="showSizeChangeEl" @current-change="handlePageChanges" />
</div>
</template>
<script setup>
import { ref, computed, watchEffect, watch } from 'vue';
import { deepClone } from '@/utils/index.js';
const prop = defineProps({
optionObj: {
type: Object,
default: () => {
return {
};
}
},
searchShowNum: { //搜索栏显示个数
type: Number,
default: 2
},
isPagination: { //是否分页
type: Boolean,
default: true
},
fixSearch: {
type: Object,
default: null
},
extraSearch: {
type: Object,
default: null
},
initGetData: {
type: Boolean,
default: true
}
});
const emit = defineEmits(['getData']);
const searchShow = ref(false);
const loading = ref(false);
const searchform = ref({});
const total = ref(0);
const searchList = computed(() => {
return prop.optionObj.table.filter((item) => {
return item.type;
});
});
const tableList = computed(() => {
return prop.optionObj.table.filter((item) => {
return !item.notable;
});
});
const tableData = ref([]);
const searchformcp = computed(() => {
console.log(prop.fixSearch);
let obj = {};
searchList.value.forEach((item) => {
obj[item.prop] = '';
});
if (prop.isPagination) {
obj = Object.assign({}, obj, { page: searchform.value.page || 1, size: searchform.value.size || 10 });
}
if(prop.fixSearch){
obj = Object.assign({}, obj, prop.fixSearch);
}
return obj;
});
watchEffect(() => {
searchform.value = deepClone(searchformcp.value);
});
// watch(() => prop.extraSearch, (e) => {
// searchform.value = Object.assign({}, searchform.value, e);
// search();
// }, { deep: true });
// watchEffect(() => {
// })
function search () {
searchform.value.page = 1;
getdata();
}
function extraSearchFunc (){
searchform.value = Object.assign({}, searchform.value, prop.extraSearch);
search();
}
function clearAction () {
searchform.value = deepClone(searchformcp.value);
}
function showSizeChangeEl (size) {
searchform.value.size = size;
searchform.value.page = 1;
getdata();
}
function handlePageChanges (page) {
searchform.value.page = page;
getdata();
}
function getdata (){
loading.value = !loading.value;
emit('getData', searchform.value, successfunc, errorfunc);
console.log(prop.fixSearch);
}
function successfunc (data, totals){
console.log(data, totals);
loading.value = false;
tableData.value = data;
total.value = totals;
}
function errorfunc (err){
console.log(err);
loading.value = false;
tableData.value = [];
total.value = 0;
}
if(prop.initGetData){
getdata();
}
defineExpose({
searchform,
getdata,
extraSearchFunc
});
</script>
<style lang="scss" scoped>
.el-pagination{
margin-top: 1.5rem;
margin-right: 1.5rem;
margin-bottom: 4rem;
justify-content: flex-end;
position: relative;
}
/* 更具体的 CSS 选择器 */
:deep(.el-pagination__total) {
position: absolute;
left: 3rem;
transform: translateY(-50%);
}
:deep(.el-table) {
transform: scale(1);
transform-origin: 0 0;
}
:deep(.el-table tr) {
height: 5.2rem;
}
:deep(.el-pagination__editor.el-input) {
width: 5.6rem;
}
:deep(.el-table th > .cell) {
border-right: 1px solid #d8e3e5;
}
:deep(.el-table--border td,
.el-table--border th,
.el-table__body-wrapper .el-table--border.is-scrolling-left ~ .el-table__fixed) {
border-right: none !important;
}
:deep(.el-table) {
margin-top: 1rem;
overflow-x: auto !important;
overflow-y: auto;
}
:deep(.el-table__body-wrapper) {
overflow-y: auto;
}
:deep(.el-pager li.is-active) {
color: var(--themeColor);
}
:deep(.el-pager li:hover) {
color: var(--themeColor);
}
:deep(.el-pagination button:hover) {
color: var(--themeColor);
}
:deep(.el-table__header th div.cell) {
color: #002226;
}
</style>
elSelectLoad.vue 分页加载select下拉框公共组件
<template>
<el-select v-model="newValue" clearable placeholder="请选择"
v-select-loadmore:[loadmoreClass]="onLoadmore"
:popper-class="loadmoreClass"
filterable remote :remote-method="userSearch" @visible-change="handleDropdownVisibleChange">
<el-option
v-for="item in userList"
:key="item.id"
:label="item.name"
:value="returndata?item.name:item"
/>
</el-select>
</template>
<script setup>
import { watch, ref } from 'vue';
const prop = defineProps({
value: {
type: String,
default: ''
},
loadmoreClass: {
type: String,
default: ''
},
obj: {
type: Object,
default: () => {
return {};
}
},
returndata: {
type: Number,
default: 1
}
});
const newValue = ref(prop.value);
const newObj = ref(prop.obj);
const userList = ref([]);
const emit = defineEmits(['update:value', 'getData']);
watch(newValue, (newValue) => {
emit('update:value', newValue);
});
// 下拉框滚动
function onLoadmore (){
newObj.value.page++;
getUsers();
};
function userSearch (e) {
if (e) {
newObj.value.search = e;
userList.value = [];
newObj.value.page = 1;
getUsers();
}
};
function getUsers (){
emit('getData', newObj.value, (list) => {
list.map((item) => {
userList.value.push(item);
});
});
}
// 下拉框关闭
function handleDropdownVisibleChange (open){
if (!open) {
userList.value = [];
newObj.value.page = 1;
newObj.value.search = '';
}
else getUsers();
};
</script>
<style lang="scss" scoped>
</style>
表格组件使用规则
//isPagination是否分页,默认分页 @getData调用的接口 下面方法固定写法,将数组和total传过去,fixSearch参数为搜索固定条件,不会变动必带的参数,如果需要父组件中变动的参数,使用extraSearch,改了extraSearch,需要重新调用暴露出来的获取数据方法,对应initGetData属性,设为false默认不调用获取数据接口,等待你主动调
<TableSearch ref="tableref" :optionObj="optionObj" :initGetData="flase" @getData="getDataList" :isPagination="false" :fixSearch="{ worksapceId: $route.query?.id }" :extraSearch="extraSearch">
<template v-for="(item,index) in optionObj.topBtn" #[item] :key="index">
<el-button class="plain" plain @click="ActionFunc(index)">{{ item }}</el-button>
</template>
<template #action="{row}">
<span class="mainColor" @click="getDetail(row.id, 1)">编辑</span>
<span class="mainColor" style="margin-left: 1rem" @click="getDetail(row.id, 2)">删除</span>
</template>
</TableSearch>
const optionObj = reactive({
topBtn: ['新增'], //顶部按钮
table: [
{ prop: 'name', label: '标准名称', type: 'input', pl: '请输入标准名称', notable: true },
{ prop: 'selectTest', label: '选择框', type: 'select', pl: '请输入标准名称', notable: true,options: [{ name: '张三', key: '1' }],optionSetting: { label: 'name', value: 'key' } },
{ prop: 'cnName', label: '标准名称' },
{ prop: 'enName', label: '标准英文缩写', type: 'input' },
{ prop: 'creator', label: '创建人', type: 'selectload', setting: {
loadmoreClass: 'single22-select-loadmore',
obj: {
page: 1,
size: 10,
search: '',
status: 1
},
getData: getUsersCopy
} },
{ prop: 'createTime', label: '创建时间', width: '200px' },
{ prop: 'modifier', label: '最近更新人' },
{ prop: 'updateTime', label: '最近更新时间', width: '200px' },
{ prop: 'action', label: '操作', slot: true, width: '220px' }
]
});
const extraSearch = reactive({})
function ActionFunc (index){
console.log('🚀 ~ file: workspace.vue:35 ~ ActionFunc ~ index:', index);
}
// 获取数据
function getDataList (data, callback, error) {
nextTick(() => {
getField(data).then((res) => {
callback && callback(res.data.records, res.data.totals);
})
.catch((err) => {
error && error(err);
});
});
};
//selectload 获取数据
async function getUsersCopy (data, callback) {
const res = await getUser(data);
callback && callback(res.records);
}