<template>
<a-form layout="horizontal" class="ant-advanced-search-form" :labelCol="labelCol" :wrapperCol="wrapperCol" :form="formData" ref="formData">
<a-row>
<a-col :span="showToggleBtn ? 22 : 24">
<a-row :gutter="4">
<a-col :key="'formDara_'+i" v-for="(item,i) in conf.slice(0,hideNumSide)" :span="item.span || 8" :class="'item_' +i">
<slot v-if="item.slot" :name="item.slot" :data="item" :index="i" :conf="conf"/>
<template v-else>
<a-form-item :label-col="labelCol" :wrapper-col="wrapperCol" :labelAlign="item.labelAlign">
<!-- 输入框 -->
<div class="form-label" :class="[i === 0 ? 'first-label' :'']">
{{item.label}}
</div>
<a-input v-if="item.type === 'input'" v-model="formData[item.prop]" :placeholder="item.placeholder"
:disabled="item.disabled" @pressEnter="keyEnter" @change="onchange(item.type,item.prop,formData[item.prop])">
<a-icon slot="prefix" v-if="item.prefix" :type="item.prefix" @click.native="keyEnter"/>
<a-icon slot="suffix" v-if="item.suffix" :type="item.suffix" @click.native="keyEnter" :class="item.suffix.includes('search') ? 'suffix-point' :''"/>
<div :slot="st.name" v-for="(st,sti) in item.slotList" :key="sti" >
<slot :name="st.name" :item="item"/>
</div>
</a-input>
<!-- 下拉选项 -->
<a-select :disabled="item.disabled" v-else-if="item.type === 'select'" :placeholder="item.placeholder" @select="selectChange" v-model="formData[item.prop]" allowClear @change="onchange(item.type,item.prop,formData[item.prop])">
<!-- 内部插槽数组 -->
<div :slot="st.name" v-for="(st,sti) in item.slotList || []" :key="sti" >
<slot :name="st.name" :item="item"/>
</div>
<a-select-option :value="optionsItem.value" v-for="(optionsItem,oi) in C_selectOptions[item.prop] || item.selectOptions || []" :key="'select_'+ oi" :disabled="optionsItem.disabled"
@search="search">
{{optionsItem.label}}
</a-select-option>
</a-select>
<!-- 日期控件 -->
<a-range-picker :locale="locale" class="ant-form-item-children_date" :separator="item.separator || '至'" v-model="formData[item.prop]" @change="onchange('date',item.prop,formData[item.prop])" :placeholder="item.placeholder || []" v-else-if="item.type === 'date-d'" >
<span slot="suffixIcon">
<slot :name="item.suffixIcon">
<i class="iconfont icon-common-date ant-calendar-picker-icon"/>
</slot>
</span>
</a-range-picker>
<a-range-picker :locale="locale" class="ant-form-item-children_date" v-model="formData[item.prop]" @change="onchange('date',item.prop,formData[item.prop])" :placeholder="item.placeholder || []" v-else-if="item.type === 'date-r'"
:ranges="{'明 天':[moment().add(1,'day'),moment().add(1,'day')], '未来7天': [moment().add(1,'day'),moment().add(1,'week')],
'未来15天': [moment().add(1,'day'),moment().add(15,'day')],'未来30天': [moment().add(1,'day'),moment().add(30,'day')],
'未来60天': [moment().add(1,'day'),moment().add(60,'day')],'未来90天': [moment().add(1,'day'),moment().add(90,'day')]}" />
<a-date-picker v-else-if="item.type === 'date-dd'" :separator="item.separator || '至'"
@change="onchange('date',item.prop,formData[item.prop])" :placeholder="item.placeholder" v-model="formData[ite.prop]" v-bind="item.binding" style="width:100%" :format="item.dateFormatList">
<span slot="suffixIcon">
<slot :name="item.suffixIcon">
<i class="iconfont icon-common-date ant-calendar-picker-icon"/>
</slot>
</span>
</a-date-picker>
<a-input-group v-else-if="item.type === 'inputGroup'" compact :size="item.size" class="inputgroup">
<template v-for="(ranger, rangeri) in item.groups">
<a-input v-if="rangeri !== 0"
style=" width: 30px; border-left: 0; pointer-events: none; backgroundColor: #fff"
:placeholder="ranger.separator || '~'"
disabled
:key="'group_'+i+'_'+rangeri+'place'"
/>
<a-input :key="'group_'+i+'_'+rangeri" v-model="formData[item.prop][rangeri]" :placeholder="ranger.placeholder" :disabled="ranger.disabled" @pressEnter="keyEnter" @change="onchangeGroup(item)" class="inputgroup-input">
<a-icon slot="prefix" v-if="rangeri.prefix" :type="rangeri.prefix" @click.native="keyEnter"/>
<a-icon slot="suffix" v-if="rangeri.suffix" :type="rangeri.suffix" @click.native="keyEnter" :class="rangeri.suffix.includes('search') ? 'suffix-point' :''"/>
<div :slot="st.name" v-for="(st,sti) in ranger.slotList" :key="sti" >
<slot :name="st.name" :item="item"/>
</div>
</a-input>
</template>
</a-input-group>
<slot :name="item.slotInner" v-else-if="item.slotInner" :data="item" :index="i" :conf="formConfs"/>
</a-form-item>
</template>
</a-col>
</a-row>
</a-col>
<a-col :span="2" v-if="showToggleBtn || conf.length > hideNumSide" >
<slot name="rightSpan">
<a-form-item class="changeBtn">
<YtButton :type="changeClickIcon ? 'default':'primary'" height="36px" :color="changeClickIcon ? '#62727E':'white'"
border-color="#CFD9E1" @click="changeIcon">更多筛选 <a-icon :type="changeClickIcon ? 'down-circle' : 'up-circle'" theme="filled" :style="{color:changeClickIcon ? '#62727E':'white' }"/></YtButton>
</a-form-item>
</slot>
</a-col>
</a-row>
<!-- 第二轮卡片 -->
<template v-if="!changeClickIcon">
<a-row :gutter="4" class="max-lg-3" >
<a-col :key="'formDara_'+(i+hideNumSide)" v-for="(item,i) in conf.slice(hideNumSide)" :span="item.span || 8">
<slot v-if="item.slot" :name="item.slot" :data="item" :index="i" :conf="conf"/>
<template v-else>
<a-form-item :label-col="labelCol" :wrapper-col="wrapperCol" :labelAlign="item.labelAlign">
<!-- 输入框 -->
<div class="form-label">
{{item.label}}
</div>
<a-input v-if="item.type === 'input'" v-model="formData[item.prop]" :placeholder="item.placeholder"
:disabled="item.disabled" @pressEnter="keyEnter" @change="onchange(item.type,item.prop,formData[item.prop])">
<a-icon slot="prefix" v-if="item.prefix" :type="item.prefix" />
<a-icon slot="suffix" v-if="item.suffix" :type="item.suffix" />
<div :slot="st.name" v-for="(st,sti) in item.slotList" :key="sti" >
<slot :name="st.name" :item="item"/>
</div>
</a-input>
<!-- 下拉选项 -->
<a-select :disabled="item.disabled" v-else-if="item.type === 'select'" :placeholder="item.placeholder" @select="selectChange" v-model="formData[item.prop]" allowClear @change="onchange(item.type,item.prop,formData[item.prop])">
<!-- 内部插槽数组 -->
<div :slot="st.name" v-for="(st,sti) in item.slotList || []" :key="sti" >
<slot :name="st.name" :item="item"/>
</div>
<a-select-option :value="optionsItem.value" v-for="(optionsItem,oi) in C_selectOptions[item.prop] || item.selectOptions || []" :key="'select_'+ oi" :disabled="optionsItem.disabled"
@search="search">
{{optionsItem.label}}
</a-select-option>
</a-select>
<!-- 日期控件 -->
<a-range-picker :locale="locale" class="ant-form-item-children_date" v-model="formData[item.prop]" @change="onchange('date',item.prop,formData[item.prop])" :placeholder="item.placeholder || []" v-else-if="item.type === 'date-d'" />
<a-range-picker :locale="locale" class="ant-form-item-children_date" v-model="formData[item.prop]" @change="onchange('date',item.prop,formData[item.prop])" :placeholder="item.placeholder || []" v-else-if="item.type === 'date-r'"
:ranges="{'明 天':[moment().add(1,'day'),moment().add(1,'day')], '未来7天': [moment().add(1,'day'),moment().add(1,'week')],
'未来15天': [moment().add(1,'day'),moment().add(15,'day')],'未来30天': [moment().add(1,'day'),moment().add(30,'day')],
'未来60天': [moment().add(1,'day'),moment().add(60,'day')],'未来90天': [moment().add(1,'day'),moment().add(90,'day')]}" />
<a-date-picker v-else-if="item.type === 'date-dd'"
@change="onchange('date',item.prop,formData[item.prop])" :placeholder="item.placeholder" v-model="formData[ite.prop]" v-bind="item.binding" style="width:100%" :format="item.dateFormatList">
<span slot="suffixIcon">
<slot :name="item.suffixIcon"/>
</span>
</a-date-picker>
<a-input-group v-else-if="item.type === 'inputGroup'" compact :size="item.size" class="inputgroup">
<template v-for="(ranger, rangeri) in item.groups">
<a-input v-if="rangeri !== 0"
style=" width: 30px; border-left: 0; pointer-events: none; backgroundColor: #fff"
:placeholder="ranger.separator || '~'"
disabled
:key="'group_'+i+'_'+rangeri+'place'"
/>
<a-input :key="'group_'+i+'_'+rangeri" v-model="formData[item.prop][rangeri]" :placeholder="ranger.placeholder" :disabled="ranger.disabled" @pressEnter="keyEnter" @change="onchangeGroup(item)" class="inputgroup-input">
<a-icon slot="prefix" v-if="rangeri.prefix" :type="rangeri.prefix" @click.native="keyEnter"/>
<a-icon slot="suffix" v-if="rangeri.suffix" :type="rangeri.suffix" @click.native="keyEnter" :class="rangeri.suffix.includes('search') ? 'suffix-point' :''"/>
<div :slot="st.name" v-for="(st,sti) in ranger.slotList" :key="sti" >
<slot :name="st.name" :item="item"/>
</div>
</a-input>
</template>
</a-input-group>
<slot :name="item.slotInner" v-else-if="item.slotInner" :data="item" :index="i" :conf="formConfs"/>
</a-form-item>
</template>
</a-col>
</a-row>
<div class="stand-height"></div>
</template>
<!-- 后置插槽 -->
<slot name="action"/>
</a-form>
</template>
<script>
/*ant 中文*/
import locale from 'ant-design-vue/es/date-picker/locale/zh_CN';
import moment from 'moment';
export default {
name:'YtFormSearch',// 表单收缩卡片
props:{
test:Boolean,
// 表单配置选项
/* type: t 输入框,D 返回时间,s 下拉选项 d 单个时间 inputgroup 输入框组合
label:显示文字 , prop:对应表单的字段名称,suffix:后置图标,prefix:前置图标,disabled:禁用
slot:外部插槽 slotInner: 内部插槽【from-item】中的
slotList:[{name:'原生插槽字段'}]
group:[ {prop: 表单字段名称,placeholder: 提示语, disabled: 禁用 , separator: 间隔符 }]
*/
formConfs:{
type:Array,
default:()=>([])
},
value:Object,
//设置某表单数据
setFormValue:Function,
changeShowNum:Number,
hideNumSide:{ // 切换显示的边界索引
type:Number,
default:3
},
labelCol:{
type:Object,
default:()=>({
span:7
})
},
wrapperCol:{
default:()=>({
span:17
})
},
// 异步获取下拉选项
selectOptions:{
type:Object,
default:()=>({})
},
showToggleBtn:{type:Boolean,default:true},//显示按钮
cache: String, // vuex需要缓存 名称
storageCache: String , // 本地缓存名称
completeCache: Function // 完成缓存加载后 调用事件函数
},
data(){
return {
mode: {
'd':'default',
'default':'default',
'm' : 'multiple',
'multiple' : 'multiple',
't' : 'tags',
'tags' : 'tags',
'c' : 'combobox',
'combobox':'combobox'
},
formData:{...this.value},
locale,
changeClickIcon:true
}
},
computed:{
conf(){
return (this.formConfs|| []).map( v => ({
...v,
placeholder:v.placeholder || ( (v.type.includes('input') ? '请输入' : '请选择') + v.label),
mode:this.mode[v.mode] || 'default'
}))
},
C_selectOptions(){
return this.selectOptions
}
},
watch:{
'value':{
handler(cval){
this.value && (this.formData = JSON.parse(JSON.stringify(this.value)))
},
deep:true,
}
},
mounted(){
if( this.cache && this.$store.state?.YtSearchFrom?.[this.cache] ){
Object.assign(this.formData, this.$store.state.YtSearchFrom[this.cache])
this.$emit('input',this.formData)
this.completeCache && this.completeCache()
}
if(this.storageCache && !!sessionStorage.getItem('YtSearchFrom_' + this.storageCache)){
Object.assign(this.formData, JSON.parse(sessionStorage.getItem('YtSearchFrom_' + this.storageCache)))
this.$emit('input',this.formData)
this.completeCache && this.completeCache()
}
this.test && console.log(this.formData , this.formConfs)
},
methods:{
moment,
setFormData(prop,value = ''){
if(this.setFormValue) return this.setFormValue(this.formData)
this.formData[prop] = value
},
//回车查询
keyEnter(){
this.test && console.log('回车=》',this.formData)
this.$emit('keyEnter',this.formData)
},
// 输入框值变化时
onchange(type,propName,value){
this.test && console.log('change=》',propName,value)
this.onchange.duled && clearTimeout(this.onchange.duled)
this.onchange.duled = setTimeout( _ => {
this.caching() // 缓存机制
this.$emit('input',this.formData)
this.$emit('onchange',{type,propName,value})
this.$emit('onchange'+type,{type,propName,value})
}, 800)
},
search(value){
// 输入后值变化时
this.$emit('search',value)
},
//
selectChange(value,options){
this.test && console.log('selectChange=》',value,this.formData)
this.$emit('selectChange',{value,formData:this.formData})
},
// 清空所有查询条件
clearAllCase(){
Object.keys(this.formData).forEach(v => {
Array.isArray(this.formData[v]) ? this.formData[v] = [] : this.formData[v] = undefined
})
this.$emit('input',this.formData)
this.$emit('clear',this.formData)
},
//切换按钮
changeIcon(){
this.changeClickIcon = !this.changeClickIcon
this.$emit('toggleBtn')
},
// 组合输入框事件
onchangeGroup(item){
const {type, prop } = item
const isFlag = this.formData[prop].every(v => v !== '' && v !== undefined)
item.onError = !isFlag
if(isFlag) this.onchange(type, prop, this.formData[prop]) // 都写入数据才能
this.$emit('onchangeGroup',type, prop, this.formData[prop],item)
this.test && console.log(isFlag, this.formData[prop], 'onchangeGroup')
},
// 缓存机制
caching(){
const {cache, storageCache , $store:{ state }} = this
if( cache ){
// 存在VUEX 缓存集合
const data = JSON.parse(JSON.stringify(this.formData))
if(state.YtSearchFrom && Object.prototype.toString.call(state.YtSearchFrom).slice(8, -1) === 'object' ){
state.YtSearchFrom[cache] = data
} else {
state.YtSearchFrom = {
[cache]: data
}
}
}
// 存入本地缓存
if(storageCache){
sessionStorage.setItem('YtSearchFrom_'+ storageCache, JSON.stringify(this.formData))
}
this.test && console.log(sessionStorage.getItem('YtSearchFrom_'+ storageCache), 'state', state.YtSearchFrom)
}
}
}
</script>
<style lang="scss" scoped>
.ant-advanced-search-form {
@media screen and (max-width:1528px){
/deep/ .ant-col-8{
width:32.22%;
}
}
box-sizing: border-box;
/deep/ .ant-form-item {
display:flex;
align-items:center;
justify-content: center;
margin-bottom:16px;
.ant-form-item-label{
label{
color:#8595A1;
}
}
.suffix-point{
cursor: pointer;
}
}
/*站位高度*/
.stand-height{
height:16px;
}
// 全局表单样式
/deep/ .ant-form-item-control-wrapper {
flex: 1;
.ant-form-item-control{
padding-right:8px;
flex:1;
.ant-calendar-picker{
width:100%;
}
.ant-form-item-children{
display: flex;
.form-label{
max-width: 100px;
min-width:56px;
display: flex;
justify-content: flex-end;
align-items: center;
height: 38px;
line-height: 18px;
text-align: right;
padding-right:8px;
box-sizing: border-box;
& + div,& + span{
flex:1;
}
}
.item_1{
max-width:372px;
}
// 第一个输入框的label
.first-label{
width:0;
padding:0;
min-width:0;
}
.inputgroup {
display:flex;
flex-wrap: nowrap;
.inputgroup-input{
&:nth-child(1+n){
border-left:none;
}
}
}
}
}
}
.changeBtn /deep/ .ant-form-item-control-wrapper .ant-form-item-control{
padding-right:0px;
.ant-form-item-children{
display: flex;
justify-content: flex-end;
align-items: center;
}
}
/*特殊大于三的表单样式*/
.max-lg-3{
background-color:#f9fafb;
padding:16px 16px 0 16px;
margin:0px!important;
/deep/ .ant-form-item-control-wrapper {
.ant-form-item-control{
.ant-form-item-children{
.form-label{
width:100px;
}
}
}
}
}
}
</style>
<style lang="scss">
.ant-calendar-picker-container{
.ant-calendar-footer-extra{
.ant-tag-blue{
width: 81px;
text-align: center;
}
.ant-tag-blue:last-child{
margin: 0;
}
}
}
</style>
网友评论