This commit is contained in:
huzhushan 2021-04-16 12:34:02 +08:00
parent 8a102fc996
commit 33b6ea9551
4 changed files with 498 additions and 6 deletions

View File

@ -0,0 +1,494 @@
<template>
<div class="page-box">
<!-- 搜索选项 -->
<el-form
v-if="!!search"
class="search"
:model="searchModel"
:inline="true"
label-position="left"
:label-width="search.labelWidth"
ref="searchForm"
>
<el-form-item
v-for="item in search.fields"
:key="item.name"
:label="item.label"
:prop="item.name"
>
<el-select
v-if="item.type === 'select'"
v-model="searchModel[item.name]"
:filterable="!!item.filterable"
:multiple="!!item.multiple"
clearable
:placeholder="`请选择${item.label}`"
:style="{ width: search.inputWidth, ...item.style }"
>
<el-option
v-for="option of item.options"
:key="option.value"
:label="option.name"
:value="option.value"
></el-option>
</el-select>
<el-radio-group
v-model="searchModel[item.name]"
v-else-if="item.type === 'radio'"
:style="{ width: search.inputWidth, ...item.style }"
>
<el-radio
v-for="option of item.options"
:key="option.value"
:label="option.value"
>{{ option.name }}</el-radio
>
</el-radio-group>
<el-radio-group
v-model="searchModel[item.name]"
v-else-if="item.type === 'radio-button'"
:style="{ width: search.inputWidth, ...item.style }"
>
<el-radio-button
v-for="option of item.options"
:key="option.value"
:label="option.value"
>{{ option.name }}</el-radio-button
>
</el-radio-group>
<el-checkbox-group
v-model="searchModel[item.name]"
v-else-if="item.type === 'checkbox'"
:style="{ width: search.inputWidth, ...item.style }"
>
<el-checkbox
v-for="option of item.options"
:key="option.value"
:label="option.value"
>{{ option.name }}</el-checkbox
>
</el-checkbox-group>
<el-checkbox-group
v-model="searchModel[item.name]"
v-else-if="item.type === 'checkbox-button'"
:style="{ width: search.inputWidth, ...item.style }"
>
<el-checkbox-button
v-for="option of item.options"
:key="option.value"
:label="option.value"
>{{ option.name }}</el-checkbox-button
>
</el-checkbox-group>
<el-date-picker
v-else-if="item.type === 'date'"
v-model="searchModel[item.name]"
type="date"
format="YYYY-MM-DD"
clearable
@change="handleDateChange($event, item, 'YYYY-MM-DD')"
:placeholder="`请选择${item.label}`"
:style="{ width: search.inputWidth, ...item.style }"
></el-date-picker>
<el-date-picker
v-else-if="item.type === 'datetime'"
v-model="searchModel[item.name]"
type="datetime"
clearable
@change="handleDateChange($event, item, 'YYYY-MM-DD HH:mm:ss')"
format="YYYY-MM-DD HH:mm:ss"
:placeholder="`请选择${item.label}`"
:style="{ width: search.inputWidth, ...item.style }"
></el-date-picker>
<el-date-picker
v-else-if="item.type === 'daterange'"
v-model="searchModel[item.name]"
type="daterange"
format="YYYY-MM-DD"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
clearable
@change="handleRangeChange($event, item, 'YYYY-MM-DD')"
:style="{ width: search.inputWidth, ...item.style }"
></el-date-picker>
<el-date-picker
v-else-if="item.type === 'datetimerange'"
v-model="searchModel[item.name]"
type="datetimerange"
format="YYYY-MM-DD HH:mm:ss"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
@change="handleRangeChange($event, item, 'YYYY-MM-DD HH:mm:ss')"
:style="{ width: search.inputWidth, ...item.style }"
></el-date-picker>
<el-input-number
v-else-if="item.type === 'number'"
v-model="searchModel[item.name]"
:placeholder="`请输入${item.label}`"
controls-position="right"
:min="item.min"
:max="item.max"
:style="{ width: search.inputWidth, ...item.style }"
/>
<el-input
v-else-if="item.type === 'textarea'"
type="textarea"
clearable
v-model="searchModel[item.name]"
:placeholder="`请输入${item.label}`"
:style="{ width: search.inputWidth, ...item.style }"
></el-input>
<el-input
v-else
v-model="searchModel[item.name]"
clearable
:placeholder="`请输入${item.label}`"
:style="{ width: search.inputWidth, ...item.style }"
></el-input>
</el-form-item>
<el-form-item class="search-btn">
<el-button type="primary" icon="el-icon-search" @click="handleSearch"
>查询</el-button
>
<el-button @click="handleReset" icon="el-icon-refresh-right"
>重置</el-button
>
</el-form-item>
</el-form>
<!-- title 工具栏 -->
<div class="head" v-if="!hideTitleBar">
<slot name="title">
<span class="title">{{ title }}</span>
</slot>
<div class="toolbar">
<slot name="toolbar"></slot>
</div>
</div>
<!-- table表格栏 -->
<div class="table">
<el-table
v-loading="loading"
:data="tableData"
:row-key="rowKey"
tooltip-effect="dark"
stripe
:border="border"
@selection-change="handleSelectionChange"
>
<el-table-column
v-for="item in columns"
:key="item.label"
:filter-method="item.filters && filterHandler"
show-overflow-tooltip
v-bind="item"
>
<template #header="scope" v-if="!!item.labelSlot">
<slot :name="item.labelSlot" v-bind="scope"></slot>
</template>
<template #default="scope" v-if="!!item.tdSlot">
<slot :name="item.tdSlot" v-bind="scope"></slot>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<el-pagination
v-if="paginationConfig.show && total > 0"
class="pagination"
:style="paginationConfig.style"
@size-change="handleSizeChange"
v-model:currentPage="pageNum"
@current-change="handleCurrentChange"
:page-sizes="paginationConfig.pageSizes"
v-model:pageSize="pageSize"
:layout="paginationConfig.layout"
:total="total"
></el-pagination>
</div>
</template>
<script>
import { defineComponent, reactive, toRefs, onBeforeMount } from "vue";
const formatDate = (date, format) => {
var obj = {
"M+": date.getMonth() + 1,
"D+": date.getDate(),
"H+": date.getHours(),
"m+": date.getMinutes(),
"s+": date.getSeconds(),
"q+": Math.floor((date.getMonth() + 3) / 3),
"S+": date.getMilliseconds(),
};
if (/(y+)/i.test(format)) {
format = format.replace(
RegExp.$1,
(date.getFullYear() + "").substr(4 - RegExp.$1.length)
);
}
for (var k in obj) {
if (new RegExp("(" + k + ")").test(format)) {
format = format.replace(
RegExp.$1,
RegExp.$1.length == 1
? obj[k]
: ("00" + obj[k]).substr(("" + obj[k]).length)
);
}
}
return format;
};
const getSearchModel = (search) => {
const searchModel = {};
if (search && search.fields) {
search.fields.forEach((item) => {
switch (item.type) {
case "checkbox":
case "checkbox-button":
searchModel[item.name] = [];
break;
default:
break;
}
if (item.defaultValue !== undefined) {
searchModel[item.name] = item.defaultValue;
//
if (
(item.type === "daterange" || item.type === "datetimerange") &&
!!item.trueNames &&
Array.isArray(item.defaultValue)
) {
item.defaultValue.forEach((val, index) => {
searchModel[item.trueNames[index]] = val;
});
}
}
});
}
return searchModel;
};
export default defineComponent({
props: {
//
request: {
type: Function,
},
//
title: {
type: String,
default: "",
},
//
hideTitleBar: {
type: Boolean,
default: false,
},
// false
search: {
type: [Boolean, Object],
default: false,
},
border: {
type: Boolean,
default: false,
},
//
columns: {
type: Array,
default: function (params) {
return [];
},
},
// KeyelementUItablerow-key
rowKey: {
type: String,
default: "id",
},
// false
pagination: {
type: [Boolean, Object],
default: () => ({}),
},
},
setup(props, { emit }) {
//
// 1transformtransform
// 2name
const optimizeFields = (search) => {
const searchModel = JSON.parse(JSON.stringify(state.searchModel));
if (search && search.fields) {
search.fields.forEach((item) => {
if (!searchModel.hasOwnProperty(item.name)) {
return;
}
if (!!item.transform) {
searchModel[item.name] = item.transform(searchModel[item.name]);
}
if (
(item.type === "daterange" || item.type === "datetimerange") &&
!!item.trueNames
) {
delete searchModel[item.name];
}
});
}
return searchModel;
};
//
const getTableData = async () => {
state.loading = true;
const searchModel = optimizeFields(props.search);
const { data, total } = await props.request({
pageNum: state.pageNum,
pageSize: state.pageSize,
...searchModel,
});
state.loading = false;
state.tableData = data;
state.total = total;
};
onBeforeMount(() => {
getTableData();
});
const state = reactive({
searchModel: getSearchModel(props.search),
loading: false,
tableData: [],
total: 0,
pageNum: 1,
pageSize: (!!props.pagination && props.pagination.pageSize) || 10,
paginationConfig: {
show: false,
},
//
handleSearch() {
state.pageNum = 1;
getTableData();
},
//
handleReset() {
if (JSON.stringify(state.searchModel) === "{}") {
return;
}
state.pageNum = 1;
state.searchModel = getSearchModel(props.search);
getTableData();
},
//
refresh() {
getTableData();
},
//
handleCurrentChange(page) {
getTableData();
},
// size
handleSizeChange(value) {
state.pageNum = 1;
getTableData();
},
//
handleSelectionChange(arr) {
emit("selectionChange", arr);
},
//
filterHandler(value, row, column) {
const property = column["property"];
return row[property] === value;
},
//
handleDateChange(date, item, format) {
state.searchModel[item.name] = !!date ? formatDate(date, format) : "";
},
handleRangeChange(date, item, format) {
const arr = !!date && date.map((d) => formatDate(d, format));
state.searchModel[item.name] = !!arr ? arr : [];
if (!item.trueNames) {
return;
}
if (!!arr) {
arr.forEach((val, index) => {
state.searchModel[item.trueNames[index]] = val;
});
} else {
item.trueNames.forEach((key) => {
delete state.searchModel[key];
});
}
},
});
if (typeof props.pagination === "object") {
const { layout, pageSizes, style } = props.pagination;
state.paginationConfig = {
show: true,
layout: layout || "total, sizes, prev, pager, next, jumper",
pageSizes: pageSizes || [10, 20, 30, 40, 50, 100],
style: style || {},
};
}
return {
...toRefs(state),
};
},
});
</script>
<style lang="scss" scoped>
.page-box {
width: 100%;
box-sizing: border-box;
.search {
padding: 20px 20px 0;
background: #fff;
margin-bottom: 10px;
display: flex;
flex-wrap: wrap;
.el-form-item {
margin-bottom: 20px;
}
.search-btn {
margin-left: auto;
}
::v-deep(.el-input-number .el-input__inner) {
text-align: left;
}
}
.head {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 20px 0;
background: #fff;
.title {
font-size: 16px;
}
}
.table {
padding: 20px;
background: #fff;
::v-deep(th) {
background: #f6f6f6;
color: rgba(0, 0, 0, 0.85);
}
}
.pagination {
padding: 0 20px 20px;
background: #fff;
text-align: right;
:last-child {
margin-right: 0;
}
}
}
</style>

View File

@ -1 +1,2 @@
export { default as SvgIcon } from "@/components/SvgIcon/index.vue";
export { default as ProTable } from "@/components/ProTable/index.vue";

View File

@ -28,8 +28,5 @@ Object.entries(Components).forEach(([key, component]) => {
app.component(key, component)
})
// 引入vue3-pro-table
import Vue3ProTable from "vue3-pro-table";
app.use(Vue3ProTable);
app.use(ElementPlus, { locale }).use(store).use(router).mount('#app')

View File

@ -1,5 +1,5 @@
<template>
<vue3-pro-table
<pro-table
ref="table"
title="列表"
:request="getList"
@ -28,7 +28,7 @@
<el-button size="mini" type="primary">编辑</el-button>
<el-button size="mini" type="danger">删除</el-button>
</template>
</vue3-pro-table>
</pro-table>
</template>
<script>