Vue3中使用element-plus封装表单列表组件,一行代码实现一个页面
1。QhTable子组件
<template> <div class="qh-base-pages" v-loading="loading"> <div class="qh-table-header" v-if="defaultForm.length > 0"> <div class="l"> <slot name="left"></slot> </div> <div class="default-form"> <form> <div class="cell" v-for="(item, index) in defaultForm" :key="index"> <Input v-if="item.type == 'input'" :item="item" :picon="item.picon == 'search' ? Search : ''" @returnItem="returnItem" /> <SelectList v-if="item.type == 'select'" :item="item" @returnItem="returnItem" /> </div> <div class="cell"> <el-button @click="exportExcel">导出</el-button> </div> <div class="cell"> <el-button @click="handleReset">重置</el-button> </div> </form> </div> </div> <div class="qh-table"> <div class="qh-table-wrapper"> <el-table :data="data?.list" stripe :height="data.height" :max-height="data.height || '72vh'" :show-overflow-tooltip="{ placement: 'left-end' }" :tooltip-options="{ effect: 'dark', placement: 'top', showArrow: true, }" :row-class-name="tableRowClassName" > <template v-slot:empty> <div class="qh-no-data"> <el-empty description="暂无数据" /> </div> </template> <!-- 循环列表数据 --> <el-table-column v-for="(col, index) in data?.cols" :key="index" :prop="col.prop" :label="col.label" :width="col.width" :fixed="col.fixed" :align="col.align || 'center'" :sortable="col.sortable" > <!-- 自定义头部内容 --> <template #header> <div v-if="col.headerSlot" class="sub_header_tr_cell"> {{ col.label }} <div class="sub_header_tr_title"> {{ col.headerSlot.title }} </div> </div> </template> <template #default="scope"> <!-- // col格子按钮 tools --> <div v-if="col.tools"> <div v-if="col.tools.name"> <template v-if="col.tools.isProp"> <span v-if="col.tools.chind[scope.row[col.tools.isProp]] == '-'" >{{ col.tools.chind[scope.row[col.tools.isProp]] }}</span > <span v-else class="link" @click="openRowDialog(col.tools.prop, scope.row)" >{{ col.tools.chind[scope.row[col.tools.isProp]] }}</span > </template> <span v-else class="link" @click=" openRowDialog( col.tools.prop, scope.row[col.tools.prop] ? scope.row[col.tools.prop] : scope.row ) " >{{ col.tools.name }}</span > </div> <span v-else class="link" @click="openRowDialog(scope.row, col.prop)" >{{ scope.row[col.prop] }}</span > </div> <!-- // 是否开启switch切换按钮 --> <div v-if="col.switch"> <el-switch v-model="scope.row[col.prop]" @change="changeSwitch(scope.row[col.prop], scope.row)" /> </div> <!-- // 展示图片 isPic isVideo --> <div v-if="scope.row[col.prop] && (col.isPic || col.isVideo)" class="isPic" :class="{ isVideo: 'isVideo' }" > <el-icon v-if="col.isVideo" @click="openAvatarPopup(scope.row[col.prop], 'video')" ><CaretRight /></el-icon> <el-avatar shape="square" :size="36" fit="cover" @click="openAvatarPopup(scope.row[col.prop])" :src="scope.row[col.prop]" /> </div> <!-- // 多颜色展示 colors --> <div v-if="col.colors"> <span v-for="colorEle in col.colors" :key="colorEle.value" :style="{ color: colorEle.value == scope.row[col.prop] && colorEle.color, }" > {{ colorEle.value === scope.row[col.prop] ? colorEle.name : "" }} </span> </div> <!-- // 单位 units --> <div v-if="col.units" class="units"> <template v-if="scope.row[col.prop] > 0"> <span v-if="col.units.dir == 'left'">{{ col.units.name }}</span >{{ col.units.value ? (scope.row[col.prop] / col.units.value).toFixed(2) : scope.row[col.prop] }}<span v-if="col.units.dir == 'right'">{{ col.units.prop ? scope.row[col.units.prop] : col.units.name }}</span> </template> <template v-else>-</template> </div> <!-- // 换算 mat --> <div class="mat" v-if="col.mat && scope.row[col.prop] > '0'"> <span v-if="col.mat.dir == 'left'">{{ col.mat.name }}</span >{{ (scope.row[col.prop] / col.mat.value).toFixed(2) }}<span v-if="col.mat.dir == 'right'">{{ col.mat.name }}</span> </div> <!-- // 多字段显示 --> <div v-if="col.propElse"> <div class="units"> {{ scope.row[col.prop] ? scope.row[col.prop] : "-" }} </div> <div class="mat" style="color: #273c62" v-if="scope.row[col.propElse]" > {{ scope.row[col.propElse] || "-" }} </div> </div> <!-- // 默认展示 base --> <span v-if=" !col.tools && !col.isPic && !col.isVideo && !col.colors && !col.units && !col.switch && !col.propElse " > {{ scope.row[col.prop] === "" ? "-" : scope.row[col.prop] }} </span> </template> </el-table-column> </el-table> </div> <div class="qh-pagination"> <div class="total"> 当前共有 <span class="num">{{ props.data.total || "0" }}</span> 条数据 </div> <el-pagination v-model:current-page="currentPage" background v-model:page-size="pageSize" :page-sizes="[20, 50, 100, 200]" layout="sizes, prev, pager, next" :total="props.data.total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </div> <QhPopup :visible="avatarVisible" :data="popupData" @close="closePopup" ></QhPopup> </div> </template> <script setup> import { ref, reactive } from "vue"; import { post, get } from "@/utils/http"; import table2Excel from "js-table2excel"; import { Input, SelectList, QhPopup } from "@/components"; import { Search, CaretRight } from "@element-plus/icons-vue"; import { ElLoading } from "element-plus"; //给父组件上报状态 const emit = defineEmits([ "updaTable", "updaDefaultForm", "openRowDialog", "updataPostList", ]); const props = defineProps({ data: { type: Object, default: {}, }, loading: { type: Boolean, default: false, }, defaultForm: { type: Array, default: [], }, Sinit: { type: Object, default: {}, }, excelInit: { type: Object, default: {}, }, }); const Tdata = props?.data; const Sinit = props?.Sinit; const excelInit = props?.excelInit; // 重置表单 const handleReset = () => { const defaultForm = props?.defaultForm; for (const key in defaultForm) { defaultForm[key].value = ""; } emit("updaDefaultForm", defaultForm); }; // 点击cel链接 const openRowDialog = (rowVal, prop) => { emit("openRowDialog", rowVal, prop); }; // changeSwitch切换 const changeSwitch = (v, row) => { emit("updataPostList", v, row); }; // 当前页码 const currentPage = ref(Sinit.page || 1); const pageSize = ref(Sinit.size || 20); const returnItem = (data) => { emit("updaDefaultForm", props?.defaultForm); }; // 页码改变 const handleSizeChange = (val) => { Sinit.size = val; emit("updaTable", Sinit); }; const handleCurrentChange = (val) => { Sinit.page = val; emit("updaTable", Sinit); }; // 导出exel表格 const exportExcel = () => { const loading = ElLoading.service({ lock: true, text: "导出中请稍等...", background: "rgba(0, 0, 0, 0.6)", }); post(excelInit.apiUrl, excelInit.data).then((res) => { if (res.code == 0) { const lists = res?.data?.list; let list = JSON.stringify(lists); // 用定义的数据 list = formatExportData(JSON.parse(list)); table2Excel( excelInit.exportCols, list, excelInit.name + new Date().getTime() ); loading.close(); } else { loading.close(); } }); }; const formatExportData = (list) => { // 处理特殊字段 list.forEach((item) => { excelInit.formatColumns.forEach((i) => { item[i.prop] = i.option[item[i.prop]]; }); for (let key in item) { if (!item[key] && item[key] == null) { item[key] = ""; } } }); return list; }; </script> <style lang="scss" scoped> .c3 { color: rgba(39, 60, 98, 0.5); } .qh-table { position: relative; :deep(.el-table th .cell) { display: flex; align-items: center; justify-content: center; } .link { color: #0084ff; text-decoration-line: underline; cursor: pointer; } } .default-form form { display: flex; justify-content: flex-end; gap: 10px; } :deep(.el-popper.is-dark) { max-width: 300px; } </style>
2。页面组件(list.vue)
<template> <QhTable :defaultForm="defaultFormData" :Sinit="searchInit" :loading="loading" :data="defaultData" :excelInit="excelInit" @updaTable="getUpdaTable" @updaDefaultForm="updaDefaultForm" /> </template> <script setup> import { ref, reactive } from "vue"; import { QhTable } from "@/components"; </script> <style lang="scss" scoped></style>
参数解释:
loading
|
表单加载中 |
const loading = ref(false);
|
|
Sinit
|
搜索字段 (Object) |
const searchInit = ref({
page: 1, // 页码
size: 20, // 数量
w_time: defaultFormData[0].value, //搜索字段1
agent_id: defaultFormData[1].value, //搜索字段2
});
|
|
defaultFormData |
搜索配置 (数组) |
const defaultFormData = reactive([
{
type: "select", //下拉选择
label: "时间周期", //名称
name: "w_time", // 字段
value: "", // 默认值
placeholder: "全部",
options: cofigStore.timePeriod, // 下拉数据配置
},
{
type: "input", // 输入框
placeholder: "请输入用户ID",
name: "user_id", // 字段
value: "",
picon: "search",
width: 210,
},
]);
|
|
defaultData |
表格配置 (对象) |
const defaultData = reactive({
total: 0, // 数据总数
cols: cols, // 表格cols
list: [], // 接口数据列表
});
|
cols =[
{ prop: "regions", label: "国家地区", width: 150 },
]
|
excelInit |
导出excel配置 |
const excelInit = ref({
apiUrl: "/v1/product_data/pay_data", //导出接口api
name: `name-`, // 导出文档名称+时间戳
exportCols: exportColsConfig,
formatColumns: formatColumns,
data: {},
});
|
exportColsConfig=[ //表单配置
{ key: "stats_date", title: "统计日期", type: "text" },
]// 特殊字符处理
formatColumns=[
{
prop: "pay_status",
option: {
1: "支付中",
2: "支付成功",
3: "支付失败",
},
},
|
getUpdaTable |
分页更新 |
const getUpdaTable = (data) => {
searchInit.value = data;
excelInit.value.data = { ...searchInit.value, export: 1 };
getTableList(searchInit.value);
};
|
|
updaDefaultForm |
搜索字符更新 |
// 获取顶部输入框数据
const updaDefaultForm = (data) => {
for (const item of data) {
searchInit.value[item.name] = item.value;
}
excelInit.value.data = { ...searchInit.value, export: 1 };
getTableList(searchInit.value);
};
|