lg_frontend/components/smallCommon/Curd.vue

378 lines
12 KiB
Vue

<template>
<div style="text-align: left">
<div class="table-search" v-if="searchItems.length > 0">
<a-form class="ant-advanced-search-form" :form="form" @submit="handleSearch" layout="inline"
@change="handleSearchFormChange">
<a-form-item v-for="menuItem in searchItems" :key="menuItem.key" :label="menuItem.label">
<a-input
v-decorator="[menuItem.key]"
:placeholder="menuItem.placeholder || ''"
v-if="menuItem.type === 'input'"
/>
<a-select
v-decorator="[menuItem.key]"
:placeholder="menuItem.placeholder || ''"
v-else-if="menuItem.type === 'select'"
:dropdown-class-name="dropdownClassName"
>
<a-select-option :value="cItem.value" v-for="cItem in menuItem.children || []" :key="cItem.value">
{{ cItem.label }}
</a-select-option>
</a-select>
<a-range-picker
:placeholder="menuItem.placeholder || ''" v-decorator="[menuItem.key]"
v-else-if="menuItem.type === 'dateRange'" format="YYYY-MM-DD"
:dropdown-class-name="dropdownClassName" />
</a-form-item>
<a-form-item>
<a-button type="primary" html-type="submit" v-if="!hideSearch">查询</a-button>
<a-button :style="{ marginLeft: '8px' }" @click="reset" v-if="!hideSearch">重置</a-button>
<slot name="search-button" v-bind:search="form.getFieldsValue()"></slot>
</a-form-item>
</a-form>
</div>
<a-divider v-if="!hideButton && searchItems.length > 0"/>
<div class="table-operations" v-if="!hideButton">
<a-button @click="addRow" type="primary">
添加
</a-button>
</div>
<a-table v-bind="tableProps" :pagination="page" :row-key="primaryKey" :columns="realColumns"
:data-source="tableDataSource" @change="handleChange">
<span slot="action" slot-scope="text, record">
<a-button type="danger" size="small" @click="deleteRow(record)">删除</a-button>
<a-divider type="vertical"/>
<a-button type="primary" size="small" @click="editRow(record)">编辑</a-button>
</span>
<span slot="details" slot-scope="text, record">
<!-- <a-button type="danger" size="small" @click="deleteRow(record)">删除</a-button>-->
<!-- <a-divider type="vertical"/>-->
<a-button type="primary" size="small" @click="viewDetails(record)">详情</a-button>
</span>
</a-table>
<a-modal
:title="dialog.title"
:visible="dialog.visible"
:confirm-loading="dialog.loading"
@ok="handleOk"
@cancel="handleCancel"
>
<a-form class="ant-advanced-search-form" :form="editForm" @submit="handleSearch" @change="handleSearchFormChange">
<a-form-item v-for="menuItem in formItems" :key="menuItem.key" :label="menuItem.label" v-if="!menuItem.hide">
<a-input
v-bind="menuItem.props || {}"
v-decorator="gtDecorator(menuItem)"
:placeholder="menuItem.placeholder || ''"
v-if="menuItem.type === 'input'"
/>
<a-select
v-decorator="gtDecorator(menuItem)"
:placeholder="menuItem.placeholder || ''"
:dropdown-class-name="dropdownClassName"
v-else-if="menuItem.type === 'select'"
v-bind="menuItem.props || {}"
>
<a-select-option :value="cItem.value" v-for="cItem in menuItem.children || []" :key="cItem.value">
{{ cItem.label }}
</a-select-option>
</a-select>
<a-tree-select
v-bind="menuItem.props || {}"
v-decorator="gtDecorator(menuItem)"
:placeholder="menuItem.placeholder || ''"
:dropdown-class-name="dropdownClassName"
allow-clear
:tree-data="menuItem.children"
tree-default-expand-all
style="width: 100%"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
v-else-if="menuItem.type === 'treeSelect'"
>
<a-select-option :value="cItem.value" v-for="cItem in menuItem.children || []" :key="cItem.value">
{{ cItem.label }}
</a-select-option>
</a-tree-select>
<a-range-picker v-bind="menuItem.props || {}" v-decorator="gtDecorator(menuItem)"
v-else-if="menuItem.type === 'dateRange'" format="YYYY-MM-DD" :dropdown-class-name="dropdownClassName" />
<a-date-picker style="width: 100%" v-decorator="gtDecorator(menuItem)" v-bind="menuItem.props || {}"
v-else-if="menuItem.type === 'date'" format="YYYY-MM-DD" :dropdown-class-name="dropdownClassName"/>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
import moment from "moment";
import { get } from 'lodash'
export default {
name: "user",
data() {
return {
cacheData: [],
isValidate: false,
tableDataSource: [],
form: this.$form.createForm(this, {name: `form_${new Date().valueOf()}`}),
editForm: this.$form.createForm(this, {name: `edit_form_${new Date().valueOf()}`}),
dialog: {
title: '',
visible: false,
isEdit: '',
loading: false
},
selectRow: null,
page: {
pageSize: 10,
current: 1,
total: 0
},
searchFormModel: {}
}
},
props: {
tableProps: {
type: Object,
default: () => ({})
},
dropdownClassName: {
type: String,
default: ''
},
hideSearch: {
type: Boolean,
default: false
},
hideAction: {
type: Boolean,
default: false
},
hideButton: {
type: Boolean,
default: false
},
// 表单内容配置
formItems: {
type: Array,
default: () => []
},
// 列表列配置
columns: {
type: Array,
default: () => []
},
primaryKey: {
type: String,
default: 'id'
},
apiConf: {
type: Object,
default: () => ({})
},
customSearch: {
type: Function,
default: () => null
}
},
computed: {
searchItems() {
return this.formItems.filter(item => !!item.isSearch)
},
realColumns() {
if (this.hideAction) return [...this.columns]
return [
...this.columns,
{
title: '操作',
dataIndex: 'action',
scopedSlots: {customRender: 'action'},
fixed: 'right',
width: 155
},
]
}
},
watch: {},
mounted() {
this.handleSearch()
},
methods: {
viewDetails(data) {
this.$emit('viewDetails', data)
},
gtDecorator(menuItem) {
if (menuItem.rules) {
this.isValidate = true
return [
menuItem.key,
{rules: menuItem.rules}
]
}
return [
menuItem.key
]
},
handleSearchFormChange(changedFields) {
this.searchFormModel = {...this.searchFormModel, ...changedFields}
},
addRow() {
this.handleCancel()
this.$emit('edit', false)
this.dialog.visible = true
},
async editRow(row) {
if (this.apiConf.detailApi) {
const {api, method, detailHandler} = this.apiConf.detailApi
const {data} = await this[`$${method}`](api, {[this.primaryKey]: row[this.primaryKey]})
this.selectRow = detailHandler && detailHandler(data) || data
} else {
this.selectRow = row
}
this.dialog.title = '编辑'
this.dialog.visible = true
this.dialog.isEdit = true
this.dialog.loading = false
this.$emit('edit', true)
setTimeout(() => {
this.editForm.setFieldsValue(this.selectRow)
}, 200)
},
deleteRow(row) {
const self = this
if (!self.apiConf.deleteApi) return
this.$confirm({
title: '确认要删除么?',
okText: '确认',
okType: 'danger',
cancelText: '再想想',
onOk() {
const {api, deleteKey, paramsType, method} = self.apiConf.deleteApi
let params = {}
if (paramsType === 'Array') {
params = [row[self.primaryKey]]
} else {
params[deleteKey] = row[self.primaryKey]
}
self[`$${method}`](api, params, {params: params}).then(res => {
self.handleSearch()
})
}
});
},
handleChange({pageSize, current}) {
this.page.pageSize = pageSize
this.page.current = current
this.handleSearch()
},
reset() {
this.form.resetFields();
},
doSearch () {
if (this.customSearch) {
this.tableDataSource = this.customSearch(JSON.parse(JSON.stringify(this.cacheData)))
}
},
async handleSearch(e) {
e && e.preventDefault();
const rangeList = ['dateRange']
const values = this.form.getFieldsValue()
const searchValues = {}
for (const formItem of this.formItems.filter(item => item.isSearch)) {
if (rangeList.indexOf(formItem.type) >= 0) {
formItem.fields.forEach((field, index) => {
if (formItem.type.indexOf('date') >= 0) {
searchValues[field] = values[formItem.key] && values[formItem.key][index] && moment(values[formItem.key][index]).format('YYYY-MM-DD') || ''
}
})
} else {
searchValues[formItem.key] = values[formItem.key]
}
}
const {api, noPage, method, renderKey, after} = this.apiConf.listApi
const {data} = await this[`$${method}`](api, {
...searchValues,
pageSize: this.page.pageSize,
current: this.page.current,
})
if (noPage) {
this.page = false
this.cacheData = renderKey ? get(data, renderKey) : data
this.tableDataSource = renderKey ? get(data, renderKey) : data
after && after(data)
} else {
this.page.total = data.total || 0
this.cacheData = renderKey ? get(data, renderKey) : data.items
this.tableDataSource = renderKey ? get(data, renderKey) : data.items
after && after(data)
}
},
async handleOk() {
if (this.isValidate) {
this.editForm.validateFields(async (err, values) => {
if (!err) {
if (this.dialog.isEdit) {
const {api, method, updateKey} = this.apiConf.editApi
await this[`$${method}`](api, {
[updateKey || this.primaryKey]: this.selectRow[this.primaryKey],
...values
})
} else {
const {api, method} = this.apiConf.addApi
await this[`$${method}`](api, values)
}
this.handleCancel()
this.handleSearch()
}
});
} else {
const values = this.editForm.getFieldsValue()
if (this.dialog.isEdit) {
const {api, method, updateKey} = this.apiConf.editApi
await this[`$${method}`](api, {
[updateKey || this.primaryKey]: this.selectRow[this.primaryKey],
...values
})
} else {
const {api, method} = this.apiConf.addApi
await this[`$${method}`](api, values)
}
this.handleCancel()
this.handleSearch()
}
},
handleCancel() {
this.selectRow = null
this.dialog.title = '添加'
this.dialog.visible = false
this.dialog.isEdit = false
this.dialog.loading = false
this.editForm.resetFields()
},
}
}
</script>
<style scoped lang="less">
.table-operations {
margin-bottom: 16px;
}
.ant-form-item {
margin-bottom: 0;
}
.ant-divider-horizontal {
margin: 16px 0;
}
.table-operations > button {
margin-right: 8px;
}
</style>