seriesForm.vue 9.92 KB
<template>
  <view>
    <!-- :label-style="{'width':'120rpx','overflow':'hidden','text-overflow':'ellipsis','white-space':'nowrap',display:'block'}" label-width="120rpx" -->
    <u-form :model="seriesForm" ref="seriesRef">
      <u-form-item style="display: flex" v-for="(item, index) in seriesFunctionList" label-position="left" :key="item.identifier" :prop="item.identifier">
        <view v-if="!isTCPTransport"" :class="Array.isArray(item.dataType.specs)?'positionTop':'positionLeft'">
          <view class="text">{{ item.functionName }}</view>
          <u-input
            v-if="item.dataType.type == 'INT' || item.dataType.type == 'DOUBLE'"
            shape="circle"
            type="number"
            v-model.number="seriesForm[item.identifier]"
            :placeholder="`${$t('common.inputText')}${item.functionName}`"
            @blur="(e)=>handleBlur(e,item.identifier)"
          />
          <u-input v-if="item.dataType.type == 'TEXT'" shape="circle" type="text" v-model="seriesForm[item.identifier]" :placeholder="`请输入${item.functionName}`" />
          <view v-if="item.dataType.type == 'BOOL'" @click="handleBool(item.functionName, item.dataType, index)">
            <u-input
              shape="circle"
              v-model="seriesForm[item.identifier]"
              :placeholder="`${$t('common.chooseText')}${item.functionName}`"
              disabled
              disabledColor="#fff"
              suffixIcon="arrow-down"
            />
            <u-picker
              :show="showPickerView"
              :columns="[boolList]"
              keyName="label"
              @cancel="handleCancelBool(index)"
              @close="handleCancelBool(index)"
              @confirm="(e) => handleSelectBool(e, item.identifier, index)"
            ></u-picker>
          </view>
          <view v-if="item.dataType.type == 'ENUM'" @click="handleEnum(item.functionName, item.dataType, index)">
            <u-input
              shape="circle"
              v-model="seriesForm[item.identifier]"
              :placeholder="`${$t('common.chooseText')}${item.functionName}`"
              disabled
              disabledColor="#fff"
              suffixIcon="arrow-down"
            />
            <u-picker
              :show="showPickerView"
              :columns="[enumList.map((item) => ({ label: item.name, value: item.value }))]"
              keyName="label"
              @cancel="handleCancelEnum(index)"
              @close="handleCancelEnum(index)"
              @confirm="(e) => handleSelectEnum(e, item.identifier, index)"
            ></u-picker>
          </view>
          <template v-if="Array.isArray(item.dataType.specs)">
            <structuralForm class="seriesForm" :ref="item.identifier" :seriesInputData="item.dataType.specs || []"></structuralForm>
          </template>
        </view>
        <view v-else class="positionLeft" style=" border: 1px dashed #f0f0f0; padding: 20rpx;">
          <view class="text">{{ $t('device.serviceCommand') }}</view>
          <u-input v-model="seriesForm.serviceCommand" type="text" shape="circle" :disabled="true"></u-input>
        </view>
      </u-form-item>
    </u-form>
  </view>
</template>

<script>
import structuralForm from './structuralForm.vue'
export default {
  name: 'StructForm',
  props: {
    seriesInputData: {
      type: Array,
      default: () => [],
    },
    isTCPTransport:{
      type:Boolean,
      default:false
    }
  },
  components: {
    structuralForm,
  },
  data() {
    return {
	  showPickerView:false,
      boolInfo: {},
      enumInfo: {},
      seriesForm: {},
      seriesRules: {},
      seriesFunctionList: [],
      boolList: [],
      enumList: [],
    }
  },
  async mounted() {
    await this.$nextTick(() => {
      this.createInit()
    })
  },
  watch: {
    seriesInputData: {
      deep: true,
      handler(newVal, oldVal) {
        this.createInit()
      },
    },
  },

  methods: {
    createInit() {
      this.seriesForm = {}
      this.boolInfo = {}
      this.seriesFunctionList = this.seriesInputData
      for(const item of this.seriesInputData){
        this.$set(item, 'isShowModel', false)//动态添加picker的控制变量
        const {
          dataType,
          identifier,
          functionName,
          serviceCommand
        } = item || {}
        const {specs,type} = dataType || {}
        if(this.isTCPTransport){
          this.$set(this.seriesForm,'serviceCommand',serviceCommand)
          break;
        }
        if (Array.isArray(specs)) {
          specs.forEach((itemSpecs) => {
            this.$set(this.seriesForm, identifier, {
              [itemSpecs.identifier]: '',
            })
          })
        } else {
          this.$set(this.seriesForm, identifier, '')
        }

        //设置验证规则
        const { valueRange, length = 10240 } = specs || {}
        const { max = 2147483647, min = -2147483647 } = valueRange || {}
        if (type !== 'STRUCT') {
          this.seriesRules[identifier] = [
            { required: true, message: type == 'BOOL' || type == 'ENUM' ? this.$t('common.chooseText') : this.$t('common.inputText') + functionName },
            type == 'INT' || type == 'DOUBLE'
              ? {
                  type: 'number',
                  trigger: 'change',
                  validator: (_rule, value) => {
                    const reg = /^[0-9]*$/
                    if (!reg.test(value)) return Promise.reject(new Error(`${functionName}${this.$t('device.notANumber')}`))
                    if (value < min || value > max) return Promise.reject(new Error(`${functionName}${this.$t('device.rangeValues',{min,max})}`))

                    return Promise.resolve(value)
                  },
                }
              : type == 'TEXT'
              ? {
                  type: 'string',
                  trigger: 'change',
                  validator: (_rule, value) => {
                    if ((value?.length || 0) > length) return Promise.reject(new Error(`${functionName}${this.$t('device.dataLengthLess')}${length}`))

                    return Promise.resolve(value)
                  },
                }
              : {},
          ]
        }
      }
      //设置验证规则
      this.$nextTick(() => {
        !this.isTCPTransport && this.$refs.seriesRef.setRules(this.seriesRules)
      })
    },
    isEmptyObject(obj) {
      return Object.keys(obj).length === 0 && obj.constructor === Object
    },

    //打开Bool的picker
    handleBool(name, dataType, num) {
      this.seriesFunctionList.forEach((item, index) => {
        if (index == num) {
			this.showPickerView = true
            item.isShowModel = true
        }
      })
      const { specs } = dataType || {}
      const { boolClose, boolOpen } = specs || {}
      if(!boolClose&&!boolOpen){
        uni.$u.toast(this.$t('device.noCurrently') + name)
        this.boolList = []
        return 
      }
      this.boolList = [
        { label: boolClose + '-0', value: 0 },
        { label: boolOpen + '-1', value: 1 },
      ]
    },
    handleSelectBool(e, name, num) {
      const { value } = e || {}
      this.boolInfo[name] = value[0].value
      this.$set(this.seriesForm, name, value[0].label)
      this.seriesFunctionList.forEach((item, index) => {
        if (index == num) {
          item.isShowModel = false
		  this.showPickerView = false
        }
      })
    },
    handleBlur(value,name){
      if(!value) return
      this.$set(this.seriesForm,name,Number(value))
    },

    //打开Enum的picker
    handleEnum(name, dataType, num) {
      const { specsList } = dataType || {}
      this.enumList = specsList || []
      console.log(this.enumList,'enumInfo')
      if(!this.enumList.length){
        return uni.$u.toast(this.$t('device.noCurrently') + name)
      }
      this.seriesFunctionList.forEach((item, index) => {
        if (index == num) {
          item.isShowModel = true
		  this.showPickerView = true
        }
      })
    },
    //确定选中
    handleSelectEnum(e, name, num) {
      const { value } = e || {}
      this.enumInfo[name] = value[0].value
      this.$set(this.seriesForm, name, value[0].label)
      this.seriesFunctionList.forEach((item, index) => {
        if (index == num) {
          item.isShowModel = false
		  this.showPickerView = false
        }
      })
    },

    
    //关闭Enum和Bool的picker弹框
    handleCancelEnum(num){
      this.seriesFunctionList.forEach((item, index) => {
        if (index == num) {
          item.isShowModel = false
		  this.showPickerView = false
        }
      })
    }, 
    handleCancelBool(num){
      this.seriesFunctionList.forEach((item, index) => {
        if (index == num) {
          item.isShowModel = false
		  this.showPickerView = false
        }
      })
    },

    // 获取表单数据
    getFormField() {
      const keys = Object.keys(this.seriesForm)
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i]
        if (Array.isArray(this.$refs[key])) {
          const values = this.$refs[key][0]?.getFormField()
          if (!this.isEmptyObject(values)) {
            this.seriesForm[key] = values
          }
        }
      }
      return {
        ...this.seriesForm,
        ...this.boolInfo,
        ...this.enumInfo,
      }
    },


    handleValidate() {
      const keys = Object.keys(this.seriesForm)
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i]
        if (Array.isArray(this.$refs[key])) {
          this.$refs[key][0]?.handleValidate(valid=>{
            if(!valid) return false
          })
        } else {
          this.$refs.seriesRef.validate(valid=>{
            if(!valid) return false
          })
        }
        return true
      }
    },
  },
}
</script>

<style lang="scss" scoped>
.positionLeft {
  display: flex;
  align-items: center;
  .text{
    
  max-width: 190rpx;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  }
}

.positionTop {
  display: flex;
  flex-direction: column;
  border: 1px dashed #f0f0f0;
  padding: 20rpx;
  .seriesForm{
    margin-left:30rpx
  }
}
</style>