init: 初始化 hgmj 后台管理项目
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,363 @@
|
||||
<template>
|
||||
<div class="config-table">
|
||||
<!-- search area -->
|
||||
<el-form class="config-table__search" size="mini" inline>
|
||||
<el-form-item
|
||||
v-for="item in searchConfig"
|
||||
:key="item.key"
|
||||
:label="item.label"
|
||||
>
|
||||
<el-input
|
||||
v-if="item.type === 'input'"
|
||||
size="small"
|
||||
v-model="params[item.key]"
|
||||
:placeholder="item.placeholder"
|
||||
clearable
|
||||
@blur="inputBlur"
|
||||
@focus="inputFocus"
|
||||
></el-input>
|
||||
<el-input-number
|
||||
v-else-if="item.type === 'number'"
|
||||
:style="{ width: item.width || '192px' }"
|
||||
v-model="params[item.key]"
|
||||
size="small"
|
||||
:min="item.min"
|
||||
:max="item.max"
|
||||
:placeholder="item.placeholder"
|
||||
></el-input-number>
|
||||
<el-select
|
||||
v-else-if="item.type === 'select'"
|
||||
size="small"
|
||||
v-model="params[item.key]"
|
||||
:placeholder="item.placeholder"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="op in item.options"
|
||||
:key="op.value"
|
||||
:value="op.value"
|
||||
:label="op.label"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<el-date-picker
|
||||
v-if="item.type.startsWith('date')"
|
||||
v-model="params[item.key]"
|
||||
:type="item.type"
|
||||
size="small"
|
||||
:placeholder="item.placeholder"
|
||||
:start-placeholder="item.startPlaceholder"
|
||||
:end-placeholder="item.endPlaceholder"
|
||||
:clearable="item.clearable === undefined ? true : item.clearable"
|
||||
></el-date-picker>
|
||||
<el-button
|
||||
v-else-if="item.type === 'button' && !item.hidden"
|
||||
:disabled="item.isBatch && !isBatchButtonEnable"
|
||||
type="primary"
|
||||
:icon="`el-icon-${item.icon}`"
|
||||
size="small"
|
||||
@click="buttonAction(item)"
|
||||
>{{ item.placeholder }}</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- table area -->
|
||||
<div class="config-table__table">
|
||||
<el-table
|
||||
height="100%"
|
||||
ref="table"
|
||||
:data="tableData"
|
||||
border
|
||||
@selection-change="selectChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="isSelection"
|
||||
type="selection"
|
||||
width="40"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.id"
|
||||
:min-width="column.width || 160"
|
||||
align="center"
|
||||
:label="column.name"
|
||||
:prop="column.key"
|
||||
:fixed="column.fixed"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<div v-if="column.actions" class="table-column-actions">
|
||||
<div v-for="(action, i) in column.actions" :key="i">
|
||||
<el-button
|
||||
:class="{ isNullText: !action.text }"
|
||||
v-if="action.hidden ? !action.hidden(scope.row) : true"
|
||||
:type="action | getTagStyle"
|
||||
:icon="`el-icon-${action.key || action}`"
|
||||
size="mini"
|
||||
@click="rowAction(action, scope.row)"
|
||||
>{{ action.text }}</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="column.component">
|
||||
<component
|
||||
:is="column.component"
|
||||
v-bind="
|
||||
typeof column.props === 'function'
|
||||
? column.props(scope.row[column.key], scope.row)
|
||||
: column.props
|
||||
"
|
||||
>
|
||||
{{
|
||||
column.valueHandler
|
||||
? column.valueHandler(
|
||||
scope.row[column.key],
|
||||
scope.row,
|
||||
column.key
|
||||
)
|
||||
: scope.row[column.key]
|
||||
}}</component
|
||||
>
|
||||
</div>
|
||||
<div v-else>
|
||||
{{
|
||||
column.valueHandler
|
||||
? column.valueHandler(
|
||||
scope.row[column.key],
|
||||
scope.row,
|
||||
column.key
|
||||
)
|
||||
: typeof scope.row[column.key] == "number"
|
||||
? scope.row[column.key]
|
||||
: scope.row[column.key] || "-"
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- pagination area -->
|
||||
<div v-if="this.params.pageSize" class="pagination-footer">
|
||||
<el-pagination
|
||||
:page-sizes="pageSizes"
|
||||
:current-page.sync="params.pageNumber"
|
||||
:page-size.sync="params.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
background
|
||||
></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { debounce } from "lodash";
|
||||
|
||||
export default {
|
||||
name: "ConfigTable",
|
||||
props: {
|
||||
searchConfig: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
tableColumns: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
tableData: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
pageSizes: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [5, 10, 15, 20, 50, 100];
|
||||
},
|
||||
},
|
||||
selection: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
defaultParams: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
params: {
|
||||
...this.defaultParams,
|
||||
},
|
||||
selectedData: [],
|
||||
isInputFocus: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// Object.keys(this.defaultParams).forEach(key => {
|
||||
// this.$set(this.params, key, this.defaultParams[key])
|
||||
// })
|
||||
},
|
||||
computed: {
|
||||
isSelection() {
|
||||
return (
|
||||
this.selection || this.searchConfig.findIndex((v) => v.isBatch) > -1
|
||||
);
|
||||
},
|
||||
isBatchButtonEnable() {
|
||||
return this.selectedData.length > 0;
|
||||
},
|
||||
// clearSelection 用于多选表格,清空用户的选择 —
|
||||
// toggleRowSelection 用于多选表格,切换某一行的选中状态,如果使用了第二个参数,则是设置这一行选中与否(selected 为 true 则选中) row, selected
|
||||
// toggleAllSelection 用于多选表格,切换所有行的选中状态 -
|
||||
// toggleRowExpansion 用于可展开表格,切换某一行的展开状态,如果使用了第二个参数,则是设置这一行展开与否(expanded 为 true 则展开) row, expanded
|
||||
// setCurrentRow 用于单选表格,设定某一行为选中行,如果调用时不加参数,则会取消目前高亮行的选中状态。 row
|
||||
// clearSort 用于清空排序条件,数据会恢复成未排序的状态 —
|
||||
// clearFilter 用于清空过滤条件,数据会恢复成未过滤的状态 —
|
||||
// doLayout 对 Table 进行重新布局。当 Table 或其祖先元素由隐藏切换为显示时,可能需要调用此方法 —
|
||||
// sort 手动对 Table 进行排序。参数prop属性指定排序列,order指定排序顺序。 prop: string, order: string
|
||||
// name 说明
|
||||
// append 插入至表格最后一行之后的内容,如果需要对表格的内容进行无限滚动操作,可能需要用到这个 slot。若表格有合计行,该 slot 会位于合计行之上。
|
||||
table() {
|
||||
return this.$refs.table;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
params: {
|
||||
handler() {
|
||||
// / 输入框改变做防抖处理
|
||||
// this.isInputFocus ? this.debounceSearch() : this.search()
|
||||
this.debounceSearch();
|
||||
},
|
||||
immediate: true,
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
search() {
|
||||
const params = {};
|
||||
Object.keys(this.params).forEach((key) => {
|
||||
params[key] = this.params[key];
|
||||
if (Array.isArray(this.params[key])) {
|
||||
const config = this.searchConfig.find((v) => v.key === key);
|
||||
if (config && Array.isArray(config.keys)) {
|
||||
config.keys.forEach((k, i) => (params[k] = this.params[key][i]));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.$emit("change", params);
|
||||
},
|
||||
add() {
|
||||
this.$emit("add");
|
||||
},
|
||||
debounceSearch: debounce(function() {
|
||||
this.search();
|
||||
}, 500),
|
||||
inputFocus() {
|
||||
this.isInputFocus = true;
|
||||
},
|
||||
inputBlur() {
|
||||
this.isInputFocus = false;
|
||||
},
|
||||
buttonAction(item) {
|
||||
if (this.buttonLocakTimeout) {
|
||||
clearTimeout(this.buttonLocakTimeout);
|
||||
}
|
||||
this.buttonLocakTimeout = setTimeout(() => {
|
||||
this.buttonLock = false;
|
||||
}, 500);
|
||||
if (this.buttonLock) return;
|
||||
this.buttonLock = true;
|
||||
|
||||
if (item.isBatch) {
|
||||
this.rowAction(item.key, this.selectedData);
|
||||
} else {
|
||||
this.rowAction(item.key);
|
||||
}
|
||||
},
|
||||
rowAction(action, row) {
|
||||
if (typeof this[action] === "function") {
|
||||
// eslint-disable-next-line no-useless-call
|
||||
return this[action].call(this, row);
|
||||
}
|
||||
this.$emit(action.action || action, row);
|
||||
},
|
||||
selectChange(e) {
|
||||
this.selectedData = e;
|
||||
},
|
||||
},
|
||||
filters: {
|
||||
getTagStyle(idx) {
|
||||
idx = idx.key || idx;
|
||||
if (idx === "edit") return "success";
|
||||
if (idx === "delete") return "danger";
|
||||
return "";
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.config-table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - 140px);
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
&__table {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
|
||||
/deep/ .el-button--mini {
|
||||
padding: 7px 11px !important;
|
||||
font-weight: normal !important;
|
||||
&.isNullText {
|
||||
span {
|
||||
margin-left: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-column-actions {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-footer {
|
||||
z-index: 100;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
height: 60px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 0 0 5px 5px;
|
||||
background: #ebe5e1;
|
||||
|
||||
/deep/ .el-pagination {
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user