npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@highmark/crm-utils

v0.0.36

Published

```shell npm i @highmark/crm-utils ```

Downloads

55

Readme

安装

npm i @highmark/crm-utils

引入

import utils from '@highmark/crm-utils'

工具类 - tool

tool这块引用了 lodashvueuse, 如果当前项目需要 lodashvueuse 别的方法则单独安装这两个包, 否则会出现幽灵依赖的问题

  • cloneDeep (lodash)

  • debounce (lodash)

  • throttle (lodash)

  • isEqual (lodash)

  • pick (lodash)

  • pickBy (lodash)

  • isNumber (lodash)

  • chunk (lodash)

  • useDebounceFn ( @vueuse/core )

  • useThrottleFn ( @vueuse/core )

  • delay(time=30) // 延迟

  • findNodeByName // 根据 name 获取对应树的节点 (适用于菜单树)

  • calculateStringLength(input:string): number // 计算当前字符串长度, 如果汉字则为2, 如果是英文则为1, 如果没有值则为0

vue element

  • isNonEmptySlot(slots, slotKey) // 查看指定插槽内是否有元素

  • isCommentType // 判断当前目标是否是注释类型 (用于判断虚拟节点)

  • getPaddingByElement. // 获取元素的padding值

    interface IGetPaddingByElement {
      (element: HTMLElement): GetPaddingByElementResultType
    }
    type GetPaddingByElementResultType = {
      top: number
      right: number
      bottom: number
      left: number
    }
  • findParentsWithClass // 找到当前dom节点父级包含className的节点

    interface IFindParentsWithClass {
      // className: 类名不用.开头
      (el: HTMLElement, className: string): HTMLElement[]
    }

处理 url 类. - url

  • replaceCurrentUrl // 替换当前 url

  • paramObjectToQueryString // 将对象转换为参数字符串的工具方法, 返回结果 '?name=aa&age=19'

  • parseQueryString(urlStr) // 解析 url 参数

  • parseUrl // 根据 url 获取参数对象, 返回 { hash: '#...', hostname: 'https://...' , params: { k: v, ... }}

  • mergeFormDataByCurrentUrl( {formData} ) // 融合当前 url 的 formData 参数 (注意是放在当前模块 formData 的默认赋值的上面还是下面, 这个循序会影响相同属性是否会覆盖)

  • toPageCarryFormData({ name, formData }) // 跳转页面并携带 formdata 参数, 会对 formData 进行编码

时间 - time

dayjs改造

  • subDate // 获取时间 a-b 的值, 参数(Date1, Date2)

  • forMatterDate(date, format = 'YYYY-MM-DD HH:mm:ss') // 转换时间格式

  • get30PreDay // 获取 30 天前的时间

  • getCurrentDate(format = 'YYYY-MM-DD HH:mm:ss') // 获取当前时间

  • get30PreDay // 获取三十天前的时间

  • getPreFirstYearAndCurrentDate(format = 'YYYY-MM-DD HH:mm:ss') // 获取当前时间的前一年时间和当前时间, 返回 [ 前一年时间, 当前时间 ]

  • getFirstDayOfCurrentMonth(format = 'YYYY-MM-DD HH:mm:ss') // 获取当前月的第一天

  • getCurrentTimestamp // 获取当前时间戳(以毫秒为单位)

处理业务类 - yewu

  • 😭refreshClientId // 刷新 clientId, 防止重复请求

  • formatUserAndOrg // 格式化对象为 用户带部门的对象(大多用于反显), 参数: { userName, userId, orgId, orgName }

  • 😭openDetailPopup // 打开详情页 ( 传参 { componentName, componentTitle } )

  • 😭refreshAllTabCount // 通过事件总线的方式, 刷新详情中 tabs 组件的 count

  • formatUserAndOrgAndNodeId({ userName, userId, orgId, orgName }) // 格式化对象为 用户带部门的对象, 返回 { name, id, orgs, _node_id }

  • formatNmyUserAndOrgAndNodeId_V2({ orgId, orgName, userId, userName }) // (nmy组织架构组件专用) 格式化对象为 用户带部门的对象, 返回 { userName, userId, orgId, orgName, id: '用户id!部门id' }

  • parseUserAndOrg // 将员工对象格式化为 { userName, userId, orgId, orgName }

数学类 - math

  • addNums // 计算: 加

  • subNums // 计算: 减

  • mulNums // 计算: 乘

  • divNums // 计算: 除

  • round // 四舍五入

  • isNumberStrict // 判断是否是数字 (必须数字类型, 严格模式)

  • isNumberLoose // 判断是否能转换为数字 (任何类型, 宽松模式)

  • getFixed // 解析数字, 补充后两位

  • getFixedNumber // 解析为 最多保留两位小数的数字 (常用于验证: 比较金额, 数量等), 返回数字类型

  • handleOnlyAllowNumber // 只能输入数字和. (用于 input 组件的监听限制)

  • isZero // 判断当前是否是 0 或者'0'

  • truncateDecimal( value, 保留几位 ) // 将数字保留小数 ( 向下取整, 不会约等于 )

  • truncateDecimalStr( value, 保留几位 ) // 值为字符串

  • generateRandomCode 获取随机字符串和数字 (去掉了 0 和o 和 I 和 1, l, 以免歧义)

  • isSame 比较两个数字是否相等

转换 - tran

  • tranId // 转换 id, 如果是正常的 id, 则返回原值, 如果是空或者下面的 id, 则返回 null, 也会判断00000000-0000-0000-0000-000000000000

  • tranDate // 转换时间, 如果是正常的时间, 则返回原值, 如果是空或者下面的 id, 则返回 null, 也会判断1900-01-01 00:00:00

  • tranNumber // 转换为数字, Infinity 或者 NaN 或者 null 或者'' 或者 NaN 或者 undefined 都返回 0

  • parseValueJudgeEmpty // 判断值是否为空, 如果为空返回 '-'

  • tranTipInnerHtml(...args) // 生成tips 的html片段

  • replaceInvalidValuesWithNull(value) // 替换无效值为null, 目标为对象或数组 (用于格式化获取请求回来的数据, 避免出现脏数据)(深度克隆)

校验 - validate

  • isNonEmptyArray // 检查数组是否非空且长度大于 1

  • getFormRulesByCurrentEnv // 根据当前环境(移动端/pc)获取验证规则

    • mobile: { // 数字: 支持验证负数, 支持字符串格式 isNumber // 金额: 数字类型 && 不等于 0 isNonEmptyNumber // 检查数组是否非空且长度大于 1 isNonEmptyArray // 必须填写 requiredInput // 必须选择 requiredSelect // 必须上传 (目标数组, 报错信息) requiredUploadByTarget(附件数组,'报错消息') // 自定义规则 (如果有错误直接返回报错信息, 没有错误不用管) customValidator({ cb:(value)=>{ return '报错信息' } }) }
    • pc: { // 数字: 支持验证负数, 支持字符串格式 isNumber // 金额: 数字类型 && 不能为 0 isNonEmptyNumber, // 检查数组是否非空且长度大于 1 isNonEmptyArray, // 必须填写 requiredInput, // 必须选择 requiredSelect, // 必须上传 requiredUpload, // 自定义规则 (如果有错误直接返回报错信息, 没有错误不用管) customValidator({ cb:(value)=>{ return '报错信息' } }) }

file 文件处理

  • getMd5ByFile // 文件转换为 MD5

  • blobTOBase64 // blob 转 base64

  • blobToFile // blob 转文件

  • urlTOBlob // url 转 blob

  • urlTOFile // url 转 file

  • fileTOBase64 // file 转 base64

  • fileTOBlob // file 转 blob

  • base64TOBlob // base64 转 Blob

  • elementTOImage // img 元素转 base64

permission 权限处理

import { permission } from '../../config/permission'

  • isDisabled // 当前是否是禁用( 响应式 ), 使用: isDisabled(permission.BTN_DETAIL)

    // 计算属性 ComputedRef<Array<string>> 或者 Ref<Array<string> >都可以
    type permissionListProxyType = {
      value: Array<string>
    }
    interface IIsDisabled {
      (action: string, permissionListProxy: permissionListProxyType): Ref<boolean>
    }
  • isEnabled // 当前是否是启用( 响应式 ), 使用: isEnabled(permission.BTN_DETAIL)

client 客户端相关 - client

  • isMobile
  • isSafari
  • useIsMobileHook // 返回 { isMobileRef }
  • isSafari: isSafariType // 当前是否是Safari浏览器
  • isPc: isMobileRefType // 当前是否是PC端
  • isDing: isDingType // 当前是否是钉钉浏览器

vite

  • openEditDetailComponent
options: {

  viewsModuleName?: string    				// 模块名称

  viewModuleId?: string       				// 模块id

  detailComponentName?: string  			// 详情页组件名称

  destroyPropName?: string   					// 组件销毁的props属性名 (对应props值为函数类型)

  routeMapper?: InstanceType<typeof Map<number, string>>   // 模块id和路由映射

  methodMapper: InstanceType<typeof Map<string, any>>   // Map<触发方法名, 传参>

  metaGlobModules: any                // import.meta.glob

}

二次封装

import utils from '@highmark/crm-utils'

/**
 * 创建一个映射,用于存储路由ID和对应的页面路径
 */
const routeMapper = new Map()
// { 模块id, 模块name }
routeMapper.set(1, 'about') // 注意 模块name为views内的模块id, 这里建议与路由的name一致

/**
 * 打开详情页功能。
 * 用于加载并显示指定的详情组件,支持组件名称和组件ID映射的方式。
 * @param {Object} param 一个包含多个配置选项的对象。
 * @param {Map<string, any>} param.methodMapper 组件暴露的方法映射 Map<方法名, 传参|null>
 * @param {string} param.viewsModuleName 视图模块的名称。
 * @param {string} param.viewModuleId 视图模块的ID。
 * @param {string} param.detailComponentName 详情组件的名称,默认为"AddAndEdit.vue"。
 * @param {string} param.destroyPropName 销毁属性的名称,默认为'destroy'。
 */
export function openAddAndDetail({
  exposedMethods,
  viewsModuleName,
  viewModuleId,
  detailComponentName,
  destroyPropName
} = {}) {
  // 判断当前浏览器环境
  const { isMobileRef } = utils.client.useIsMobileHook()

  // 根据当前运行环境动态导入所有视图文件以支持路径的通配符匹配
  let metaGlobModules = ''

  if (isMobileRef.value) {
    // 配置 移动端 详情 路径
    metaGlobModules = import.meta.glob(`@/views/**/mobile/**/**.vue`)
  } else {
    // 配置 pc 详情 路径
    metaGlobModules = import.meta.glob(`@/views/**/pc/**/**.vue`)
  }

  // 调用utils工具库中的方法,以打开编辑详情组件,并传入相关配置
  utils.vite.openEditDetailComponent({
    metaGlobModules,
    methodMapper: methodMapper, // new Map(Object.entries({ open: { dataId: '数据id' } }))
    viewsModuleName: viewsModuleName,
    routeMapper: routeMapper, // 路由映射器,用于解析路由ID到实际路径
    viewModuleId: viewModuleId,
    detailComponentName: detailComponentName || 'AddAndEdit.vue', // 如果未提供详情组件名称,则默认为"AddAndEdit.vue"
    destroyPropName: destroyPropName || 'destroy' // 如果未提供销毁props名称,则默认为'destroy'
  })
}

使用

openAddAndDetail({
  // exposedMethods,
  // viewsModuleName,
  viewModuleId, // 如果配置了 routeMapper 映射, 直接传入模块id即可弹出详情
  //  触发组件暴露方法的映射 Map<方法名, 传参>
  methodMapper: new Map(
    Object.entries({
      // 如果携带数据值为 { dataId, ... }
      open: { dataId: '数据详情的id' }
    })
  )
  // detailComponentName,
  // destroyPropName
})

注意 ( 详情页props必须配置 destroy 属性, 必须暴露 open, close 方法, 如弹窗销毁必须触发销毁props.destroy的方法 ):

const props = defineProps({
  // 销毁
  destroy: {
    type: Function,
    default: null
  }
})

const isShow = ref(false)

/**
 * 触发销毁prop
 **/
const executeDestroyProp = () => {
  if (typeof props.destroy === 'function') {
    props.destroy()
  }
}

const close = () => {
  isShow.value = false
  // 必须执行触发销毁prop
  executeDestroyProp()
}

defineExpose({
  open,
  close
})

公共常量 constant

微服务事件类

utils.constant.microEventTypes

import utils from '@highmark/crm-utils'

// 传向基座
utils.constant.microEventTypes.toBase.OPEN_DETAIL_POPUP
// 传向子模块
utils.constant.microEventTypes.toChild.OPEN_DETAIL_POPUP
// 传向其他兄弟模块
utils.constant.microEventTypes.toSibling.OPEN_DETAIL_POPUP
简单描述传递参数

参数说明 陆续补充

/**
   * 发送到基组件的事件类型
   */
  toBase: {
    /**
     * 打开详细信息弹窗
     * 传参 {
     *  eventType:string,   // 事件类型
     *  moduleId?:string,   // 路由id
     *  moduleName?:string, // 路由Name
     *  appid?:string,      // 微服务Id
     *  detailData?:Record<string, any>  // 详情对象信息
     * }
     */
    OPEN_DETAIL_POPUP,
    /**
     * 刷新待办消息列表数据
     * 传参 {
     *  eventType:string,
     * }
     */
    REFRESH_TODO_MESSAGE_LIST_DATA,
    /**
     * token 过期登出
     * 传参 {
     *  eventType:string,
     * }
     */
    TOKEN_EXPIRES_SIGN_OUT,
    /**
     * 子模块加载路由成功后通知基座的事件
     * 传参 {
     *  eventType:string,
     * }
     */
    LOAD_ROUTES_SUCCESS,
    /**
     * 子模块通知基座已经打开详情;
     * 传参 { state: 'on' | 'off' }
     */
    SWITCH_CHILDREN_DETAIL_POPUP_STATE
  },
  /**
   * 发送到子组件的事件类型
   */
  toChild: {
    /**
     * 打开详细信息弹窗
     *  传参 {
     *  eventType:string,   // 事件类型
     *  moduleId?:string,   // 路由id
     *  moduleName?:string, // 路由Name
     *  appid?:string,      // 微服务Id
     *  detailData?:Record<string, any>  // 详情对象信息
     * }
     */
    OPEN_DETAIL_POPUP,
    /**
     * 用户权限信息
     * 传参 {
     *  eventType:string,   // 事件类型
     *  menus:Array<{ name:string, path:string, children: any[], meta: {  appid:string, title:string, type:string, icon:string, ... } }>,  // 菜单
     *  permission: string[],  // 按钮权限
     *  refreshToken: string,  // 刷新token
     *  token: string,         // token
     *  userInfo: Record<string, any>  // 用户信息
     *  refreshTokenFn: 刷新 token 和 refreshToken的方法
     *                  ( 注意: 该方法为异步函数, 返回值 { token, refreshToken } )
     *  baseRouter,     // 基座router路由对象
     * }
     */
    AUTH_DATA,
    /**
     * 通知 子模块 更新本地 token 和 refreshToken
     * 传参 {
     *  token, refreshToken
     *  }
     */
    UPDATE_TOKEN_AND_REFRESHTOKEN,
    /**
     * 通知 子模块 的 keepAlive 路由列表
     * 传参 {
     *  keepAliveList: string[]
     * }
     */
    UPDATE_KEEP_ALIVE_LIST,
     /**
     * 通知子模块刷新页面
     */
    REFRESH_PAGE
  },
  /**
   * 发送到同级组件的事件类型
   */
  toSibling: {
    /**
     * 打开详细信息弹窗
     *  传参 {
     *  eventType:string,   // 事件类型
     *  moduleId?:string,   // 路由id
     *  moduleName?:string, // 路由Name
     *  appid?:string,      // 微服务Id
     *  detailData?:Record<string, any>  // 详情对象信息
     * }
     */
    OPEN_DETAIL_POPUP
  }
子模块获取auth的案例
// 获取用户权限相关信息
const { authData } = initAuthData()

// 可以拿到token, 菜单...等信息
// console.log(authData.token)

// 初始化权限信息
function initAuthData() {
  const data = window.microApp.getData() // 返回主应用下发的data数据

  let authData // 权限信息

  // 判断类型为权限才会赋值
  if (data.eventType === crmUtils.constant.microEventTypes.toChild.AUTH_DATA) {
    authData = data || {}
  }

  return {
    authData
  }
}