<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])">
<!-- 內(nèi)部插槽數(shù)組 -->
<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])">
<!-- 內(nèi)部插槽數(shù)組 -->
<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: 內(nèi)部插槽【from-item】中的
slotList:[{name:'原生插槽字段'}]
group:[ {prop: 表單字段名稱身堡,placeholder: 提示語邓尤, disabled: 禁用 , separator: 間隔符 }]
*/
formConfs:{
type:Array,
default:()=>([])
},
value:Object,
//設置某表單數(shù)據(jù)
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 // 完成緩存加載后 調(diào)用事件函數(shù)
},
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]) // 都寫入數(shù)據(jù)才能
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>
2021-09-17 擴展一年前寫的表單生成器
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鲫构,“玉大人浓恶,你說我怎么就攤上這事〗岜浚” “怎么了包晰?”我有些...
- 文/不壞的土叔 我叫張陵,是天一觀的道長炕吸。 經(jīng)常有香客問我伐憾,道長,這世上最難降的妖魔是什么赫模? 我笑而不...
- 正文 為了忘掉前任树肃,我火速辦了婚禮,結(jié)果婚禮上嘴瓤,老公的妹妹穿的比我還像新娘扫外。我一直安慰自己,他們只是感情好廓脆,可當我...
- 文/花漫 我一把揭開白布筛谚。 她就那樣靜靜地躺著,像睡著了一般停忿。 火紅的嫁衣襯著肌膚如雪驾讲。 梳的紋絲不亂的頭發(fā)上,一...
- 文/蒼蘭香墨 我猛地睜開眼纸肉,長吁一口氣:“原來是場噩夢啊……” “哼溺欧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柏肪,我...
- 正文 年R本政府宣布控汉,位于F島的核電站笔诵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏姑子。R本人自食惡果不足惜乎婿,卻給世界環(huán)境...
- 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望街佑。 院中可真熱鬧谢翎,春花似錦、人聲如沸沐旨。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽磁携。三九已至褒侧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谊迄,已是汗流浹背闷供。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- 母親的第一次住院 從我記事起,母親進進出出舟误,忙忙碌碌葡秒,很少生病,更不曾住院嵌溢。母親走路咚咚的眯牧,吃飯呼嚕兩下一碗...
- 二十歲那年遇見你 正是各自花樣好年紀 我們約好了要一起去大理 從此一菜一湯省硬幣 三年之后我再遇見你 那時的你已經(jīng)...
- 收到朋友送來的兩本樣書秧骑,有點小意外版确,小驚喜。我一向是只管領稿費乎折,不太在意樣書绒疗,因為都是些為稻粱謀的東西,不值得敝帚...
- 今天青石的票圈出鏡率最高的健提,莫過于張藝謀的新片終于定檔了琳猫。 一張滿溢著水墨風的海報一次次的出現(xiàn)在票圈里,也就是老謀...