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

@cqsjjb/jjb-data-provider

v0.0.6

Published

A data provider library for application state management, including permission control and dynamic field text replacement

Readme

@cqsjjb/jjb-data-provider

应用数据提供者库,提供权限管理和字段动态文本功能。

功能特性

  • 🔐 权限管理:自动获取当前路由的按钮权限,支持权限检查
  • 📝 字段动态文本:支持字段代码的动态替换和查询
  • 🚀 自动更新:监听路由变化,自动更新权限和字段数据
  • 💾 数据缓存:内存缓存机制,避免重复请求,提升性能
  • 🎯 类型支持:完整的 TypeScript 类型定义

安装

yarn add @cqsjjb/jjb-data-provider

或使用 npm:

npm install @cqsjjb/jjb-data-provider

快速开始

1. 在应用根组件中引入 Provider

import React from 'react';
import { AppDataProvider } from '@cqsjjb/jjb-data-provider';

function App() {
  return (
    <AppDataProvider>
      {/* 你的应用组件 */}
    </AppDataProvider>
  );
}

export default App;

2. 使用权限控制组件

import { PermissionCode } from '@cqsjjb/jjb-data-provider';

function MyComponent() {
  return (
    <div>
      {/* 单个权限控制 */}
      <PermissionCode code="edit">
        <button>编辑</button>
      </PermissionCode>

      {/* 多个权限控制(只要有一个权限存在就显示) */}
      <PermissionCode code={['add', 'edit']}>
        <button>操作</button>
      </PermissionCode>
    </div>
  );
}

3. 使用 Hooks

方式 1:使用通用 Hook(推荐)

import { useAppData } from '@cqsjjb/jjb-data-provider';

function MyComponent() {
  const { checkPermission, replaceFieldCode, checkField, permissions, fields } = useAppData();

  // 检查权限
  const canEdit = checkPermission('edit');
  const canAddOrEdit = checkPermission(['add', 'edit']);

  // 替换字段代码
  const message = replaceFieldCode('请输入{add}'); // 假设 fields 中有 { fieldCode: 'add', fieldRename: '姓名' }
  // 结果: '请输入姓名'

  // 查询字段信息
  const fieldName = checkField('add'); // 返回字段重命名或空字符串
  const fieldNameWithDefault = checkField('add', '默认字段名'); // 返回字段重命名或'默认字段名'

  return (
    <div>
      {canEdit && <button>编辑</button>}
      <p>{message}</p>
    </div>
  );
}

方式 2:使用专门的权限 Hook

import { usePermission } from '@cqsjjb/jjb-data-provider';

function MyComponent() {
  const checkPermission = usePermission();
  const canEdit = checkPermission('edit');

  return (
    <div>
      {canEdit && <button>编辑</button>}
    </div>
  );
}

方式 3:使用字段 Hook

import { useField } from '@cqsjjb/jjb-data-provider';

function MyComponent() {
  const { checkField, replaceFieldCode } = useField();
  const fieldName = checkField('add');
  const message = replaceFieldCode('请输入{add}');

  return (
    <div>
      <label>{fieldName}</label>
      <input placeholder={message} />
    </div>
  );
}

方式 4:使用数据 Hook

import { usePermissions, useFields } from '@cqsjjb/jjb-data-provider';

function MyComponent() {
  const permissions = usePermissions();
  const fields = useFields();

  // 遍历权限列表
  const hasAnyPermission = permissions.length > 0;

  // 遍历字段列表
  const fieldMap = fields.reduce((acc, field) => {
    acc[field.fieldCode] = field.fieldRename;
    return acc;
  }, {});

  return (
    <div>
      {hasAnyPermission && <p>您有 {permissions.length} 个权限</p>}
    </div>
  );
}

方式 5:使用 Context(传统方式)

import React, { useContext } from 'react';
import { AppDataContext } from '@cqsjjb/jjb-data-provider';

function MyComponent() {
  const { checkPermission, replaceFieldCode, checkField } = useContext(AppDataContext);
  // ... 使用方式同方式 1
}

API 文档

AppDataProvider

Provider 组件,用于提供权限和字段数据。

Props:

| 属性 | 类型 | 必填 | 说明 | |------|------|------|------| | children | React.ReactNode | 是 | 子组件 |

功能:

  • 在组件初始化时自动获取当前路由的按钮权限和字段数据
  • 监听路由变化(支持 Navigation API 和 popstate 事件),自动更新权限和字段数据
  • sessionStorage 中获取 token 用于 API 请求

PermissionCode

权限控制组件,根据权限 code 控制子组件的显示。

Props:

| 属性 | 类型 | 必填 | 说明 | |------|------|------|------| | code | string | string[] | 是 | 权限 code 或权限 code 数组 | | children | React.ReactNode | 是 | 子组件 |

说明:

  • 如果传入数组,只要有一个权限存在就显示子组件
  • 如果没有权限,子组件将不会渲染

Hooks API

useAppData

获取应用数据的通用 Hook,返回所有权限和字段相关的方法和数据。

返回值: AppDataContextValue

示例:

const { permissions, fields, checkPermission, checkField, replaceFieldCode } = useAppData();

usePermission

权限检查 Hook,专门用于权限检查场景。

返回值: (permissionCode: string | string[]) => boolean

示例:

const checkPermission = usePermission();
const canEdit = checkPermission('edit');
const canAddOrEdit = checkPermission(['add', 'edit']);

useField

字段相关操作 Hook,返回字段查询和替换方法。

返回值: { checkField: Function, replaceFieldCode: Function }

示例:

const { checkField, replaceFieldCode } = useField();
const fieldName = checkField('add');
const message = replaceFieldCode('请输入{add}');

usePermissions

获取权限列表 Hook,返回权限数组。

返回值: string[]

示例:

const permissions = usePermissions();
// permissions: ['add', 'edit', 'delete']

useFields

获取字段列表 Hook,返回字段数组。

返回值: Field[]

示例:

const fields = useFields();
// fields: [{ fieldCode: 'add', fieldRename: '姓名', fieldName: '用户姓名' }]

缓存管理 API

clearRouteDataCache

清除指定路由的缓存或清空所有缓存。

参数:

  • path?: string - 路由路径,如果不传则清除所有缓存

示例:

import { clearRouteDataCache } from '@cqsjjb/jjb-data-provider';

// 清除指定路由的缓存
clearRouteDataCache('/some/path');

// 清除所有缓存
clearRouteDataCache();

getRouteDataCache

获取指定路由的缓存数据。

参数:

  • path: string - 路由路径

返回值: RouteCacheData | undefined

示例:

import { getRouteDataCache } from '@cqsjjb/jjb-data-provider';

const cache = getRouteDataCache('/some/path');
if (cache) {
  console.log('权限:', cache.permissions);
  console.log('字段:', cache.fields);
}

getAllRouteDataCache

获取所有路由的缓存数据。

返回值: Map<string, RouteCacheData>

示例:

import { getAllRouteDataCache } from '@cqsjjb/jjb-data-provider';

const allCache = getAllRouteDataCache();
allCache.forEach((data, path) => {
  console.log(`路由 ${path} 的缓存:`, data);
});

AppDataContext

Context 对象,通过 useContext Hook 使用(推荐使用 useAppData Hook)。

Context 值类型:

interface AppDataContextValue {
  /** 权限列表 */
  permissions: string[];
  /** 字段列表 */
  fields: Field[];
  /** 检查权限方法 */
  checkPermission: (permissionCode: string | string[]) => boolean;
  /** 替换字段代码方法 */
  replaceFieldCode: (template: string) => string;
  /** 查询字段信息方法 */
  checkField: (fieldCode: string, defaultValue?: string) => string;
}

permissions

权限列表,字符串数组。由 Provider 自动从后端 API 获取。

fields

字段列表,包含字段的动态文本信息。

interface Field {
  /** 字段代码 */
  fieldCode: string;
  /** 字段重命名 */
  fieldRename: string;
  /** 字段名称 */
  fieldName: string;
}

checkPermission

检查权限方法。

参数:

  • permissionCode: string | string[] - 权限 code 或权限 code 数组

返回值:

  • boolean - 是否拥有该权限(传入数组时,只要有一个权限存在就返回 true

示例:

const { checkPermission } = useContext(AppDataContext);

// 单个权限检查
const canEdit = checkPermission('edit');

// 多个权限检查(只要有一个权限存在就返回 true)
const canAddOrEdit = checkPermission(['add', 'edit']);

replaceFieldCode

替换字段代码方法,将模板字符串中的字段 code 替换为 fieldRename

参数:

  • template: string - 模板字符串,例如 '请输入{add}'

返回值:

  • string - 格式化后的字符串

示例:

const { replaceFieldCode } = useContext(AppDataContext);

// 假设 fields 中有 { fieldCode: 'add', fieldRename: '姓名' }
const message = replaceFieldCode('请输入{add}'); // 返回: '请输入姓名'

checkField

查询字段信息方法,根据字段code查找对应的字段重命名。

参数:

  • fieldCode: string - 字段代码
  • defaultValue?: string - 默认值,当字段不存在时返回该值,默认为空字符串

返回值:

  • string - 字段重命名字符串,如果不存在则返回 defaultValue

示例:

const { checkField } = useContext(AppDataContext);

// 使用默认值(空字符串)
const fieldName = checkField('add'); // 返回字段重命名或空字符串

// 自定义默认值
const fieldName2 = checkField('add', '默认字段名'); // 返回字段重命名或'默认字段名'

使用示例

示例 1:按钮权限控制

import { PermissionCode } from '@cqsjjb/jjb-data-provider';

function UserList() {
  return (
    <div>
      <h1>用户列表</h1>
      <PermissionCode code="add">
        <button>新增用户</button>
      </PermissionCode>
      <PermissionCode code="edit">
        <button>编辑</button>
      </PermissionCode>
      <PermissionCode code="delete">
        <button>删除</button>
      </PermissionCode>
    </div>
  );
}

示例 2:条件渲染

import { usePermission } from '@cqsjjb/jjb-data-provider';

function UserForm() {
  const checkPermission = usePermission();
  const canEdit = checkPermission('edit');

  return (
    <form>
      <input type="text" disabled={!canEdit} />
      {canEdit && <button type="submit">保存</button>}
    </form>
  );
}

或使用通用 Hook:

import { useAppData } from '@cqsjjb/jjb-data-provider';

function UserForm() {
  const { checkPermission } = useAppData();
  const canEdit = checkPermission('edit');

  return (
    <form>
      <input type="text" disabled={!canEdit} />
      {canEdit && <button type="submit">保存</button>}
    </form>
  );
}

示例 3:动态文本替换

import { useField } from '@cqsjjb/jjb-data-provider';

function SearchForm() {
  const { replaceFieldCode } = useField();

  return (
    <form>
      <input 
        type="text" 
        placeholder={replaceFieldCode('请输入{add}进行搜索')} 
      />
      <button type="submit">搜索</button>
    </form>
  );
}

或使用通用 Hook:

import { useAppData } from '@cqsjjb/jjb-data-provider';

function SearchForm() {
  const { replaceFieldCode } = useAppData();

  return (
    <form>
      <input 
        type="text" 
        placeholder={replaceFieldCode('请输入{add}进行搜索')} 
      />
      <button type="submit">搜索</button>
    </form>
  );
}

示例 4:字段信息查询

import { useField } from '@cqsjjb/jjb-data-provider';

function FieldDisplay() {
  const { checkField } = useField();
  const fieldName = checkField('userName', '用户名');

  return (
    <div>
      <label>
        {fieldName}:
        <input type="text" />
      </label>
    </div>
  );
}

示例 5:权限列表遍历

import { usePermissions } from '@cqsjjb/jjb-data-provider';

function PermissionList() {
  const permissions = usePermissions();

  return (
    <div>
      <h3>当前权限列表:</h3>
      <ul>
        {permissions.map(permission => (
          <li key={permission}>{permission}</li>
        ))}
      </ul>
    </div>
  );
}

示例 6:字段列表遍历

import { useFields } from '@cqsjjb/jjb-data-provider';

function FieldList() {
  const fields = useFields();

  return (
    <div>
      <h3>字段映射:</h3>
      <table>
        <thead>
          <tr>
            <th>字段代码</th>
            <th>字段重命名</th>
          </tr>
        </thead>
        <tbody>
          {fields.map(field => (
            <tr key={field.fieldCode}>
              <td>{field.fieldCode}</td>
              <td>{field.fieldRename}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

示例 7:组合使用多个 Hook

import { usePermission, useField, usePermissions } from '@cqsjjb/jjb-data-provider';

function ComplexComponent() {
  // 只获取需要的功能,避免不必要的重渲染
  const checkPermission = usePermission();
  const { replaceFieldCode } = useField();
  const permissions = usePermissions();

  const canEdit = checkPermission('edit');
  const message = replaceFieldCode('请输入{add}');
  const hasPermissions = permissions.length > 0;

  return (
    <div>
      {hasPermissions && (
        <div>
          <p>{message}</p>
          {canEdit && <button>编辑</button>}
        </div>
      )}
    </div>
  );
}

示例 8:缓存管理

import { clearRouteDataCache, getRouteDataCache } from '@cqsjjb/jjb-data-provider';

// 用户登出时清除所有缓存
function handleLogout() {
  // 清除所有路由缓存
  clearRouteDataCache();
  // 执行登出逻辑...
}

// 权限变更后清除指定路由的缓存
function handlePermissionChange(routePath) {
  // 清除指定路由的缓存,下次访问时会重新请求
  clearRouteDataCache(routePath);
}

// 查看缓存数据(调试用)
function checkCache(routePath) {
  const cache = getRouteDataCache(routePath);
  if (cache) {
    console.log('权限缓存:', cache.permissions);
    console.log('字段缓存:', cache.fields);
  } else {
    console.log('该路由暂无缓存');
  }
}

API 接口说明

Provider 会自动调用以下 API 接口:

获取按钮权限

接口地址: GET /system/operation/menus/list/current/buttons-perms

请求参数:

| 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | path | string | 是 | 当前路由路径 |

请求头:

Content-Type: application/json
token: <从 sessionStorage 获取>

响应数据:

{
  "data": ["add", "edit", "delete"]
}

获取字段动态文本

接口地址: GET /system/operation/menus/menu-field/by-path

请求参数:

| 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | path | string | 是 | 当前路由路径 |

请求头:

Content-Type: application/json
token: <从 sessionStorage 获取>

响应数据:

{
  "data": [
    {
      "fieldCode": "add",
      "fieldRename": "姓名",
      "fieldName": "用户姓名",
      "visibleEnum": "FALSE"
    }
  ]
}

说明: 只有 visibleEnum'FALSE' 的字段会被保存到 fields 中。

缓存机制

为了提升性能,减少不必要的网络请求,AppDataProvider 实现了内存缓存机制:

工作原理

  1. 首次访问:当首次访问某个路由时,会发起接口请求获取权限和字段数据,并将结果缓存到内存中
  2. 再次访问:当再次访问相同路由时,直接从缓存中读取数据,不再发起接口请求
  3. 缓存存储:缓存存储在模块级别的 Map 对象中,以路由路径为 key

使用场景

缓存机制在以下场景特别有用:

  • 频繁路由切换:用户在多个页面间快速切换时,避免重复请求
  • 浏览器前进/后退:使用浏览器导航时,直接使用缓存数据
  • 性能优化:减少网络请求,提升页面响应速度

缓存管理

如果需要清除缓存(例如用户权限变更、登出等场景),可以使用缓存管理 API:

import { clearRouteDataCache, getRouteDataCache, getAllRouteDataCache } from '@cqsjjb/jjb-data-provider';

// 清除指定路由的缓存
clearRouteDataCache('/some/path');

// 清除所有缓存(例如用户登出时)
clearRouteDataCache();

// 查看指定路由的缓存
const cache = getRouteDataCache('/some/path');

// 查看所有缓存
const allCache = getAllRouteDataCache();

缓存数据结构

interface RouteCacheData {
  /** 权限列表 */
  permissions?: string[];
  /** 字段列表 */
  fields?: Field[];
}

环境变量

Provider 会从 process.env.app.API_HOST 获取 API 地址,如果不存在则使用 window.location.origin

注意事项

  1. Token 存储:组件从 sessionStorage.getItem('token') 获取 token,请确保在调用 API 前已设置 token
  2. 路由监听:组件优先使用 Navigation API 监听路由变化,如果不支持则降级使用 popstate 事件
  3. 字段过滤:只有 visibleEnum'FALSE' 的字段会被保存到 fields
  4. 权限数组:当传入权限数组时,checkPermissionPermissionCode 组件使用 some 逻辑(只要有一个权限存在就返回 true
  5. 缓存机制
    • 缓存存储在内存中,页面刷新后会清空
    • 如果用户权限或字段配置发生变化,建议调用 clearRouteDataCache() 清除缓存
    • 用户登出时,建议清除所有缓存以确保数据安全
  6. Hook 使用建议
    • 推荐使用 useAppData 获取所有功能(最常用)
    • 如果只需要权限检查,使用 usePermission 更简洁
    • 如果只需要字段操作,使用 useField 更聚焦
    • 如果只需要数据列表,使用 usePermissionsuseFields 避免不必要的重渲染
  7. 性能优化:使用专门的 Hook(如 usePermissionuseField)可以避免在不需要的数据变化时触发组件重渲染

许可证

MIT

作者

jjb-front-team