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

xdc-ui-lib

v2.2.0

Published

常用组件库

Readme

xdc-ui-lib

Vue 3 组件库,包含常用的业务组件,基于 ant-design-vue

环境要求

  • Node.js:建议 18+
  • Vue:3.x
  • ant-design-vue:4.x

安装

npm install xdc-ui-lib ant-design-vue

快速开始

import { createApp } from 'vue'
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/reset.css'

import XdcUiLib from 'xdc-ui-lib'
import 'xdc-ui-lib/xdc-ui-lib.css'

const app = createApp(App)
app.use(Antd)
app.use(XdcUiLib)
app.mount('#app')

发布/构建说明(维护者)

  • 构建:pnpm run build
  • 发布:进入构建产物目录 xdc-ui-lib/ 后执行 npm publish

常见发布报错:

  • 403 Forbidden - You cannot publish over the previously published versions
    • 说明:尝试重复发布同一个版本号(例如 2.1.9 已经发布过)
    • 处理:修改版本号后再发布(建议使用 npm version patch|minor|major 递增版本)

组件列表(目录)


CategorySearch 分类搜索组件

一个功能强大的分类搜索组件,支持多种筛选类型和列设置功能。

基本用法

<template>
  <CategorySearch
    :loading="loading"
    :filter-types="filterTypes"
    :columns="columns"
    @search="handleSearch"
  />
</template>

<script setup>
import { CategorySearch } from 'xdc-ui-lib';

const filterTypes = [
  {
    id: 'name',
    label: '名称',
    type: 'input',
    placeholder: '请输入名称'
  },
  {
    id: 'status',
    label: '状态',
    type: 'select',
    options: [
      { label: '启用', value: 1 },
      { label: '禁用', value: 0 }
    ]
  }
];

const columns = [
  { title: '名称', dataIndex: 'name' },
  { title: '状态', dataIndex: 'status' }
];
</script>

支持的筛选类型

  • input: 文本输入
  • textarea: 多行文本
  • select: 下拉选择
  • cascader: 级联选择
  • treeSelect: 树形选择
  • checkbox: 多选框
  • radio: 单选框
  • date: 日期选择
  • datetime: 日期时间选择
  • dateRange: 日期范围
  • datetimeRange: 日期时间范围
  • time: 时间选择
  • numberRange: 数字范围
  • rate: 评分
  • slider: 滑块
  • switch: 开关
  • slot: 自定义插槽

高级功能

<template>
  <CategorySearch
    type="form"
    :filter-types="filterTypes"
    :form-layout="'vertical'"
    :form-span="8"
    v-model:filter-value="searchParams"
    @search="handleSearch"
  />
</template>
<template>
  <CategorySearch
    :show-setting-columns="true"
    :columns="columns"
    :disabled-columns="['id', 'name']"
    @columnsChange="handleColumnsChange"
  />
</template>
<template>
  <CategorySearch :filter-types="filterTypes">
    <template #filter-slots="{ filter, filterTemp, confirm }">
      <CustomComponent
        v-if="filter.id === 'customField'"
        v-model:value="filterTemp[filter.id]"
        @change="confirm"
      />
    </template>
  </CategorySearch>
</template>
const filterTypes = [
  {
    id: 'status',
    type: 'select',
    label: $t('table.probe') + $t('table.Blank') + $t('table.Status'),
    options: [...]
  }
];

Props

| 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | type | 组件模式:input 为“输入框 + tag + 下拉面板”;form 为“表单平铺模式” | 'input' \| 'form' | 'input' | | filterValue | 当前筛选值(用于回显/受控)。Input 模式下会转换为 tag;Form 模式下会同步到表单模型 | Record<string, any> | {} | | loading | 加载态;为 true 时会阻止搜索/刷新等操作 | boolean | 必传 | | filterTypes | 筛选项配置数组(决定可选条件、控件类型、options 等) | any[] | 必传 | | placeholder | Input 模式下输入框占位文案 | string | '点击选择搜索条件' | | storageKey | 本地缓存 key;不传则自动基于 location + 配置生成,确保同页不同配置不冲突 | string | '' | | hideRefresh | 是否隐藏刷新/搜索按钮 | boolean | false | | showSwitch | 是否显示“切换”按钮(点击会 emit switch) | boolean | false | | showSave | 是否显示“保存”按钮(将当前筛选条件写入缓存) | boolean | false | | showSettingColumns | 是否显示“列设置”入口(作用于 columns) | boolean | true | | columns | 表格列配置(用于列设置面板的显隐/排序/固定) | any[] | [] | | disabledColumns | 列设置中禁用的列(不可隐藏/不可拖拽/不可固定),匹配 dataIndex/key | string[] | ['id','name'] | | isDefaultSearch | 初始化时是否读取缓存并自动触发一次搜索 | boolean | true | | formLayout | Form 模式布局(grid 时内部用 CSS 变量控制列数) | 'horizontal' \| 'vertical' \| 'inline' \| 'grid' | 'grid' | | formSpan | Form 模式 grid 布局下列数(--form-columns) | number | 4 | | labelCol | AntD Form 的 labelCol(仅 form 模式相关) | any | - | | wrapperCol | AntD Form 的 wrapperCol(仅 form 模式相关) | any | - | | labelBorder | grid 表单是否显示 label 边框样式(.grid-form) | boolean | false | | colon | label 是否显示冒号(AntD Form colon) | boolean | false | | collapsedCount | Form 模式折叠时展示前 N 个筛选项:传了才启用折叠逻辑(支持 0) | number | undefined | | defaultCollapsed | Form 模式默认是否折叠(仅在启用折叠逻辑时生效) | boolean | true |

存储键生成规则

组件会根据以下规则生成存储键:

  1. 如果提供了 storageKey:直接使用提供的值
  2. 如果没有提供 storageKey:自动生成基于页面路径和配置的唯一键

当没有提供 storageKey 时,组件会自动生成一个基于以下信息的唯一存储键:

  • 当前页面路径
  • 筛选类型配置
  • 表格列配置

生成的键格式为:category_search_auto_${hash}

这样可以确保每个页面和配置组合都有唯一的存储键,避免数据冲突。

<template>
  <!-- 使用路由名称作为存储键 -->
  <CategorySearch
    :storage-key="`search-${$route.name}`"
    :loading="loading"
    :filter-types="filterTypes"
    @search="handleSearch"
  />
</template>
<template>
  <CategorySearch
    storage-key="user-list-search"
    :loading="loading"
    :filter-types="filterTypes"
    @search="handleSearch"
  />
</template>
<template>
  <!-- 不提供 storageKey,自动生成 -->
  <CategorySearch
    :loading="loading"
    :filter-types="filterTypes"
    :columns="columns"
    @search="handleSearch"
  />
</template>

Events

| 事件名 | 说明 | 回调参数 | |--------|------|----------| | search | 搜索事件 | (params: object) | | switch | 切换事件 | (filters: array) | | clear | 清空事件 | - | | reset | 重置事件 | - | | columnsChange | 列变化事件 | (columns: array) | | update:columns | 列更新事件 | (columns: array) | | update:filterValue | 筛选值更新事件 | (value: object) |


SearchPanel 搜索面板组件

SearchPanel 是一个“搜索条件构建器”组件,支持两种模式:

  • type="input":输入框 + tag 的交互式条件选择(带下拉面板)
  • type="form":表单平铺模式(可折叠),更适合复杂筛选场景

同时内置:

  • 筛选条件本地缓存(基于 storageKey
  • 条件保存/恢复
  • 筛选项显示/隐藏/排序(“列设置”面板,但作用对象是 filterTypes)
  • 国际化(使用内置 useI18nt('searchPanel.xxx')

基本用法(Input 模式)

<template>
  <SearchPanel
    :loading="loading"
    :filter-types="filterTypes"
    v-model:filter-value="params"
    @search="onSearch"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { SearchPanel } from 'xdc-ui-lib'

const loading = ref(false)
const params = ref<Record<string, any>>({})

const filterTypes = [
  { id: 'name', label: '名称', type: 'input', placeholder: '请输入名称' },
  {
    id: 'status',
    label: '状态',
    type: 'select',
    options: [
      { label: '启用', value: 1 },
      { label: '禁用', value: 0 },
    ],
  },
]

function onSearch(payload: Record<string, any>) {
  console.log('search:', payload)
}
</script>

基本用法(Form 模式)

<template>
  <SearchPanel
    type="form"
    :loading="loading"
    :filter-types="filterTypes"
    :form-layout="'grid'"
    :form-span="4"
    :collapsed-count="6"
    v-model:filter-value="params"
    @search="onSearch"
  />
</template>

支持的筛选类型(filterTypes[].type)

与 CategorySearch 基本一致,另外支持更多日期 picker:

  • input / textarea
  • select / cascader / treeSelect
  • checkbox / radio
  • date / datetime / month / week / quarter / year
  • time
  • dateRange / datetimeRange
  • numberRange
  • rate / slider / switch
  • slot

Props

| 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | type | 组件模式:input 为“输入框 + tag + 下拉面板”;form 为“表单平铺模式” | 'input' \| 'form' | 'input' | | loading | 外部 loading 状态;为 true 时会阻止搜索/刷新等操作 | boolean | false | | filterTypes | 筛选项配置数组(决定可选条件、控件类型、options 等) | any[] | 必传 | | optionDict | 统一下拉数据字典:key 与 filterTypes[i].dictKey/optionKey/id 对应;优先级高于 filterTypes[i].options/treeData | Record<string, any[]> | {} | | filterValue | 当前筛选值(用于回显/受控) | Record<string, any> | {} | | placeholder | Input 模式占位文案 | string | '点击选择搜索条件' | | storageKey | 本地缓存 key;不传时默认使用 search-panel:${pathname}${search} | string | '' | | hideRefresh | 是否隐藏刷新/搜索按钮 | boolean | false | | showSwitch | 是否显示“切换”按钮(点击会 emit switch) | boolean | false | | showSave | 是否显示“保存”按钮(将当前筛选条件写入缓存) | boolean | false | | showSettingColumns | 是否显示“筛选项显示设置”按钮(作用对象为 filterTypes) | boolean | true | | disabledFilterTypes | 不允许隐藏的筛选项 id 列表(例如必须展示的条件) | string[] | [] | | isDefaultSearch | 初始化时是否读取缓存并自动触发一次搜索 | boolean | true | | formLayout | Form 模式布局:horizontal/vertical/inline/grid | 'horizontal' \| 'vertical' \| 'inline' \| 'grid' | 'grid' | | formSpan | Form 模式 grid 布局下列数(CSS 变量:--form-columns) | number | 4 | | labelCol | AntD Form 的 labelCol(horizontal/grid 相关) | any | - | | wrapperCol | AntD Form 的 wrapperCol(horizontal/grid 相关) | any | - | | labelBorder | Form 模式是否显示 label 边框样式(grid-form) | boolean | false | | colon | Form 模式 label 是否显示冒号(AntD Form colon) | boolean | false | | collapsedCount | Form 模式折叠时展示前 N 个筛选项:传了才启用折叠逻辑(支持 0) | number | undefined | | defaultCollapsed | Form 模式默认是否折叠(仅在启用折叠逻辑时生效) | boolean | true | | searchDisabled | Form 模式“查询”按钮禁用 | boolean | false | | clearHidden | Form 模式是否隐藏“清除”按钮 | boolean | false | | clearDisabled | Form 模式“清除”按钮禁用 | boolean | false | | columns | 兼容旧入参(已不再使用) | any[] | [] | | disabledColumns | 兼容旧入参(已不再使用) | string[] | [] |

说明:组件内部还存在 collapsible 默认值,但当前 props 定义里未显式声明(属于历史字段/可忽略)。

Events

| 事件名 | 说明 | 回调参数 | |------|------|----------| | search | 点击刷新/确认/表单搜索时触发(会扁平化部分日期结构) | (params: Record<string, any>) | | switch | 点击切换按钮触发 | (filters: any[]) | | clear | 调用 reset/清空时触发 | () | | reset | (当前代码未 emit reset,仅保留事件名;如需可补) | () | | columnsChange | (历史事件名:当前主要用于 filterTypes 显示设置,不建议依赖) | (cols: any[]) | | update:columns | (历史 v-model:当前主要用于 filterTypes 显示设置,不建议依赖) | (cols: any[]) | | update:filterValue | v-model 回写,用于回显/受控 | (value: any) |

Slots

| 插槽名 | 说明 | 参数 | |------|------|------| | icon | Input 模式右侧自定义操作按钮区域(点击事件需自行处理) | - | | filter-slots | 当 filterTypes[].type === 'slot' 时渲染 | { filter, filterTemp, confirm } |

方法(Expose)

通过 ref 可调用:

  • reset():清空条件并触发一次 search
  • search():触发一次 search(内部有 throttle 800ms)

ColumnSetting 表格列设置组件

用于表格列的显示/隐藏、拖拽排序、左右固定,并支持 localStorage 持久化。

适用场景

  • 表格列“显隐/排序/固定(左/右)”需要给用户自定义
  • 需要把列配置持久化到 localStorage(同页面刷新仍保持)
  • 需要禁用某些关键列(不可隐藏/不可拖拽)

基本用法

<template>
  <ColumnSetting
    v-model:columns="columnSetting"
    storageKey="user-list-columns"
    :disabledColumns="['id']"
  >
    <template #trigger>
      <a-button>列设置</a-button>
    </template>
  </ColumnSetting>

  <a-table :columns="columnSetting" :data-source="dataSource" />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { ColumnSetting } from 'xdc-ui-lib'

const columns = [
  { title: 'ID', dataIndex: 'id', key: 'id' },
  { title: '名称', dataIndex: 'name', key: 'name' },
  { title: '状态', dataIndex: 'status', key: 'status' },
]

const dataSource = []

const columnSetting = ref([])
</script>

与其他组件的关系

ColumnSetting 已解耦,可 独立使用(不依赖 CategorySearch / SearchPanel 等组件)。

  • 只要提供 v-model:columns 绑定的列配置,即可完成列的显隐/排序/固定与持久化。
  • 如需在其他组件中集成(例如放在表格工具栏里),直接按本章「基本用法(与 antd Table 配合)」接入即可。

Props

| 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | columns | 原始列配置(列设置作用对象)。列项建议包含 title/dataIndex/key,以便稳定识别与排序 | ColumnSettingColumn[] | 必传 | | storageKey | localStorage 存储 key;不传则默认使用 column-setting:${pathname}${search}(同页面不同 query 会区分) | string | '' | | disabledColumns | 禁用列 id(匹配 dataIndex/key):不可隐藏、不可拖拽、不可固定 | string[] | [] | | hiddenColumns | 完全隐藏且不可操作的列 id(匹配 dataIndex/key):不会在面板出现 | string[] | ['index','action'] | | size | 表格密度(可选);传了会参与缓存,并通过 v-model:size 同步给外部 | 'small' \| 'middle' \| 'large' | undefined | | needConfirm | 是否需要点击“确认”才真正对外生效:

  • false:用户操作即时 emit(默认)
  • true:用户操作仅在弹层内暂存,点击确认才 emit & 写缓存;关闭/取消会丢弃未确认修改 | boolean | false |

说明:ColumnSetting 通过 v-model:columns 输出 可见列(已过滤 checked=false 且去掉 checked 字段)。如果你需要拿到“包含 checked/fixed/排序”的全量结构,建议在业务侧用 useColumnSetting hook。

Events

| 事件名 | 说明 | 回调参数 | |------|------|----------| | update:modelValue | 列设置变更(全量) | (cols: array) | | update:visibleColumns | 可见列变更(过滤 checked=false) | (cols: array) | | change | 同 update:modelValue | (cols: array) | | reset | 点击重置触发 | - |


BaseTable 表格增强组件

BaseTable 是对 ant-design-vuea-table 做的“增强但不打扰”的封装:

  • 不重复声明 a-table 的全部 props/emits:通过 useAttrs() 全量透传
  • 动态转发所有 a-table 插槽:不影响你使用官方的 slots
  • 提供可选工具条(标题/操作区)
  • 内置列设置按钮(复用 ColumnSetting),以及刷新/密度(size)切换
  • loading 兼容增强、error 空态兜底

基本用法

<template>
  <BaseTable
    :columns="columns"
    :data-source="dataSource"
    :pagination="pagination"
    @change="onChange"
  />
</template>

<script setup lang="ts">
import { BaseTable } from 'xdc-ui-lib'

const columns = [
  { title: 'ID', dataIndex: 'id', key: 'id' },
  { title: '名称', dataIndex: 'name', key: 'name' },
]

const dataSource = []
const pagination = { current: 1, pageSize: 10, total: 0 }

function onChange(...args: any[]) {
  console.log('table change', args)
}
</script>

工具条(title + 操作)

<BaseTable title="用户列表" :columns="columns" :data-source="dataSource" @refresh="fetchList" />

列设置(ColumnSetting 集成)

BaseTable 会在工具条右侧渲染列设置入口(前提:你传入了 columns)。

你可以直接把 ColumnSetting 的相关 props 当作 attribute 传给 BaseTable:

<BaseTable
  title="用户列表"
  :columns="columns"
  :data-source="dataSource"
  storageKey="user-list-columns"
  :disabledColumns="['id']"
/>

Props(BaseTable 自身声明的)

说明:除下表外,a-table 的所有 props/事件都可以直接 v-bind/监听传入。

| 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | title | 工具条标题(默认展示在左侧) | string | - | | toolbar | 是否展示工具条;不传时按“title/slot/toolbarActions 是否存在”自动判断 | boolean | undefined | | toolbarActions | 是否显示右侧默认操作区(列设置/刷新/密度) | boolean | true | | error | 错误信息(string 或 Error),用于空态兜底 | string \| Error \| null | null | | loading | loading 增强:boolean / {spinning, tip} / AntD 原生 loading 对象 | boolean \| {spinning?: boolean; tip?: string} \| Record<string, any> | undefined | | defaultSize | 默认表格密度(仅当外部未传 size 时生效) | 'small' \| 'middle' \| 'large' | 'middle' | | showRefresh | 是否显示刷新按钮(工具条右侧) | boolean | true | | showDensity | 是否显示密度切换(外部传了 size 时会自动隐藏) | boolean | true | | autoHeight | 是否自动计算 scroll.y(不覆盖外部显式传入的 scroll.y) | boolean | true | | autoHeightOffset | 自动高度模式下额外扣减高度(px) | number | 40 | | autoHeightMinY | 自动高度模式下 scroll.y 最小值(px) | number | 10 |

Events(BaseTable 自身声明的)

| 事件名 | 说明 | 回调参数 | |------|------|----------| | refresh | 点击刷新按钮触发 | () | | update:size | 点击密度切换触发;若外部未受控,会同时更新内部 size | (size: 'small' \| 'middle' \| 'large') |

Slots

| 插槽名 | 说明 | |------|------| | toolbar-left | 覆盖工具条左侧区域(默认显示 title) | | toolbar-right | 覆盖工具条右侧区域(默认显示 toolbarActions 区) | | toolbar-extra | 在默认 toolbarActions 区后追加内容 |

除以上 3 个工具条插槽外,所有 a-table 的插槽都会被动态透传(例如 bodyCellheaderCellexpandedRowRenderemptyText 等)。

默认行为(仅在外部未传时生效)

  • rowKey 默认为 'id'
  • scroll 默认为 { x: 'max-content' }
  • locale.emptyText 默认为 '暂无数据'(若传入 error 且外部未提供 empty slot/locale.emptyText,则显示 error)

BaseForm 动态表单组件

一个功能强大的动态表单组件,支持多种表单元素类型、布局方式和自定义功能。

基本用法

<template>
  <BaseForm
    v-model="formData"
    :items="formItems"
    :submit-loading="loading"
    submit-text="提交"
    @submit="handleSubmit"
  />
</template>

<script setup>
import { BaseForm } from 'xdc-ui-lib';

const formData = reactive({
  username: '',
  email: '',
  age: null,
  gender: '',
  hobbies: []
});

const formItems = [
  {
    name: 'username',
    label: '用户名',
    type: 'input',
    placeholder: '请输入用户名',
    required: true,
    rules: [
      { required: true, message: '请输入用户名' },
      { min: 3, max: 20, message: '用户名长度为3-20个字符' }
    ]
  },
  {
    name: 'email',
    label: '邮箱',
    type: 'input',
    placeholder: '请输入邮箱',
    required: true,
    rules: [
      { required: true, message: '请输入邮箱' },
      { type: 'email', message: '请输入正确的邮箱格式' }
    ]
  },
  {
    name: 'age',
    label: '年龄',
    type: 'number',
    min: 0,
    max: 120
  },
  {
    name: 'gender',
    label: '性别',
    type: 'radio',
    options: [
      { label: '男', value: 'male' },
      { label: '女', value: 'female' }
    ]
  },
  {
    name: 'hobbies',
    label: '兴趣爱好',
    type: 'checkbox',
    options: [
      { label: '读书', value: 'reading' },
      { label: '运动', value: 'sports' },
      { label: '音乐', value: 'music' }
    ]
  }
];
</script>

支持的表单元素类型

  • input: 文本输入框
  • password: 密码输入框
  • textarea: 多行文本框
  • number: 数字输入框
  • select: 下拉选择器
  • treeSelect: 树形选择器
  • radio: 单选框组
  • checkbox: 复选框组
  • checkbox-single: 单个复选框
  • switch: 开关
  • date: 日期选择器
  • time: 时间选择器
  • dateRange: 日期范围选择器
  • slider: 滑块
  • rate: 评分
  • custom: 自定义组件

布局方式

<BaseForm
  :items="formItems"
  layout="horizontal"
  :label-col="{ span: 4 }"
  :wrapper-col="{ span: 20 }"
/>
<BaseForm :items="formItems" layout="vertical" />
<BaseForm :items="formItems" layout="grid" :columns="3" />

自定义插槽

<BaseForm :items="formItems">
  <template #field-customField="{ item, modelValue, updateValue }">
    <div class="custom-field">
      <a-input
        :value="modelValue"
        placeholder="自定义字段"
        @input="(e) => updateValue(e.target.value)"
      />
    </div>
  </template>
</BaseForm>
<BaseForm :items="formItems" :show-actions="true">
  <template #actions="{ submit, reset, validateForm, formData, loading }">
    <a-space>
      <a-button type="primary" :loading="loading" @click="submit">确认提交</a-button>
      <a-button @click="reset">重置</a-button>
      <a-button type="dashed" @click="handlePreview">预览数据</a-button>
    </a-space>
  </template>
</BaseForm>
<BaseForm :items="formItems">
  <!-- 只在 input 类型的表单项中可用 -->
  <template #username-prefix>
    <UserOutlined />
  </template>
  <template #username-suffix>
    <InfoCircleOutlined />
  </template>
  <template #username-after="{ item, value }">
    <small>用户名将用于登录</small>
  </template>
</BaseForm>
<BaseForm :items="formItems">
  <template #form-item-customField="{ item, modelValue, updateValue }">
    <a-form-item :label="item.label">
      <div class="custom-form-item">
        <a-input
          :value="modelValue"
          placeholder="自定义表单项"
          @input="(e) => updateValue(e.target.value)"
        />
        <small>这是完全自定义的表单项</small>
      </div>
    </a-form-item>
  </template>
</BaseForm>
<BaseForm :items="formItems">
  <template #custom-items="{ formData }">
    <a-form-item label="自定义表单项">
      <a-input v-model:value="formData.customField" placeholder="自定义字段" />
    </a-form-item>
  </template>
</BaseForm>

复杂表单示例

<template>
  <BaseForm
    ref="formRef"
    v-model="formData"
    :items="formItems"
    :initial-values="initialValues"
    :submit-loading="loading"
    submit-text="创建用户"
    @submit="handleSubmit"
    @field-change="handleFieldChange"
  >
    <!-- 头像上传自定义字段 -->
    <template #field-avatar="{ modelValue, updateValue }">
      <div class="avatar-upload">
        <a-upload
          name="avatar"
          list-type="picture-card"
          :show-upload-list="false"
          :before-upload="beforeUpload"
          @change="(info) => handleAvatarChange(info, updateValue)"
        >
          <img v-if="modelValue" :src="modelValue" alt="avatar" />
          <div v-else>
            <PlusOutlined />
            <div>上传头像</div>
          </div>
        </a-upload>
      </div>
    </template>

    <!-- 技能标签自定义字段 -->
    <template #field-skills="{ modelValue, updateValue }">
      <a-select
        :value="modelValue"
        mode="tags"
        placeholder="输入技能并按回车添加"
        @change="updateValue"
      />
    </template>
  </BaseForm>
</template>

Props

| 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | modelValue | 表单数据模型 | object | {} | | items | 表单项配置数组 | array | [] | | layout | 表单布局 | 'horizontal' | 'vertical' | 'grid' | 'horizontal' | | columns | 网格布局列数 | number | 2 | | labelCol | 标签列配置 | object | { span: 4 } | | wrapperCol | 控件列配置 | object | { span: 20 } | | colon | 是否显示冒号 | boolean | true | | labelAlign | 标签对齐方式 | 'left' | 'right' | 'right' | | scrollToFirstError | 是否滚动到第一个错误字段 | boolean | true | | showActions | 是否显示操作按钮 | boolean | false | | hideDefaultActions | 是否隐藏默认操作按钮 | boolean | false | | showReset | 是否显示重置按钮 | boolean | true | | submitText | 提交按钮文本 | string | '提交' | | resetText | 重置按钮文本 | string | '重置' | | submitLoading | 提交时是否显示加载状态 | boolean | false | | initialValues | 初始值 | object | {} |

Events

| 事件名 | 说明 | 回调参数 | |--------|------|----------| | update:modelValue | 模型值更新事件 | (value: object) | | submit | 提交事件 | (values: object) | | reset | 重置事件 | (values: object) | | finish | 表单提交成功事件 | (values: object) | | finish-failed | 表单提交失败事件 | (errorInfo: any) | | values-change | 表单值变化事件 | (changedValues: object, values: object) | | field-change | 字段值变化事件 | (name: string, value: any, item: object) | | field-blur | 字段失焦事件 | (name: string, value: any, item: object) | | field-search | 字段搜索事件 | (name: string, value: string, item: object) | | field-press-enter | 字段回车事件 | (name: string, value: any, item: object) |


BaseModal 模态框组件

一个增强的模态框组件,支持模态框管理和全局控制。

基本用法

<template>
  <BaseModal
    v-model="visible"
    title="标题"
    :width="600"
    @ok="handleOk"
    @cancel="handleCancel"
  >
    <p>模态框内容</p>
  </BaseModal>
</template>

<script setup>
import { BaseModal } from 'xdc-ui-lib';

const visible = ref(false);

const handleOk = () => {
  console.log('确认');
  visible.value = false;
};

const handleCancel = () => {
  console.log('取消');
  visible.value = false;
};
</script>

使用模态框管理

<template>
  <BaseModal v-model="visible" modal-id="user-modal" title="用户信息">
    <p>用户信息内容</p>
  </BaseModal>
</template>

<script setup>
import { BaseModal, useModalManager } from 'xdc-ui-lib';

const { closeAllModals } = useModalManager();

const closeAll = () => {
  closeAllModals();
};
</script>

Props

| 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | modelValue | 是否显示模态框 | boolean | false | | open | 是否显示模态框(与 modelValue 相同) | boolean | false | | modalId | 模态框唯一标识,用于模态框管理 | string | - |

Events

| 事件名 | 说明 | 回调参数 | |--------|------|----------| | update:modelValue | 模态框显示状态更新 | (value: boolean) | | update:open | 模态框显示状态更新 | (value: boolean) | | ok | 确认按钮点击事件 | (e: Event) | | cancel | 取消按钮点击事件 | (e: Event) | | after-close | 模态框关闭后事件 | - |

插槽

| 插槽名 | 说明 | |--------|------| | default | 模态框内容 | | title | 标题内容 | | footer | 底部内容 | | closeIcon | 关闭图标 |

模态框管理 Hook

import { useModalManager } from 'xdc-ui-lib';

const { registerModal, unregisterModal, closeAllModals } = useModalManager();

方法:

  • registerModal(id: string, ref: ModalRef): 注册模态框
  • unregisterModal(id: string): 注销模态框
  • closeAllModals(): 关闭所有模态框

全局事件:

  • close-all-modals: 关闭所有模态框的全局事件
window.dispatchEvent(new Event('close-all-modals'));

FileUpload 文件上传组件

基于 ant-design-vue 的文件上传组件,支持多选、大小限制、数量限制、删除等功能。

使用

<template>
  <FileUpload
    :limit="3"
    :fileSizeLimit="2 * 1024 * 1024"
    btnTxt="上传文件"
    @select="onSelect"
    @exceed="onExceed"
  />
</template>

<script setup>
import { FileUpload } from 'xdc-ui-lib';

function onSelect(files) {
  console.log('已选文件:', files);
}
function onExceed(file) {
  alert('文件超出大小限制: ' + file.name);
}
</script>

Props

| 属性 | 说明 | 类型 | 默认值 | |------|------|------|--------| | accept | 接受的文件类型 | string | '' | | btnTxt | 按钮文字 | string | '上传' | | btnType | 按钮类型 | string | 'button' | | btnProps | 按钮属性 | object | {} | | limit | 最大文件数 | number | 1 | | multiple | 是否多选 | boolean | 自动由 limit 控制 | | disabled | 是否禁用 | boolean | false | | icon | 自定义图标 | 组件/函数/null | undefined | | fileSizeLimit | 单文件大小限制(字节) | number | 5242880 |

Events

| 事件名 | 说明 | 回调参数 | |--------|------|----------| | select | 文件选择后触发 | files/file | | exceed | 文件超出大小限制时 | file |


FullScreenContainer 全屏容器组件

用于页面/区域的“全屏展示”容器组件,常见于:大屏、表格/图表全屏查看、需要在不改路由的情况下临时全屏等场景。

说明:该组件为库内注册组件,可直接从 xdc-ui-lib 引入使用。

基本用法

<template>
  <FullScreenContainer>
    <div style="height: 300px; background: #f5f5f5">内容区域</div>
  </FullScreenContainer>
</template>

<script setup lang="ts">
import { FullScreenContainer } from 'xdc-ui-lib'
</script>

常见用法(配合工具栏按钮)

<template>
  <a-button @click="toggle">切换全屏</a-button>

  <FullScreenContainer ref="fsRef">
    <BaseTable :columns="columns" :data-source="dataSource" />
  </FullScreenContainer>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { FullScreenContainer, BaseTable } from 'xdc-ui-lib'

const fsRef = ref<any>()

function toggle() {
  // 若组件内部 expose 了方法,可在此调用(以实际实现为准)
  // fsRef.value?.toggle?.()
}
</script>

Props

| 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | noScroll | 是否隐藏内层白色容器滚动条;false 时内层 overflow:autotrue 时内层 overflow:hidden | boolean | true | | fill | 是否填满父容器;true 外层 width/height:100% 且内层绝对定位铺满;false 外层高度随内容(height:auto) | boolean | true | | flex | 外层是否采用 flex(column);用于“上面标题/筛选区 + 下面表格自适应吃满剩余高度” | boolean | true | | gutter | 外层 padding(外层与内层之间间隙) | number \| string | 16 | | padding | 内层白色容器 padding(内容与白色容器边缘间距) | number \| string | 16 | | background | 内层白色容器背景色 | string | '#fff' | | maxHeight | 外层最大高度;用于“外层不滚、内层滚”的场景 | number \| string | '100vh' | | style | 透传给内层白色容器(.fsc-content)的 style(对象或字符串) | Record<string, any> \| string | - | | contentFill | 是否为 slot 内容自动包一层 flex 容器(flex:1; min-height:0),用于 BaseTable 等组件直接放入时可正确撑开不被压扁 | boolean | false |

Slots

| 插槽名 | 说明 | |------|------| | default | 容器内容 |

Events

当前组件未定义/抛出自定义事件。


Hooks / 工具

useModalManager 模态框管理

用于对多个 BaseModal 进行注册/注销,并支持“一键关闭全部弹窗”。

import { useModalManager } from 'xdc-ui-lib'

const { registerModal, unregisterModal, closeAllModals } = useModalManager()

API:

  • registerModal(id: string, ref: { close?: () => void })
  • unregisterModal(id: string)
  • closeAllModals()

提示:BaseModal 内部会用到这个能力(如果你在业务里需要自行管理多个弹窗,也可以直接使用该 hook)。

useColumnSetting 表格列设置 Hook

用于在业务侧以 hook 方式接入列设置(显隐/排序/固定/持久化),底层复用 useColumnSettingStore 的缓存逻辑。

import { computed } from 'vue'
import { useColumnSetting, type ColumnSettingColumn } from 'xdc-ui-lib'

const baseColumns: ColumnSettingColumn[] = [
  { title: 'ID', dataIndex: 'id', key: 'id' },
  { title: '名称', dataIndex: 'name', key: 'name' },
]

const {
  tableRef,
  selectedColumns,
  currentSize,
  initColumns,
  getDisplayColumnsData,
  handleColumnChange,
  persist,
} = useColumnSetting({
  columns: () => baseColumns,
  storageKey: 'user-list-columns',
  disabledColumns: ['id'],
  // hiddenColumns: ['action'],
  // size: 'middle',
  // persistOnChange: true,
})

initColumns()

const displayColumns = computed(() => {
  // 仅示例:你也可以直接用 selectedColumns 过滤 checked
  return getDisplayColumnsData().filter((c) => c.checked)
})

核心入参(UseColumnSettingOptions):

  • columns:列定义(支持 ref/computed/function)
  • storageKey:本地缓存 key(建议业务传,避免 hash 变更影响)
  • disabledColumns?:禁止操作的列
  • hiddenColumns?:完全隐藏且不可操作的列
  • size?:表格密度(可选,参与缓存)
  • persistOnChange?:列变更时是否自动写缓存(默认 true;needConfirm 场景可设 false,最后手动 persist()

useFilterTypeDisplay 筛选项显示设置 Hook

用于 SearchPanel 的“筛选项显示/隐藏/排序”配置管理(存储与 ColumnSetting 类似)。

import { ref } from 'vue'
import { useFilterTypeDisplay } from 'xdc-ui-lib'

const storageKey = ref('search-panel:user-list')
const filterTypes = ref<any[]>([
  { id: 'name', label: '名称', type: 'input' },
  { id: 'status', label: '状态', type: 'select' },
])

const {
  selectedItems,
  init,
  toggleVisibility,
  onCheckAllChange,
  reset,
} = useFilterTypeDisplay({
  storageKey,
  filterTypes,
  disabledIds: ref(['name']),
})

init()

国际化(i18n)

组件库内置了基础国际化能力(默认 zh-CN),并支持切换语言、以及由业务侧传入自定义语言包。

import { initI18n, setLocale, getLocale, setMessages, getMessages, zhCN, enUS } from 'xdc-ui-lib'

// 1) 在 app.use(组件库) 前/后都可以初始化(组件库 install 内部也会默认 initI18n)
initI18n({
  locale: 'zh-CN',
  // messages: 自定义语言包(可选)
})

// 2) 运行时切换语言
setLocale('en-US')
console.log(getLocale())

// 3) 覆盖内置语言包(可选)
setMessages({
  ...zhCN,
  // 按 LocaleMessages 结构补齐/覆盖字段
} as any)

console.log(getMessages())

可用导出:

  • initI18n(options?)
  • setLocale(locale) / getLocale()
  • setMessages(messages) / getMessages()
  • zhCN / enUS / messages
  • useI18n():组件内部/业务侧均可使用(返回 t(key) 等)

开发

# 安装依赖
npm install

# 启动开发服务器
npm run dev

# 构建
npm run build