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

@qynpm/form

v1.0.2

Published

基于 Vue 3 和 Element Plus 的 schema 表单工具包。

Downloads

281

Readme

@qynpm/form

基于 Vue 3 + Element Plus 的 schema 驱动表单工具包。

当前提供:

  • useFormItem
  • useSave
  • useSyncQueryParams

安装

pnpm add @qynpm/form

Peer Dependencies:

  • vue >= 3.4
  • element-plus >= 2.0
  • @element-plus/icons-vue >= 2.0
  • pinia >= 2.0
  • vue-router >= 4.0
  • @qynpm/ui >= 1.0.0

引入

这是一个以 hooks 为主的工具包,通常按需引入即可:

import { useFormItem, useSave, useSyncQueryParams } from '@qynpm/form'

设计说明

useFormItem 采用 schema 驱动模式:

  • 第一参数 model 用来描述字段结构、默认值、控件类型和渲染方式
  • 第二参数 options 用来描述 query 同步、缓存、紧凑布局、保存能力等
  • 内部维护响应式 modelForm
  • 页面侧通过 formItem / formItems 输出表单项
  • 提交时通过 modelFormgetModelForm() 获取当前值

补充说明:

  • QyDialog 现在通过 @qynpm/ui 提供,createInstance 仍属于包内运行时实现
  • 当前版本更适合作为体系内拆包使用,还不是完全脱离宿主约定的通用表单库
  • 图标能力仍然默认复用宿主现有方案
  • imageInput 暂时仍然是过渡能力,后续可以继续拆成独立包

快速上手

<template>
  <el-form v-bind="form.getFormProps()">
    <component :is="form.formItem" prop="shopName" />
    <component :is="form.formItem" prop="shopType" />

    <el-form-item>
      <el-button type="primary" @click="handleSubmit">提交</el-button>
      <el-button @click="form.reset">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script setup lang="ts">
import { useFormItem } from '@qynpm/form'

const form = useFormItem(
  [
    {
      label: '店铺名称',
      key: 'shopName',
      type: 'string',
      rules: [{ required: true, message: '请输入店铺名称', trigger: 'blur' }]
    },
    {
      label: '店铺类型',
      key: 'shopType',
      type: 'select',
      value: 'erp',
      options: [
        { label: 'ERP', value: 'erp' },
        { label: 'Production', value: 'production' }
      ]
    }
  ],
  {
    id: 'shop-form'
  }
)

function handleSubmit() {
  console.log(form.getModelForm())
}
</script>

API

useFormItem(model, options?)

model

类型:FormItemSet<Key>[]

| 字段 | 类型 | 说明 | | --- | --- | --- | | label | string | 表单项标题 | | key | string | 字段名,对应 modelForm 的 key | | asKey | string | 没有 key 时的备用唯一标识 | | type | 'string' \| 'number' \| 'imageInput' \| 'select' \| 'date' \| 'inputNumber' \| 'radio' \| 'qyMoneyInput' \| 'qyRemoteSelect' \| 'qyImageUpload' \| 'qyDatePicker' \| 'qyInputNumber' | 控件类型 | | value | any | 默认值 | | props | Record<string, any> | 透传给控件的 props | | rules | FormItemRule[] | Element Plus 校验规则 | | options | Array \| Ref | select / radio 选项 | | render | Function | 自定义渲染函数 |

类型映射

@qynpm/form 保留旧 schema 类型,但内部基础组件已经切到 @qynpm/ui

| schema 类型 | 默认组件 | 说明 | | --- | --- | --- | | string | QyInput | 普通文本输入,type="number" 仍按输入框字符串语义处理 | | number | QyInput | 兼容旧 ElInput 用法,不等同于数字步进器 | | select | QySelect | 保留旧 options: { ref, label, value } 映射和数字值转换 | | radio | QyRadioGroup | 保留旧 options 映射,支持普通 radio 和 button radio | | date | QyDatePicker | 保留 datetimerange 结束时间归一逻辑 | | inputNumber | QyInputNumber | 普通数字输入,默认值仍为 0 | | imageInput | QyRemarkImage | 备注文本 + 单图协议,走特殊适配路径 |

显式 qy* 类型只保留语义和旧基础类型明显不同的组件:

| schema 类型 | 默认组件 | 使用场景 | | --- | --- | --- | | qyMoneyInput | QyMoneyInput | 金额、费用、税费 | | qyRemoteSelect | QyRemoteSelect | 远程筛选下拉 | | qyImageUpload | QyImageUpload | 单图字段;配置 multiple 后用于财审凭证、付款凭证等多图数组 | | qyDatePicker | QyDatePicker | 需要显式表达 UI 日期组件时使用 | | qyInputNumber | QyInputNumber | 需要显式表达 UI 数字输入时使用 |

不再额外暴露 qyInputqySelectqyRadioGroup。对应能力已经分别收敛到 stringselectradio,避免 schema API 重复。

imageInput 暂不改名为 remarkImage。当前项目内仍存在老组件 @qiyin/components/remarkImage,而 @qynpm/ui 中也有 QyRemarkImage。为了避免出现第三套命名,form 继续使用旧 schema 名 imageInput 承接备注图文协议。

options

| 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | form | Record<string, any> | {} | 初始化表单值,会覆盖 schema 默认值 | | syncQuery | boolean | false | 是否和 URL query 同步 | | compact | boolean | false | 是否启用紧凑布局 class | | cache | { key: string } | undefined | 启用 localStorage 缓存 | | customSetterGetter | Record<string, CustomSetterGetter> | {} | query 同步时的自定义序列化 / 反序列化 | | showFilter | boolean | true | useSave 是否展示快捷筛选项 | | id | string | undefined | useSave 使用的唯一标识 |

返回值

| 字段 | 类型 | 说明 | | --- | --- | --- | | model | FormItemSet[] | 原始 schema | | modelForm | Reactive<Record<string, any>> | 响应式表单值对象 | | formProps | ComputedRef | 表单 props 计算结果 | | getModelForm() | () => Record<string, any> | 获取当前表单值快照 | | formItem() | ({ prop \| itemKey }) => VNode | 渲染单个表单项 | | formItems() | (props) => VNode[] | 批量渲染表单项,支持 includes / excludes | | reset() | () => void | 重置到默认值,并清理缓存 | | getFormProps() | () => { model, rules } | 返回可直接绑定到 el-form 的 props | | save() | (buttonProps?) => VNode \| null | 保存按钮 | | apply() | (buttonProps?) => VNode \| null | 应用按钮 | | SaveComponent() | () => JSX.Element | 保存 / 应用按钮组 | | getFormItemVNode() | (item) => VNode | 获取单个表单项 VNode |

useSave(options)

用于保存和恢复表单条件:

import { useSave } from '@qynpm/form'

const { save, apply, SaveComponent } = useSave({
  id: 'query-form',
  modelForm,
  showFilter: true
})

useSyncQueryParams(queryParams, options?)

用于查询表单与地址栏联动:

const form = useFormItem(schema, {
  syncQuery: true
})

当前保持的行为包括:

  • query 初始化回填
  • 数组值默认序列化 / 反序列化
  • date 时间区间转换
  • 尝试同步更新 tagsView 中的 query

使用示例

基础表单

<component :is="form.formItem" prop="shopName" />
<component :is="form.formItem" prop="shopType" />

批量渲染

<component :is="form.formItems" />

includes / excludes

<component :is="form.formItems" includes="keyword,status,channel" />
<component :is="form.formItems" excludes="remark" />

query 表单

const queryForm = useFormItem(schema, {
  syncQuery: true,
  id: 'query-form'
})

启用缓存

const form = useFormItem(schema, {
  cache: {
    key: 'shop-form-cache'
  }
})

自定义渲染

{
  label: '自定义字段',
  key: 'custom',
  type: 'string',
  render: (h, { modelForm, Component }) =>
    h('div', { class: 'flex gap-2' }, [
      Component,
      h('span', modelForm.custom || '')
    ])
}

保存 / 应用按钮

<template>
  <component :is="form.SaveComponent" />
</template>

样式与运行时说明

  • 宿主项目需要引入 element-plus/dist/index.css
  • @qynpm/form 当前会自动注入包内样式
  • 宿主项目需要提供 @element-plus/icons-vue
  • 如果使用 syncQuery,宿主项目需要接入 piniavue-router
  • 包内图标仍然默认复用宿主图标体系
  • imageInput 默认使用 /permission-api/common/uploadsAdmin-Token,如宿主上传接口不同,需要显式传入 api / tokenKey

本地开发

pnpm dev
pnpm build
  • pnpm dev:启动 playground 预览页
  • pnpm build:构建到 dist/

Workspace 联调:

{
  "dependencies": {
    "@qynpm/form": "workspace:*"
  }
}

已知限制

  1. useFormItemuseSave 目前仍然是配套关系,后续可以再评估是否继续拆开。
  2. createInstance 仍在包内,后续可根据拆包策略决定是否继续下沉。
  3. 当前图标能力仍然偏体系内约定。
  4. imageInput 是备注图文协议,默认上传接口只适合当前起印体系;跨项目使用时需要确认 api / tokenKey

当前联调说明

当前不再通过手动修改 form / ui 源码 import 来切换联调模式,而是统一使用顶层 Vite 开关控制。

开关位置:

  • qy-workspace 顶层 vite.config.ts

当前配置:

const ENABLE_LOCAL_QIYIN_DEBUG = true

规则如下:

  1. 当值为 true
  • @qiyin/form / @qynpm/form 映射到本地源码入口 index.ts
  • @qynpm/ui 映射到本地源码入口 ../UI/lib/index.js
  • 适合 workspace 本地联调
  1. 当值为 false
  • 走各自包的正常入口
  • 更接近线上/发包后的使用方式

注意:

  1. 修改开关后需要重启对应项目的 dev 服务