The form enclosed

Because of the versatility of the form, a UView-based form is encapsulated, because the backend needs to save one for every edit and expose the userLeave event in it. Currently there are only a few common components, and common extensions can be added later

ComForm/index.vue

<template>
  <view class="com-form">
    <u-form
      v-if="formRest"
      :model="formData"
      ref="uForm"
      label-width="140"
    >
      <u-form-item
        v-for="(item, key) in formDesc"
        :key="key"
        :label="['rate', 'PropertyType'].includes(item.type) ? '' : item.label"
        :label-style="item.labelStyle"
      >
        <! -- input -->
        <u-input @blur="onUserLeave({item, value: formData[key]})" :clearable="false" v-if="item.type === 'input'" v-model="formData[key]" :input-align="item.attr.inputAlign" :placeholder="item.attr.placeholder" />
        
        <! -- select -->
        <template v-if="item.type === 'select'">
          <u-input 
						type="select"
						:value="formData[key]"
						@click="item.show = true"
            :placeholder="item.attr.placeholder"
						:input-align="item.attr.inputAlign"
					/>
          <u-select
            v-model="item.show"
            :mode="item.mode"
            :list="item.options"
            :label-name="item.attr.labelName"
            :value-name="item.attr.valueName"
            @confirm="e => select(e, key, item)"
          />
        </template>

        <! -- houseType -->
        <u-input
          v-if="item.type === 'houseType'"
          :value="formData[key]"
          type="select"
          @click="houseSelectOpen(key, item)"
          :placeholder="item.attr.placeholder"
          :input-align="item.attr.inputAlign"
        />
        
        <! -- region -->
        <template v-if="item.type === 'region'">
          <u-input
            :value="formData[key] && (formData[key].province.label + formData[key].city.label + formData[key].area.label)"
            type="select"
            @click="regionShow = true"
            :placeholder="item.attr.placeholder"
            :input-align="item.attr.inputAlign"
          />
          <u-picker
            mode="region"
            v-model="regionShow"
            :default-region="formData[key] && [formData[key].province.label, formData[key].city.label, formData[key].area.label]"
            @confirm="e => regionChange(e, key, item)"
          />
        </template>

        <! -- rate -->
        <rate
          v-if="item.type === 'rate'"
          :label="item.label"
          :init-data="formData[key]"
          @change="e => rateChange(e, key, item)"
        />

        <! -- Tags -->
        <tags
          v-if="item.type === 'PropertyType'"
          v-model="formData[key]"
          @tagChange="onUserLeave({item, value: formData[key]})"
          :label="item.label"
          :custom="item.allowCustom"
        />

      </u-form-item>
    </u-form>
    <house-select ref="houseSelect" :seleData="houseListData" label="House Type Selection" @change="numSeleChange" />
  </view>
</template>

<script>
import HouseSelect from '@/components/houseType/compoundNumSele'
import Rate from './components/Rate'
import Tags from './components/Tags'

export default {
  name: 'ComForm'.components: {
    HouseSelect,
    Rate,
    Tags
  },
  model: {
    prop: 'formData'.event: 'input'
  },
  props: {
    // Form description
    formDesc: {
      type: Object.required: true
    },
    // Form data
    formData: {
      type: Object.required: true
    }
  },
  data () {
    return {
      defaultRegion: ['Jiangxi'.'Nanchang'.'West Lake District'].regionShow: false.formRest: true.houseListData: [{label"Number of bedrooms".key"Field name".value"Selected value".unit"Room".customfalse.// Whether the current value is custom
          customValue:' '.// A custom value
          data: [{label"1".value"1".chechedfalse },
            { label"2".value"2".chechedfalse },
            { label"3".value"3".chechedfalse}]}, {label"Number of living rooms and restaurants".key"Field name".value"Selected value".unit"Hall".customfalse.// Whether the current value is custom
          customValue:' '.// A custom value
          data: [{label"0".value"0".chechedfalse },
            { label"1".value"1".chechedfalse },
            { label"2".value"2".chechedfalse}]}, {label"Number of toilets".key"Field name".value"Selected value".unit"Who".customfalse.// Whether the current value is custom
          customValue:' '.// A custom value
          data: [{label"0".value"0".chechedfalse },
            { label"1".value"1".chechedfalse },
            { label"2".value"2".chechedfalse}]}]}},methods: {
    getValue(field) {
      return this.formData[field]
    },
    houseSelectOpen (key, item) {
			this.$refs.houseSelect.open(key, item)
    },
    onUserLeave(e) { // The user leaves the event
      this.$emit('userLeave', e)
    },
    numSeleChange ({list, key, item}) {
	  this.houseListData = list
	  let value = ' '
      this.houseListData.map((item, index) = > {
          if (item.custom) {
              value === ' ' ? value = item.customValue + item.unit : value = value + item.customValue + item.unit
          } else {
              value === ' ' ? value = item.value + item.unit : value = value + item.value + item.unit
          }
      })
      this.formData[key] = value
      this.onUserLeave({item, value: this.formData[key]})
    },
    regionChange (e, key, item) {
      this.formData[key] = e
      this.onUserLeave({item, value: this.formData[key]})
    },
    select (e, key, item) {
      let str = ' '
      e.forEach(item= > {
        str += item.value
      })
      this.formData[key] = str

      this.onUserLeave({item, value: this.formData[key]})
    },
    rateChange (e, key, item) {
      this.formData[key] = e
      this.onUserLeave({item, value: this.formData[key]})
    }
  }
}
</script>
Copy the code

Star component

ComForm/components/Rate.vue

<template>
  <view class="rate">
    <view class="title">
      <view>{{label}}</view>
      <! </view> -->
    </view>
    <view class="rate__content">
      <u-rate
        :count="count"
        :size="size"
        :active-color="activeColor"
        v-model="rate"
        @change="e => $emit('change', e)"
      />
    </view>
  </view>
</template>

<script>
export default {
  name: 'Rate'.props: {
    label: {
      type: String.default: 'Customer intent'
    },
    initData: {
      type: Number.default: 0
    }
  },
  data () {
    return {
      count: 10.size: '53'.rate: 0.activeColor: '#FF7716'
    }
  },
  created () {
    this.rate = this.initData
  }
}
</script>

<style lang="scss" scoped>
.rate {
  width: 100vw;
  margin: -20rpx -32rpx 0;
  border-top: 10rpx solid #F7F8FA;
  padding: 27rpx 32rpx;
  background: white;
  .title {
    display: flex;
    justify-content: space-between;
  }
  &__content {
    margin-top: 30rpx;
    margin-left: -5rpx; }}</style>
Copy the code

The label component

ComForm/components/Tags.vue

<template>
  <view class="tags">
    <view class="title">{{label}}</view>
    <view>
      <template v-for="(tag, index) in tags">
        <u-tag
          v-if="tag.selected"
          :key="tag.text + index"
          :text="tag.text"
          mode="dark"
          type="primary"
          :closeable="custom"
          @click="tag.selected = false"
          @close="removeTag(index)"
        />
        <u-tag
          v-else
          :key="tag.text + index"
          :text="tag.text"
          mode="dark"
          type="info"
          bg-color="#F7F8FA"
          color="# 323233"
          :closeable="custom"
          @click="tag.selected = true"
          @close="removeTag(index)"
        />
      </template>
      <view v-if="custom" class="add" @click="modalShow = true">
        <text class="iconfont icon-jiahao" />Add tags</view>
    </view>
    <u-modal 
      v-model="modalShow"
      show-cancel-button
      :mask-close-able="true"
      title="Add labels"
      confirm-text="Save"
      @confirm="addTag"
    >
      <view class="slot-content">
        <u-field
          v-model="modalValue"
          label-width="0"
          placeholder="Labels of no more than 8 characters"
          :border-bottom="false"
          focus
          maxlength="8"
          confirm-type="Save"
          :field-style="fieldStyle"
        />
      </view>
   </u-modal>
  </view>
</template>

<script>
export default {
  name: 'Tags'.model: {
    prop: 'tags'.event: 'input'
  },
  props: {
    tags: {
      type: Array.default: () = >[]},label: {
      type: String.default: 'Type of Property'
    },
    custom: {
      type: Boolean.default: false}},watch: {
    tags: {
      deep: true,
      handler (newVal) {
        this.$emit('tagChange')
        // this.$emit('input', newVal)
      }
    }
  },
  data () {
    return {
      modalShow: false.modalValue: ' '.fieldStyle: {
        border: '1px solid #C0C4CC'.padding: '13rpx 21rpx'.borderRadius: '4px'}}},methods: {
    addTag () {
      this.tags.push({
        text: this.modalValue,
        selected: true
      })
      this.modalValue = ' '
    },
    removeTag (index) {
      this.tags.splice(index, 1)}}}</script>

<style lang="scss" scoped>
.tags {
  margin-bottom: 25rpx;
  .title {
    margin-bottom: 18rpx;
  }
  u-tag, .u-tag {
    display: inline-block;
    margin-right: 20rpx;
    margin-bottom: 20rpx;
    font-size: 26rpx;
    &:last-child {
      margin-right: 0; }}.add {
    position: relative;
    display: inline-block;
    line-height: initial;
    font-size: 24rpx;
    padding: 12rpx 22rpx;
    padding-left: 70rpx;
    background: #F7F8FA;
    border-radius: 3px;
    .iconfont {
      position: absolute;
      top: 50%;
      left: 22rpx;
      margin-right: 10rpx;
      transform: translateY(-50%); }}}</style>
Copy the code

use

<template>
	<com-form
      v-model="form"
      :form-desc="formDesc"
      @userLeave="onUserLeave"
    />
</template>

<script>
const formType = [
  'input'.// Single line of text
  'textarea'.// Multi-line text
  'region'./ / address
  'date'./ / time
  'select'./ / a drop-down box
  'PropertyType'.// Label selection
  'houseType'.// Select the house type
  'rate'.// Star intention degree
]

export default {
    data () {
        return {
            formDesc: {
				name: {
					type: 'input'.label: 'name'.attr: {
						placeholder: 'Please note customer name'.inputAlign: 'right'}},phone: {
					type: 'input'.label: 'phone'.attr: {
						placeholder: 'Please note customer phone number'.inputAlign: 'right'}},houseType: {
					type: 'houseType'.label: 'room'.attr: {
						placeholder: 'Please comment on house type'.inputAlign: 'right'}},region: {
					type: 'region'.label: '地区范围'.attr: {
						placeholder: 'Please specify area'.inputAlign: 'right'}},rate: {
					type: 'rate'}},form: {}}}.methods: {
        setFormDesc (data) { / / render the form
			const formDesc = {}
			const form = {}
			data.forEach((item, index) = > {
				formDesc[item.code] = {
					type: formType[item.dataType],
					label: item.label,
					allowCustom: item.allowCustom,
					attr: {
						placeholder: item.placeholder,
						inputAlign: 'right'.customIntentionId: item.customIntentionId,
						id: item.id,
						code: item.code
					}
				}

				if (formType[item.dataType] === 'region') { // region processing
					let splitArr = []
					let data = {
						province: {
							label: ' '
						},
						city: {
							label: ' '
						},
						area: {
							label: ' '}}if (item.customerIntentionValue) {
						splitArr = item.customerIntentionValue.split('|')}else if (item.initData) {
						splitArr = item.initData.split('|')}if (splitArr.length) {
						data = {
							province: {
								label: splitArr[0]},city: {
								label: splitArr[1]},area: {
								label: splitArr[2]
							}
						}
					}
					form[item.code] = data
				} else if (formType[item.dataType] === 'PropertyType') { // Label type special processing
					const data = []
					let splitArr = item.initData ? item.initData.split('|') : []
					let splitSelectedArr = item.customerIntentionValue ? item.customerIntentionValue.split('|') : []
					// if (item.customerIntentionValue) {
					// splitArr = item.customerIntentionValue.split('|')
					// } else if (item.initData) {
					// splitArr = item.initData.split('|')
					// }
				
					if(item.allowCustom && splitSelectedArr ! = =' ') {	// Back end requirements, custom tags only selected
						splitSelectedArr.forEach(el= > {
							let tagItem = {
								text: el,
								selected: true
							}
							data.push(tagItem)
						})
						form[item.code] = data
						return
					}
					if(splitArr ! = =' ') { // Common tags
						splitArr.forEach(el= > { / / assignment
							let tagItem = {
								text: el,
								selected: false
							}
							if(splitSelectedArr ! = =' ') {
								let splitSelected = splitSelectedArr.find(selectedItem= > selectedItem === el)
								if (splitSelected) {
									tagItem.selected = true
								}
							}
							data.push(tagItem)
						})
					}
					form[item.code] = data
				} else if (formType[item.dataType] === 'rate') { // Convert the string passed from the back end
					form[item.code] = Number(item.customerIntentionValue) || Number(item.initData)
				} else {
					form[item.code] = item.customerIntentionValue || item.initData
				}
			})
			this.formDesc = formDesc
			this.form = form
		}
    }
}
</script>
Copy the code