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

@kayak-sj/design

v1.0.2

Published

PC 组件库(Vue3 + Element Plus,对应旧 @kayak/kayak-design-vue2)

Readme

@kayak-sj/design

PC UI 组件库,基于 Vue 3 + Element Plus,提供管理台通用表单、表格、弹窗、查询面板等二次封装。

对应旧工程 @kayak/kayak-design-vue2(Vue 2 + Element UI)。

定位

| 该放 | 不该放 | | -------------------------------------------------- | --------------------------------------- | | KButtonKFormKTableKDialog 等 UI 组件 | 业务页面(权益预算、ROI 分析) | | useFormSchema 等表单 composable | 接口请求、store(→ @kayak-sj/http) | | 组件样式、props/emits 定义 | 权限判断逻辑(→ @kayak-sj/cms-base) | | Element Plus 二次封装 | 路由、布局框架(→ @kayak-sj/cms-base) | | 组件文档、单元测试 | 系统管理领域逻辑(→ @kayak-sj/cms-base) |

判断口诀: 换一套业务(会员台)还能原样复用 → design;绑定了「权益」业务语义 → 不放这里。

详见 包职责约定

技术栈

  • Vue 3 + TypeScript(Composition API + <script setup>
  • Element Plus(peer dependency)
  • @vueuse/core、dayjs、lodash-es、sortablejs、echarts

目录结构

design/
├── README.md
├── package.json
├── vitest.config.ts
└── src/
    ├── index.ts                 # 统一导出 + setupDesign
    ├── components/
    │   ├── index.ts             # 组件聚合导出
    │   ├── k-button/            # KButton
    │   ├── k-dialog/            # KDialog
    │   ├── k-form/              # KForm + formComponent 子控件
    │   ├── k-handle-page/       # KHandlePage 维护页布局
    │   ├── k-link-button/       # KLinkButton 操作列按钮组
    │   ├── k-pagination/        # KPagination
    │   ├── k-panel/             # KPanel
    │   ├── k-panel-query/       # KPanelQuery 查询面板
    │   └── k-table/             # KTable + composables
    ├── styles/
    │   ├── index.scss           # 全局样式入口 @kayak-sj/design/styles
    │   ├── tokens/              # 设计令牌(颜色等)
    │   ├── element-plus/        # EP 主题与覆盖
    │   ├── base/                # 工具类
    │   └── components/          # 各组件 SCSS
    └── utils/
        └── createStubComponent.ts

子路径导出

| 路径 | 说明 | | --------------------------------------- | ------------------------------------------ | | @kayak-sj/design | 主入口(组件、composables、类型) | | @kayak-sj/design/styles | 全局样式(须在 element-plus CSS 之后引入) | | @kayak-sj/design/styles/tokens | SCSS 设计令牌 | | @kayak-sj/design/components | 组件独立导出 |

快速开始

1. 安装依赖

{
  "dependencies": {
    "@kayak-sj/design": "workspace:*",
    "element-plus": "^2.9.0",
    "vue": "^3.5.0"
  }
}

2. 引入样式

在应用入口(main.ts)中,引入 Element Plus 样式,引入 design 样式:

import 'element-plus/dist/index.css'
import '@kayak-sj/design/styles'

3. 按需引用组件(推荐)

<script setup lang="ts">
import { KTable, KLinkButton, type KTableInstance } from '@kayak-sj/design'
import { useTemplateRef } from 'vue'

const tableRef = useTemplateRef<KTableInstance>('tableRef')
</script>

<template>
  <KTable ref="tableRef" :action="fetchList" :columns="columns" />
</template>

4. 全局注册(可选)

import { setupDesign } from '@kayak-sj/design'

setupDesign(app)

组件一览

已迁移

| 组件 | 说明 | 旧工程对应 | | ------------- | -------------------------------------- | ----------------------- | | KTable | 声明式列表 + 查询 + 分页 + action 请求 | k-table | | KForm | 声明式表单,支持 v-model | k-form | | KPanelQuery | 查询面板(内嵌于 KTable 或独立使用) | k-panel-query | | KDialog | 弹窗封装 | k-dialog | | KHandlePage | 维护页布局(内容区 + 底部操作栏) | has-footer + KAffix | | KLinkButton | 表格操作列按钮组 | LinkButton | | KButton | 按钮封装 | k-button | | KPagination | 分页 | k-pagination | | KPanel | 面板容器 | k-panel | | KCard | 卡片容器(ElCard 薄封装) | el-card / k-card | | KUpload | 文件/图片上传、模板下载、裁剪预览 | k-upload |

迁移占位(Stub)

以下组件已导出但为占位实现,调用时会在控制台警告,待后续迁移:

KAffix · KBreadcrumb · KCascader · KColorPicker · KEcharts

KTable 列表页

KTable 采用 声明式 columns + composables 编排,对齐旧版能力并适配 Vue 3:

<script setup lang="ts">
import { KLinkButton, KTable, type KTableInstance, type KTablePageOptions } from '@kayak-sj/design'
import { useTemplateRef } from 'vue'

import { useDictServiceProvider } from '@/composables/useDictServiceProvider'

useDictServiceProvider()

const tableRef = useTemplateRef<KTableInstance>('tableRef')

const tableOptions: KTablePageOptions = {
  columns: [
    { prop: 'role_name', label: '角色名称' },
    { prop: 'status', label: '状态', dict: 'status' },
    { type: 'operates', label: '操作', width: 200 }
  ],
  query: {
    form: {
      formConfigs: [{ id: 'role_name', label: '角色名称', component: 'Input' }]
    }
  },
  tableKey: 'permission-role',
  enableColumnCache: true
}

function rowOperates(row: Record<string, unknown>) {
  return [{ label: '编辑', onClick: () => openEdit(row) }]
}
</script>

<template>
  <KTable ref="tableRef" :action="FETCH_ROLE" v-bind="tableOptions" add-button="新建角色" @add="openAdd">
    <template #operates="{ row }">
      <KLinkButton :data="rowOperates(row)" />
    </template>
  </KTable>
</template>

常用能力:

  • action 模式:传入接口函数,自动合并查询参数与分页
  • 列格式化dictshowType(date / amount / phone)、自定义 formatter
  • 列显隐缓存enableColumnCache + tableKey
  • 树表懒加载load + TreeLoadHandler
  • 行拖拽排序sort prop
  • 多选 / 单选selectionShowcolumns[].type: 'radio'

Expose:getTableData / getQueryNode / getCheckedRows / refresh 等(见 KTableInstance)。

页面侧 composable

| 导出 | 用途 | | ---- | ---- | | useKTableTemplateRef | 获取 KTable 实例(refresh / toggleRowSelection 等) | | useKTableCrossPageSelection | 弹窗列表跨页多选回显(打开弹框灌入已选 → 翻页保留 → data-loaded 回勾) | | useExportKTableReport | 报表导出(见业务迁移文档) |

弹窗选择器(商户 / 产品 / 信用卡等)不要把草稿选择写进 KTable 内部,用 useKTableCrossPageSelection

<script setup lang="ts">
import { KDialog, KTable, useKTableCrossPageSelection } from '@kayak-sj/design'
import { shallowRef } from 'vue'

const dialogVisible = shallowRef(false)
const { selection, setSelection, onDataLoaded, onSelectionChange } =
  useKTableCrossPageSelection<MerchantRow>({ rowKey: 'merchant_id' })

function openDialog(checked: MerchantRow[]) {
  setSelection(checked)
  dialogVisible.value = true
}
</script>

<template>
  <KDialog v-model:visible="dialogVisible" title="选择" @confirm="() => emit('confirm', selection)">
    <KTable
      ref="tableRef"
      :action="FETCH_LIST"
      selection-show
      row-key="merchant_id"
      @data-loaded="onDataLoaded"
      @selection-change="onSelectionChange"
    />
  </KDialog>
</template>

要点:

  • 打开弹框时 setSelection(已确认行);确定时用 selection 写回业务 model
  • 模板 ref="tableRef" 与 composable 默认 tableRefKey 对齐(内部 useKTableTemplateRef
  • rowKey 支持 MaybeRefOrGetter(如卡种/卡片切换主键)
  • mode: 'single' 时走 setRadioSelection 回显;多选为默认
  • 可选传入外部 tableRef(单测 mock 用)

参考实现:pc-rightsChooseMerchant / ChooseProduct / ChooseCreditCarduseChooseRightsDialog

KForm 表单

采用 Schema / Model 分离,详见 KForm 架构设计

L1 查询面板(非受控)

KPanelQueryKTablequery 配置驱动:

<KPanelQuery :query="{ form: { formConfigs } }" @query="handleQuery" />

L2 编辑表单(v-model + schema)

<script setup lang="ts">
import { ref } from 'vue'
import { KForm, useFormSchema, type KFormSchemaField } from '@kayak-sj/design'

interface MenuForm {
  menu_type: string
  grant: string
  perms?: string
}

const form = ref<MenuForm>({ menu_type: 'C', grant: '0' })

const baseFields: KFormSchemaField<MenuForm>[] = [
  { id: 'menu_type', component: 'Radio', label: '菜单类型', dict: 'menu_type' },
  {
    id: 'perms',
    component: 'Input',
    label: '权限标识',
    visibleWhen: (m) => m.menu_type !== 'M'
  }
]

const schema = useFormSchema(baseFields, form)
</script>

<template>
  <KForm v-model="form" :form-configs="schema" label-width="120px" />
</template>

Expose:validateFields / getFieldsValue / getParams / setFieldsValue / resetForm

支持的 formComponent

Input · Select · SelectMultiple · DatePicker · Radio · Checkbox · InputNumber · Cascader · TreeSelect · Text · InputMixInput · InputMixSelect · RadioInput · Complex · ScrollSelect

KHandlePage 维护页

维护页通用布局,替代各 handle 页重复的 footer 样板代码:

<script setup lang="ts">
import { KForm, KHandlePage, useFormSchema, useHandlePageInit } from '@kayak-sj/design'

const { pageLoading } = useHandlePageInit(loadDetail)
</script>

<template>
  <KHandlePage :loading="pageLoading" :on-submit="handleSubmit" @cancel="handleCancel">
    <KForm v-model="form" :form-configs="schema" />
  </KHandlePage>
</template>

useHandlePageInit 包裹 initPage,编辑/详情态自动管理局部 loading。

字典服务 DICT_KEY

design 层不直接依赖旧版 $dict 全局插件。字典翻译通过 inject 解耦:

import { DICT_KEY, type DictService } from '@kayak-sj/design'

const dictService: DictService = {
  getLabel: (dictType, value) => labelMap[dictType]?.[String(value)] ?? String(value ?? ''),
  getGroupDict: (dictType) => groupMap[dictType] ?? []
}

app.provide(DICT_KEY, dictService)

@kayak-sj/cms-base 提供 useDictServiceProvider(),列表页在 setup 中调用即可:

import { useDictServiceProvider } from '@kayak-sj/cms-base/...'

useDictServiceProvider()

表格列 dict、查询表单 dict 字段均通过 DICT_KEY 解析。

主要 API

| 导出 | 说明 | | ------------------- | ------------------------------------------------------------ | | setupDesign | 全局注册所有组件 | | useFormSchema | 根据 model 派生表单 schema(联动) | | useHandlePageInit | 维护页 init loading 管理 | | DICT_KEY | 字典服务注入 Key | | KTablePageOptions | 列表页声明式配置类型 | | KFormSchemaField | 带联动声明的表单字段类型 |

与 cms-base 的边界

| 关注点 | 归属 | | ------------------------------------ | ----------------- | | HTTP 请求实现 | @kayak-sj/http | | 登录态、权限判断、请求提示适配 | @kayak-sj/cms-base | | 表格/表单渲染、列格式化、字典 inject | @kayak-sj/design | | 系统管理页面编排、API 封装 | @kayak-sj/cms-base |

  • design 组件通过 inject(DICT_KEY) 获取字典,不 import hasPermission
  • 权限控制的新建按钮、操作列请在页面层判断后传入 props
  • 不要在 design 中引入 axios、Pinia store 或业务 API

开发

# 类型检查
pnpm --filter @kayak-sj/design typecheck

# 单元测试
pnpm --filter @kayak-sj/design test

当前已有 useFormSchemauseKFormModeluseKTableCrossPageSelectionuseTableData 等 composable 单测(Vitest)。

依赖关系

apps(pc-rights 等)
  └─ @kayak-sj/cms-base
       └─ @kayak-sj/design    ← 本包

| 包 | 关系 | | ----------------- | ---------------------------- | | @kayak-sj/cms-base | 主要消费方,列表/表单/维护页 | | @kayak-sj/http | 与 design 解耦,不互相依赖 | | @kayak-sj/utils | 纯工具,design 可按需引用 |

发版

当前为 workspace 内部包(private: true)。验证通过后可:

  1. 移除 private: true
  2. 发布到私服(对应旧 @kayak/kayak-design-vue2 的 Vue3 版本)

相关文档