# 常用函数

提供常用的VUE 的模板函数

# Loading 加载


<script>
  const loading = this.$loading({
    lock: true,
    text: '正在提交数据......',
    // text: '正在加载数据......',
    spinner: 'el-icon-loading',
    background: 'rgba(0, 0, 0, 0.3)'
  })
  
  loading.close()
</script>

# El-table 表格

# 序号

<el-table-column label="#" type="index" align="center" width="50">
  <template slot-scope="scope">
    <span>{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}</span>
  </template>
</el-table-column>

# El-input-number 数字输入框


<el-form-item label="建筑面积" prop="buildArea">
  <div style="display: flex; width: 100%">
    <el-input-number
        :min="0"
        :precision="2"
        style="width: calc(100% - 80px)"
        controls-position="right"
        v-model="form.buildArea"
        placeholder="请输入建筑面积"
    />
    <div class="el-input-group__append" style="width: 80px; height: 40px;text-align: center;">平方米</div>
  </div>
</el-form-item>

# El-cascader 级联选择器

<!-- 搜索 -->
<el-form-item label="所属区域" prop="gridId">
  <el-cascader clearable
               placeholder="请选择所属区域"
               :props="areaProps"
               :show-all-levels="false"
               :options="areaTree"
               v-model="queryParams.areaCode"
  ></el-cascader>
</el-form-item>

<!-- 新增 -->
<el-form-item label="所属区域" prop="areaCode">
  <el-cascader clearable
               ref="cascader"
               @change="getNodeChange"
               placeholder="请选择所属区域"
               style="width: 100%"
               :props="areaProps"
               :options="areaTree1"
               v-model="form.areaCode"
  ></el-cascader>
</el-form-item>

<script>
  export default {
    data() {
      return {
        areaInitCode: '0',
        areaInitLevel: 1,
        loadingArea:false,
        areaTree: [],
        areaTree1: [],
        areaProps: {
          lazy: true,
          checkStrictly: true,
          emitPath: false,
          lazyLoad: (node, resolve) => {
            console.log('node==>', node)
            if (node.value) {
              getAreaTreeApi(node.value).then(res => {
                const data = res.data.map(item => {
                  return {
                    label: item.areaName,
                    value: item.areaCode,
                    ...item
                  }
                })
                resolve(data)
              })
            }
          }
        },
      }
    },
    methods: {
      async initArea() {
        this.loadingArea = false
        try {
          const res = await getAreaTreeApi(this.areaInitCode)
          this.areaTree = res.data.map(item => {
            return {
              label: item.areaName,
              value: item.areaCode,
              ...item
            }
          })
          this.loadingArea = true
        } catch (e) {
          this.$modal.msgError('获取搜索框中的所属区域失败')
        }
      },
      getNodeChange() {
        const checkedNodes = this.$refs?.cascader?.getCheckedNodes()
        console.log('getCheckedNodes==>', checkedNodes)
        this.$set(this.form.company.area, 'areaCode', checkedNodes?.[0].value)
        this.$set(this.form.company.area, 'areaName', checkedNodes?.[0].label)
        this.$set(this.form, 'gridName', checkedNodes?.[0]?.pathLabels?.join(' / '))
        this.$set(this.form.company, 'fullName', checkedNodes?.[0]?.pathLabels?.join(' / '))
        this.$refs.cascader.dropDownVisible = false
      },
      // 以下是修改用到的
      async handleUpdate() {
        // 获取区域树
        if (this.form.gridId) {
          this.areaTree1 = await this.getAreaTreeByCode(this.form.gridId)
        } else {
          this.areaTree1 = [...this.areaTree]
        }
      },
      async getAreaTreeByCode(fullCode) {
        // 解析完整代码,获取每一层级的代码
        const temp = fullCode.substring(0, 6)
        // 完整的层级数组
        const fullLevels = ['0', temp.substring(0, 2) + '0000', temp.substring(0, 4) + '00', temp]
        // 根据 this.areaInitLevel 截取数组
        const levels = fullLevels.slice(this.areaInitLevel)

        for (let i = 6; i < fullCode.length; i += 3) {
          levels.push(fullCode.substring(0, i + 3))
        }
        console.log('levels==>', levels)
        // 从根代码开始递归构建区域树
        return await this.buildTree(levels, 0)
      },
      async buildTree(levels, currentLevelIndex) {
        // 获取当前层级的代码
        const currentCode = levels[currentLevelIndex]
        // 延迟 500 毫秒
        await new Promise((resolve) => setTimeout(resolve, 300))
        // 调用 API 获取当前层级的区域数据
        const res = await getAreaTreeApi(currentCode)
        const currentLevelData = res.data.map((item) => ({
          label: item.areaName,
          value: item.areaCode,
          ...item,
          children: []
        }))

        // 如果当前层级是最后一层,直接返回当前层级数据
        if (currentLevelIndex === levels.length - 1) {
          return currentLevelData
        }

        // 否则,递归获取下一层级的数据,并将其作为当前层级的 children
        for (let i = 0; i < currentLevelData.length; i++) {
          const currentArea = currentLevelData[i]
          if (currentArea.value === levels[currentLevelIndex + 1]) {
            // 找到匹配的子区域,递归获取其子层级
            currentArea.children = await this.buildTree(levels, currentLevelIndex + 1)
            break // 只处理匹配的子区域
          }
        }

        return currentLevelData
      },
    }
  }
</script>

# $Set

# 对象使用方法


<script>
  export default {
    setValue() {
      // 如果没有使用 this.$set,视图不会更新
      this.$set(this.form, '字段名', undefined);
    }
  }
</script>

# 数组使用方法


<script>
  export default {
    setValue() {
      // 使用索引直接修改数组元素,视图可能不会更新  
      // this.arr[1] = 'orange'; // 这可能不会触发视图更新  

      // 使用 this.$set  
      this.$set(this.arr, 1, 'orange'); // 这会触发视图更新  
    }
  }
</script>

# Computed


<script>
  export default {
    calcPrice() {
      const {pchmNum, pchmUnitPrice} = this.form
      if (pchmNum && pchmUnitPrice) {
        let price = pchmNum * pchmUnitPrice;
        this.form.pchmLumpSum = price
        return price;
      } else {
        return 0
      }
    }
  }
</script>

# Watch

# 基础用法


<script>
  export default {
    watch: {
      id: {
        handler(newValue, oldValue) {
          console.log('value==>', newValue)
        },
        deep: true,
        immediate: true
      },
    }
  }
</script>

# 搜索框用法


<script>
  export default {
    watch: {
      showSearch: {
        handler(value) {
          if (value === false) {
            this.tableHeight += this.$refs.queryForm?.$el?.clientHeight ?? 0
          } else if (value === true) {
            this.$nextTick(() => {
              this.tableHeight -= this.$refs.queryForm?.$el?.clientHeight ?? 0
            })
          }
        }
      }
    }
  }
</script>

# 路由用法

搭配 路由跳转-JS 使用


<script>
  export default {
    watch: {
      $route: {
        handler(value) {
          console.log('value==>', value)
          if (value.path === ENUM.ROUTE.NOTICE_DESCRIPTION) {
            let id = value.query.row
            console.log('id==>', id)
            if (!id) {
              this.$modal.msgError('获取项目ID失败,请关闭当前页面重新进入!')
            } else {
              this.currentId = id
            }
          }
        },
        deep: true,
        immediate: true
      }
    },
  }
</script>

# 透传

提示

包含 属性透传具名插槽透传事件监听器透传


<template>
  <el-dialog v-bind="$attrs" v-on="$listeners">
    <slot></slot>
    <template v-for="(_, name) in $slots" v-slot:[name]="data">
      <slot :name="name" v-bind="data"/>
    </template>
  </el-dialog>
</template>