index.vue 11.7 KB
Newer Older
JingChao's avatar
JingChao committed
1 2 3 4 5 6 7 8
/**
* @Author think
* @Date 2019-07-16 20:00
*/

<template>
  <section class="h-form">
    <s-tab
JingChao's avatar
JingChao committed
9
      v-for="com in layoutConfig" v-if="com.configType==='Stab' && com.layoutFiledList.length"
JingChao's avatar
JingChao committed
10
      :key="com.configId"
JingChao's avatar
JingChao committed
11
      :default-active="tabIndex" :class="com.cssClass" :has-border="showTabBorder"
JingChao's avatar
JingChao committed
12 13 14
      :show-divider="showTabDivider"
      @tabClick="layoutTabClick"
      @click.native="tabNativeClick(com)">
JingChao's avatar
JingChao committed
15 16 17
      <tab-item v-for="tab in com.layoutFiledList" :key="tab.filedId">
        <section v-html="tab.tabContent || tab.filedName"/>
      </tab-item>
JingChao's avatar
JingChao committed
18 19
    </s-tab>
    <h-content :class="{'has-footer':hasBottom}">
JingChao's avatar
JingChao committed
20 21
      <template v-for="(com, index) in layoutConfig">
        <list-item
JingChao's avatar
JingChao committed
22
          v-if="com.configType==='Form' && com.layoutFiledList.length" v-show="checkFromHide(com)"
JingChao's avatar
JingChao committed
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
          :class="com.cssClass" :key="com.configId">
          <item v-show="showFormTitle" class="form-title" @click.native="hideFormClick(index)">
            <div slot="name">{{ com.configName }}</div>
            <img
              slot="right-icon" :class="{'hide-down-icon':!com.hideForm,'hide-up-icon':com.hideForm}"
              class="right-icon " src="./right-arrow@2x.png">
          </item>
          <item
            v-for="filed in com.layoutFiledList"
            v-show="!com.hideForm" :key="filed.filedId" :class="filed.cssClass" :has-border="filed.hasBorder"
            :showContent="filed.showContent" :proportion="proportionArray(filed.proportion)" :showName="filed.showName"
            :showArrow="filed.showArrow"
            :item-height="filed.filedHeight">
            <img v-if="filed.leftIcon" slot="left-icon" :src="filed.leftIcon" class="left-icon">
            <div slot="name" :class="{'required':filed.inputMode=='required'}">{{ filed.filedName }}</div>
            <input
              v-if="filed.filedType==='INPUT'" slot="content"
40
              :readonly="filedReadOnly(filed)"
JingChao's avatar
JingChao committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
              :placeholder="filed.placeholder" v-model="data[com.configCode][filed.filedCode]" :type="filed.inputType"
              :name="filed.filedCode">
            <input
              v-else-if="filed.filedType==='SELECT'"
              slot="content" :name="filed.filedCode"
              v-model="data[com.configCode][filed.filedCode+'_n']" :placeholder="filed.placeholder" readonly
              @click="showSelect(com,filed)">
            <input
              v-else-if="filed.filedType=='TIME'"
              slot="content" :name="filed.filedCode"
              v-model="data[com.configCode][filed.filedCode]" :placeholder="filed.placeholder" readonly
              @click="showTime(com,filed)">
            <h-switch
              v-else-if="filed.filedType==='SWITCH'" slot="content" v-model="data[com.configCode][filed.filedCode]"
              :name="filed.filedCode"
56 57 58 59 60
              :disable="filedReadOnly(filed)"/>
            <h-check
              v-else-if="filed.filedType==='CHECKBOX'" slot="content" v-model="data[com.configCode][filed.filedCode]"
              :name="filed.filedCode"
              :disable="filedReadOnly(filed)"/>
JingChao's avatar
JingChao committed
61 62 63 64
            <div v-else slot="content" @click="filedClick(com,filed)" v-html="data[com.configCode][filed.filedCode]"/>
            <img v-if="filed.rightIcon" slot="right-icon" :src="filed.rightIcon" class="right-icon">
          </item>
        </list-item>
65 66 67 68 69 70 71 72 73 74
        <template v-if="showBtn">
          <section v-if="com.configType==='Button' && com.layoutFiledList.length" class="layout-button">
            <h-button
              v-for="btn in com.layoutFiledList"
              :key="btn.filedId" :class="btn.cssClass"
              size="normal" @click.native="btnClick(com,btn)">
              <section v-html="btn.btnContent || btn.filedName"/>
            </h-button>
          </section>
        </template>
JingChao's avatar
JingChao committed
75
      </template>
JingChao's avatar
JingChao committed
76
    </h-content>
77 78 79 80 81 82 83 84 85 86 87 88
    <template v-if="showBtn">
      <bottom-tab
        v-for="(com, index) in layoutConfig" v-if="com.configType==='BottomTab' && com.layoutFiledList.length"
        :key="index" :show-divider="showBtnDivider"
        :class="com.cssClass">
        <tab-button
          v-for="btn in com.layoutFiledList" :key="btn.filedId" :disabled="filedReadOnly(btn)" :class="btn.cssClass"
          @click.native="btnClick(com,btn)">
          <section v-html="btn.btnContent || btn.filedName"/>
        </tab-button>
      </bottom-tab>
    </template>
JingChao's avatar
JingChao committed
89 90 91 92
  </section>
</template>
<script>
export default {
JingChao's avatar
JingChao committed
93
  name: 'HLayout',
JingChao's avatar
JingChao committed
94 95 96 97 98 99 100 101 102 103 104
  props: {
    layoutData: {
      type: Array,
      default: () => [],
    },
    showFormTitle: {
      type: Boolean,
      default: true,
    },
    showTabDivider: {
      type: Boolean,
JingChao's avatar
JingChao committed
105
      default: true,
JingChao's avatar
JingChao committed
106 107 108 109 110 111 112 113 114
    },
    showTabBorder: {
      type: Boolean,
      default: false,
    },
    showBtnDivider: {
      type: Boolean,
      default: true,
    },
115 116 117 118
    showBtn: {
      type: Boolean,
      default: true,
    },
JingChao's avatar
JingChao committed
119 120 121 122
    formData: {
      type: Object,
      default: () => {},
    },
123 124 125 126
    readOnly: {
      type: Boolean,
      default: false,
    },
JingChao's avatar
JingChao committed
127 128 129 130 131 132 133 134 135 136 137 138
  },
  data () {
    return {
      tabIndex: 0,
      data: {},
      layoutConfig: [],
      activeTab: null,
      activeTabFiled: null,
      hasBottom: false,
    }
  },
  computed: {
JingChao's avatar
JingChao committed
139

JingChao's avatar
JingChao committed
140
  },
JingChao's avatar
JingChao committed
141 142 143 144 145
  /**
   * 通过布局代码解析出form表单中定义了那些字端。取出字端的默认值等
   * 取出布局中的全部按钮,返回给父组件,用于按钮逻辑的处理
   * 取出后通过$set以及$email函数把值传递给父组件
   */
JingChao's avatar
JingChao committed
146 147 148 149
  created () {
    let vm = this
    if (vm.layoutData.length && vm.layoutData[0].layoutConfigList.length) {
      vm.layoutConfig = vm.layoutData[0].layoutConfigList
JingChao's avatar
JingChao committed
150
      let btns = []
JingChao's avatar
JingChao committed
151
      vm.layoutConfig.forEach((com, index) => {
JingChao's avatar
JingChao committed
152
        if (com.configType === 'BottomTab') {
JingChao's avatar
JingChao committed
153 154
          vm.hasBottom = true
        }
JingChao's avatar
JingChao committed
155
        if (com.configType === 'Form') {
JingChao's avatar
JingChao committed
156 157 158
          let form = com
          let temp = {}
          if (form.layoutFiledList.length) {
JingChao's avatar
JingChao committed
159 160 161
            let fileds = form.layoutFiledList
            fileds.forEach((filed, index) => {
              if (vm.formData[form.configCode] && (vm.formData[form.configCode][filed.filedCode] !== undefined)) {
JingChao's avatar
JingChao committed
162
                temp[filed.filedCode] = vm.formData[form.configCode][filed.filedCode]
JingChao's avatar
JingChao committed
163
                if (filed.filedType === 'SELECT') {
JingChao's avatar
JingChao committed
164 165
                  temp[filed.filedCode + '_n'] = vm.formData[form.configCode][filed.filedCode + '_n']
                }
JingChao's avatar
JingChao committed
166 167 168 169 170 171
              } else {
                if (filed.filedType === 'SELECT') {
                  temp[filed.filedCode] = filed.defaultValue
                  temp[filed.filedCode + '_n'] = filed.defaultValueN
                } else if (filed.filedType === 'SWITCH') {
                  temp[filed.filedCode] = !!filed.defaultValue
172 173
                } else if (filed.filedType === 'CHECKBOX') {
                  temp[filed.filedCode] = !!filed.defaultValue
JingChao's avatar
JingChao committed
174 175 176
                } else {
                  temp[filed.filedCode] = filed.defaultValue
                }
JingChao's avatar
JingChao committed
177 178
              }
            })
JingChao's avatar
JingChao committed
179 180 181 182
            // 保留父组件data的值
            if (vm.formData[form.configCode]) {
              temp = Object.assign(temp, vm.formData[form.configCode])
            }
JingChao's avatar
JingChao committed
183 184
            vm.$set(vm.data, [form.configCode], temp)
          }
JingChao's avatar
JingChao committed
185
        } else if (com.configType === 'Stab') {
JingChao's avatar
JingChao committed
186 187
          vm.activeTab = com.configCode
          vm.activeTabFiled = com.layoutFiledList.length ? com.layoutFiledList[vm.tabIndex].filedCode : ''
JingChao's avatar
JingChao committed
188
        } else if (com.configType === 'Button' || com.configType === 'BottomTab') {
JingChao's avatar
JingChao committed
189 190 191 192 193 194 195 196
          if (com.layoutFiledList.length) {
            let btnFileds = com.layoutFiledList
            btnFileds.forEach((btnFiled, index) => {
              let btn = {'btnType': com.configType, 'btnCode': btnFiled.filedCode, 'btnName': btnFiled.filedName}
              btns.push(btn)
            })
            vm.$set(vm.data, 'btns', btns)
          }
JingChao's avatar
JingChao committed
197 198 199 200 201 202
        }
      })
      vm.$emit('input', vm.data)
    }
  },
  methods: {
203 204 205 206
    filedReadOnly (filed) {
      let vm = this
      return vm.readOnly ? true : (filed.inputMode === 'readOnly')
    },
JingChao's avatar
JingChao committed
207 208 209 210 211
    /**
     * item左右距离查询出来为字符串 在此转换为数组
     * @param proportion
     * @returns {*}
     */
JingChao's avatar
JingChao committed
212 213 214
    proportionArray (proportion) {
      return proportion.split(',')
    },
JingChao's avatar
JingChao committed
215 216 217 218
    /**
     * STAB的点击事件
     * @param index
     */
JingChao's avatar
JingChao committed
219 220 221 222 223
    layoutTabClick (index) {
      let vm = this
      vm.tabIndex = index
      this.$emit('tabClick', index)
    },
JingChao's avatar
JingChao committed
224 225 226 227
    /**
     * tab的点击事件用于判断当前的哪个tab的哪个子元素是活跃状态,用于动态切换显示form
     * @param com 当前组件
     */
JingChao's avatar
JingChao committed
228 229 230 231 232
    tabNativeClick (com) {
      let vm = this
      vm.activeTab = com.configCode
      vm.activeTabFiled = com.layoutFiledList.length ? com.layoutFiledList[vm.tabIndex].filedCode : ''
    },
JingChao's avatar
JingChao committed
233 234 235 236 237
    /**
     * 根据tab的显示动态判断tab下的form显示情况
     * @param com 当前的form组件
     */
    checkFromHide (com) {
JingChao's avatar
JingChao committed
238 239 240 241 242
      let vm = this
      if (com.tabConfigCode && com.tabFiledCode) {
        if (com.tabConfigCode === vm.activeTab && com.tabFiledCode === vm.activeTabFiled) {
          return true
        }
JingChao's avatar
JingChao committed
243 244
      }
      return false
JingChao's avatar
JingChao committed
245
    },
JingChao's avatar
JingChao committed
246 247 248 249 250 251 252 253 254 255 256 257 258
    /**
     * Form title点击事件用于隐藏form下的内容
     * @param index
     */
    hideFormClick (index) {
      let vm = this
      vm.layoutConfig[index]['hideForm'] = !vm.layoutConfig[index]['hideForm']
    },
    /**
     * 下拉框点击函数 交由父组件处理 传递父组件当前点击对象以及字端名
     * @param com 当前组件
     * @param filed 当前字端
     */
JingChao's avatar
JingChao committed
259
    showSelect (com, filed) {
260
      if (this.readOnly) return
JingChao's avatar
JingChao committed
261 262 263
      if (filed.inputMode !== 'readOnly') {
        this.$emit('showSelect', com.configCode, filed.filedCode)
      }
JingChao's avatar
JingChao committed
264
    },
JingChao's avatar
JingChao committed
265 266 267 268 269
    /**
     * 时间点击函数 交由父组件处理 传递父组件当前点击对象以及字端名
     * @param com 当前组件
     * @param filed 当前字端
     */
JingChao's avatar
JingChao committed
270
    showTime (com, filed) {
271
      if (this.readOnly) return
JingChao's avatar
JingChao committed
272 273 274
      if (filed.inputMode !== 'readOnly') {
        this.$emit('showTime', com.configCode, filed.filedCode)
      }
JingChao's avatar
JingChao committed
275
    },
JingChao's avatar
JingChao committed
276 277 278 279 280 281
    /**
     * 其他非input的字端点击函数 用于超链接等其他字端的逻辑处理 暴露给父组件一个点击事件传递父组件当前点击对象以及字端名
     * @param com 当前组件
     * @param filed 当前字端
     */
    filedClick (com, filed) {
282 283 284
      if (!this.readOnly) {
        this.$emit('filedClick', com.configCode, filed.filedCode)
      }
JingChao's avatar
JingChao committed
285 286 287 288 289 290 291
    },
    /**
     * 按钮点击事件 交由父组件处理 传递当前的按钮对象
     * @param com 当前组件
     * @param filed 当前字端
     */
    btnClick (com, filed) {
292 293 294 295 296 297 298 299 300
      if (!this.readOnly) {
        let btnType = com.configType
        let btnCode = filed.filedCode
        this.data.btns.forEach((btn, index) => {
          if (btn.btnType === btnType && btn.btnCode === btnCode) {
            this.$emit('btnClick', btn)
          }
        })
      }
JingChao's avatar
JingChao committed
301
    },
JingChao's avatar
JingChao committed
302 303 304 305
  },
}
</script>

JingChao's avatar
JingChao committed
306
<style lang="less">
JingChao's avatar
JingChao committed
307 308 309 310
  .h-form {
    .hls-switch-tab {
      .tab-content {
        .h-tab-item {
JingChao's avatar
JingChao committed
311 312
          .h-item {
            img {
JingChao's avatar
JingChao committed
313 314 315 316 317 318
              width: 20px;
            }
          }
        }
      }
    }
JingChao's avatar
JingChao committed
319

JingChao's avatar
JingChao committed
320 321 322 323 324 325 326 327
    .content {
      .form-title {
        .contents {
          .add-name {
            font-weight: 500;
          }
        }
      }
JingChao's avatar
JingChao committed
328 329 330 331 332 333 334 335 336 337 338 339
      .layout-button{
        margin-top: 30px;
        display: flex;
        justify-content: center;
        .hls-h-button{
          width: 50%;
          border-radius: 20px;
          background-color:@theme-color;
          border: none;
          color: #fff;
        }
      }
JingChao's avatar
JingChao committed
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360

      .hls-item {
        .contents {
          .add-content {
            .right-icon {
              height: 12px;
            }

            .hide-up-icon {
              transform: rotate(90deg);
            }

            .hide-down-icon {
              transform: rotate(-90deg);
            }
          }
        }
      }
    }
  }
</style>