You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

336 lines
9.9 KiB
Vue

<template>
<div :class="{ search__col: layout === 'right' }">
<el-row :gutter="20">
<el-col :span="layout === 'right' ? 22 : 24">
<el-form
ref="ruleForm"
inline
:model="formInline"
:rules="rules"
:label-width="labelWidth"
:label-position="labelPosition"
:hide-required-asterisk="hideRequiredAsterisk"
@submit.prevent
>
<el-form-item
v-for="(item, $index) in data"
:key="$index"
:label="item.label"
:prop="item.field"
:rules="item.rules"
>
<template v-if="item.itemType === 'switch'">
<el-switch
v-model="formInline[item.field]"
v-bind="{...getItemBindValue(item)}"
@change="((val) => {changeVal(val, item)})"
/>
</template>
<template v-if="item.itemType === 'input'">
<el-input
v-model="formInline[item.field]"
v-bind="{...getItemBindValue(item)}"
@change="((val) => {changeVal(val, item)})"
/>
</template>
<template v-if="item.itemType === 'select'">
<el-select
v-model="formInline[item.field]"
v-bind="{...getItemBindValue(item)}"
@change="((val) => {changeVal(val, item)})"
>
<el-option
v-for="v in item.options"
:key="item.optionValue ? v[item.optionValue] : v.value"
:value="item.optionValue ? v[item.optionValue] : v.value"
:label="item.optionLabel ? v[item.optionLabel] : v.title"
/>
</el-select>
</template>
<template v-if="item.itemType === 'radio'">
<el-radio-group
v-model="formInline[item.field]"
@change="((val) => {changeVal(val, item)})"
>
<template v-if="item.radioType === 'radio'">
<el-radio
v-for="v in item.options"
:key="item.optionValue ? v[item.optionValue] : v.value"
v-bind="{...getItemBindValue(item)}"
:label="item.optionValue ? v[item.optionValue] : v.value"
>
{{ item.optionLabel ? v[item.optionLabel] : v.label }}
</el-radio>
</template>
<template v-else-if="item.radioType === 'button'">
<el-radio-button
v-for="v in item.options"
:key="item.optionValue ? v[item.optionValue] : v.value"
v-bind="{...getItemBindValue(item)}"
:label="item.optionValue ? v[item.optionValue] : v.value"
>
{{ item.optionLabel ? v[item.optionLabel] : v.label }}
</el-radio-button>
</template>
</el-radio-group>
</template>
<!-- element近期会新增treeSelect组件所以不打算在自己维护一套等待ing -->
<!-- <template v-if="item.itemType === 'treeSelect'">
<el-tree-select
v-model:value="formInline[item.field]"
:size="item.size"
:dropdown-style="item.dropdownStyle"
:tree-data="item.options"
:placeholder="item.placeholder"
:tree-checkable="item.treeCheckable"
:max-tag-count="item.maxTagCount"
:tree-default-expand-all="item.treeDefaultExpandAll"
:allow-clear="item.allowClear"
style="min-width: 201px;"
@change="((val) => {changeVal(val, item)})"
>
<template #title="{ title }">
<span>{{ title }}</span>
</template>
</el-tree-select>
</template> -->
<template v-if="item.itemType === 'timePicker'">
<el-time-picker
v-model="formInline[item.field]"
v-bind="{...getItemBindValue(item)}"
@change="((val) => {changeVal(val, item)})"
/>
</template>
<template v-if="item.itemType === 'timeSelect'">
<el-time-select
v-model="formInline[item.field]"
v-bind="{...getItemBindValue(item)}"
@change="((val) => {changeVal(val, item)})"
/>
</template>
<template v-if="item.itemType === 'datePicker' || item.itemType === 'dateTimePicker'">
<el-date-picker
v-model="formInline[item.field]"
v-bind="{...getItemBindValue(item)}"
@change="((val) => {changeVal(val, item)})"
/>
</template>
</el-form-item>
<el-form-item v-if="data.length > 0 && layout === 'classic'">
<el-button
type="primary"
icon="el-icon-search"
@click="submitForm"
>
查询
</el-button>
<el-button
v-if="showReset"
icon="el-icon-refresh-right"
@click="resetForm"
>
重置
</el-button>
</el-form-item>
</el-form>
</el-col>
<el-col :span="layout === 'right' ? 2 : 24">
<div
v-if="data.length > 0 && (layout === 'bottom' || layout === 'right')"
class="search__bottom"
:class="{ 'search__bottom--col': layout === 'right' }"
>
<div class="search__bottom--button">
<el-button
type="primary"
icon="el-icon-search"
@click="submitForm"
>
查询
</el-button>
</div>
<div class="search__bottom--button">
<el-button
v-if="showReset"
:style="{
'margin-left': layout !== 'right' ? '15px' : '0',
'margin-top': layout === 'right' ? '27px' : '0'
}"
icon="el-icon-refresh-right"
@click="resetForm"
>
重置
</el-button>
</div>
</div>
</el-col>
</el-row>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, watch, ref, unref } from 'vue'
import { deepClone } from '@/utils'
export default defineComponent({
name: 'Search',
props: {
// 表单域标签的宽度,例如 '50px'。作为 Form 直接子元素的 form-item 会继承该值。支持 auto。
labelWidth: {
type: String as PropType<string>,
default: ''
},
labelPosition: {
type: String as PropType<'right' | 'left' | 'top'>,
default: 'right'
},
// 隐藏所有表单项的必选标记
hideRequiredAsterisk: {
type: Boolean as PropType<boolean>,
default: true
},
// 表单数据对象
data: {
type: Object as PropType<{ [key: string]: any }>,
default: () => {}
},
// 表单验证规则
rules: {
type: Object as PropType<{ [key: number]: any }>,
default: () => []
},
// 是否显示重置按钮
showReset: {
type: Boolean as PropType<boolean>,
default: true
},
// 是否显示导出按钮
showExport: {
type: Boolean as PropType<boolean>,
default: false
},
// 风格
layout: {
type: String as PropType<'classic' | 'bottom' | 'right'>,
default: 'classic'
}
},
emits: ['search-submit', 'reset-submit', 'change'],
setup(props, { emit }) {
const ruleForm = ref<HTMLElement | null>(null)
const formInline = ref<{ [key: string]: any }>({})
watch(
() => props.data,
(data) => {
initForm(data)
},
{
deep: true,
immediate: true
}
)
function getItemBindValue(item: any) {
const delArr: string[] = ['label', 'itemType', 'value', 'field']
const obj = deepClone(item)
for (const key in obj) {
if (delArr.indexOf(key) !== -1) {
delete obj[key]
}
}
return obj
}
function initForm(data: any): void {
for (const v of data) {
formInline.value[v.field] = formInline.value[v.field] || v.value
}
}
async function submitForm(): Promise<void> {
const form = unref(ruleForm) as any
if (!form) return
try {
form.validate((valid: boolean) => {
if (valid) {
console.log(valid)
emit('search-submit', unref(formInline))
} else {
console.log('error submit!!')
return false
}
})
} catch (err) {
console.log(err)
}
}
async function resetForm(): Promise<void> {
const form = unref(ruleForm) as any
if (!form) return
await form.resetFields()
emit('reset-submit', unref(formInline))
}
function changeVal(val: any, item: any): void {
if (item.onChange) {
emit('change', {
field: item.field,
value: unref(formInline.value[item.field])
})
}
}
return {
getItemBindValue,
ruleForm,
formInline,
submitForm,
resetForm,
changeVal
}
}
})
</script>
<style lang="less" scoped>
.ant-form-inline {
.ant-form-item {
min-height: 60px;
}
.ant-form-item-with-help {
margin-bottom: 0;
}
}
.search__bottom {
text-align: center;
padding-bottom: 20px;
.search__bottom--button {
display: inline-block;
}
}
.search__bottom--col {
padding-bottom: 0;
margin-top: 5px;
position: relative;
.search__bottom--button {
display: inline-block;
}
}
.search__bottom--col::before {
content: "";
width: 1px;
height: 100%;
border-left: 1px solid #d9d9d9;
position: absolute;
top: 0;
left: 0;
}
</style>