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

@kordar/easyui-tpl

v2.0.9

Published

基于 `rc-easyui`、`@kordar/easyui` 与 `@kordar-lib/*` 生态构建的后台模板工程。项目内置布局、菜单/标签联动、权限校验、国际化、后台资源管理页面示例,可直接作为 React 管理后台项目的起步模板,也适合作为二次封装 EasyUI 业务组件的参考工程。

Readme

@kordar/easyui-tpl

基于 rc-easyui@kordar/easyui@kordar-lib/* 生态构建的后台模板工程。项目内置布局、菜单/标签联动、权限校验、国际化、后台资源管理页面示例,可直接作为 React 管理后台项目的起步模板,也适合作为二次封装 EasyUI 业务组件的参考工程。

目录

项目定位与特性

本模板聚焦“后台基础壳 + 通用业务页 + EasyUI 交互封装”三类能力:

  • 布局能力:BaseLayout 提供头部工具区、侧边栏、标签页、内容区联动
  • 列表与表单:useLocalTableuseTablePaginationPanel、通用表单与表格工具函数
  • 权限体系:基于 @kordar-lib/base 与 reducers 的权限校验、按钮显隐、页面跳转保护
  • 国际化:@kordar-lib/i18n 集成,内置 en / zh_CN 示例语言包
  • 主题切换:通过 SettingBarItem@kordar/easyuiuseTheme() 打通本地主题切换
  • 示例页面:提供用户、角色、权限、字典、路由、设置、登录、首页、大屏设计等后台页面

适用场景:

  • 快速搭建基于 rc-easyui 的 React 管理后台
  • 沉淀企业后台“布局 + 表格 + 权限 + 国际化”的统一工程模板
  • 作为二次封装 @kordar/easyui 业务组件的宿主工程

快速开始

安装

npm install

本地开发

npm run -w @kordar/easyui-tpl dev

默认 Vite 入口为 examples/main.tsx

构建

npm run -w @kordar/easyui-tpl build

构建产物输出到 dist,包含:

  • ESM:dist/index.js
  • CJS:dist/index.umd.cjs
  • 样式:dist/index.min.css

最小接入示例

import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'

import App from './App'
import './init'
import './example.scss'
import { persistor, store } from './store'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <Provider store={store}>
    <PersistGate loading={null} persistor={persistor}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </PersistGate>
  </Provider>
)

项目结构总览

easyui-tpl/
├── src/
│   ├── components/    # 基础组件与工具条组件
│   ├── composable/    # 页面启动、表格、菜单与刷新 Hook
│   ├── hoc/           # 文档/配置增强 HOC
│   ├── service/       # Admin/Rbac/Resource/Auth/Config 服务层
│   ├── util/          # 表单、表格、懒加载、辅助函数
│   ├── views/         # 后台业务页面模块
│   ├── init.ts        # request / api 注册入口
│   └── index.ts       # 对外导出入口
├── examples/          # 可运行示例工程(入口、路由、Store、Mock)
├── public/            # i18n 语言包
├── README.md
└── vite.config.ts

目录职责说明:

  • src/components:布局、语言切换、主题切换、分页、提示、用户菜单等
  • src/composable:应用启动、菜单与标签联动、本地/远程表格、路由跳转、刷新控制等
  • src/service:统一封装资源接口、认证接口、配置接口
  • src/views:开箱即用的后台页面示例
  • examples:本地演示应用与调试入口

初始化与运行机制

1. 安装 request 与 API 映射

examples/init.ts 展示了语言包、EasyUI locale 包、接口地址与 request 实例的初始化方式:

import { install } from '../src'
import { request } from './util/http'

install({
  request,
  apis: {
    menus: 'menus',
    loginSubmit: 'login/submit',
    adminInfo: 'resource/admin/info',
  },
})

2. 应用启动

根组件通过 useAppStarter() 完成语言包同步与登录态重定向:

import { LocaleProvider, Messager } from 'rc-easyui'
import { useAppStarter } from '../src'
import { alertMessagerRef, interactiveMessagerRef } from '@kordar/easyui'

function App() {
  const { easyuiLangPkg } = useAppStarter()

  return (
    <LocaleProvider locale={easyuiLangPkg?.value}>
      <>
        <BaseRouter />
        <Messager ref={alertMessagerRef} />
        <Messager ref={interactiveMessagerRef} />
      </>
    </LocaleProvider>
  )
}

3. 页面渲染链路

典型页面渲染流程如下:

  1. install() 注册 request 与 API 表
  2. useAppStarter() 载入当前语言包并执行自动跳转
  3. BaseLayout 读取菜单、固定欢迎页、权限列表
  4. useMenuAndTabData() 维护侧栏和标签页联动
  5. 业务页通过 withDocHoc() 注入 pageConfig / fetchConfig
  6. 表格页通过 useLocalTable()useTable() 管理分页、搜索、刷新与权限

导出模块清单

src/index.ts 当前主要导出如下能力:

组件与 HOC

| 模块 | 导出名 | 说明 | | --- | --- | --- | | 布局组件 | BaseLayout | 后台主布局壳 | | 工具条组件 | LocaleBarItem | 语言切换菜单 | | 工具条组件 | PaginationPanel | 分页栏桥接组件 | | 工具条组件 | SettingBarItem | 主题切换入口 | | 提示组件 | Tooltip | 文本溢出提示组件 | | HOC | withDocHoc | 页面语言与后台配置注入 | | Context | AppLayoutContext | 布局上下文 |

Hook / 工具 / 服务 / 页面

| 分类 | 导出名 | 说明 | | --- | --- | --- | | Hook | useMenuAndTabData | 菜单与标签页联动 | | Hook | useAppStarter | 应用启动初始化 | | Hook | useLocalTable | 本地表格状态封装 | | Hook | useTable | 远程表格状态封装 | | Hook | useAppRedirect | 路由跳转保护 | | 服务 | resourceService / rbacService / adminService / configService | 资源、权限、管理员、配置接口封装 | | 页面 | AdminView / RolesView / PermissionsView / DictView 等 | 业务页面模块 |

核心组件模块说明与使用方法

本章只说明模板工程内部已经封装完成、并能直接在项目中复用的核心模块。所有示例均基于当前仓库真实源码组织,并优先沿用 examples 中的使用方式。

BaseLayout

源码位置

功能定位

  • 提供后台统一骨架:头部栏、侧边栏、标签页、主内容区、页脚
  • 负责菜单树加载、标签页同步、当前路由切换与权限加载
  • 适合作为整个后台应用的根布局组件

适用场景

  • 多菜单、多标签页的管理后台
  • 需要统一接入用户栏、语言切换、主题切换的项目
  • 需要把业务页面通过路由 Outlet 渲染到主工作区的工程

基础参数

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | footer | React.ReactNode | undefined | 传入页脚区域内容 | | ...props | any | - | 其余属性原样透传给 @kordar/easyuiFullBodyLayout |

固定内部配置:

  • tabsCfg = { border: false, plain: true, scrollable: true, narrow: false }
  • sideCfg = { border: false, animate: true, multiple: true, showCollapsedText: false }

基础调用

import { BaseLayout } from '@kordar/easyui-tpl'

export default function AppLayout() {
  return (
    <BaseLayout footer={<span>Powered by Kordar</span>}>
      {/* BaseLayout 内部会自行渲染 TabsPanel 与 <Outlet /> */}
    </BaseLayout>
  )
}

进阶调用

import { Layout } from 'antd'
import { TabsPanel } from '@kordar/easyui'
import { BaseLayout } from '@kordar/easyui-tpl'

export default function CustomLayout() {
  return (
    <BaseLayout footer={<span>Footer Area</span>} className="app-layout">
      <Layout style={{ padding: '4px', height: 48 }}>
        <TabsPanel data={[]} tabsCfg={{ scrollable: true }} />
      </Layout>
      <Layout style={{ padding: 12, height: '100%' }}>
        <div>这里放自定义业务面板</div>
      </Layout>
    </BaseLayout>
  )
}

事件列表

| 事件 / 回调 | 触发时机 | 回调参数 | 说明 | | --- | --- | --- | --- | | toggle(value) | 点击折叠/展开侧边栏 | value: boolean | 由内部调用 setSidebarCollapsed() 更新状态 | | sidebarCfg.onItemClick(selection) | 点击侧栏菜单项 | selection: SideBarItem | 内部映射到 onMenuSelection() |

说明:BaseLayout 本身没有额外向外暴露 React 事件 props,但会透传底层 FullBodyLayout 的能力。

实例方法

  • 无额外对外 ref 方法

预览区域

建议运行 npm run dev 后进入示例应用,重点观察:

  1. 左侧菜单切换
  2. 顶部 User / Locale / Theme 工具条
  3. 标签页关闭与当前路由联动

LocaleBarItem

源码位置

功能定位

  • 提供头部语言切换菜单
  • 基于 @kordar/easyuiuseLocale(true) 切换当前语言,并刷新页面资源

适用场景

  • 中英文后台
  • 需要把 rc-easyui locale 与业务语言包同步切换的工程

基础参数

该组件当前不接收额外 props。

基础调用

import { LocaleBarItem } from '@kordar/easyui-tpl'

export default function HeaderRight() {
  return <LocaleBarItem />
}

进阶调用

import { BaseLayout, LocaleBarItem } from '@kordar/easyui-tpl'

export default function LayoutWithLocale() {
  return (
    <BaseLayout
      slots={{
        barRight: <LocaleBarItem />,
      }}
    />
  )
}

事件列表

| 事件 / 回调 | 触发时机 | 回调参数 | 说明 | | --- | --- | --- | --- | | onMenuItemClick | 选择语言项时 | key: string | 内部绑定到 changeLocale() |

实例方法

  • 无额外实例方法

预览区域

运行示例后,点击头部语言图标,验证 MenuButton 展开、语言切换以及文案刷新效果。

SettingBarItem

源码位置

功能定位

  • 提供主题切换抽屉入口
  • 使用 DrawerPanel + Panel + RadioButton 构建主题配置面板

适用场景

  • 需要支持多主题后台
  • 希望把主题切换能力统一放在顶部工具区

基础参数

该组件当前不接收额外 props。

基础调用

import { SettingBarItem } from '@kordar/easyui-tpl'

export default function HeaderTheme() {
  return <SettingBarItem />
}

进阶调用

import { SettingBarItem } from '@kordar/easyui-tpl'

function RightBar() {
  return (
    <>
      <SettingBarItem />
    </>
  )
}

事件列表

| 事件 / 回调 | 触发时机 | 回调参数 | 说明 | | --- | --- | --- | --- | | onClick | 点击调色板按钮时 | MouseEvent | 内部调用 ref.current.toggle() 打开抽屉 | | onChange | 主题单选框切换时 | checked: boolean | 内部触发 changeTheme(value) |

实例方法

  • 对外无 ref 方法
  • 内部依赖 DrawerPaneltoggle() 方法控制开关

预览区域

建议截取“主题抽屉展开 + 多个 RadioButton 主题项”的界面作为组件截图。

PaginationPanel

源码位置

功能定位

  • 把表格上下文中的分页状态桥接到 rc-easyui/Pagination
  • 统一分页栏配置,降低各页面重复样板代码

适用场景

  • 所有基于 TableContext 的列表页
  • 使用 useLocalTable()useTable() 的分页列表页面

基础参数

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | ctx | TableContext | 必填 | 需要提供 pageChange(pageNumber, pageSize) 方法 | | ctxState | TableContextState | 必填 | 分页状态容器,提供 total/pageNumber/pageSize/layout/pageSizes |

基础调用

import { PaginationPanel } from '@kordar/easyui-tpl'

function PageFooter({ ctx, ctxState }: any) {
  return <PaginationPanel ctx={ctx} ctxState={ctxState} />
}

进阶调用

import { PaginationPanel, useTable } from '@kordar/easyui-tpl'

function UserTablePage() {
  const [ctx, ctxState] = useTable({ defaultPageSize: 20 }, '')

  return (
    <>
      <div style={{ minHeight: 320 }}>表格区域</div>
      <PaginationPanel ctx={ctx} ctxState={ctxState} />
    </>
  )
}

事件列表

| 事件 / 回调 | 触发时机 | 回调参数 | 说明 | | --- | --- | --- | --- | | ctx.pageChange(pageNumber, pageSize) | 分页变更时 | pageNumber: number, pageSize: number | 由 Pagination.onPageChange 转发 |

实例方法

  • 无额外实例方法

预览区域

建议在列表页底部截图分页条,重点保留页码、总数、刷新按钮区域。

Tooltip

源码位置

功能定位

  • 为溢出文本提供轻量级提示层
  • 支持 hover / click / focus 三种触发方式
  • 支持自动翻转、跟随鼠标、深浅主题切换

适用场景

  • 表格超长字段
  • 面包屑或标题溢出展示
  • 需要轻量级 tooltip 且不依赖第三方重型提示组件的场景

基础参数

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | text | ReactNode | 必填 | Tooltip 展示内容 | | children | ReactNode | 必填 | 被包裹的触发节点 | | position | 'top' \| 'bottom' \| 'left' \| 'right' | 'bottom' | 提示层方向 | | trigger | 'hover' \| 'click' \| 'focus' | 'hover' | 触发方式 | | delay | number | 50 | 延迟显示时间,单位 ms | | maxWidth | number | 250 | 最大宽度 | | theme | 'dark' \| 'light' | 'dark' | 样式主题 | | followMouse | boolean | false | 是否跟随鼠标 | | autoFlip | boolean | true | 空间不足时是否自动翻转方向 |

基础调用

import { Tooltip } from '@kordar/easyui-tpl'

export default function NameCell() {
  return (
    <Tooltip text="这是完整内容" position="bottom">
      <span style={{ display: 'inline-block', width: 120, overflow: 'hidden', textOverflow: 'ellipsis' }}>
        这是完整内容
      </span>
    </Tooltip>
  )
}

进阶调用

import { Tooltip } from '@kordar/easyui-tpl'

export default function HoverCard() {
  return (
    <Tooltip
      text={<div>可跟随鼠标展示更长的提示内容</div>}
      trigger="hover"
      position="right"
      followMouse
      theme="light"
      maxWidth={320}
    >
      <div style={{ width: 180 }}>将鼠标移动到这里</div>
    </Tooltip>
  )
}

事件列表

该组件不对外暴露额外回调 props,内部通过以下 DOM 事件驱动显示逻辑:

  • onMouseEnter / onMouseLeave
  • onMouseMove
  • onClick
  • onFocus / onBlur

实例方法

  • 无额外实例方法

预览区域

建议在表格超长文本场景截图,展示默认隐藏、悬停后浮层出现的前后对比效果。

withDocHoc

源码位置

功能定位

  • 为业务页面统一注入:
    • pageConfig:当前页面对应语言包
    • fetchConfig:页面初始化配置数据
    • fetchVersion:配置重新拉取后的版本号
  • 自动同步 document.title

适用场景

  • 页面需要按语言包动态生成标题、按钮文案、表格列名
  • 页面需要在加载时请求配置项,如字典、枚举、状态列表

基础参数

withDocHoc() 接收一个 DocHocProps 配置对象:

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | name | string | 必填 | 页面名称,对应语言包 Page/<name> | | fetchConfig | () => Promise<any> | undefined | 页面初始化配置请求函数 |

基础调用

import { withDocHoc } from '@kordar/easyui-tpl'

const RolesPage = ({ pageConfig, fetchConfig }: any) => {
  return <div>{pageConfig.title}</div>
}

export default withDocHoc({ name: 'Roles' })(RolesPage)

进阶调用

import { resourceService, withDocHoc } from '@kordar/easyui-tpl'

const RouterPage = ({ pageConfig, fetchConfig, fetchVersion }: any) => {
  return <div>{fetchVersion}: {pageConfig.title}</div>
}

export default withDocHoc({
  name: 'Router',
  fetchConfig: () => resourceService.configs('router'),
})(RouterPage)

注入属性

| 属性 | 类型 | 说明 | | --- | --- | --- | | pageConfig | Record<string, any> | 当前页面语言包配置 | | fetchConfig | Record<string, any> | 后台返回的配置数据 | | fetchVersion | number | 配置版本号,适合触发下游重渲染 |

事件列表

  • 无额外对外事件

实例方法

  • 无额外实例方法

AppLayoutContext

源码位置

功能定位

  • 用于在布局层向下传递 dispatchuseAppSelectorlocation 等上下文能力
  • 主要服务于布局区内部或扩展组件读取全局状态

上下文结构

| 字段 | 类型 | 说明 | | --- | --- | --- | | dispatch | AppDispatch | Redux dispatch | | useAppSelector | TypedUseSelectorHook<RootState> | 类型化 selector | | location | Location | 当前路由信息 |

基础调用

import { useContext } from 'react'
import { AppLayoutContext } from '@kordar/easyui-tpl'

export default function LayoutConsumer() {
  const ctx = useContext(AppLayoutContext)
  return <div>{String(!!ctx.dispatch)}</div>
}

事件 / 方法

  • 无对外事件
  • 无实例方法

UserBarItem(内部组件)

源码位置

说明

  • 当前未在 src/index.ts 中导出
  • BaseLayout 内部使用,负责显示当前用户名与退出登录菜单

行为特征

  • 读取 state.user.info
  • 点击 Exit 后调用 $confirm()
  • 退出时清理布局状态并跳转到 /login

如需对外复用,建议先在 src/index.ts 中显式导出,并补充 props 类型定义。

useAppStarter

源码位置

功能定位

  • 应用根组件启动专用 Hook
  • 同步当前语言包并执行自动登录态重定向

函数签名

function useAppStarter(): { easyuiLangPkg?: PkgItem }

返回值

| 字段 | 类型 | 说明 | | --- | --- | --- | | easyuiLangPkg | PkgItem \| undefined | 当前激活的 EasyUI 语言包 |

基础调用

const { easyuiLangPkg } = useAppStarter()

useMenuAndTabData

源码位置

功能定位

  • 维护菜单、标签页、当前选中项、固定欢迎页等布局核心状态
  • BaseLayout 侧栏和标签页联动的核心实现

函数签名

function useMenuAndTabData(menuservice: TabMenuService<number>)

返回值

| 字段 | 说明 | | --- | --- | | collapsed | 侧栏折叠状态 | | menuList | 当前侧栏菜单树 | | menuAll | 全量菜单树 | | onMenuSelection | 菜单点击回调 | | menuArea | 顶部分组菜单 | | setMenuAreaId | 切换当前菜单分区 | | choiceId | 当前选中菜单 ID | | menuTabList | 当前标签页列表 | | onTabClosed | 关闭标签页 | | onTabSelected | 选中标签页 |

useLocalTable / useTable

源码位置

功能定位

  • useLocalTable:本地数据表格状态封装
  • useTable:远程分页表格状态封装
  • 两者都会自动注入权限校验器和用户版本号,用于页面刷新控制

函数签名

function useLocalTable(cfg: LocalTableConfig, dependency?: any)
function useTable(cfg: LocalTableConfig, dependency?: any)

默认表格状态

{
  data: [],
  pageNumber: 1,
  pageSize: cfg.defaultPageSize ?? 20,
  total: 0,
  loading: false,
  border: false,
  pageSizes: [10, 20, 30, 40, 50],
  layout: ['list', 'sep', 'first', 'prev', 'links', 'next', 'last', 'sep', 'refresh', 'info'],
  style: { width: '100%', height: '100%' },
  selectionValues: []
}

基础调用

import { useTable } from '@kordar/easyui-tpl'

const [ctx, ctxState] = useTable(
  {
    defaultPageSize: 20,
    checkAccessItems: [],
  },
  ''
)

useRefreshKey

源码位置

功能定位

  • 通过自增 key 的方式强制触发下游组件刷新

函数签名

function useRefreshKey(): [number, Function]

基础调用

const [refreshKey, forceRefresh] = useRefreshKey()

useAppRedirect

源码位置

功能定位

  • 封装应用登录态跳转与历史地址恢复逻辑
  • 基于 @kordar-components/reactuseAppRedirect 再封装

函数签名

function useAppRedirect()

内部依赖

  • useLocation()
  • state.app.historyLocation
  • Admin.isGuest()
  • App.saveHistoryLocation(location)

业务页面模块说明

模板内置了可直接复用的后台页面模块,主要用于快速搭建基础系统:

| 页面模块 | 导出名 | 场景说明 | 实现入口 | | --- | --- | --- | --- | | 管理员 | AdminView | 管理员列表、搜索、编辑、授权入口 | src/views/admin/index.tsx | | 首页 | HomeView | 后台首页占位页 | src/views/home/index.tsx | | 设置 | SettingView | 系统设置列表与编辑 | src/views/setting/index.tsx | | 登录 | LoginView | 登录页与登录配置读取 | src/views/login/index.tsx | | 角色 | RolesView | 角色列表、编辑、授权 | src/views/roles/index.tsx | | 权限 | PermissionsView | 权限列表、编辑、快速新增 | src/views/permissions/index.tsx | | 字典 | DictView | 字典列表与详情项联动 | src/views/dict/index.tsx | | 路由 | RouterView | 路由资源管理 | src/views/router/index.tsx | | 404 | NotFoundView | 未匹配页面 | src/views/page/404.tsx | | 大屏设计 | ScreenDesign | 大屏设计示例入口 | src/views/srceen/design/index.tsx |

这些页面大多数都采用以下统一模式:

  • 使用 withDocHoc({ name, fetchConfig }) 注入页面语言包与配置数据
  • 使用 resourceService.configs(name) 或相似服务读取枚举配置
  • 通过 TableContext 管理搜索、分页、刷新和选择状态

组件模块扩展开发指南

1. 自定义组件目录创建规范

建议遵循现有目录分层,不要把业务组件直接堆在根目录:

src/
├── components/
│   └── MyWidget.tsx
├── composable/
│   └── useMyWidget.ts
├── service/
│   └── MyWidgetService.ts
├── util/
│   └── my-widget.ts
└── views/
    └── my-widget/
        ├── index.tsx
        ├── search.tsx
        ├── table.tsx
        ├── form.tsx
        └── context.ts

推荐规则:

  • 通用组件放 src/components
  • 页面级状态 Hook 放 src/composable
  • 接口调用封装放 src/service
  • 页面级模块放 src/views/<module>
  • 最终记得在 src/index.ts 注册导出

2. 基础模板编写规范

推荐采用当前仓库统一风格:

import React, { FC } from 'react'

export interface MyWidgetProps {
  title?: string
  onChange?: (value: string) => void
}

const MyWidget: FC<MyWidgetProps> = ({ title = 'Demo', onChange }) => {
  return <div className="k-my-widget">{title}</div>
}

export default MyWidget

规范建议:

  • 优先使用明确的 Props 类型,不要长期保留 FC<any>
  • 组件名、文件名、导出名保持一致
  • 复杂业务逻辑下沉到 Hook 或 util,不把所有流程堆在组件体内
  • 与后台语义强相关的交互,优先封装为回调而不是在外层拼装

3. 样式隔离实现要求

当前工程使用全局 SCSS 与第三方主题样式混合方式,扩展时建议:

  • 组件类名前缀统一使用 k- 或业务模块前缀,避免污染 rc-easyui 默认类
  • 通用样式合并到 src/index.scss 或组件自有样式文件
  • 避免直接覆盖 rc-easyui 全局基础类,优先加作用域父类
  • 主题相关样式优先挂靠 html[theme='xxx'] 或模板现有主题机制

建议写法:

.k-my-widget {
  display: flex;

  .k-my-widget__title {
    font-weight: 600;
  }
}

4. 属性注册、事件封装、逻辑扩展流程

推荐扩展流程:

  1. 在组件内定义清晰的 Props 接口
  2. 把对外可变项收敛为 props,而不是依赖外部全局变量
  3. 把交互动作通过 onXxx 回调暴露出去
  4. 将数据加载、分页、刷新、权限判断提取到 Hook
  5. src/index.ts 中补齐导出
  6. examples 中补一个可运行演示页面用于调试

一个标准回调封装示例:

export interface SwitchPanelProps {
  value?: boolean
  onChange?: (value: boolean) => void
}

const SwitchPanel: FC<SwitchPanelProps> = ({ value = false, onChange }) => {
  const handleToggle = () => onChange?.(!value)
  return <button onClick={handleToggle}>{String(value)}</button>
}

5. 通用工具函数、混入逻辑复用方法

当前仓库已提供若干可复用工具,建议优先复用而不是重复实现:

| 工具模块 | 位置 | 适用场景 | | --- | --- | --- | | resourceAccessItems() | src/util/form.ts | 生成资源类页面的权限点配置 | | removeEventFn() / resourceRemoveEvent() | src/util/form.ts | 封装删除确认与成功刷新逻辑 | | permissionTree() / roleTree() | src/util/helper.ts | 权限树、角色树数据转换 | | fetchConfigOptions() | src/util/helper.ts | 将后台配置转成下拉选项 | | renderTooltip() / renderFetchConfigValue() | src/util/tables.tsx | 表格列渲染 | | Lazy() | src/util/lazy.tsx | 页面级懒加载包装 |

复用建议:

  • 表格列展示优先复用 renderTooltip(),统一长文本处理方式
  • 资源增删改页面优先复用 resourceAccessItems()resourceRemoveEvent()
  • 页面配置项转换优先复用 fetchConfigOptions(),避免重复拼装 { value, text }

6. 扩展组件的单元测试要求

当前包脚本中预留了:

npm test

虽然仓库内尚未补齐完整测试目录,但新增组件时建议遵循以下要求:

  • 至少覆盖渲染成功、关键 props、生效回调三个层面
  • 涉及分页、弹层、菜单选择的组件,重点校验事件分发是否正确
  • 涉及权限隐藏的组件,重点校验不同权限组合下的 UI 结果
  • Hook 至少校验默认状态、状态流转和边界输入

建议测试目录:

src/components/__tests__/
src/composable/__tests__/

建议测试技术栈:

  • Jest
  • @testing-library/react
  • jsdom

7. 本地调试流程

推荐调试流程:

  1. src/ 中实现或修改组件
  2. examples 中创建一个最小可复现入口
  3. 执行 npm run dev 启动 Vite
  4. 通过浏览器逐项验证布局、事件、权限、国际化、主题切换
  5. 完成后执行 npm run build 验证产物构建

可参考的调试入口:

样式、国际化与主题说明

关键依赖(外部)

  • React 生态:reactreact-domreact-routerreact-router-domreact-i18next
  • UI:rc-easyuirc-drawer@kordar/easyui@kordar/react-screen
  • 工具:axioslodash-es
  • Kordar 库:@kordar-lib/base@kordar-lib/i18n@kordar-lib/menus@kordar-lib/reducers@kordar-lib/request

样式

示例样式在 examples/example.scss 中已引入:

@import '@kordar-lib/iconfont/dist/index.min.css';
@import '@kordar/easyui/dist/index.min.css';
@import '@kordar/react-screen/dist/index.min.css';

index.html 会按本地持久化主题加载 rc-easyui 主题与 react.css

国际化

初始化(示例)

examples/init.ts 展示了语言包与请求初始化的方式。你可以按需接入实际后端接口,完善登录、菜单、权限等配置。

本地验证与文档自检

本次文档改写的示例校验原则

  • 所有组件示例均优先基于当前仓库真实源码组织
  • 导入路径均以当前 src/index.ts 的真实导出为准
  • 内部组件如 UserBarItem 已明确标注“未对外导出”

建议本地验证命令

npm run dev
npm run build

链接自检清单

  • 本 README 中所有文件链接均使用当前仓库内真实存在的相对路径
  • 目录跳转使用显式锚点,避免标题重命名导致的 TOC 失效
  • 未引入不存在的截图文件或外部失效链接

截图预览区域使用建议

为避免 README 中引用不存在的静态资源导致链接失效,当前文档采用“预览区域说明”方式预留截图位置。建议在你们正式沉淀文档时:

  1. examples 运行页面截取组件真实界面
  2. 统一放入例如 docs/readme-assets/ 目录
  3. 将本 README 中的“预览区域”说明替换为真实图片链接

示例格式:

![BaseLayout Preview](./docs/readme-assets/base-layout.png)

许可证

MIT