{"_id":"@bolian/dynamic-form","_rev":"3-fd47553cda81ffbb8bdcb9178ae753fb","name":"@bolian/dynamic-form","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.0":{"name":"@bolian/dynamic-form","version":"1.0.0","_id":"@bolian/dynamic-form@1.0.0","maintainers":[{"name":"einzbern","email":"278575486@qq.com"}],"dist":{"shasum":"19427e0413f86cb07ac4da0550cc163017130d6c","tarball":"https://registry.npmjs.org/@bolian/dynamic-form/-/dynamic-form-1.0.0.tgz","fileCount":5,"integrity":"sha512-/aQ2Mc74mVytd1HlkpN5K/wRgvgLVqCuvW0XFvVzQWMKyQWSyA3GEQdPqww4WMoy5wRLPI5OJKI1e9IqUrDfIg==","signatures":[{"sig":"MEUCIEtGxk1bTrEFrzv8DuP1hcMZBEIxyj7wNZy4+FXNGT7oAiEAv1o1S/sXgaDGNtBzUo7GCvK0ujl1gtSsXPKTcUHBM60=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":257213},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"dev":"tsup --watch","build":"tsup"},"_npmUser":{"name":"einzbern","email":"278575486@qq.com"},"_npmVersion":"11.13.0","description":"动态表单 & 问卷设计器组件","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.1","tsup":"^8.4.0","react":"^19.2.7","react-dom":"^19.2.7","typescript":"npm:@typescript/typescript6@^6.0.2","@types/react":"^19.2.16","@dnd-kit/core":"^6.3.1","@types/react-dom":"^19.0.2","@ant-design/icons":"^5.6.0","@dnd-kit/sortable":"^10.0.0","@dnd-kit/utilities":"^3.2.2"},"peerDependencies":{"antd":">=6.5","react":">=18","react-dom":">=18","@dnd-kit/core":">=6","@ant-design/icons":">=5","@dnd-kit/sortable":">=10","@dnd-kit/utilities":">=3"},"_npmOperationalInternal":{"tmp":"tmp/dynamic-form_1.0.0_1789117729169_0.9290647750789169","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@bolian/dynamic-form","version":"1.0.1","_id":"@bolian/dynamic-form@1.0.1","maintainers":[{"name":"einzbern","email":"278575486@qq.com"}],"dist":{"shasum":"1f1ce22a56f8f4c3a9f5225e7f8dfe3f84f67635","tarball":"https://registry.npmjs.org/@bolian/dynamic-form/-/dynamic-form-1.0.1.tgz","fileCount":9,"integrity":"sha512-mWgGSCT9qei0fFt4ImxfZU1Xuj1SViEX4Ah/S5MwBpKBoWnYZ8OPTzea3MAMGrNnAjM4IslwZKnvgkostcG4Uw==","signatures":[{"sig":"MEUCIAbcyB5z2unHdfAZ9d6nds00vDSGuLGJGpO7c8sAwXnMAiEAoxaGuNlXPDgyqP++9MiUoEapj8EAsNj7/523b185iUA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIBy01w+y5HM4+R/9rFeUrkKxzk6HsKZEF0gVXl4BqVefAiEA9+4pP5DqPsIzSZ6utUIwNTCd+XyRU+PH6qGM+PI9xeg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":257536},"main":"./index.cjs","type":"module","types":"./index.d.ts","module":"./index.js","exports":{".":{"import":{"types":"./index.d.ts","default":"./index.js"},"require":{"types":"./index.d.cts","default":"./index.cjs"}},"./dist/*":"./dist/*"},"scripts":{"dev":"tsup --watch","build":"tsup"},"_npmUser":{"name":"einzbern","email":"278575486@qq.com"},"_npmVersion":"11.13.0","description":"动态表单 & 问卷设计器组件","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.1","tsup":"^8.4.0","react":"^19.2.7","react-dom":"^19.2.7","typescript":"npm:@typescript/typescript6@^6.0.2","@types/react":"^19.2.16","@dnd-kit/core":"^6.3.1","@types/react-dom":"^19.0.2","@ant-design/icons":"^5.6.0","@dnd-kit/sortable":"^10.0.0","@dnd-kit/utilities":"^3.2.2"},"peerDependencies":{"antd":">=6.5","react":">=18","react-dom":">=18","@dnd-kit/core":">=6","@ant-design/icons":">=5","@dnd-kit/sortable":">=10","@dnd-kit/utilities":">=3"},"_npmOperationalInternal":{"tmp":"tmp/dynamic-form_1.0.1_1789372881118_0.4470167700096357","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"_id":"@bolian/dynamic-form@1.0.2","dist":{"shasum":"4cb5b470e765322cd342c0dec3a0350ccc971604","tarball":"https://registry.npmjs.org/@bolian/dynamic-form/-/dynamic-form-1.0.2.tgz","fileCount":10,"integrity":"sha512-58KhqAMM6mOi63yUUhz0ajgnWCFfhFsh6mNOBzBg0u4Bxgm8KzJyyrbFNjALDnLuHfRTWtibw286HbA9TMFeyw==","signatures":[{"sig":"MEQCIEsIAGGix2CJ4sLyzeVgXexNsshNm5Mk2icdg/y8xqT/AiAx8Qb8XUgA/px9pl3dDgnaHR9URXLcIqdyF8SeKj7XzA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHv7it9EFR5MF4v6nA/dLNaTvDTmPt1oNpaivmy1jLCgAiBbrL4Nj/BFbf3qquwtu4j7/tGmtHBf/n2gviSQ1ynXEg=="}],"unpackedSize":267210},"main":"./index.cjs","name":"@bolian/dynamic-form","type":"module","types":"./index.d.ts","module":"./index.js","exports":{".":{"import":{"types":"./index.d.ts","default":"./index.js"},"require":{"types":"./index.d.cts","default":"./index.cjs"}},"./dist/*":"./dist/*"},"scripts":{"dev":"tsup --watch","build":"tsup"},"version":"1.0.2","_npmUser":{"name":"einzbern","email":"278575486@qq.com"},"_npmVersion":"11.13.0","description":"动态表单 & 问卷设计器组件","directories":{},"maintainers":[{"name":"einzbern","email":"278575486@qq.com"}],"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.1","tsup":"^8.4.0","react":"^19.2.7","react-dom":"^19.2.7","typescript":"npm:@typescript/typescript6@^6.0.2","@types/react":"^19.2.16","@dnd-kit/core":"^6.3.1","@types/react-dom":"^19.0.2","@ant-design/icons":"^5.6.0","@dnd-kit/sortable":"^10.0.0","@dnd-kit/utilities":"^3.2.2"},"peerDependencies":{"antd":">=6.5","react":">=18","react-dom":">=18","@dnd-kit/core":">=6","@ant-design/icons":">=5","@dnd-kit/sortable":">=10","@dnd-kit/utilities":">=3"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dynamic-form_1.0.2_1790149217465_0.23209859590549708"}}},"time":{"created":"2026-09-11T09:08:48.965Z","modified":"2026-09-23T07:40:18.068Z","1.0.0":"2026-09-11T09:08:49.312Z","1.0.1":"2026-09-14T08:01:21.210Z","1.0.2":"2026-09-23T07:40:17.553Z"},"description":"动态表单 & 问卷设计器组件","maintainers":[{"name":"einzbern","email":"278575486@qq.com"}],"readme":"# @bolian/dynamic-form\n\n动态表单与问卷设计器组件库，基于 React、Ant Design 和 `@dnd-kit`。\n\n主要能力：\n\n- `FormDesigner`：拖拽式动态表单设计器\n- `DynamicForm`：根据表单配置自动渲染 Ant Design 表单\n- `SurveyDesigner`：问卷 / 满意度调查设计器\n- `SurveyPreview`：问卷预览与满意度分值计算\n- `DynamicFormProvider`：注入 `request`、上传地址等宿主项目依赖\n\n## 安装\n\n```bash\nnpm install @bolian/dynamic-form\n```\n\n或使用 pnpm：\n\n```bash\npnpm add @bolian/dynamic-form\n```\n\n本包将 React、Ant Design 和 `@dnd-kit` 作为 peer dependencies，宿主项目需要自行安装：\n\n```bash\nnpm install react react-dom antd @ant-design/icons @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities\n```\n\n版本要求：\n\n- `react` >= 18\n- `react-dom` >= 18\n- `antd` >= 6.5\n- `@ant-design/icons` >= 5\n- `@dnd-kit/core` >= 6\n- `@dnd-kit/sortable` >= 10\n- `@dnd-kit/utilities` >= 3\n\n> 组件内部使用了 Tailwind CSS 工具类，建议在已启用 Tailwind CSS 的项目中使用，以保证布局和间距样式正常。\n\n## 全局配置\n\n在应用根部使用 `DynamicFormProvider` 注入请求实例和上传地址。\n\n```tsx\nimport { DynamicFormProvider } from '@bolian/dynamic-form';\n\nconst request = {\n  get: ({ url, params, headers }) =>\n    axios.get(url, { params, headers }).then((res) => res.data),\n  post: ({ url, data, headers }) =>\n    axios.post(url, data, { headers }).then((res) => res.data),\n};\n\nfunction App() {\n  return (\n    <DynamicFormProvider\n      request={request}\n      uploadAction=\"/api/file/upload\"\n    >\n      {/* 你的页面 */}\n    </DynamicFormProvider>\n  );\n}\n```\n\n`DynamicFormProvider` 支持：\n\n| 属性 | 类型 | 说明 |\n| --- | --- | --- |\n| `request` | `DynamicFormRequest` | 可选。用于获取接口类选项数据 |\n| `uploadAction` | `string` | 可选。文件 / 图片上传接口地址，默认 `/api/file/upload` |\n\n`DynamicFormRequest` 需要宿主项目提供一个包含 `get` 和 `post` 方法的对象：\n\n```ts\nexport interface DynamicFormRequest {\n  get<T = any>(option: {\n    url: string;\n    params?: any;\n    headers?: Record<string, string>;\n  }): Promise<T>;\n\n  post<T = any>(option: {\n    url: string;\n    data?: any;\n    headers?: Record<string, string>;\n  }): Promise<T>;\n}\n```\n\n## 动态表单渲染\n\n`DynamicForm` 根据 `config.fields` 自动渲染表单控件。\n\n```tsx\nimport { DynamicForm } from '@bolian/dynamic-form';\nimport type { DynamicFormConfig } from '@bolian/dynamic-form';\n\nconst config: DynamicFormConfig = {\n  id: 'form-001',\n  name: '员工信息登记',\n  description: '用于收集员工基础信息',\n  fields: [\n    {\n      id: 'name',\n      title: '姓名',\n      type: 'text',\n      fieldKey: 'name',\n      required: true,\n      placeholder: '请输入姓名',\n    },\n    {\n      id: 'gender',\n      title: '性别',\n      type: 'radio',\n      fieldKey: 'gender',\n      options: [\n        { label: '男', value: 'male' },\n        { label: '女', value: 'female' },\n      ],\n    },\n    {\n      id: 'birthday',\n      title: '出生日期',\n      type: 'date',\n      fieldKey: 'birthday',\n    },\n  ],\n};\n\nfunction UserForm() {\n  return (\n    <DynamicForm\n      config={config}\n      onFinish={(values) => {\n        console.log(values);\n      }}\n      grid\n      column={2}\n    />\n  );\n}\n```\n\n### DynamicForm 属性\n\n| 属性 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- |\n| `config` | `DynamicFormConfig` | 必填 | 表单配置 |\n| `formRef` | `RefObject<FormInstance \\| null>` | - | 可选。外部 Ant Design 表单实例 |\n| `initialValues` | `DynamicFormData` | - | 可选。初始值 |\n| `readonly` | `boolean` | `false` | 是否只读 |\n| `onFinish` | `(values: DynamicFormData) => void` | - | 提交成功回调 |\n| `layout` | `'horizontal' \\| 'vertical' \\| 'inline'` | `'horizontal'` | 表单布局 |\n| `labelCol` | `{ span: number }` | - | 标签列配置 |\n| `wrapperCol` | `{ span: number }` | - | 内容列配置 |\n| `grid` | `boolean` | `false` | 是否启用网格布局 |\n| `column` | `number` | `2` | 网格列数，`grid` 为 `true` 时生效 |\n\n表单提交后，值会以 `fieldKey`（缺失时使用字段 `id`）作为 key。\n\n## 表单设计器\n\n`FormDesigner` 提供字段拖拽、排序、属性配置和预览能力。\n\n```tsx\nimport { useRef } from 'react';\nimport {\n  FormDesigner,\n  type FormDesignerRef,\n} from '@bolian/dynamic-form';\n\nfunction FormDesignPage() {\n  const designerRef = useRef<FormDesignerRef>(null);\n\n  const handleSave = () => {\n    const data = designerRef.current?.getExportData();\n    if (!data) return;\n\n    console.log(data.title);\n    console.log(data.description);\n    console.log(data.formJson); // JSON 字符串，可直接存储或提交后端\n  };\n\n  return (\n    <div>\n      <button onClick={handleSave}>保存</button>\n      <FormDesigner ref={designerRef} />\n    </div>\n  );\n}\n```\n\n`FormDesigner` 属性：\n\n| 属性 | 类型 | 说明 |\n| --- | --- | --- |\n| `initialConfig` | `{ name: string; description: string; fields: DynamicFormField[] }` | 可选。编辑已有表单时传入初始数据 |\n\n`FormDesignerRef`：\n\n```ts\n{\n  getExportData: () => FormDesignerExportData | null;\n}\n```\n\n`getExportData()` 返回：\n\n```ts\n{\n  title: string;\n  description: string;\n  formJson: string;\n}\n```\n\n## 问卷设计器\n\n`SurveyDesigner` 支持评分题、NPS、单选、多选、填空、单行文本、数字和日期题，以及题目关联条件和满意度分值计算。\n\n```tsx\nimport { useRef } from 'react';\nimport {\n  SurveyDesigner,\n  type SurveyDesignerRef,\n} from '@bolian/dynamic-form';\n\nfunction SurveyDesignPage() {\n  const designerRef = useRef<SurveyDesignerRef>(null);\n\n  const handleSave = () => {\n    const data = designerRef.current?.getExportData();\n    if (!data) return;\n\n    console.log(data.formJson);\n    console.log(data.lowScoreThreshold);\n  };\n\n  return <SurveyDesigner ref={designerRef} />;\n}\n```\n\n`SurveyDesigner` 属性：\n\n| 属性 | 类型 | 说明 |\n| --- | --- | --- |\n| `initialConfig` | `{ title: string; titleEn?: string; description: string; descriptionEn?: string; questions: Question[]; lowScoreThreshold?: number }` | 可选。编辑已有问卷时传入初始数据 |\n\n`SurveyDesignerRef`：\n\n```ts\n{\n  getExportData: () => SurveyDesignerExportData | null;\n}\n```\n\n`getExportData()` 返回：\n\n```ts\n{\n  title: string;\n  titleEn?: string;\n  description: string;\n  descriptionEn?: string;\n  formJson: string;\n  lowScoreThreshold: number;\n}\n```\n\n### 问卷预览\n\n```tsx\nimport { useState } from 'react';\nimport {\n  SurveyPreview,\n  type SurveyData,\n} from '@bolian/dynamic-form';\n\nfunction Preview({ survey }: { survey: SurveyData }) {\n  const [open, setOpen] = useState(false);\n\n  return (\n    <>\n      <button onClick={() => setOpen(true)}>预览问卷</button>\n      <SurveyPreview\n        open={open}\n        survey={survey}\n        onClose={() => setOpen(false)}\n        lang=\"zh\"\n      />\n    </>\n  );\n}\n```\n\n`SurveyPreview` 属性：\n\n| 属性 | 类型 | 说明 |\n| --- | --- | --- |\n| `open` | `boolean` | 是否显示预览弹窗 |\n| `survey` | `SurveyData` | 问卷数据 |\n| `onClose` | `() => void` | 关闭回调 |\n| `lang` | `'zh' \\| 'en'` | 可选。默认 `'zh'` |\n\n## 支持的表单字段类型\n\n`DynamicFormField.type` 支持以下值：\n\n| 类型 | 说明 |\n| --- | --- |\n| `text` | 单行文本 |\n| `textarea` | 多行文本 |\n| `number` | 数字输入 |\n| `select` | 下拉选择 |\n| `radio` | 单选 |\n| `checkbox` | 多选 |\n| `date` | 日期 |\n| `dateRange` | 日期范围 |\n| `switch` | 开关 |\n| `imageUpload` | 图片上传 |\n| `fileUpload` | 文件上传 |\n| `treeSelect` | 树选择 |\n| `rate` | 评分 |\n\n常用字段配置：\n\n```ts\ninterface DynamicFormField {\n  id: string;\n  title: string;\n  type: FieldType;\n  fieldKey?: string;\n  required?: boolean;\n  placeholder?: string;\n  options?: FieldOption[];\n  defaultValue?: any;\n  rulesMessage?: string;\n  disabled?: boolean;\n  minLength?: number;\n  maxLength?: number;\n  min?: number;\n  max?: number;\n  width?: 'xs' | 'sm' | 'm' | 'lg' | 'xl';\n  maxCount?: number;\n  maxSize?: number;\n  multiple?: boolean;\n  treeData?: TreeNode[];\n  treeCheckable?: boolean;\n  treeCheckStrictly?: boolean;\n  optionSourceType?: 'manual' | 'dict' | 'api';\n  dictType?: string;\n  apiUrl?: string;\n  apiMethod?: 'GET' | 'POST';\n  apiParams?: string;\n  apiLabelField?: string;\n  apiValueField?: string;\n}\n```\n\n## 选项数据来源\n\n`select`、`radio`、`checkbox` 支持三种选项来源：\n\n- `manual`：直接使用 `options`\n- `dict`：读取 `sessionStorage.DICTS` 中对应 `dictType` 的字典数据\n- `api`：通过 `DynamicFormProvider` 注入的 `request` 请求接口获取\n\n接口模式配置示例：\n\n```ts\n{\n  id: 'department',\n  title: '所属部门',\n  type: 'select',\n  fieldKey: 'department',\n  optionSourceType: 'api',\n  apiUrl: '/api/system/department/list',\n  apiMethod: 'GET',\n  apiParams: '{}',\n  apiLabelField: 'name',\n  apiValueField: 'id',\n}\n```\n\n## 导出的内容\n\n包根入口会导出：\n\n```ts\nexport {\n  DynamicFormProvider,\n  useDynamicFormConfig,\n  FormDesigner,\n  SurveyDesigner,\n  SurveyPreview,\n  DynamicForm,\n};\n\nexport type {\n  DynamicFormRequest,\n  DynamicFormConfigValue,\n  FormDesignerExportData,\n  FormDesignerRef,\n  SurveyData,\n  SurveyDesignerExportData,\n  SurveyDesignerRef,\n  Question,\n  QuestionType,\n  QuestionCondition,\n  FieldType,\n  FieldOption,\n  OptionSourceType,\n  TreeNode,\n  DynamicFormField,\n  DynamicFormConfig,\n  DynamicFormData,\n};\n```\n\n从 `1.0.1` 开始，可以直接从包名导入，无需再写 `/dist`：\n\n```ts\nimport { DynamicForm } from '@bolian/dynamic-form';\n```\n","readmeFilename":"README.md"}