<template>
  <el-form
    style="display: inline-block; width: 100%"
    :inline="true"
    ref="mesform"
    @submit.prevent
    :model="formFields"
    :label-width="labelWidth"
    :rules="rules"
  >
    <template v-for="(row, findex) in formRules" :key="findex">
      <div class="mes-form-item">
        <el-form-item
          :label="item.title ? item.title + '：' : ''"
          v-show="!item.hidden"
          v-for="(item, index) in row"
          :prop="item.field"
          :key="item.field + index"
          :style="{ width: getColWidth(item) + '%' }"
        >
          <!-- render -->
          <form-expand
            v-if="item.render && typeof item.render == 'function'"
            :render="item.render"
            :par="12"
          ></form-expand>
          <!-- 2021.10.17增加表单实时方法计算 -->
          <span
            v-else-if="
              item.readonly && typeof formFields[item.field] == 'function'
            "
            >{{ formFields[item.field]() }}</span
          >
          <!-- 只读图片或文件  -->
          <div v-else-if="isReadonlyImgFile(item, formFields)">
            <div v-if="item.type == 'img'" class="form-imgs">
              <div
                class="img-item"
                v-for="(img, imgIndex) in formFields[item.field]"
                :key="imgIndex"
              >
                <img
                  :src="getSrc(img.path)"
                  :onerror="errorImg"
                  @click="previewImg(img.path)"
                />
              </div>
            </div>
            <div
              v-else
              class="form-file-list"
              v-for="(file, fileIndex) in formFields[item.field]"
              :key="fileIndex"
            >
              <a @click="dowloadFile(formFields[item.field][fileIndex])">{{
                file.name
              }}</a>
            </div>
          </div>

          <div v-else :class="{ 'form-item-extra': item.extra }">
            <!-- 只读属性 -->
            <label
              :style="item.inputStyle"
              v-if="item.type == 'label'"
              class="readonly-input"
              >{{ getText(formFields, item) }}</label
            >
            <!-- 20223.05.13集成el-tree-select -->
            <!-- :filter-method="(value)=>{filterMethod(value,item.data)}" -->
            <!-- :filterable="true" -->
            <el-tree-select
              style="width: 100%"
              v-else-if="item.type == 'treeSelect'"
              v-model="formFields[item.field]"
              :data="item.data"
              :multiple="item.multiple"
              :render-after-expand="false"
              :show-checkbox="false"
              :check-strictly="true"
              check-on-click-node
              node-key="key"
              :props="{ label: 'label' }"
            >
              <template #default="{data,node }">
                <!-- <el-checkbox v-model="node.checked"></el-checkbox> -->
               <!-- {{getNode(node, data)}} -->
               <!-- {{node.checked}} -->
               <!-- 这里还有点问题，后面处理 -->
                {{  data.label}}</template
              >
            </el-tree-select>
            <template
              v-else-if="['select', 'selectList'].indexOf(item.type) != -1"
            >
              <el-select-v2
                :disabled="item.readonly || item.disabled"
                v-show="!item.hidden"
                style="width: 100%"
                :size="size"
                v-if="item.data.length > select2Count"
                v-model="formFields[item.field]"
                filterable
                :multiple="item.type == 'select' ? false : true"
                :placeholder="item.placeholder ? item.placeholder : item.title"
                :allow-create="item.autocomplete"
                :options="item.data"
                @change="
                  (val) => {
                    item.onChange(val, item.data);
                  }
                "
                clearable
              >
                <template #default="{ item }">
                  {{ item.label }}
                </template>
              </el-select-v2>
              <el-select
                :disabled="item.readonly || item.disabled"
                v-show="!item.hidden"
                style="width: 100%"
                :size="size"
                v-else-if="item.remote || item.url"
                v-model="formFields[item.field]"
                filterable
                :multiple="item.type == 'select' ? false : true"
                :placeholder="item.placeholder ? item.placeholder : item.title"
                clearable
                :remote-method="
                  (val) => {
                    remoteSearch(item, formFields, val);
                  }
                "
              >
                <el-option
                  v-for="item in item.data"
                  :key="item.key"
                  :label="item.value"
                  :value="item.key"
                >
                </el-option>
              </el-select>
              <el-select
                :disabled="item.readonly || item.disabled"
                v-show="!item.hidden"
                style="width: 100%"
                :size="size"
                v-else
                v-model="formFields[item.field]"
                filterable
                :multiple="item.type == 'select' ? false : true"
                :placeholder="item.placeholder ? item.placeholder : item.title"
                :allow-create="item.autocomplete"
                @change="
                  (val) => {
                    item.onChange(val, item.data);
                  }
                "
                clearable
              >
                <el-option
                  v-show="!item.hidden"
                  :disabled="item.disabled"
                  v-for="item in item.data"
                  :key="item.key"
                  :label="item.value"
                  :value="item.key"
                >
                </el-option>
              </el-select>
            </template>
            <el-switch
              v-show="!item.hidden"
              v-else-if="item.type == 'switch'"
              v-model="formFields[item.field]"
              :disabled="item.readonly || item.disabled"
              active-color="#0f84ff"
              @change="item.onChange"
              inactive-color="rgb(194 194 194)"
              :active-value="
                typeof formFields[item.field] == 'boolean'
                  ? true
                  : typeof formFields[item.field] == 'string'
                  ? '1'
                  : 1
              "
              :inactive-value="
                typeof formFields[item.field] == 'boolean'
                  ? false
                  : typeof formFields[item.field] == 'string'
                  ? '0'
                  : 0
              "
            >
            </el-switch>

            <el-radio-group
              :disabled="item.readonly || item.disabled"
              v-show="!item.hidden"
              v-model="formFields[item.field]"
              v-else-if="item.type == 'radio'"
              @change="item.onChange"
            >
              <el-radio
                v-for="kv in item.data"
                :disabled="item.readonly || item.disabled"
                :key="kv.key"
                :label="kv.key"
                >{{ kv.value }}</el-radio
              >
            </el-radio-group>

            <el-checkbox-group
              :disabled="item.readonly || item.disabled"
              v-show="!item.hidden"
              v-model="formFields[item.field]"
              v-else-if="item.type == 'checkbox'"
              @change="item.onChange"
            >
              <el-checkbox
                v-for="kv in item.data"
                :key="kv.key"
                :disabled="item.readonly || item.disabled"
                :label="kv.key"
                >{{ kv.value }}</el-checkbox
              >
            </el-checkbox-group>
            <div
              class="v-date-range"
              style="display: flex"
              v-else-if="
                ['date', 'datetime'].indexOf(item.type) != -1 && item.range
              "
            >
              <el-date-picker
                :size="size"
                :disabled="item.readonly || item.disabled"
                style="flex: 1; width: auto"
                v-model="formFields[item.field][0]"
                :type="item.type == 'date' ? 'date' : 'datetime'"
                :disabledDate="(val) => getDateOptions(val, item)"
                placeholder="开始时间"
                @change="
                  (val) => {
                    dateRangeChange(val, item);
                  }
                "
                :value-format="getDateFormat(item)"
              >
              </el-date-picker>
              <span style="margin: 0px 5px; font-size: 13px; color: #6f6b6b"
                >至</span
              >
              <el-date-picker
                :size="size"
                :disabled="item.readonly || item.disabled"
                style="flex: 1; width: auto"
                v-model="formFields[item.field][1]"
                placeholder="结束时间"
                :type="item.type == 'date' ? 'date' : 'datetime'"
                :disabledDate="(val) => getDateOptions(val, item)"
                @change="
                  (val) => {
                    dateRangeChange(val, item);
                  }
                "
                :value-format="getDateFormat(item)"
              >
              </el-date-picker>
            </div>
            <!-- v-show不添加根节点就会报错没有根点节 -->
            <div
              v-show="!item.hidden"
              style="width: 100%"
              v-else-if="['date', 'datetime', 'month'].indexOf(item.type) != -1"
            >
              <el-date-picker
                :size="size"
                clearable
                :disabled="item.readonly || item.disabled"
                style="width: 100%"
                v-model="formFields[item.field]"
                @change="item.onChange"
                :type="item.type"
                :placeholder="
                  item.placeholder ? item.placeholder : '请选择' + item.title
                "
                :disabledDate="(val) => getDateOptions(val, item)"
                :value-format="getDateFormat(item)"
              >
              </el-date-picker>
            </div>

            <el-time-picker
              :size="size"
              v-else-if="item.type == 'time'"
              v-model="formFields[item.field]"
              :disabled="item.readonly || item.disabled"
              placeholder="请选择时间"
              :value-format="item.format || 'HH:mm:ss'"
              :format="item.format"
              style="width: 100%"
            >
            </el-time-picker>

            <el-scrollbar
              style="border: 1px solid #c7d8db; border-radius: 5px"
              :height="item.height || 150"
              v-else-if="
                item.type == 'editor' && (item.readonly || item.disabled)
              "
            >
              <div ref="editor" v-html="formFields[item.field]"></div>
            </el-scrollbar>
            <mes-wang-editor
              ref="editor"
              v-else-if="item.type == 'editor'"
              :url="item.url || editor.uploadImgUrl"
              :upload="item.upload || editor.upload"
              v-model="formFields[item.field]"
              :height="item.height || 350"
            ></mes-wang-editor>

            <mes-upload
              v-show="!item.hidden"
              v-else-if="isFile(item, formFields)"
              :desc="item.desc"
              :multiple="item.multiple"
              :max-file="item.maxFile"
              :max-size="item.maxSize"
              :autoUpload="item.autoUpload"
              :fileInfo="formFields[item.field]"
              :url="item.url"
              :img="item.type == 'img' || item.columnType == 'img'"
              :excel="item.type == 'excel'"
              :fileTypes="item.fileTypes ? item.fileTypes : []"
              :upload-before="item.uploadBefore"
              :upload-after="item.uploadAfter"
              :append="item.multiple"
              :on-change="
                (files) => {
                  return fileOnChange(files, item);
                }
              "
              :file-click="item.fileClick"
              :remove-before="item.removeBefore"
              :downLoad="item.downLoad ? true : false"
            ></mes-upload>
            <el-cascader
              :size="size"
              clearable
              style="width: 100%"
              v-model="formFields[item.field]"
              :disabled="item.readonly || item.disabled"
              v-else-if="item.type == 'cascader'"
              :options="item.data"
              :props="{
                checkStrictly: item.changeOnSelect || item.checkStrictly
              }"
              @change="item.onChange"
            >
            </el-cascader>
            <el-rate
              v-else-if="item.type == 'rate'"
              @change="
                (val) => {
                  item.onChange && item.onChange(val);
                }
              "
              :max="item.max"
              v-model="formFields[item.field]"
            />
            <div
              style="display: flex"
              v-else-if="item.type == 'range' || item.range"
            >
              <el-input
                :size="size"
                :disabled="item.readonly || item.disabled"
                style="flex: 1"
                v-model="formFields[item.field][0]"
                clearable
              />
              <span style="margin: 0 5px">-</span>
              <el-input
                :size="size"
                :disabled="item.readonly || item.disabled"
                style="flex: 1"
                v-model="formFields[item.field][1]"
                clearable
              />
            </div>
            <el-input
              :size="size"
              clearable
              :ref="item.field"
              :input-style="item.inputStyle"
              :disabled="item.readonly || item.disabled"
              v-else-if="item.type == 'textarea'"
              v-model="formFields[item.field]"
              type="textarea"
              :autosize="{
                minRows: item.minRows || 2,
                maxRows: item.maxRows || 10
              }"
              :placeholder="item.placeholder ? item.placeholder : item.title"
            />
            <el-input-number
              :size="size"
              style="width: 100%"
              :ref="item.field"
              :input-style="item.inputStyle"
              v-else-if="item.type == 'number'"
              v-model="formFields[item.field]"
              :min="item.min"
              :disabled="item.readonly || item.disabled"
              :max="item.max"
              controls-position="right"
            />
            <el-input
              :size="size"
              clearable
              :input-style="item.inputStyle"
              v-else-if="item.type == 'password'"
              type="password"
              v-model="formFields[item.field]"
              :disabled="item.readonly || item.disabled"
              v-show="!item.hidden"
              :placeholder="item.placeholder ? item.placeholder : item.title"
            />
            <!-- 2021.11.18修复el-input没有默认enter事件时回车异常 -->
            <el-input
              :size="size"
              clearable
              :ref="item.field"
              :input-style="item.inputStyle"
              v-else-if="item.onKeyPress"
              :placeholder="item.placeholder ? item.placeholder : item.title"
              :disabled="item.readonly || item.disabled"
              v-show="!item.hidden"
              v-model="formFields[item.field]"
              @keypress="
                ($event) => {
                  onKeyPress($event, item);
                }
              "
              @change="item.onKeyPress"
              @keyup.enter="item.onKeyPress"
            ></el-input>
            <el-input
              :size="size"
              clearable
              v-else
              :ref="item.field"
              :input-style="item.inputStyle"
              :placeholder="item.placeholder ? item.placeholder : item.title"
              :disabled="item.readonly || item.disabled"
              v-show="!item.hidden"
              v-model="formFields[item.field]"
            ></el-input>

            <div class="form-extra" v-if="item.extra">
              <form-expand
                v-if="item.extra.render"
                :render="item.extra.render"
              ></form-expand>
              <a
                v-else-if="item.extra.click"
                :style="item.extra.style"
                @click="item.extra.click(item, formFields[item.field])"
              >
                <i v-if="item.extra.icon" :class="item.extra.icon" />
                {{ item.extra.text }}
              </a>
              <a v-else :style="item.extra.style">
                <i v-if="item.extra.icon" :class="item.extra.icon" />
                {{ item.extra.text }}
              </a>
            </div>
          </div>
        </el-form-item>
      </div>
    </template>
    <slot></slot>
    <div style="width: 100%">
      <slot name="footer"></slot>
    </div>
  </el-form>
</template>
<script>
const rule = {
  change: [
    'checkbox',
    'select',
    'date',
    'datetime',
    'drop',
    'radio',
    'cascader'
  ], // 2020.05.31增加级联类型
  phone: /^[1][3,4,5,6,7,8,9][0-9]{9}$/,
  decimal: /(^[\-0-9][0-9]*(.[0-9]+)?)$/,
  number: /(^[\-0-9][0-9]*([0-9]+)?)$/
};
const inputTypeArr = ['text', 'string', 'mail', 'textarea', 'password'];
const types = {
  int: 'number',
  byte: 'number',
  decimal: 'number', // "float",
  string: 'string',
  bool: 'boolean',
  date: 'datetime',
  date: 'date',
  mail: 'email'
};
//表单验证注意：每次验证都必须执行callback,否则验证不执行回调方法
const colPow = Math.pow(10, 3);
import FormExpand from './MesForm/MesFormRender';
import {
  defineAsyncComponent,
  defineComponent,
  ref,
  reactive,
  toRefs,
  getCurrentInstance,
  onMounted,
  watch
} from 'vue';
export default defineComponent({
  components: {
    FormExpand,
    'mes-upload': defineAsyncComponent(() =>
      import('@/components/basic/MesUpload.vue')
    ),
    'mes-wang-editor': defineAsyncComponent(() =>
      import('@/components/editor/MesWangEditor.vue')
    )
  },
  props: {
    loadKey: {
      // 是否加载formRules字段配置的数据源
      type: Boolean,
      default: true
    },
    width: {
      // 表单宽度
      type: Number,
      default: 0
    },
    labelWidth: {
      // 表单左边label文字标签的宽度
      type: Number,
      default: 100
    },
    formRules: {
      // 表单配置规则，如字段类型，是否必填
      type: Array,
      default: []
    },
    formFields: {
      type: Object,
      default: () => {
        return {};
      }
    },
    editor: {
      // 2021.01.16编辑器信息 {uploadImgUrl:"",upload:null//上传方法}
      type: Object,
      default: () => {
        return {};
      }
    },
    size: {
      type: String, //large / default / small
      default: 'large'
    },
    select2Count: {
      //超出数量显示select2组件
      type: Number,
      default: 500
    }
  },
  computed: {
    rules() {
      let ruleResult = {};
      this.formRules.forEach((option, xIndex) => {
        option.forEach((item) => {
          ruleResult[item.field] = [this.getRule(item, this.formFields)];
        });
      });
      if (this.$refs.mesform) {
        setTimeout(() => {
          this.$refs.mesform.clearValidate();
        }, 100);
      }
      return ruleResult;
    }
  },
  setup(props, context) {
    const { appContext, proxy } = getCurrentInstance();
    const remoteCall = ref(true);
    const span = ref(1);
    const rangeFields = toRefs([]);
    const mesform = ref(null);
    const numberFields = toRefs([]);
    onMounted(() => {});
    const initFormRules = (init) => {
      if (props.loadKey) {
        initSource();
      }
      props.formRules.forEach((row, xIndex) => {
        if (row.length > span.value) span.value = row.length;
        let _count = 0,
          _size = 0;
        row.forEach((x) => {
          if (x.colSize > 0) {
            _size = _size + x.colSize;
            _count++;
          }
        });
        if (_count > 0 && row.length - _count > 0) {
          let _cellSize = (12 - _size) / (row.length - _count);
          row.forEach((x) => {
            if (!x.colSize) {
              x.colSize = _cellSize;
            }
          });
        }
        row.forEach((item, yIndex) => {
          if (item.type == 'number') {
            numberFields.push(item.field);
          }
          // 目前只支持select单选远程搜索，remote远程从后台字典数据源进行搜索，url从指定的url搜索
          if (item.remote || item.url) {
            // item.remoteData = [];
            item.loading = false;
            item.point = { x: xIndex, y: yIndex };
          }
          // 初始化上传文件信息
          initUpload(item, init);
          // 初始化数据源空对象
          if (item.dataKey) {
            // 下拉框都强制设置为字符串类型
            item.columnType = 'string';
            if (!item.data) {
              item.data = [];
            }
          }

          if (item.range || item.type == 'range') {
            if (
              !(props.formFields[item.field] instanceof Array) ||
              props.formFields[item.field].length != 2
            ) {
              props.formFields[item.field] = ['', ''];
            }
            rangeFields.push(item.field);
          }
        });
      });
    };

    const initSource = () => {
      let keys = [],
        binds = [];
      // 初始化字典数据源
      props.formRules.forEach((item) => {
        item.forEach((x) => {
          if (x.dataKey && (!x.data || x.data.length == 0) && !x.remote) {
            x.data = [];
            binds.push({ key: x.dataKey, data: x.data, type: x.type });
            if (keys.indexOf(x.dataKey) == -1) {
              keys.push(x.dataKey);
            }
          }
        });
      });

      if (keys.length == 0) return;
      appContext.config.globalProperties.http
        .post('/api/Sys_Dictionary/GetVueDictionary', keys)
        .then((dic) => {
          bindOptions(dic, binds);
          proxy.$emit('dicInited', dic);
        });
    };
    const bindOptions = (dic, binds) => {
      dic.forEach((d) => {
        if (d.data.length > props.select2Count) {
          if (
            !binds.some((x) => {
              return x.key == d.dicNo && x.type == 'cascader';
            })
          ) {
            d.data.forEach((item) => {
              item.label = item.value;
              item.value = item.key;
            });
          }
        }
        binds.forEach((x) => {
          if (x.key != d.dicNo) return true;
          // 如果有数据的则不查询
          if (x.data.length > 0) return true;
          //2022.03.13增加级联数据源自动转换
          if (x.type == 'cascader' || x.type == 'treeSelect') {
            let _data = JSON.parse(JSON.stringify(d.data));
            let cascaderArr = appContext.config.globalProperties.base.convertTree(
              _data,
              (node, data, isRoot) => {
                if (!node.inited) {
                  node.inited = true;
                  node.label = node.value;
                  node.value = node.key;
                }
              }
            );
            props.formRules.forEach((option) => {
              option.forEach((item) => {
                if (item.dataKey == x.key) {
                  item.orginData = x.data;
                  item.data = cascaderArr;
                }
              });
            });
          } else if (d.data.length > 0 && !d.data[0].hasOwnProperty('key')) {
            let source = d.data,
              newSource = new Array(source.length);
            for (let index = 0; index < source.length; index++) {
              newSource[index] = {
                key: source['key'] + '',
                value: source['value']
              };
            }
            x.data.push(...newSource);
          } else {
            x.data.push(...d.data);
          }
        });
      });
    };

    const initUpload = (item, init) => {
      if (!init) return;
      if (
        ['img', 'excel', 'file'].indexOf(item.type != -1) ||
        item.columnType == 'img'
      ) {
        // 只是没设置是否自动上传的，默认都是选择文件后自动上传
        if (!item.hasOwnProperty('autoUpload')) {
          item.autoUpload = true;
        }
        if (!item.hasOwnProperty('fileList')) {
          item.fileList = true;
        }
        if (!item.hasOwnProperty('downLoad')) {
          item.downLoad = true;
        }
        if (!item.removeBefore) {
          item.removeBefore = (index, file, files) => {
            return true;
          };
        }
        if (!item.fileClick) {
          item.fileClick = (index, file, files) => {
            return true;
          };
        }
        if (!item.onChange) {
          item.onChange = (files) => {
            return true;
          };
        }
        if (!item.uploadAfter) {
          item.uploadAfter = (result, files) => {
            return true;
          };
        }
        if (!item.uploadBefore) {
          item.uploadBefore = (files) => {
            return true;
          };
        }
      }
    };
    const validate = (callback) => {
      let result = true;
      mesform.value.validate((valid) => {
        if (!valid) {
          appContext.config.globalProperties.$message.error('数据验证未通过!');
          result = false;
        } else if (typeof callback === 'function') {
          try {
            callback(valid);
          } catch (error) {
            let msg = `表单验证回调方法异常：${error.message}`;
            appContext.config.globalProperties.$message.error(msg);
            console.log(msg);
          }
        }
      });
      return result;
    };

    initFormRules(true);
    return {
      remoteCall,
      span,
      rangeFields,
      numberFields,
      validate,
      mesform
      //  initFormRules,
      // initSource
    };
  },
  created() {
    this.formRules.forEach((rules) => {
      rules.forEach((option) => {
        if (option.type == 'treeSelect' && option.multiple === undefined) {
          option.multiple = true;
        }
      });
    });
  },

  data() {
    return {
      // remoteCall: true,
      errorImg: 'this.src="' + require('@/assets/imgs/error-img.png') + '"'
      // span: 1,
      // rangeFields: [],
    };
  },
  methods: {
    getColWidth(item) {
      //2021.08.30 增加动态计算表单宽度
      let _span = 0;
      this.formRules.forEach((row, xIndex) => {
        //2022.05.06 追加表单中隐藏的元素不参与动态计算表单宽度
        let rowLength = row.filter((item) => {
          return !item.hidden;
        }).length;
        if (rowLength > _span) _span = rowLength;
      });
      let rete =
        Math.round(((item.colSize || 12 / _span) / 0.12) * colPow, 10.0) /
        colPow;
      if (item.colSize) return rete.toFixed(3);
      return rete.toFixed(3);
      // return (100 - rete).toFixed(3);
    },
    previewImg(url) {
      this.base.previewImg(url, this.http.ipAddress);
    },
    getSrc(path) {
      if (!path) return;
      if (!this.base.isUrl(path) && path.indexOf('.') != -1) {
        return this.http.ipAddress + path;
      }
      return path;
    },
    // 是否为图片文件等格式并对字段的转换成数组：[{name:'1.jpg',path:'127.0.0.1/ff/1.jpg'}]
    isFile(item, formFields) {
      if (
        item.type == 'img' ||
        item.columnType == 'img' ||
        item.type == 'excel' ||
        item.type == 'file'
      ) {
        this.convertFileToArray(item, formFields);
        return true;
      }
      return false;
    },
    isReadonlyImgFile(item, formFields) {
      if ((item.disabled || item.readonly) && this.isFile(item, formFields)) {
        return true;
      }
      return false;
    },
    convertFileToArray(item, formFields) {
      if (!item.maxFile) {
        item.maxFile = 1; // 默认只能上传一个文件，可以在onInit中设置
      }

      let fileInfo = formFields[item.field];
      if (fileInfo instanceof Array) {
        return;
      }
      if (fileInfo === null || fileInfo === undefined) {
        formFields[item.field] = [];
        return;
      }
      // 将以逗号隔开的文件分割成数组127.0.0.1/aa/1.jpg,将127.0.0.1/aa/2.jpg
      if (typeof fileInfo === 'string') {
        if (fileInfo.trim() === '') {
          formFields[item.field] = [];
          return;
        }
        // 如果文件路径是字符串，则使用，拆分
        fileInfo = fileInfo.replace(/\\/g, '/');
        let files = fileInfo.split(',');
        formFields[item.field] = [];
        for (let index = 0; index < files.length; index++) {
          let file = files[index];
          let splitFile = file.split('/');
          formFields[item.field].push({
            name: splitFile.length > 0 ? splitFile[splitFile.length - 1] : file,
            path: file // this.base.isUrl(file) ? file : this.http.ipAddress + file,
          });
        }
      }
    },
    dowloadFile(file) {
      this.base.dowloadFile(
        file.path,
        file.name,
        {
          Authorization: this.$store.getters.getToken()
        },
        this.http.ipAddress
      );
    },
    validatorPhone(ruleOption, value, callback) {
      if (!ruleOption.required && !value && value != '0') {
        return callback();
      }
      if (!rule.phone.test((value || '').trim())) {
        return callback(new Error('请输入正确的手机号'));
      }
      callback();
    },
    validatorPwd(ruleOption, value, callback) {
      if (!ruleOption.required && !value && value != '0') {
        return callback();
      }
      if ((value + '').trim().length < 6) {
        return callback(new Error('密码长度不能小于6位'));
      }
      callback();
    },
    convertArrayValue(data, val) {
      // 2020.12.13增加表单多选只转换字典
      // 编辑多选table显示
      //2023.04.20修复只读为label时原数据被字典替换了的问题
      let valArr = Array.isArray(val)
        ? val.map((x) => {
            return x;
          })
        : val.split(',');
      for (let index = 0; index < valArr.length; index++) {
        var _item = data.find((x) => {
          return x.key && x.key != '0' && x.key + '' == valArr[index] + '';
        });
        if (_item) {
          valArr[index] = _item.value;
        }
      }
      return valArr.join(',');
    },
    getText(formFields, item) {
      // 2019.10.24修复表单select组件为只读的属性时没有绑定数据源
      let text = formFields[item.field];
      if (typeof text === 'function') return text(formFields);
      if (text === 'null' || text === '' || text === null || text === undefined)
        return '--';
      //2021.03.02增加只读时日期处理
      if (item.type == 'date') {
        return text.replace('T', ' ').split(' ')[0];
      }
      //2021.03.31修复表单switch只读时没有转换值的问题
      if (item.type == 'switch') {
        return text ? '是' : '否';
      }
      if (!item.data) return text;
      if (item.type == 'selectList' || item.type == 'checkbox') {
        return this.convertArrayValue(item.data, text);
      }
      var _item = item.data.find((x) => {
        return x.key == text;
      });
      return _item ? _item.value : text;
    },
    onClear(item, formFields) {
      // 远程select标签清空选项
      item.data.splice(0);
      // console.log(2);
    },
    onChange(item, value) {
      if (item.onChange && typeof item.onChange === 'function') {
        item.onChange(value, item);
      }
    },
    onRemoteChange(item, value) {
      // 第二次打开时，默认值成了undefined，待查viewgrid中重置代码
      if (value == undefined && item.data.length > 0) {
        this.formFields[item.field] = item.data[0].key;
        //  console.log('undefined');
      }
      this.remoteCall = false;
      if (item.onChange && typeof item.onChange === 'function') {
        item.onChange(value, item);
      }
    },
    getData(item) {
      return item.data;
    },

    // 远程搜索(打开弹出框时应该禁止搜索)
    remoteSearch(item, formFields, val) {
      if (!item.remote && !item.url) {
        return;
      }
      if (
        val == '' ||
        (item.data.length == 1 &&
          (val == item.data[0].key || val == item.data[0].value))
      ) {
        return;
      }
      // 弹出框或初始化表单时给data设置数组默认值2
      // 2020.09.26修复远程搜索自定义url不起作用的问题
      let url;
      if (typeof item.url === 'function') {
        url = item.url(val, item.dataKey, item);
      } else {
        url =
          (item.url || '/api/Sys_Dictionary/GetSearchDictionary') +
          '?dicNo=' +
          item.dataKey +
          '&value=' +
          val;
      }
      this.http.post(url).then((dicData) => {
        //this.$set(item, "loading", false);
        item.loading = false;
        item.data = dicData;
        this.formRules[item.point.x].splice(item.point.y, 1, item);
      });
    },
    getObject(date) {
      if (typeof date === 'object') {
        return date;
      }
      return new Date(date);
    },
    reset(sourceObj) {
      // 重置表单时，禁用远程查询
      this.$refs['mesform'].resetFields();
      if (this.rangeFields.length) {
        this.rangeFields.forEach((key) => {
          this.formFields[key].splice(0);
          this.formFields[key] = [null, null];
        });
      }
      if (!sourceObj) return;
      for (const key in this.formFields) {
        if (sourceObj.hasOwnProperty(key)) {
          this.formFields[key] = sourceObj[key];
          if (this.numberFields.indexOf(key) != -1) {
            this.formFields[key] = sourceObj[key] * 1 || 0;
          }
        }
      }
      //  this.remoteCall = true;
    },

    fileOnChange(files, item) {
      this.$refs.mesform.clearValidate(item.field);
      if (item.onChange) {
        return item.onChange(files);
      }
      return true;
    },
    isReadonly(item) {
      return item.readonly || item.disabled;
    },
    getRule(item, formFields) {
      //2021.07.17增加只读表单不验证
      //range与swtich暂时不做校验
      if (
        // item.readonly ||
        // item.disabled ||
        item.type == 'switch' ||
        item.type == 'range'
      )
        return { required: false };
      // 用户设置的自定义方法
      if (item.validator && typeof item.validator === 'function') {
        return {
          validator: (rule, val, callback) => {
            // 用户自定义的方法，如果返回了值，直接显示返回的值，验证不通过
            let message = item.validator(rule, val);
            if (message) return callback(new Error(message + ''));
            return callback();
          },
          required: item.required,
          trigger: rule.change.indexOf(item.type) != -1 ? 'change' : 'blur'
        };
      }
      if (['img', 'excel', 'file'].indexOf(item.type) != -1) {
        return {
          validator: (rule, val, callback) => {
            //2021.09.05移除文件上传默认必填
            if (
              item.required &&
              !this.isReadonly(item) &&
              (!val || !val.length)
            ) {
              return callback(
                new Error(item.type == 'img' ? '请上传照片' : '请上传文件')
              );
            }
            return callback();
          },
          required: item.required,
          trigger: 'change'
        };
      }
      // 设置数字的最大值民最小值
      if (
        item.type == 'number' ||
        item.columnType == 'number' ||
        item.columnType == 'int' ||
        item.type == 'decimal'
      ) {
        // 如果是必填项的数字，设置一个默认最大与最值小
        if (item.required && typeof item.min !== 'number') {
          item.min = 0; //item.type == "decimal" ? 0.1 : 1;
        }

        return {
          required: item.required,
          message: item.title + '只能是数字',
          title: item.title,
          trigger: 'blur',
          min: item.min,
          max: item.max,
          type: item.columnType || item.type,
          validator: (ruleObj, value, callback) => {
            if (!ruleObj.min && !ruleObj.max) {
              if (ruleObj.required) {
                if ((!value && value != '0') || !rule.decimal.test(value)) {
                  return callback(new Error('只能是数字'));
                }
              }
              return callback();
            }
            if (this.isReadonly(item)) return callback();
            if (ruleObj.type == 'number') {
              if (!rule.number.test(value)) {
                ruleObj.message = ruleObj.title + '只能是整数';
                return callback(new Error(ruleObj.message));
              }
            } else {
              if (!rule.decimal.test(value)) {
                ruleObj.message = ruleObj.title + '只能是数字';
                return callback(new Error(ruleObj.message));
              }
            }
            if (
              ruleObj.min !== undefined &&
              typeof ruleObj.min === 'number' &&
              value < ruleObj.min
            ) {
              ruleObj.message = ruleObj.title + '不能小于' + ruleObj.min;
              return callback(new Error(ruleObj.message));
            }
            if (
              ruleObj.max !== undefined &&
              typeof ruleObj.max === 'number' &&
              value > ruleObj.max
            ) {
              ruleObj.message = ruleObj.title + '不能大于' + ruleObj.max;
              return callback(new Error(ruleObj.message));
            }
            return callback();
          }
        };
      }

      // 手机、密码验证
      if (item.type == 'password' || item.type == 'phone') {
        return {
          validator:
            item.type == 'phone' ? this.validatorPhone : this.validatorPwd,
          required: item.required,
          trigger: 'blur'
        };
      }

      if (!item.required && item.type != 'mail') return { required: false };

      if (!item.hasOwnProperty('type')) item.type = 'text';

      if (inputTypeArr.indexOf(item.type) != -1) {
        let message =
          item.title +
          (item.type == 'mail' ? '必须是一个邮箱地址' : '不能为空');
        let type = item.type == 'mail' ? 'email' : types[item.columnType];
        let _rule = {
          required: true,
          message: message,
          trigger: 'blur',
          type: type,
          validator: (ruleObj, value, callback) => {
            if (
              !this.isReadonly(item) &&
              (value === '' || value === undefined || value === null)
            ) {
              return callback(new Error(ruleObj.message));
            }
            return callback();
          }
        };
        if (item.type == 'mail') {
          _rule.validator = undefined;
          return _rule;
        }
        if (item.min) {
          _rule.min = item.min;
          _rule.message = item.title + '至少' + item.min + '个字符!';
        }
        if (item.max) {
          return [
            _rule,
            {
              max: item.max,
              required: true,
              message: item.title + '最多' + item.max + '个字符!',
              trigger: 'blur'
            }
          ];
        }
        return _rule;
      }

      if (item.type == 'radio') {
        return {
          required: item.required,
          message: '请选择' + item.title,
          trigger: 'change',
          type: 'string'
        };
      }
      if (
        item.type == 'date' ||
        item.type == 'datetime' ||
        item.type == 'month' ||
        item.type == 'time'
      ) {
        return {
          required: true,
          message: '请选择' + item.title,
          trigger: 'change',
          type: item.range ? 'array' : 'string',
          validator: (rule, val, callback) => {
            if (this.isReadonly(item)) return callback();
            // 用户自定义的方法，如果返回了值，直接显示返回的值，验证不通过
            if (!val || (item.range && !val.length)) {
              return callback(new Error('请选择日期'));
            }
            return callback();
          }
        };
      }

      if (item.type == 'cascader') {
        return {
          type: 'array',
          required: true,
          min: item.min || 1,
          // message: "请选择" + item.title,
          trigger: 'change',
          validator: (rule, val, callback) => {
            if (this.isReadonly(item)) return callback();
            // 用户自定义的方法，如果返回了值，直接显示返回的值，验证不通过
            let _arr = this.formFields[item.field];
            if (!_arr || !_arr.length) {
              return callback(new Error('请选择' + item.title));
            }
            return callback();
          }
        };
      }

      if (
        ['select', 'selectList', 'checkbox', 'cascader', 'treeSelect'].indexOf(
          item.type
        ) != -1
      ) {
        let _rule = {
          type: item.type == 'select' ? 'string' : 'array',
          required: true,
          min: item.min || 1,
          message: '请选择' + item.title,
          trigger: 'change',
          validator: (rule, value, callback) => {
            if (this.isReadonly(item)) return callback();
            //2021.11.27修复多选没有提示的问题
            if (value == undefined || value === '') {
              return callback(new Error(rule.message));
            } else if (
              (item.type == 'checkbox' ||
                item.type == 'selectList' ||
                item.type == 'treeSelect') &&
              (!(value instanceof Array) || !value.length)
            ) {
              return callback(new Error(rule.message));
            }
            return callback();
          }
        };

        if (_rule.max) {
          _rule.nax = item.max;
          _rule.message = '最多只能选择' + item.max + '项';
        }
        return _rule;
      }
      return {};
    },
    compareDate(date1, date2) {
      if (!date2) {
        return true;
      }
      return (
        date1.valueOf() <
        (typeof date2 == 'number' ? date2 : new Date(date2).valueOf())
      );
    },
    getDateOptions(date, item) {
      //2021.07.17设置时间可选范围
      if ((!item.min && !item.max) || !date) {
        return false;
      }
      if (item.min && item.min.indexOf(' ') == -1) {
        //不设置时分秒，后面会自动加上 08:00
        item.min = item.min + ' 00:00:000';
      }
      return (
        this.compareDate(date, item.min) || !this.compareDate(date, item.max)
      );
    },
    getDateFormat(item) {
      if (item.type == 'month') {
        return 'YYYY-MM';
      }
      // if (item.type=='time') {
      //     return 'HH:mm:ss'
      // }
      //见https://day.js.org/docs/zh-CN/display/format
      return item.type == 'date' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss';
    },
    dateRangeChange(val, item) {
      if (!val) {
        this.$emit('update:formFields');
        return;
      }
      item.onChange && item.onChange(val);
    },
    onKeyPress($event, item) {
      if ($event.keyCode == 13) {
        return;
      }
      item.onKeyPress($event);
    },
    filterMethod(value, data) {
      return data.label.includes(value);
    },
    getNode( label,node, data){
      console.log(label)
    }
  }
});
</script>
<style lang="less" scoped>
.el-form-item {
  margin-right: 0;
}
.el-form-item {
  .form-imgs {
    img {
      float: left;
      cursor: pointer;
      object-fit: cover;
      margin: 0 10px 10px 0;
      width: 65px;
      height: 65px;
      border: 1px solid #c7c7c7;
      overflow: hidden;
      border-radius: 5px;
      box-sizing: content-box;
    }
  }
}
.el-form-item ::v-deep(.el-form-item__label) {
  padding: 0 0px 0 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.el-form-item ::v-deep(.el-range-separator) {
  text-align: center;
  width: 13px;
  padding: 0px 1px;
  font-size: 12px;
}
.el-form-item ::v-deep(.el-range__close-icon) {
  margin-right: -10px;
}
.form-item-extra {
  > *:first-child {
    flex: 1;
  }
  display: flex;
  .form-extra {
    padding-left: 7px;
    line-height: 36px;
  }
}
.mes-form-item {
  width: 100%;
}
.mes-form-item ::v-deep(.el-form-item__content) {
  display: unset !important;
}
.mes-form-item ::v-deep(.el-input--large .el-input__inner) {
  height: 34px !important;
}
.mes-form-item ::v-deep(.el-input-number--large .el-input-number__increase) {
  border-top: 1px solid #d4d4d4;
}
.mes-form-item ::v-deep(.el-input-number--large .el-input-number__decrease) {
  border-bottom: 1px solid #d4d4d4;
}
.mes-form-item ::v-deep(.el-input--large.el-date-editor) {
  height: 36px;
}
.v-date-range ::v-deep(.el-input__prefix) {
  display: none;
}
.v-date-range ::v-deep(.el-input__inner) {
  padding: 0;
}

.el-form-item ::v-deep(.el-checkbox) {
  margin-right: 8px;
}
.el-form-item ::v-deep(.el-checkbox .el-checkbox__label) {
  padding-left: 5px;
}
.el-form-item ::v-deep(textarea) {
  font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
    'Microsoft YaHei', '微软雅黑', Arial, sans-serif !important;
}
.el-form-item ::v-deep(.el-select .el-select__tags > span) {
  display: flex;
}
.el-form-item ::v-deep(.el-select-v2__combobox-input) {
  height: 30px;
}
.el-form-item ::v-deep(.el-select__tags) {
  overflow: hidden;
  height: 30px;
}
.el-form-item ::v-deep(.el-select-tags-wrapper) {
 position: absolute;
}

.el-form-item {
  vertical-align: top !important;
}
.form-file-list {
  a {
    color: #3ea9ff;
  }
  a:hover {
    cursor: pointer;
    color: #0281e7;
  }
}
</style>
