vue-treeselect 实现懒加载 + 远程模糊搜索 支持多选,可悬浮提示选择项所有层级 已封装为组件

今天实现一个客户单位组织树的功能,不限层级,数据量巨大,采用vue-treeselect 实现懒加载 + 远程搜索

这是vue+ iview组件   element的需要改一下tooltip的写法

这个支持对选择的单位全部层级进行悬浮提示(也无法在下面下拉回显,下拉需要触发懒加载,只有远程搜索才能回显层级)

代码详细解释:

tooltip 设置了最大宽度 没有选择项  或者 下拉框弹开  会disabled禁用

limit是多选展示的最大数量,我这里设置1个

 :limitText="count => '更多' + count + '个'"          是  xxx  更多x个     对提示文字修改

flat是多选时候不设置这个回显会把 给出id的所有父级也勾选 

multiple是多选

:class="{ treeClass: isEdit }"   这个是开始想通过设置placeholder 来回显层级,后面作废

:options="product_map"    下拉框的数据源

:appendToBody="appendToBody"   相当于transfer   把组件渲染到最外层,不受父级样式影响

:value-consists-of="valueConsistsOf"   选择后@select 方法获取的数据类型(id还是node层级)

:disabled="disabled"   禁用

:placeholder="placeholder"  默认提示语

  :async="isAsync"   是否开启远程搜索模式

:load-options="isAsync ? asyncOptions : loadOptions"    懒加载和远程搜索触发的方法

  :defaultExpandLevel="expandLevel"  默认展开的层级  

  :cacheOptions="false"  是否缓存搜索的数据    这里缓存会有问题

v-model="checkRroduct"   绑定的数据id

一些为空的提示语

noChildrenText="没有数据"

noOptionsText="没有数据"

noResultsText="没有搜索结果"     

 控制打开搜索模式还是懒加载

@search-change="searchChange"

 @keydown.native="treeKeydown($event)"

@keyup.native="treeKeyup($event)"

@open="itemopen"

@close="itemClose"

下拉选项的自定义展示处理

因为选项的每一项 配置 disabled在远程搜索模式有问题,所以自己重写这个了

disabled是因为项目搜索后   一些选项要禁用 

(这个气死我了)  写的破大防

[

  {id: 151,  group_id : "150,151", group_name : "xxx,xxx" },

 {id: 152,  group_id : "150,151,152", group_name : "xxx,xxx,xxx" },

{id: 162,  group_id : "160,161,162" , group_name : "xxx,xxx,xxx"},

]

如上数据 group_id 是父级到它本身 我要把这个聚合为一条树,并且 根据id去禁用   上面的150,160,161  就需要禁用,也就是没有返回id和group_id 最后一位相同的选项 

<div slot="option-label" slot-scope="{ node }">

          <div :title="node.raw.label" v-if="node.raw.disabled" @click.prevent @click.stop :class="['labelClass', 'is-disabled']">

            {{ node.raw.label }}

          </div>

          <div :title="node.raw.label" v-else class="labelClass">

            {{ node.raw.label }}

          </div>

        </div>

选中项的自定义展示处理

<div slot="value-label" slot-scope="{ node }">{{ node.raw.longTitle }}</div>

接口讲解

queryTenantByLevel    传空查询所有一级客户    传parent_id查询用户子级(懒加载使用)

queryTenantByLike   传 staff_id查询这个id的用户信息   传company_name远程模糊搜索

方法讲解

handleEditTreeDataT   修改回显时候使用这个方法   handleEditTreeData是客户中心的特殊处理

handleEditTreeDataMuti  是多选的的回显

               上面三个都做了权限控制,queryTenantByLevel返回空证明这个客户权限低,使用登录客户的staff_id请求数据

clear()    这个是对页面重置时候要调用的  清空选择项    this.$refs.cusTree.clear()             

initTreeData   是新增和页面条件查询时候用的

toSelectProduct  选中选项后触发这个方法,返回node层级

asyncOptions  远程搜索  这里面做了一个时间控制,用户输入停止后1秒才会调接口  而且这个有  bug,必须callback(null, [])  后才能正常搜索,我这里控制第一次搜索结果为空,存在问题,后续研究吧

loadOptions 懒加载方法

后端返回数据需要这些字段

company_name  客户单位的名称

group_id   顶级到当前级别的id  如果当前是一级这个取当前用户的id

group_name  顶级到当前级别的company_name拼接

parent_id  当前用户的父级id  这个结合handleEditTreeData   客户中心是新增修改父级客户

                  所以this.checkRroduct = formData.parent_id    其他地方是staff_id

staff_id  当前用户的id

如何调用

首先全局注册一下这个组件

新建js文件

import Vue from 'vue'

import CusTree from './vue-treeselect/index.vue'

Vue.component('CusTree', CusTree)

在查询条件里面使用

<FormItem>

<CusTree style="width: 200px;" ref="cusTree" placeholder="客户单位" type="A" @getCheckRroduct="getCheckRroduct"></CusTree>

</FormItem>

//  重置 

resetData() {

      this.$refs.cusTree.clear()

      this.condition = JSON.parse(JSON.stringify(this.conditionInitCache))

      this.queryData() 

    },

//   这个是获取  checkRroduct是id     label是中文名(防止后端让你传中文搜索)

getCheckRroduct(formData) {

      this.condition.customer_id = formData.checkRroduct        //  formData.label

    },

在新增修改数据里面使用

type为A是新增  其他类型需要在下面触发handleEditTreeDataT修改回显

queryTenantByLike传staff_id是查这个用户的具体信息

<CusTree :type="params.type" ref="cusTree" placeholder="客户单位" @getCheckRroduct="getCheckRroduct"></CusTree>

if (this.params.type == 'M') {

      // console.log('params', this.params)

      this.formValidate.customerId = this.params.customer_id

      this.$http.operation.queryTenantByLike({ staff_id: this.formValidate.customerId }).then(resp => {

        if (resp && resp.result_code == '0') {

          this.$refs.cusTree.handleEditTreeDataT(resp.data[0])

        } else {

          this.$Message.error(resp.result_msg)

        }

      })

    }

在多选时候 

 <CusTree flat multiple :type="params.type" ref="cusTree" placeholder="请选择通知人员" @getCheckRroduct="getCheckRroduct"></CusTree>

if (this.params.type == 'M') {

      // console.log('params', this.params)

      this.formValidate.customerId = this.params.customer_id

      this.$http.operation.queryTenantByLike({ staff_id: this.formValidate.customerId }).then(resp => {

        if (resp && resp.result_code == '0') {

          this.$refs.cusTree.handleEditTreeDataMuti(resp.data)

        } else {

          this.$Message.error(resp.result_msg)

        }

      })

    }

完整代码

<template>
  <div>
    <Tooltip max-width="200" :disabled="tooltipDisabled" :content="formData.longTitle">
      <treeselect
        :limit="1"
        :limitText="count => '更多' + count + '个'"
        :flat="flat"
        :multiple="multiple"
        :class="{ treeClass: isEdit }"
        :options="product_map"
        :appendToBody="appendToBody"
        :value-consists-of="valueConsistsOf"
        :disabled="disabled"
        :placeholder="placeholder"
        @select="toSelectProduct"
        :async="isAsync"
        :defaultExpandLevel="expandLevel"
        :cacheOptions="false"
        :disableFuzzyMatching="false"
        :load-options="isAsync ? asyncOptions : loadOptions"
        v-model="checkRroduct"
        noChildrenText="没有数据"
        noOptionsText="没有数据"
        noResultsText="没有搜索结果"
        @search-change="searchChange"
        @keydown.native="treeKeydown($event)"
        @keyup.native="treeKeyup($event)"
        @open="itemopen"
        @close="itemClose"
      >
        <div slot="option-label" slot-scope="{ node }">
          <div :title="node.raw.label" v-if="node.raw.disabled" @click.prevent @click.stop :class="['labelClass', 'is-disabled']">
            {{ node.raw.label }}
          </div>
          <div :title="node.raw.label" v-else class="labelClass">
            {{ node.raw.label }}
          </div>
        </div>
        <div slot="value-label" slot-scope="{ node }">{{ node.raw.longTitle }}</div>
      </treeselect>
    </Tooltip>
  </div>
</template>

<script>
export default {
  components: {},
  props: {
    placeholder: {
      type: String,
      default: '请选择'
    },
    indexTTT: {
      type: Number,
      default: 0
    },
    type: {
      type: String,
      default: 'A'
    },
    valueConsistsOf: {
      type: String,
      default: 'ALL_WITH_INDETERMINATE'
    },
    isEdit: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    appendToBody: {
      type: Boolean,
      default: false
    },
    multiple: {
      type: Boolean,
      default: false
    },
    flat: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      userInfo: JSON.parse(this.$libs.getSessionStorage('user-info')),
      tooltipDisabled: true,
      checkRroduct: null,
      expandLevel: 0,
      product_map: [],
      product_mapTemp: [],
      formData: {},
      searchQuery: '',
      timer: null,
      isAsync: false,
      initialCallback: false
    }
  },
  watch: {
    checkRroduct(val) {
      this.formData.checkRroduct = val || ''
      this.tooltipDisabled = !val
      if (!val) {
        this.formData.label = ''
        this.formData.longTitle = ''
      }
      this.$emit('getCheckRroduct', this.formData, this.indexTTT)
    }
  },
  mounted() {
    // console.log(this.type)
    if (this.type == 'A') {
      this.initTreeData()
    }
  },
  methods: {
    clear() {
      this.checkRroduct = null
      this.tooltipDisabled = true
    },
    // 客户中心显示父级
    handleEditTreeData(formData) {
      if (!this.isEdit) {
        this.$http.operation.queryTenantByLevel().then(resp => {
          if (resp && resp.result_code == '0') {
            if (resp.data.length == 0) {
              this.$http.operation.queryTenantByLike({ staff_id: this.userInfo.staff_id }).then(resp => {
                if (resp && resp.result_code == '0') {
                  resp.data.map(item => {
                    item.id = item.staff_id
                    item.label = item.company_name
                    item.longTitle = item.company_name
                    item.children = null
                  })
                  if (!formData.group_id) {
                    this.product_map = resp.data
                  } else {
                    this.product_map = [this.transformData(formData.group_id, formData.group_name, formData.staff_id, formData.company_name, false)]
                    this.checkRroduct = formData.parent_id
                  }
                  this.product_mapTemp = resp.data
                } else {
                  this.$Message.error(resp.result_msg)
                }
              })
            } else {
              resp.data.map(item => {
                item.id = item.staff_id
                item.label = item.company_name
                item.longTitle = item.company_name
                item.children = null
              })
              if (!formData.group_id) {
                this.product_map = resp.data
              } else {
                this.product_map = [this.transformData(formData.group_id, formData.group_name, formData.staff_id, formData.company_name, false)]
                this.formData.longTitle = formData.group_name
                this.checkRroduct = formData.parent_id
              }
              this.product_mapTemp = resp.data
            }
          } else {
            this.$Message.error(resp.result_msg)
          }
        })
      } else {
        this.formData.longTitle = formData
        this.tooltipDisabled = false
      }
    },
    // 其他页面修改
    handleEditTreeDataT(formData) {
      this.$http.operation.queryTenantByLevel().then(resp => {
        if (resp && resp.result_code == '0') {
          if (resp.data.length == 0) {
            this.$http.operation.queryTenantByLike({ staff_id: this.userInfo.staff_id }).then(resp => {
              if (resp && resp.result_code == '0') {
                resp.data.map(item => {
                  item.id = item.staff_id
                  item.label = item.company_name
                  item.longTitle = item.company_name
                  item.children = null
                })
                if (!formData || !formData.group_id) {
                  this.product_map = resp.data
                } else {
                  this.product_map = [this.transformData(formData.group_id, formData.group_name, formData.staff_id, formData.company_name, false)]
                  this.formData.longTitle = formData.group_name
                  this.formData.label = formData.company_name
                  this.formData.group_id = formData.group_id
                  this.checkRroduct = formData.staff_id
                }
                this.product_mapTemp = resp.data
              } else {
                this.$Message.error(resp.result_msg)
              }
            })
          } else {
            resp.data.map(item => {
              item.id = item.staff_id
              item.label = item.company_name
              item.longTitle = item.company_name
              item.children = null
            })
            if (!formData || !formData.group_id) {
              this.product_map = resp.data
            } else {
              this.product_map = [this.transformData(formData.group_id, formData.group_name, formData.staff_id, formData.company_name, false)]
              this.formData.longTitle = formData.group_name
              this.formData.label = formData.company_name
              this.formData.group_id = formData.group_id
              this.checkRroduct = formData.staff_id
            }
            this.product_mapTemp = resp.data
          }
        } else {
          this.$Message.error(resp.result_msg)
        }
      })
    },
    // 多选逻辑
    handleEditTreeDataMuti(formData) {
      this.$http.operation.queryTenantByLevel().then(resp => {
        if (resp && resp.result_code == '0') {
          if (resp.data.length == 0) {
            this.$http.operation.queryTenantByLike({ staff_id: this.userInfo.staff_id }).then(resp => {
              if (resp && resp.result_code == '0') {
                resp.data.map(item => {
                  item.id = item.staff_id
                  item.label = item.company_name
                  item.longTitle = item.company_name
                  item.children = null
                })
                const dataT = JSON.parse(JSON.stringify(this.handleTreeById(formData, true)))
                this.product_map = dataT
                this.checkRroduct = formData.map(item => item.staff_id)
                this.formData.longTitle = formData.map(item => item.group_name).join(',')
                this.product_mapTemp = resp.data
              } else {
                this.$Message.error(resp.result_msg)
              }
            })
          } else {
            resp.data.map(item => {
              item.id = item.staff_id
              item.label = item.company_name
              item.longTitle = item.company_name
              item.children = null
            })
            const dataT = JSON.parse(JSON.stringify(this.handleTreeById(formData, true)))
            this.product_map = dataT
            this.checkRroduct = resp.data.map(item => item.staff_id)
            this.formData.longTitle = resp.data.map(item => item.group_name)
            this.product_mapTemp = resp.data
          }
        } else {
          this.$Message.error(resp.result_msg)
        }
      })
    },
    initTreeData() {
      this.$http.operation.queryTenantByLevel().then(resp => {
        if (resp && resp.result_code == '0') {
          if (resp.data.length == 0) {
            this.$http.operation.queryTenantByLike({ staff_id: this.userInfo.staff_id }).then(resp => {
              if (resp && resp.result_code == '0') {
                resp.data.map(item => {
                  item.id = item.staff_id
                  item.label = item.company_name
                  item.longTitle = item.company_name
                  item.children = null
                })
                this.product_map = resp.data
                this.product_mapTemp = resp.data
              } else {
                this.$Message.error(resp.result_msg)
              }
            })
          } else {
            resp.data.map(item => {
              item.id = item.staff_id
              item.label = item.company_name
              item.longTitle = item.company_name
              item.children = null
            })
            this.product_map = resp.data
            this.product_mapTemp = resp.data
          }
        } else {
          this.$Message.error(resp.result_msg)
        }
      })
    },
    toSelectProduct(val) {
      console.log(val)
      if (val.disabled) {
        this.$nextTick(() => {
          this.checkRroduct = null
        })
        return
      }
      if (val.group_id) {
        this.formData.group_id = val.group_id + '/' + val.id
        this.formData.parent_id = val.id
      } else {
        this.formData.group_id = val.id
        this.formData.parent_id = val.id
      }
      this.formData.label = val.label
      this.formData.longTitle = val.longTitle
      this.$emit('getCheckRroduct', this.formData, this.indexTTT)
    },
    asyncOptions({ action, parentNode, searchQuery, callback }) {
      console.log(action, 1)
      if (action == 'ASYNC_SEARCH') {
        this.searchQuery = searchQuery
        clearTimeout(this.timer)
        this.timer = setTimeout(() => {
          this.$http.operation.queryTenantByLike({ company_name: this.searchQuery }).then(resp => {
            if (resp && resp.result_code == '0') {
              resp.data.map(item => {
                item.id = item.staff_id
                item.label = item.company_name
              })
              const dataT = JSON.parse(JSON.stringify(this.handleTreeById(resp.data)))
              // callback(null, dataT)
              // console.log(JSON.stringify(dataT))
              if (this.initialCallback) {
                callback(null, dataT)
              } else {
                this.initialCallback = true
                callback(null, []) // 初始回调返回空数组
              }
            } else {
              this.$Message.error(resp.result_msg)
            }
          })
          this.timer = null
        }, 1000)
      }
    },
    loadOptions({ action, parentNode, searchQuery, callback }) {
      // console.log(action, 2)
      if (action == 'LOAD_CHILDREN_OPTIONS') {
        this.$http.operation.queryTenantByLevel({ parent_id: parentNode.id }).then(resp => {
          if (resp && resp.result_code == '0') {
            resp.data.map(item => {
              item.id = item.staff_id
              item.label = item.company_name
              item.longTitle = parentNode.longTitle + ' / ' + item.company_name
              item.children = null
            })
            parentNode.children = resp.data
            callback()
          } else {
            this.$Message.error(resp.result_msg)
          }
        })
      }
    },
    handleTreeById(data, flag) {
      const tree = []
      const dataT = data.map(item => String(item.staff_id))

      data.forEach(item => {
        const groupId = item.group_id.split('/')
        const groupName = item.group_name.split('/')

        let currentLevel = tree

        groupId.forEach((id, index) => {
          const existingNode = currentLevel.find(node => node.id === id)
          if (existingNode) {
            currentLevel = existingNode.children
          } else {
            const newNode = {
              id,
              label: groupName[index],
              longTitle: groupName.slice(0, index + 1).join('/'),
              children: [],
              disabled: flag ? false : !dataT.includes(id)
            }
            currentLevel.push(newNode)
            currentLevel = newNode.children
          }
        })
      })
      // 遍历tree并删除children为空数组的项
      function pruneEmptyChildren(nodes) {
        return nodes.filter(node => {
          if (node.children && node.children.length === 0) {
            delete node.children // 删除children属性
            return true // 保留这个节点,因为它可能还有其他有用的属性
          }
          if (node.children) {
            pruneEmptyChildren(node.children) // 递归处理子节点
          }
          return true // 保留这个节点
        })
      }

      // 在完成树的构建后,调用pruneEmptyChildren函数
      pruneEmptyChildren(tree)
      return tree
    },
    searchChange(val) {
      if (!val) {
        this.isAsync = false
        this.initialCallback = false
        this.expandLevel = 0
        this.product_map = JSON.parse(JSON.stringify(this.product_mapTemp))
      } else {
        this.isAsync = true
        this.expandLevel = 10
      }
    },
    // 输入时打开异步,下拉open/close关闭异步
    treeKeydown() {
      this.isAsync = true
      this.expandLevel = 10
    },
    treeKeyup(e) {
      if (!e.target.value) {
        this.isAsync = false
        this.initialCallback = false
        this.expandLevel = 0
      }
    },
    itemopen() {
      this.tooltipDisabled = true
      this.isAsync = false
      this.initialCallback = false
      this.expandLevel = 0
      this.product_map = JSON.parse(JSON.stringify(this.product_mapTemp))
    },
    itemClose() {
      this.isAsync = false
      this.tooltipDisabled = !this.checkRroduct
      this.initialCallback = false
      this.expandLevel = 0
    },
    transformData(groupId, groupName, staff_id, name, flag) {
      const groups = groupId.split('/')
      const names = groupName.split('/')

      // 检查groupId和groupName的分割是否匹配
      if (groups.length !== names.length) {
        throw new Error('groupId和groupName的分割不匹配')
      }

      // 递归函数来构建树形结构
      function buildTree(index) {
        if (flag && index >= groups.length) {
          // 当到达叶子节点时,添加额外的staff信息
          return {
            id: staff_id,
            label: name,
            longTitle: `${names.slice(0, index).join(' / ')} / ${name}`,
            children: []
          }
        } else if (index >= groups.length) {
          return null
        }
        const currentGroupId = groups[index]
        const currentGroupName = names[index]
        const longTitle = index === 0 ? currentGroupName : `${names.slice(0, index + 1).join(' / ')}`

        const child = buildTree(index + 1) // 递归构建子节点

        return {
          id: Number(currentGroupId),
          label: currentGroupName,
          longTitle: longTitle,
          children: child ? [child] : flag ? null : [] // 如果有子节点,则放入数组中
        }
      }

      // 从根节点开始构建树
      const root = buildTree(0)

      return root
    }
  }
}
</script>

<style lang="scss" scoped>
.labelClass {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.treeClass {
  ::v-deep .vue-treeselect__placeholder {
    color: black;
  }
}

.is-disabled {
  /* 设置禁用选项的样式 */
  color: #ccc;
  cursor: not-allowed;
  /* 可以添加更多样式 */
}
</style>

后记: 附上vue-treeselect的组件样式修改

// 选择框的样式
::v-deep .vue-treeselect__control {
  background-color: rgb(10, 19, 33) !important;
  border: rgb(10, 19, 33);
}
// 下拉框的样式
// ::v-deep .vue-treeselect__option {
//   color: #2d8cf0;
// }
// 选中项的样式
::v-deep .vue-treeselect__single-value {
  color: #2d8cf0;
}
// 默认提示语的样式
::v-deep .vue-treeselect__placeholder {
  color: #2d8cf0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/579189.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java高阶私房菜-JVM垃圾回收机制及算法原理探究

目录 垃圾回收机制 什么是垃圾回收机制 JVM的自动垃圾回收机制 垃圾回收机制的关键知识点 初步了解判断方法-引用计数法 GCRoot和可达性分析算法 什么是可达性分析算法 什么是GC Root 对象回收的关键知识点 标记对象可回收就一定会被回收吗&#xff1f; 可达性分析算…

阳光电源社招前程无忧智鼎题库及远程包过助攻需要重点考察什么?

阳光电源社招前程无忧智鼎题库及远程包过助攻需要重点考察什么&#xff1f; 结合长期服务大型国有企业校招工作的经验&#xff0c;我们总结出阳光电源社招笔试的典型模式&#xff1a;行政职业能力测试企业应知应会测试心理测评&#xff0c;综合考察候选人的政治素养、文化素养…

VC2022 + protobuf

google这是有私心啊&#xff0c;protobuf从某个版本开始&#xff0c;依赖了一个google自己推出的大型组件集&#xff0c;Abseil&#xff0c;有点类似于Boost了&#xff0c;业内用的人&#xff0c;从个人狭窄的圈子来说&#xff0c;应该是不多的&#xff0c;据说google的众贤用的…

【UnityRPG游戏制作】RPG项目的背包系统商城系统和BOSS大界面

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

【C++】简易二叉搜索树

目录 一、概念&#xff1a; 二、代码实现&#xff1a; 大致结构&#xff1a; 1、遍历&#xff1a; 2、insert 3、find 4、erase 三、总结&#xff1a; 一、概念&#xff1a; 二叉搜索树又称为二叉排序树&#xff0c;是一种具有特殊性质的二叉树&#xff0c;对于每一个节…

springboot+springsecurity+vue前后端分离权限管理系统

有任何问题联系本人QQ: 1205326040 1.介绍 优秀的权限管理系统&#xff0c;核心功能已经实现&#xff0c;采用springbootvue前后端分离开发&#xff0c;springsecurity实现权限控制&#xff0c;实现按钮级的权限管理&#xff0c;非常适合作为基础框架进行项目开发。 2.效果图…

ICP点云配准初探

ICP点云配准初探 1 简介2 常用的点云配准算法3 ICP&#xff08;Iterative Closest Point&#xff0c;最近点迭代法&#xff09;3.1 ICP要解决的问题3.2 ICP的核心思想3.3 算法流程3.4 总结 4 ICP优缺点 1 简介 在逆向工程&#xff0c;计算机视觉&#xff0c;文物数字化等领域中…

香港BTC、ETH现货ETF同时通过,对行业意义几何?

香港比美国更快一步通过以太坊现货 ETF。 2024 年 4 月 15 日&#xff0c;香港嘉实国际资产管理有限公司&#xff08;Harvest Global Investments&#xff09;今天宣布&#xff0c;得到香港证监会的原则上批准&#xff0c;将推出两大数字资产&#xff08;比特币及以太坊&#…

​可视化大屏C位图:园区鸟瞰

将园区鸟瞰图作为可视化大屏设计的焦点图有以下几个好处&#xff1a; 提供全局视图&#xff1a;园区鸟瞰图可以展示整个园区的布局和结构&#xff0c;提供全局视图。这对于大型园区或复杂的场所来说尤为重要&#xff0c;用户可以一目了然地了解整个园区的规模、分布和关联关系…

go设计模式之工厂方法模式

工厂方法模式 什么是工厂方法模式 工厂方法模式是一种创建型设计模式&#xff0c;它定义了一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。工厂方法使一个类的实例化推迟到其子类。 这个接口就是工厂接口&#xff0c;子类就是具体工厂类&#xff0c;而需要创…

频率分析和离散傅里叶变换——DSP学习笔记四

背景知识 四种基本的傅里叶变换 基本思想&#xff1a;将信号表示为不同频率 正弦分量的线性组合 正弦信号和复指数时间信号的有用特性 相同频率但不同相位的正弦信号的任何线性组合&#xff0c;都是有着相同频率但不同相位&#xff0c;且幅度可能受改变的正弦信号。 复指数时…

EXCEL表格中的数字,为什么每次打开会自动变成日期?

一、典型现象 在工作中&#xff0c;有时会发现公司里的报表&#xff0c;经过多人多次的重复的使用和修改后&#xff0c;会出现这种情况&#xff1a; 1.在表格里按照需要输入数字&#xff0c;保存工作簿。 2.然而&#xff0c;再次打开工作簿&#xff0c;里面的数字变成日期&a…

Linux多线程(二) 线程同步 信号量互斥锁读写锁条件变量

多个进程同时访问某些资源时&#xff0c;必须考虑同步问题&#xff0c;以确保任一时刻只有一个进程可以拥有对资源的独占式访问。通常&#xff0c;程序对关键资源的访问代码只是很短的一段&#xff0c;我们称这段代码为关键代码段或者临界区&#xff0c;对进程同步&#xff0c;…

火绒安全概述

页面简介&#xff1a; 火绒安全是一款集多种安全功能于一体的国产软件&#xff0c;旨在为用户提供全面的计算机保护。本页面将详细介绍火绒安全的核心功能和使用方式。 页面内容概览&#xff1a; 杀毒防护 实时监控&#xff1a;详细介绍火绒安全如何实时检测系统中的文件和程序…

【强训笔记】day5

NO.1 思路&#xff1a;找到数量最小的字符&#xff0c;就可以知道you的数量&#xff0c;用o的数量减去you的数量再减去1就是oo的数量。 代码实现&#xff1a; #include<iostream>using namespace std;int main() {int q;cin >> q;int a, b, c;while (q--){cin &g…

Java web应用性能分析之【sysbench基准测试】

Java web应用性能分析之【CPU飙高分析之MySQL】-CSDN博客 Java web应用性能分析之【Linux服务器性能监控分析概叙】-CSDN博客 Java web应用性能分析概叙-CSDN博客 Java web应用性能分析之【基准测试】-CSDN博客 上面基本科普了一下基准测试&#xff0c;这里我们将从sysbench…

雷电模拟器,安卓手机模拟器电脑端去广告精简优化版 v9.0.70 (240427)

软件介绍 在众多安卓模拟器中&#xff0c;雷电模拟器作为电脑端手游的首选平台&#xff0c;由上海畅指网络科技有限公司研发并免费提供给用户。此模拟器搭载了先进的内核技术&#xff08;基于版本&#xff09;&#xff0c;确保了软件运行的高速性和稳定性。雷电模拟器还引入了…

【yolov8yolov5驾驶员抽烟-打电话-喝水-吃东西检测】

YOLO算法DMS驾驶员抽烟-打电话-喝水-吃东西检测数据集 YOLOv8和YOLOv5是深度学习中用于目标检测的先进算法&#xff0c;它们在实时性和准确性方面表现出色&#xff0c;适用于各种视频监控和图像处理应用&#xff0c;包括驾驶员行为监测。这些算法通过单次前向传播即可预测图像…

javaScript基础2

javaScript 一.运算符二.流程控制1.顺序流程控制2.分支流程控制&#xff08;1&#xff09;if/if..else/if多分支&#xff08;2&#xff09;.三元表达式&#xff08;4&#xff09;.switch和if else区别 3.循环流程控制(1).for循环/双重for循环(2).一些例子(3).while循环/do..whi…

SpringBoot 接口防抖(防重复提交)的一些实现方案

啥是防抖 所谓防抖&#xff0c;一是防用户手抖&#xff0c;二是防网络抖动。 在Web系统中&#xff0c;表单提交是一个非常常见的功能&#xff0c;如果不加控制&#xff0c;容易因为用户的误操作或网络延迟导致同一请求被发送多次&#xff0c;进而生成重复的数据记录。 要针对…
最新文章