docs: 为LangChain Agent添加完整的表单配置文档集
添加详细的文档集,为LangChain Agent生成表单配置提供完整的参考指南。包括: - 数据结构总览:核心FormField、ComponentProps、Option等结构定义 - 组件类型参考:30+种表单组件的详细说明和配置要点 - 配置规范:component_props的完整属性规范和数据提交格式 - LangChain Agent使用指南:自然语言到组件的映射、必填识别、选项提取规则 - 示例数据:20+个真实配置示例和完整表单模板 - 规则控制系统:字段显示/隐藏规则的详细实现机制 - API接口文档:表单管理和数据操作的所有接口说明 - 页面数据提取指南:从实际运行表单中提取配置的方法
Showing
10 changed files
with
3978 additions
and
0 deletions
CHANGELOG.md
0 → 100644
docs/agent/00-数据结构总览.md
0 → 100644
| 1 | +# 数据结构总览 | ||
| 2 | + | ||
| 3 | +## 核心数据结构 | ||
| 4 | + | ||
| 5 | +### 1. 表单字段结构 (FormField) | ||
| 6 | + | ||
| 7 | +每个表单字段都是一个对象,包含以下核心属性: | ||
| 8 | + | ||
| 9 | +```typescript | ||
| 10 | +interface FormField { | ||
| 11 | + // 字段标识 | ||
| 12 | + key: string // 字段唯一标识,如 "field_1" | ||
| 13 | + name: string // 表单验证用的名称,通常等于 key | ||
| 14 | + | ||
| 15 | + // 字段值 | ||
| 16 | + value: any // 字段当前值 | ||
| 17 | + default?: any // 默认值 | ||
| 18 | + | ||
| 19 | + // 组件相关 | ||
| 20 | + component: Component // Vue 组件引用 | ||
| 21 | + component_props: ComponentProps // 组件属性配置 | ||
| 22 | + | ||
| 23 | + // 验证相关 | ||
| 24 | + required?: boolean // 是否必填 | ||
| 25 | + rules?: ValidationRule[] // 验证规则 | ||
| 26 | + type?: string // 表单输入类型(text/textarea等) | ||
| 27 | + | ||
| 28 | + // 其他 | ||
| 29 | + index?: number // 字段排序索引 | ||
| 30 | +} | ||
| 31 | +``` | ||
| 32 | + | ||
| 33 | +### 2. 组件属性结构 (ComponentProps) | ||
| 34 | + | ||
| 35 | +```typescript | ||
| 36 | +interface ComponentProps { | ||
| 37 | + // 基础属性 | ||
| 38 | + tag: string // 组件类型标识(如 "input", "radio") | ||
| 39 | + name: string // 组件名称 | ||
| 40 | + label: string // 字段标签(显示名称) | ||
| 41 | + placeholder?: string // 占位符文本 | ||
| 42 | + default?: any // 默认值 | ||
| 43 | + | ||
| 44 | + // 显示控制 | ||
| 45 | + disabled?: boolean // 是否隐藏 | ||
| 46 | + disabled_show?: boolean // 隐藏时是否显示图标 | ||
| 47 | + readonly?: boolean // 是否只读 | ||
| 48 | + required?: boolean // 是否必填 | ||
| 49 | + | ||
| 50 | + // 选项类组件 | ||
| 51 | + options?: Option[] // 选项列表(radio/checkbox/select) | ||
| 52 | + | ||
| 53 | + // 样式相关 | ||
| 54 | + align?: string // 文本对齐方式(left/center/right) | ||
| 55 | + direction?: string // 排列方向(vertical/horizontal) | ||
| 56 | + background_color?: string // 背景色 | ||
| 57 | + | ||
| 58 | + // 高级功能 | ||
| 59 | + note?: string // 提示文本(支持HTML) | ||
| 60 | + is_camera_scan?: boolean // 是否启用微信扫一扫 | ||
| 61 | + camera_scan_type?: string // 扫码类型(ALL_CODE/QR_CODE/BAR_CODE) | ||
| 62 | + | ||
| 63 | + // 图片上传 | ||
| 64 | + max_count?: number // 最大上传数量 | ||
| 65 | + max_size?: number // 最大文件大小(MB) | ||
| 66 | + | ||
| 67 | + // 评分 | ||
| 68 | + x_score?: number // 分数值 | ||
| 69 | + | ||
| 70 | + // 分组相关 | ||
| 71 | + is_field_group?: boolean // 是否是集合组 | ||
| 72 | + group_field_name?: string // 所属组字段名 | ||
| 73 | +} | ||
| 74 | +``` | ||
| 75 | + | ||
| 76 | +### 3. 选项结构 (Option) | ||
| 77 | + | ||
| 78 | +用于 Radio、Checkbox、Picker 等组件: | ||
| 79 | + | ||
| 80 | +```typescript | ||
| 81 | +interface Option { | ||
| 82 | + // 基础 | ||
| 83 | + title: string // 选项显示文本 | ||
| 84 | + value: any // 选项值 | ||
| 85 | + checked?: boolean // 是否默认选中 | ||
| 86 | + | ||
| 87 | + // 样式 | ||
| 88 | + color?: string // 选项颜色 | ||
| 89 | + background_color?: string // 背景色 | ||
| 90 | + | ||
| 91 | + // 状态 | ||
| 92 | + disabled?: boolean // 是否禁用 | ||
| 93 | + | ||
| 94 | + // 描述信息 | ||
| 95 | + desc_text?: string // 描述文本 | ||
| 96 | + desc_type?: string // 描述类型(text/url) | ||
| 97 | + desc_url?: string // 描述链接URL | ||
| 98 | + desc_btn_name?: string // 描述按钮名称 | ||
| 99 | + | ||
| 100 | + // 补充信息 | ||
| 101 | + is_input?: boolean // 是否需要输入补充信息 | ||
| 102 | + input_required?: boolean // 补充信息是否必填 | ||
| 103 | + input_placeholder?: string // 补充信息占位符 | ||
| 104 | + affix?: string // 补充信息值 | ||
| 105 | +} | ||
| 106 | +``` | ||
| 107 | + | ||
| 108 | +### 4. API 响应结构 | ||
| 109 | + | ||
| 110 | +```typescript | ||
| 111 | +interface APIResponse<T = any> { | ||
| 112 | + code: number // 状态码:1=成功,其他=失败 | ||
| 113 | + msg: string // 响应消息 | ||
| 114 | + data: T // 响应数据 | ||
| 115 | + show?: boolean // 是否显示错误提示 | ||
| 116 | +} | ||
| 117 | +``` | ||
| 118 | + | ||
| 119 | +## 数据流转 | ||
| 120 | + | ||
| 121 | +### 1. 表单渲染流程 | ||
| 122 | + | ||
| 123 | +``` | ||
| 124 | +后端API → 表单配置数据 → createComponentType() → 动态组件渲染 | ||
| 125 | +``` | ||
| 126 | + | ||
| 127 | +### 2. 表单提交流程 | ||
| 128 | + | ||
| 129 | +``` | ||
| 130 | +用户输入 → 组件v-model → item.value → addFormDataAPI() → 后端保存 | ||
| 131 | +``` | ||
| 132 | + | ||
| 133 | +## 关键概念 | ||
| 134 | + | ||
| 135 | +### 1. 动态组件系统 | ||
| 136 | + | ||
| 137 | +项目使用 `component_props.tag` 属性决定渲染哪种组件: | ||
| 138 | +- 系统通过 `src/hooks/useComponentType.js` 中的 `createComponentType()` 函数 | ||
| 139 | +- 根据 `tag` 值动态分配对应的 Vue 组件 | ||
| 140 | +- 支持 30+ 种组件类型 | ||
| 141 | + | ||
| 142 | +### 2. 验证系统 | ||
| 143 | + | ||
| 144 | +- 基于 Vant Form 的验证系统 | ||
| 145 | +- 通过 `rules` 数组配置验证规则 | ||
| 146 | +- 必填项自动添加 `{ required: true, message: 'xxx' }` | ||
| 147 | + | ||
| 148 | +### 3. 规则系统 | ||
| 149 | + | ||
| 150 | +- 字段可以通过规则控制其他字段的显示/隐藏 | ||
| 151 | +- 通过 `emit("active")` 触发规则检查 | ||
| 152 | +- 规则组件:`RuleField`、`MultiRuleField` | ||
| 153 | + | ||
| 154 | +### 4. Cookie 保存 | ||
| 155 | + | ||
| 156 | +- 未完成表单自动保存到 Cookie | ||
| 157 | +- 格式:`{ form_code: { field_key: value } }` | ||
| 158 | +- 过期时间:1 天 | ||
| 159 | + | ||
| 160 | +### 5. 周期选择 | ||
| 161 | + | ||
| 162 | +- 某些表单支持周期选择 | ||
| 163 | +- 通过 API `/srv/?a=cycle_list` 获取可用周期 | ||
| 164 | +- 周期选择后 URL 会携带 `x_cycle` 参数 |
docs/agent/01-表单字段组件类型.md
0 → 100644
| 1 | +# 表单字段组件类型 | ||
| 2 | + | ||
| 3 | +## 支持的组件类型列表 | ||
| 4 | + | ||
| 5 | +项目支持 **30+ 种** 动态表单字段组件,通过 `component_props.tag` 属性指定。 | ||
| 6 | + | ||
| 7 | +## 文本输入类 | ||
| 8 | + | ||
| 9 | +### 1. input - 单行文本输入 | ||
| 10 | +- **组件**: `TextField` | ||
| 11 | +- **用途**: 短文本输入,如姓名、标题等 | ||
| 12 | +- **特殊功能**: 微信扫一扫(`is_camera_scan`) | ||
| 13 | + | ||
| 14 | +### 2. textarea - 多行文本输入 | ||
| 15 | +- **组件**: `TextareaField` | ||
| 16 | +- **用途**: 长文本输入,如备注、描述等 | ||
| 17 | +- **特性**: 自动高度(`autosize`) | ||
| 18 | + | ||
| 19 | +### 3. number - 数字输入 | ||
| 20 | +- **组件**: `NumberField` | ||
| 21 | +- **用途**: 数字类型输入,如年龄、数量等 | ||
| 22 | + | ||
| 23 | +## 选择类 | ||
| 24 | + | ||
| 25 | +### 4. radio - 单项选择 | ||
| 26 | +- **组件**: `RadioField` | ||
| 27 | +- **用途**: 单选选项,如性别、是否等 | ||
| 28 | +- **数据结构**: `options` 数组 | ||
| 29 | +- **特殊功能**: | ||
| 30 | + - 选项颜色(`color`, `background_color`) | ||
| 31 | + - 补充信息输入(`is_input`) | ||
| 32 | + - 描述信息(`desc_text`, `desc_url`) | ||
| 33 | + | ||
| 34 | +### 5. checkbox - 多项选择 | ||
| 35 | +- **组件**: `CheckboxField` | ||
| 36 | +- **用途**: 多选选项,如爱好、标签等 | ||
| 37 | +- **数据结构**: `options` 数组 | ||
| 38 | +- **排列方向**: `direction` (vertical/horizontal) | ||
| 39 | + | ||
| 40 | +### 6. select - 单列选择器 | ||
| 41 | +- **组件**: `PickerField` | ||
| 42 | +- **用途**: 下拉单选 | ||
| 43 | +- **数据结构**: `options` 数组 | ||
| 44 | +- **返回值**: 选中的 `value` | ||
| 45 | + | ||
| 46 | +## 日期时间类 | ||
| 47 | + | ||
| 48 | +### 7. date - 日期选择器 | ||
| 49 | +- **组件**: `DatePickerField` | ||
| 50 | +- **用途**: 选择日期 | ||
| 51 | + | ||
| 52 | +### 8. time - 时间选择器 | ||
| 53 | +- **组件**: `TimePickerField` | ||
| 54 | +- **用途**: 选择时间 | ||
| 55 | + | ||
| 56 | +### 9. datetime - 日期时间选择器 | ||
| 57 | +- **组件**: `DateTimePickerField` | ||
| 58 | +- **用途**: 选择日期和时间 | ||
| 59 | + | ||
| 60 | +### 10. calendar - 日历选择器 | ||
| 61 | +- **组件**: `CalendarField` | ||
| 62 | +- **用途**: 日历形式选择日期 | ||
| 63 | + | ||
| 64 | +## 上传类 | ||
| 65 | + | ||
| 66 | +### 11. image_uploader - 图片上传 | ||
| 67 | +- **组件**: `ImageUploaderField` | ||
| 68 | +- **用途**: 上传图片到七牛云 | ||
| 69 | +- **配置**: | ||
| 70 | + - `max_count`: 最大数量 | ||
| 71 | + - `max_size`: 最大文件大小(MB) | ||
| 72 | +- **返回值**: `[{ url, name }]` | ||
| 73 | + | ||
| 74 | +### 12. file_uploader - 文件上传 | ||
| 75 | +- **组件**: `FileUploaderField` | ||
| 76 | +- **用途**: 上传普通文件 | ||
| 77 | + | ||
| 78 | +## 特殊输入类 | ||
| 79 | + | ||
| 80 | +### 13. phone - 手机号输入 | ||
| 81 | +- **组件**: `PhoneField` | ||
| 82 | +- **用途**: 手机号码输入和验证 | ||
| 83 | +- **验证**: 11位手机号格式 | ||
| 84 | + | ||
| 85 | +### 14. email - 邮箱输入 | ||
| 86 | +- **组件**: `EmailField` | ||
| 87 | +- **用途**: 邮箱地址输入和验证 | ||
| 88 | + | ||
| 89 | +### 15. id_card - 身份证输入 | ||
| 90 | +- **组件**: `IdentityField` | ||
| 91 | +- **用途**: 身份证号码输入和验证 | ||
| 92 | + | ||
| 93 | +### 16. name - 姓名输入 | ||
| 94 | +- **组件**: `NameField` | ||
| 95 | +- **用途**: 中文姓名输入 | ||
| 96 | + | ||
| 97 | +### 17. gender - 性别选择 | ||
| 98 | +- **组件**: `GenderField` | ||
| 99 | +- **用途**: 性别选择(男/女) | ||
| 100 | + | ||
| 101 | +## 位置类 | ||
| 102 | + | ||
| 103 | +### 18. address - 地址选择器 | ||
| 104 | +- **组件**: `AreaPickerField` | ||
| 105 | +- **用途**: 省/市/区三级联动选择 | ||
| 106 | +- **数据**: 使用 `@vant/area-data` | ||
| 107 | + | ||
| 108 | +## 展示类 | ||
| 109 | + | ||
| 110 | +### 19. desc - 文字描述 | ||
| 111 | +- **组件**: `DesField` | ||
| 112 | +- **用途**: 纯文字展示,不支持输入 | ||
| 113 | + | ||
| 114 | +### 20. divider - 分割线 | ||
| 115 | +- **组件**: `DividerField` | ||
| 116 | +- **用途**: 视觉分割线 | ||
| 117 | + | ||
| 118 | +### 21. note - 富文本控件 | ||
| 119 | +- **组件**: `NoteField` | ||
| 120 | +- **用途**: 富文本内容展示 | ||
| 121 | + | ||
| 122 | +### 22. marquee - 跑马灯 | ||
| 123 | +- **组件**: `MarqueeField` | ||
| 124 | +- **用途**: 滚动公告文字 | ||
| 125 | + | ||
| 126 | +## 特殊功能类 | ||
| 127 | + | ||
| 128 | +### 23. sign - 电子签名 | ||
| 129 | +- **组件**: `SignField` | ||
| 130 | +- **用途**: 手写签名板 | ||
| 131 | +- **依赖**: `vue-esign` | ||
| 132 | + | ||
| 133 | +### 24. rate - 评分选择器 | ||
| 134 | +- **组件**: `RatePickerField` | ||
| 135 | +- **用途**: 星级评分 | ||
| 136 | + | ||
| 137 | +### 25. appointment - 预约控件 | ||
| 138 | +- **组件**: `AppointmentField` | ||
| 139 | +- **用途**: 时间段预约选择 | ||
| 140 | +- **数据结构**: 复杂的日期+时间段结构 | ||
| 141 | + | ||
| 142 | +### 26. rule - 活动规则控件 | ||
| 143 | +- **组件**: `RuleField` | ||
| 144 | +- **用途**: 显示规则说明,支持弹窗 | ||
| 145 | + | ||
| 146 | +### 27. multi_rule - 活动规则控件(多选) | ||
| 147 | +- **组件**: `MultiRuleField` | ||
| 148 | +- **用途**: 多选规则选项 | ||
| 149 | + | ||
| 150 | +### 28. contact - 联系人控件 | ||
| 151 | +- **组件**: `ContactField` | ||
| 152 | +- **用途**: 联系人信息输入 | ||
| 153 | + | ||
| 154 | +### 29. button - 按钮控件 | ||
| 155 | +- **组件**: `ButtonField` | ||
| 156 | +- **用途**: 自定义按钮 | ||
| 157 | + | ||
| 158 | +### 30. custom - 自定义控件 | ||
| 159 | +- **组件**: `CustomField` | ||
| 160 | +- **用途**: 完全自定义的组件 | ||
| 161 | + | ||
| 162 | +## 高级类 | ||
| 163 | + | ||
| 164 | +### 31. group - 组集合输入控件 | ||
| 165 | +- **组件**: `GroupField` | ||
| 166 | +- **用途**: 将多个字段分组显示 | ||
| 167 | +- **配置**: `field_groups` 数组 | ||
| 168 | + | ||
| 169 | +### 32. org_picker - 树形选择控件 | ||
| 170 | +- **组件**: `OrgPickerField` | ||
| 171 | +- **用途**: 组织架构树形选择 | ||
| 172 | + | ||
| 173 | +### 33. volunteer_group - 义工组别选择 | ||
| 174 | +- **组件**: `VolunteerGroupField` | ||
| 175 | +- **用途**: 义工组别单选 | ||
| 176 | + | ||
| 177 | +### 34. table_editor - 表格编辑控件 | ||
| 178 | +- **组件**: `TableField` | ||
| 179 | +- **用途**: 动态表格编辑,支持增删行 | ||
| 180 | + | ||
| 181 | +### 35. video - 视频控件 | ||
| 182 | +- **组件**: `VideoField` | ||
| 183 | +- **状态**: 已注释,暂未使用 | ||
| 184 | + | ||
| 185 | +## 组件注册位置 | ||
| 186 | + | ||
| 187 | +所有组件在 `src/hooks/useComponentType.js` 中注册: | ||
| 188 | + | ||
| 189 | +```javascript | ||
| 190 | +export function createComponentType(data) { | ||
| 191 | + _.each(data, (item, index) => { | ||
| 192 | + // 统一名称 | ||
| 193 | + item.name = item.key | ||
| 194 | + | ||
| 195 | + // 根据 tag 分配组件 | ||
| 196 | + if (item.component_props.tag === 'input') { | ||
| 197 | + item.component = TextField; | ||
| 198 | + } | ||
| 199 | + if (item.component_props.tag === 'radio') { | ||
| 200 | + item.component = RadioField; | ||
| 201 | + } | ||
| 202 | + // ... 更多组件 | ||
| 203 | + }) | ||
| 204 | +} | ||
| 205 | +``` | ||
| 206 | + | ||
| 207 | +## 新增组件流程 | ||
| 208 | + | ||
| 209 | +1. 在 `src/components/` 下创建组件目录 | ||
| 210 | +2. 创建 `index.vue` 组件文件 | ||
| 211 | +3. 在 `src/hooks/useComponentType.js` 添加 if 判断分支 | ||
| 212 | +4. 组件必须支持以下 props: | ||
| 213 | + - `item`: Object (包含 component_props 和 value) | ||
| 214 | + - 必须通过 emit 发送 "active" 事件 |
docs/agent/02-component_props-配置规范.md
0 → 100644
| 1 | +# component_props 配置规范 | ||
| 2 | + | ||
| 3 | +## 通用属性 | ||
| 4 | + | ||
| 5 | +所有组件类型都支持的属性: | ||
| 6 | + | ||
| 7 | +| 属性 | 类型 | 必填 | 默认值 | 说明 | | ||
| 8 | +|------|------|------|--------|------| | ||
| 9 | +| `tag` | string | ✅ | - | 组件类型标识,决定渲染哪个组件 | | ||
| 10 | +| `name` | string | ✅ | - | 组件名称 | | ||
| 11 | +| `label` | string | ✅ | - | 字段标签(显示名称) | | ||
| 12 | +| `default` | any | ❌ | - | 默认值 | | ||
| 13 | +| `placeholder` | string | ❌ | "请输入" | 占位符文本 | | ||
| 14 | +| `required` | boolean | ❌ | false | 是否必填 | | ||
| 15 | +| `disabled` | boolean | ❌ | false | 是否隐藏字段 | | ||
| 16 | +| `disabled_show` | boolean | ❌ | false | 隐藏时是否显示闭眼图标 | | ||
| 17 | +| `readonly` | boolean | ❌ | false | 是否只读 | | ||
| 18 | +| `note` | string | ❌ | - | 提示文本(支持HTML) | | ||
| 19 | + | ||
| 20 | +## 选项类组件属性 | ||
| 21 | + | ||
| 22 | +Radio、Checkbox、Picker 等组件额外支持: | ||
| 23 | + | ||
| 24 | +| 属性 | 类型 | 说明 | | ||
| 25 | +|------|------|------| | ||
| 26 | +| `options` | Option[] | 选项列表数组 | | ||
| 27 | +| `direction` | string | 排列方向:`vertical`(垂直)/ `horizontal`(水平) | | ||
| 28 | +| `align` | string | 文本对齐:`left` / `center` / `right` | | ||
| 29 | + | ||
| 30 | +### Option 结构 | ||
| 31 | + | ||
| 32 | +```typescript | ||
| 33 | +interface Option { | ||
| 34 | + title: string // 显示文本 | ||
| 35 | + value: any // 选项值 | ||
| 36 | + checked?: boolean // 默认选中 | ||
| 37 | + disabled?: boolean // 禁用状态 | ||
| 38 | + color?: string // 选项颜色 | ||
| 39 | + background_color?: string // 背景色 | ||
| 40 | + | ||
| 41 | + // 描述信息 | ||
| 42 | + desc_text?: string // 描述文本 | ||
| 43 | + desc_type?: string // "text" 或 "url" | ||
| 44 | + desc_url?: string // 描述链接 | ||
| 45 | + desc_btn_name?: string // 描述按钮名称 | ||
| 46 | + | ||
| 47 | + // 补充信息 | ||
| 48 | + is_input?: boolean // 是否需要补充信息输入 | ||
| 49 | + input_required?: boolean // 补充信息是否必填 | ||
| 50 | + input_placeholder?: string // 补充信息占位符 | ||
| 51 | + affix?: string // 补充信息值 | ||
| 52 | +} | ||
| 53 | +``` | ||
| 54 | + | ||
| 55 | +## 文本输入类属性 | ||
| 56 | + | ||
| 57 | +### input / textarea / number | ||
| 58 | + | ||
| 59 | +| 属性 | 类型 | 说明 | | ||
| 60 | +|------|------|------| | ||
| 61 | +| `align` | string | 文本对齐方式 | | ||
| 62 | +| `is_camera_scan` | boolean | 是否启用微信扫一扫 | | ||
| 63 | +| `camera_scan_type` | string | 扫码类型:`ALL_CODE` / `QR_CODE` / `BAR_CODE` | | ||
| 64 | +| `is_edit_camera_scan_result` | boolean | 是否允许编辑扫码结果 | | ||
| 65 | + | ||
| 66 | +## 上传类属性 | ||
| 67 | + | ||
| 68 | +### image_uploader | ||
| 69 | + | ||
| 70 | +| 属性 | 类型 | 默认值 | 说明 | | ||
| 71 | +|------|------|--------|------| | ||
| 72 | +| `max_count` | number | 9 | 最大上传数量 | | ||
| 73 | +| `max_size` | number | 10 | 最大文件大小(MB) | | ||
| 74 | +| `image_type` | string | "jpg/..." | 允许的图片类型 | | ||
| 75 | + | ||
| 76 | +**返回值结构**: | ||
| 77 | +```javascript | ||
| 78 | +{ | ||
| 79 | + key: "image_uploader", | ||
| 80 | + filed_name: "field_1", | ||
| 81 | + value: [ | ||
| 82 | + { url: "https://...", name: "image.jpg" } | ||
| 83 | + ] | ||
| 84 | +} | ||
| 85 | +``` | ||
| 86 | + | ||
| 87 | +### file_uploader | ||
| 88 | + | ||
| 89 | +与 `image_uploader` 类似,用于普通文件上传。 | ||
| 90 | + | ||
| 91 | +## 日期时间类属性 | ||
| 92 | + | ||
| 93 | +### date / time / datetime / calendar | ||
| 94 | + | ||
| 95 | +| 属性 | 类型 | 说明 | | ||
| 96 | +|------|------|------| | ||
| 97 | +| `min_date` | Date/Date[] | 最小可选日期 | | ||
| 98 | +| `max_date` | Date/Date[] | 最大可选日期 | | ||
| 99 | +| `formatter` | Function | 格式化函数 | | ||
| 100 | + | ||
| 101 | +## 预约控件属性 | ||
| 102 | + | ||
| 103 | +### appointment | ||
| 104 | + | ||
| 105 | +**复杂配置结构**: | ||
| 106 | + | ||
| 107 | +```javascript | ||
| 108 | +{ | ||
| 109 | + tag: "appointment", | ||
| 110 | + label: "预约时间", | ||
| 111 | + appointment_title: "选择入寺时间", | ||
| 112 | + options: [ | ||
| 113 | + { | ||
| 114 | + title: "03月27日", // 日期标题 | ||
| 115 | + placeholder: "剩余余量 9878", // 提示信息 | ||
| 116 | + disabled: false, // 是否禁用该日期 | ||
| 117 | + columns: [ // 时间段列表 | ||
| 118 | + { | ||
| 119 | + checked: false, | ||
| 120 | + disabled: false, | ||
| 121 | + value: "1", | ||
| 122 | + text: "16:00-17:30 余1399" | ||
| 123 | + } | ||
| 124 | + ] | ||
| 125 | + } | ||
| 126 | + ] | ||
| 127 | +} | ||
| 128 | +``` | ||
| 129 | + | ||
| 130 | +## 规则控件属性 | ||
| 131 | + | ||
| 132 | +### rule / multi_rule | ||
| 133 | + | ||
| 134 | +| 属性 | 类型 | 说明 | | ||
| 135 | +|------|------|------| | ||
| 136 | +| `desc_text` | string | 规则内容(支持 `\n` 换行) | | ||
| 137 | +| `desc_type` | string | `text`(弹窗)或 `url`(跳转) | | ||
| 138 | +| `desc_url` | string | 规则详情链接 | | ||
| 139 | +| `desc_btn_name` | string | 按钮名称,如"查看详情" | | ||
| 140 | + | ||
| 141 | +## 组集合控件属性 | ||
| 142 | + | ||
| 143 | +### group | ||
| 144 | + | ||
| 145 | +```javascript | ||
| 146 | +{ | ||
| 147 | + tag: "group", | ||
| 148 | + label: "物品详情", | ||
| 149 | + field_groups: [ | ||
| 150 | + { | ||
| 151 | + tag: "input", | ||
| 152 | + label: "物品描述", | ||
| 153 | + field_name: "field_10", | ||
| 154 | + group_field_name: "field_4", // 所属组字段 | ||
| 155 | + // ... 其他属性 | ||
| 156 | + } | ||
| 157 | + ] | ||
| 158 | +} | ||
| 159 | +``` | ||
| 160 | + | ||
| 161 | +## 评分控件属性 | ||
| 162 | + | ||
| 163 | +### rate | ||
| 164 | + | ||
| 165 | +| 属性 | 类型 | 说明 | | ||
| 166 | +|------|------|------| | ||
| 167 | +| `x_score` | number | 显示分值(会显示在标签旁) | | ||
| 168 | + | ||
| 169 | +## 表格控件属性 | ||
| 170 | + | ||
| 171 | +### table_editor | ||
| 172 | + | ||
| 173 | +| 属性 | 类型 | 说明 | | ||
| 174 | +|------|------|------| | ||
| 175 | +| `default` | string/html | 默认表格内容(HTML格式) | | ||
| 176 | + | ||
| 177 | +## 特殊功能属性 | ||
| 178 | + | ||
| 179 | +### 微信扫码 | ||
| 180 | + | ||
| 181 | +仅 `input` 类型支持: | ||
| 182 | + | ||
| 183 | +```javascript | ||
| 184 | +{ | ||
| 185 | + tag: "input", | ||
| 186 | + is_camera_scan: true, | ||
| 187 | + camera_scan_type: "ALL_CODE" // ALL_CODE | QR_CODE | BAR_CODE | ||
| 188 | +} | ||
| 189 | +``` | ||
| 190 | + | ||
| 191 | +### 补充信息 | ||
| 192 | + | ||
| 193 | +Radio、Checkbox 支持选择后输入补充信息: | ||
| 194 | + | ||
| 195 | +```javascript | ||
| 196 | +options: [ | ||
| 197 | + { | ||
| 198 | + title: "其他", | ||
| 199 | + value: "other", | ||
| 200 | + is_input: true, // 启用补充输入 | ||
| 201 | + input_required: true, // 补充信息必填 | ||
| 202 | + input_placeholder: "请输入补充信息", | ||
| 203 | + affix: "" // 补充信息值 | ||
| 204 | + } | ||
| 205 | +] | ||
| 206 | +``` | ||
| 207 | + | ||
| 208 | +### 显示隐藏控制 | ||
| 209 | + | ||
| 210 | +通过规则动态控制字段显示/隐藏: | ||
| 211 | + | ||
| 212 | +```javascript | ||
| 213 | +{ | ||
| 214 | + tag: "input", | ||
| 215 | + disabled: false // true=隐藏,false=显示 | ||
| 216 | +} | ||
| 217 | +``` | ||
| 218 | + | ||
| 219 | +## 样式属性 | ||
| 220 | + | ||
| 221 | +### 对齐方式 | ||
| 222 | + | ||
| 223 | +```javascript | ||
| 224 | +{ | ||
| 225 | + align: "left" // left | center | right | ||
| 226 | +} | ||
| 227 | +``` | ||
| 228 | + | ||
| 229 | +### 颜色 | ||
| 230 | + | ||
| 231 | +选项类组件支持单独配置颜色: | ||
| 232 | + | ||
| 233 | +```javascript | ||
| 234 | +options: [ | ||
| 235 | + { | ||
| 236 | + title: "重要", | ||
| 237 | + value: "important", | ||
| 238 | + color: "#ff0000", // 文字颜色 | ||
| 239 | + background_color: "#fff0f0" // 背景色 | ||
| 240 | + } | ||
| 241 | +] | ||
| 242 | +``` | ||
| 243 | + | ||
| 244 | +## 数据提交格式 | ||
| 245 | + | ||
| 246 | +### 普通字段 | ||
| 247 | + | ||
| 248 | +```javascript | ||
| 249 | +{ | ||
| 250 | + key: "field_1", | ||
| 251 | + value: "用户输入的值" | ||
| 252 | +} | ||
| 253 | +``` | ||
| 254 | + | ||
| 255 | +### 选项类字段(Radio) | ||
| 256 | + | ||
| 257 | +```javascript | ||
| 258 | +{ | ||
| 259 | + key: "field_1", | ||
| 260 | + value: "选项值", | ||
| 261 | + affix: "补充信息: xxx", // 如果有补充信息 | ||
| 262 | + type: "radio" | ||
| 263 | +} | ||
| 264 | +``` | ||
| 265 | + | ||
| 266 | +### 选项类字段(Checkbox) | ||
| 267 | + | ||
| 268 | +```javascript | ||
| 269 | +{ | ||
| 270 | + key: "field_1", | ||
| 271 | + value: ["值1", "值2"], // 数组 | ||
| 272 | + type: "checkbox" | ||
| 273 | +} | ||
| 274 | +``` | ||
| 275 | + | ||
| 276 | +### 图片上传 | ||
| 277 | + | ||
| 278 | +```javascript | ||
| 279 | +{ | ||
| 280 | + key: "field_1", | ||
| 281 | + filed_name: "field_1", | ||
| 282 | + value: [ | ||
| 283 | + { url: "https://...", name: "image.jpg" } | ||
| 284 | + ], | ||
| 285 | + type: "image_uploader" | ||
| 286 | +} | ||
| 287 | +``` |
docs/agent/03-API-接口文档.md
0 → 100644
| 1 | +# API 接口文档 | ||
| 2 | + | ||
| 3 | +## 基础配置 | ||
| 4 | + | ||
| 5 | +### 请求基础配置 | ||
| 6 | + | ||
| 7 | +所有请求默认携带参数: | ||
| 8 | +```javascript | ||
| 9 | +{ | ||
| 10 | + f: 'custom_form' // 固定参数 | ||
| 11 | +} | ||
| 12 | +``` | ||
| 13 | + | ||
| 14 | +### 响应格式 | ||
| 15 | + | ||
| 16 | +```typescript | ||
| 17 | +interface APIResponse<T = any> { | ||
| 18 | + code: number // 1=成功,其他=失败 | ||
| 19 | + msg: string // 响应消息 | ||
| 20 | + data: T // 响应数据 | ||
| 21 | + show?: boolean // 是否显示错误提示(code !== 1 时) | ||
| 22 | +} | ||
| 23 | +``` | ||
| 24 | + | ||
| 25 | +### 请求封装 | ||
| 26 | + | ||
| 27 | +```javascript | ||
| 28 | +import { fn, fetch } from '@/api/fn'; | ||
| 29 | + | ||
| 30 | +// GET 请求 | ||
| 31 | +fn(fetch.get('/srv/?a=xxx', params)) | ||
| 32 | + | ||
| 33 | +// POST 请求 | ||
| 34 | +fn(fetch.post('/srv/?a=xxx', params)) | ||
| 35 | +``` | ||
| 36 | + | ||
| 37 | +## 表单管理接口 | ||
| 38 | + | ||
| 39 | +### 1. 新增表单 | ||
| 40 | + | ||
| 41 | +**接口**: `/srv/?a=add_form` | ||
| 42 | +**方法**: POST | ||
| 43 | +**参数**: | ||
| 44 | +```javascript | ||
| 45 | +{ | ||
| 46 | + client_id: string, // 主体客户id | ||
| 47 | + name: string, // 表单名称 | ||
| 48 | + note: string // 表单描述 | ||
| 49 | +} | ||
| 50 | +``` | ||
| 51 | + | ||
| 52 | +### 2. 查询表单配置(字段和规则) | ||
| 53 | + | ||
| 54 | +**接口**: `/srv/?a=query_form_all_field` | ||
| 55 | +**方法**: GET | ||
| 56 | +**参数**: | ||
| 57 | +```javascript | ||
| 58 | +{ | ||
| 59 | + f: "custom_form", // 固定参数 | ||
| 60 | + form_code: string, // 表单唯一标识(必填) | ||
| 61 | + page_type: string, // 页面类型:add/edit/view(可选) | ||
| 62 | + data_id: string, // 数据ID(编辑时使用) | ||
| 63 | + flow_node_code: string // 流程节点代码(可选) | ||
| 64 | +} | ||
| 65 | +``` | ||
| 66 | + | ||
| 67 | +**返回**: | ||
| 68 | +```javascript | ||
| 69 | +{ | ||
| 70 | + code: 1, | ||
| 71 | + msg: "OK", | ||
| 72 | + data: { | ||
| 73 | + id: 835950, | ||
| 74 | + code: "nxqkbf", | ||
| 75 | + name: "表单名称", | ||
| 76 | + table_name: "customize_35697_nxqkbf", | ||
| 77 | + max_field_num: 3, | ||
| 78 | + field_list: [ | ||
| 79 | + { | ||
| 80 | + tag: "input", // 组件类型 | ||
| 81 | + field_name: "field_1", // 字段名 | ||
| 82 | + label: "姓名", // 显示标签 | ||
| 83 | + required: true, // 是否必填 | ||
| 84 | + data_type: "text", // 数据类型 | ||
| 85 | + placeholder: "请输入", | ||
| 86 | + disabled: false, | ||
| 87 | + readonly: false | ||
| 88 | + } | ||
| 89 | + ], | ||
| 90 | + rule_list: [ // 字段显示/隐藏规则 | ||
| 91 | + { | ||
| 92 | + field_names: ["field_2"], | ||
| 93 | + mode: "SHOW", | ||
| 94 | + logical_op: "OR", | ||
| 95 | + expr_list: [...] | ||
| 96 | + } | ||
| 97 | + ], | ||
| 98 | + flow_process_list: null // 工作流流程列表 | ||
| 99 | + } | ||
| 100 | +} | ||
| 101 | +``` | ||
| 102 | + | ||
| 103 | +**调用示例**: | ||
| 104 | +```bash | ||
| 105 | +curl "https://oa-dev.onwall.cn/srv/?a=query_form_all_field&f=custom_form&form_code=nxqkbf" | ||
| 106 | +``` | ||
| 107 | + | ||
| 108 | +--- | ||
| 109 | + | ||
| 110 | +### 2.1. 查询表单设置(表单级配置) | ||
| 111 | + | ||
| 112 | +**接口**: `/srv/?a=query_form_setting` | ||
| 113 | +**方法**: GET | ||
| 114 | +**参数**: | ||
| 115 | +```javascript | ||
| 116 | +{ | ||
| 117 | + f: "custom_form", // 固定参数 | ||
| 118 | + form_code: string // 表单唯一标识(必填) | ||
| 119 | +} | ||
| 120 | +``` | ||
| 121 | + | ||
| 122 | +**返回**: | ||
| 123 | +```javascript | ||
| 124 | +{ | ||
| 125 | + code: 1, | ||
| 126 | + msg: "OK", | ||
| 127 | + data: [{ | ||
| 128 | + id: 835950, | ||
| 129 | + code: "nxqkbf", | ||
| 130 | + name: "表单名称", | ||
| 131 | + max_field_num: 3, // 最大字段数 | ||
| 132 | + data_count: 7, // 已提交数据条数 | ||
| 133 | + extend: { | ||
| 134 | + server_time: "2026-03-16 17:15:40", | ||
| 135 | + is_back_user: false // 是否后台用户 | ||
| 136 | + }, | ||
| 137 | + property_list: { | ||
| 138 | + sjsj_enable: 1, // 是否启用数据收集 | ||
| 139 | + commit_action: "text", // 提交动作类型 | ||
| 140 | + commit_text_type: "default", | ||
| 141 | + commit_text_template: "提交成功", // 提交文本模板 | ||
| 142 | + edit_commit_action: "text", | ||
| 143 | + edit_commit_text_type: "default", | ||
| 144 | + edit_commit_text_template: "提交成功" | ||
| 145 | + } | ||
| 146 | + }] | ||
| 147 | +} | ||
| 148 | +``` | ||
| 149 | + | ||
| 150 | +**调用示例**: | ||
| 151 | +```bash | ||
| 152 | +curl "https://oa-dev.onwall.cn/srv/?a=query_form_setting&f=custom_form&form_code=nxqkbf" | ||
| 153 | +``` | ||
| 154 | + | ||
| 155 | +--- | ||
| 156 | + | ||
| 157 | +### 2.2. 两个接口的区别 | ||
| 158 | + | ||
| 159 | +| 接口 | 获取内容 | 用途 | | ||
| 160 | +|------|---------|------| | ||
| 161 | +| `query_form_all_field` | 字段列表、规则列表 | 渲染表单结构 | | ||
| 162 | +| `query_form_setting` | 表单配置、提交设置 | 获取表单级属性 | | ||
| 163 | + | ||
| 164 | +### 3. 添加表单字段 | ||
| 165 | + | ||
| 166 | +**接口**: `/srv/?a=add_form_field` | ||
| 167 | +**方法**: POST | ||
| 168 | +**参数**: | ||
| 169 | +```javascript | ||
| 170 | +{ | ||
| 171 | + form_code: string, // 表单唯一标识 | ||
| 172 | + component_code: string // 组件标识 | ||
| 173 | +} | ||
| 174 | +``` | ||
| 175 | + | ||
| 176 | +### 4. 添加表单字段属性设置 | ||
| 177 | + | ||
| 178 | +**接口**: `/srv/?a=add_form_setting` | ||
| 179 | +**方法**: POST | ||
| 180 | +**参数**: | ||
| 181 | +```javascript | ||
| 182 | +{ | ||
| 183 | + form_code: string, // 表单唯一标识 | ||
| 184 | + field_name: string, // 表单字段名(表单级属性可为空) | ||
| 185 | + component_code: string, // 组件标识 | ||
| 186 | + property_code: string, // 属性标识 | ||
| 187 | + setting_value: string // 属性值(JSON数组字符串) | ||
| 188 | +} | ||
| 189 | +``` | ||
| 190 | + | ||
| 191 | +### 5. 查询表单设置 | ||
| 192 | + | ||
| 193 | +**接口**: `/srv/?a=query_form_setting` | ||
| 194 | +**方法**: GET | ||
| 195 | +**参数**: | ||
| 196 | +```javascript | ||
| 197 | +{ | ||
| 198 | + form_code: string // 表单唯一标识 | ||
| 199 | +} | ||
| 200 | +``` | ||
| 201 | + | ||
| 202 | +**返回**: | ||
| 203 | +```javascript | ||
| 204 | +{ | ||
| 205 | + enable: number, // 0=停止表单,1=开启表单 | ||
| 206 | + is_time_range: number, // 0=不设定,1=设定 | ||
| 207 | + is_count_down: number, // 0=不显示,1=显示 | ||
| 208 | + begin_time: string, // 开启时间 | ||
| 209 | + end_time: string // 停止时间 | ||
| 210 | +} | ||
| 211 | +``` | ||
| 212 | + | ||
| 213 | +### 6. 验证便当密码 | ||
| 214 | + | ||
| 215 | +**接口**: `/srv/?a=verify_password` | ||
| 216 | +**方法**: POST | ||
| 217 | +**参数**: | ||
| 218 | +```javascript | ||
| 219 | +{ | ||
| 220 | + form_code: string, // 表单唯一标识 | ||
| 221 | + mmtx_password: string // 用户输入的密码 | ||
| 222 | +} | ||
| 223 | +``` | ||
| 224 | + | ||
| 225 | +### 7. 义工组长查询义工信息 | ||
| 226 | + | ||
| 227 | +**接口**: `/srv/?a=volunteer_source_leader` | ||
| 228 | +**方法**: GET | ||
| 229 | +**参数**: | ||
| 230 | +```javascript | ||
| 231 | +{ | ||
| 232 | + form_code: string, // 表单唯一标识 | ||
| 233 | + page_type: string, // 页面类型 | ||
| 234 | + force_back: string, // 是否强制后台账号模式检查 | ||
| 235 | + volunteer_source: string, // 报名渠道:self/leader | ||
| 236 | + volunteer_phone: string // 义工手机号 | ||
| 237 | +} | ||
| 238 | +``` | ||
| 239 | + | ||
| 240 | +## 数据管理接口 | ||
| 241 | + | ||
| 242 | +### 1. 添加表单数据 | ||
| 243 | + | ||
| 244 | +**接口**: `/srv/?a=add_formdata` | ||
| 245 | +**方法**: POST | ||
| 246 | +**参数**: | ||
| 247 | +```javascript | ||
| 248 | +{ | ||
| 249 | + form_code: string, // 表单唯一标识 | ||
| 250 | + data: object // 待添加的数据(JSON对象) | ||
| 251 | +} | ||
| 252 | +``` | ||
| 253 | + | ||
| 254 | +**示例**: | ||
| 255 | +```javascript | ||
| 256 | +{ | ||
| 257 | + form_code: "form_001", | ||
| 258 | + data: { | ||
| 259 | + field_1: "张三", | ||
| 260 | + field_2: "13800138000", | ||
| 261 | + field_3: ["选项1", "选项2"] | ||
| 262 | + } | ||
| 263 | +} | ||
| 264 | +``` | ||
| 265 | + | ||
| 266 | +### 2. 查询表单数据 | ||
| 267 | + | ||
| 268 | +**接口**: `/srv/?a=query_formdata` | ||
| 269 | +**方法**: GET | ||
| 270 | +**参数**: | ||
| 271 | +```javascript | ||
| 272 | +{ | ||
| 273 | + form_code: string, // 表单唯一标识 | ||
| 274 | + id: string // 数据ID | ||
| 275 | +} | ||
| 276 | +``` | ||
| 277 | + | ||
| 278 | +### 3. 修改表单数据 | ||
| 279 | + | ||
| 280 | +**接口**: `/srv/?a=modi_formdata` | ||
| 281 | +**方法**: POST | ||
| 282 | +**参数**: | ||
| 283 | +```javascript | ||
| 284 | +{ | ||
| 285 | + form_code: string, // 表单唯一标识 | ||
| 286 | + id: string, // 数据ID | ||
| 287 | + data: object // 待修改的数据(JSON对象) | ||
| 288 | +} | ||
| 289 | +``` | ||
| 290 | + | ||
| 291 | +### 4. 流程表单数据 | ||
| 292 | + | ||
| 293 | +**接口**: `/srv/?a=flow_formdata` | ||
| 294 | +**方法**: POST | ||
| 295 | +**参数**: | ||
| 296 | +```javascript | ||
| 297 | +{ | ||
| 298 | + form_code: string, // 表单唯一标识 | ||
| 299 | + data_id: string, // 数据ID | ||
| 300 | + data: object, // 表单数据 | ||
| 301 | + flow_node_code: string, // 流程节点 | ||
| 302 | + flow_node_action_id: string, // 流程节点按钮ID | ||
| 303 | + flow_content: string // 流程审批意见 | ||
| 304 | +} | ||
| 305 | +``` | ||
| 306 | + | ||
| 307 | +## 组件接口 | ||
| 308 | + | ||
| 309 | +### 1. 查询组件 | ||
| 310 | + | ||
| 311 | +**接口**: `/srv/?a=query_component` | ||
| 312 | +**方法**: GET | ||
| 313 | +**参数**: | ||
| 314 | +```javascript | ||
| 315 | +{ | ||
| 316 | + group_code: string, // 分组标识 | ||
| 317 | + component_code: string, // 组件标识 | ||
| 318 | + name: string // 组件名称(模糊查询) | ||
| 319 | +} | ||
| 320 | +``` | ||
| 321 | + | ||
| 322 | +### 2. 查询部门列表 | ||
| 323 | + | ||
| 324 | +**接口**: `/srv/?a=flow_setting&t=flow_dept_list` | ||
| 325 | +**方法**: GET | ||
| 326 | +**参数**: | ||
| 327 | +```javascript | ||
| 328 | +{ | ||
| 329 | + form_code: string // 表单code | ||
| 330 | +} | ||
| 331 | +``` | ||
| 332 | + | ||
| 333 | +**请求头建议**: | ||
| 334 | +```javascript | ||
| 335 | +{ | ||
| 336 | + headers: { | ||
| 337 | + "only-data": true, // 去重 | ||
| 338 | + "keep-data": true // 缓存 | ||
| 339 | + } | ||
| 340 | +} | ||
| 341 | +``` | ||
| 342 | + | ||
| 343 | +### 3. 查询角色列表 | ||
| 344 | + | ||
| 345 | +**接口**: `/srv/?a=flow_setting&t=flow_role_list` | ||
| 346 | +**方法**: GET | ||
| 347 | +**参数**: | ||
| 348 | +```javascript | ||
| 349 | +{ | ||
| 350 | + form_code: string // 表单code | ||
| 351 | +} | ||
| 352 | +``` | ||
| 353 | + | ||
| 354 | +### 4. 搜索用户部门角色 | ||
| 355 | + | ||
| 356 | +**接口**: `/srv/?a=flow_setting&t=search_user_dept_role` | ||
| 357 | +**方法**: GET | ||
| 358 | +**参数**: | ||
| 359 | +```javascript | ||
| 360 | +{ | ||
| 361 | + form_code: string, // 表单code | ||
| 362 | + word: string // 搜索内容 | ||
| 363 | +} | ||
| 364 | +``` | ||
| 365 | + | ||
| 366 | +## 通用接口 | ||
| 367 | + | ||
| 368 | +### 1. 发送验证码 | ||
| 369 | + | ||
| 370 | +**接口**: `/srv/?a=sms` | ||
| 371 | +**方法**: POST | ||
| 372 | +**参数**: | ||
| 373 | +```javascript | ||
| 374 | +{ | ||
| 375 | + phone: string // 手机号码 | ||
| 376 | +} | ||
| 377 | +``` | ||
| 378 | + | ||
| 379 | +### 2. 获取七牛上传 Token | ||
| 380 | + | ||
| 381 | +**接口**: `/srv/?a=upload` | ||
| 382 | +**方法**: POST | ||
| 383 | +**参数**: | ||
| 384 | +```javascript | ||
| 385 | +qs.stringify({ | ||
| 386 | + name: string, // 文件名 | ||
| 387 | + hash: string // 文件哈希(ETag) | ||
| 388 | +}) | ||
| 389 | +``` | ||
| 390 | + | ||
| 391 | +### 3. 保存文件 | ||
| 392 | + | ||
| 393 | +**接口**: `/srv/?a=upload&t=save_file` | ||
| 394 | +**方法**: POST | ||
| 395 | +**参数**: | ||
| 396 | +```javascript | ||
| 397 | +qs.stringify({ | ||
| 398 | + format: string, // 图片格式 | ||
| 399 | + hash: string, // 文件哈希 | ||
| 400 | + height: number, // 图片高度 | ||
| 401 | + width: number, // 图片宽度 | ||
| 402 | + filekey: string // 七牛返回的文件key | ||
| 403 | +}) | ||
| 404 | +``` | ||
| 405 | + | ||
| 406 | +## 周期接口 | ||
| 407 | + | ||
| 408 | +### 1. 获取周期列表 | ||
| 409 | + | ||
| 410 | +**接口**: `/srv/?a=cycle_list` | ||
| 411 | +**方法**: GET | ||
| 412 | +**参数**: | ||
| 413 | +```javascript | ||
| 414 | +{ | ||
| 415 | + form_code: string // 表单唯一标识 | ||
| 416 | +} | ||
| 417 | +``` | ||
| 418 | + | ||
| 419 | +**返回**: | ||
| 420 | +```javascript | ||
| 421 | +{ | ||
| 422 | + is_cycle: boolean, // 是否需要周期选择 | ||
| 423 | + cycle_list: [ // 周期列表 | ||
| 424 | + { | ||
| 425 | + cycle_id: string, | ||
| 426 | + cycle_name: string, | ||
| 427 | + start_date: string, | ||
| 428 | + end_date: string | ||
| 429 | + } | ||
| 430 | + ] | ||
| 431 | +} | ||
| 432 | +``` | ||
| 433 | + | ||
| 434 | +## HTTP 请求缓存控制 | ||
| 435 | + | ||
| 436 | +### 请求去重(only-data) | ||
| 437 | + | ||
| 438 | +避免短时间内重复请求: | ||
| 439 | + | ||
| 440 | +```javascript | ||
| 441 | +fn(fetch.get('/api/xxx', params, { | ||
| 442 | + headers: { "only-data": true } | ||
| 443 | +})) | ||
| 444 | +``` | ||
| 445 | + | ||
| 446 | +### 持久化缓存(keep-data) | ||
| 447 | + | ||
| 448 | +缓存请求结果(30秒,最多50条): | ||
| 449 | + | ||
| 450 | +```javascript | ||
| 451 | +fn(fetch.get('/api/xxx', params, { | ||
| 452 | + headers: { "keep-data": true } | ||
| 453 | +})) | ||
| 454 | +``` | ||
| 455 | + | ||
| 456 | +### 同时使用 | ||
| 457 | + | ||
| 458 | +```javascript | ||
| 459 | +fn(fetch.get('/api/xxx', params, { | ||
| 460 | + headers: { | ||
| 461 | + "only-data": true, | ||
| 462 | + "keep-data": true | ||
| 463 | + } | ||
| 464 | +})) | ||
| 465 | +``` | ||
| 466 | + | ||
| 467 | +## 错误处理 | ||
| 468 | + | ||
| 469 | +### 特殊错误码 | ||
| 470 | + | ||
| 471 | +| 错误码 | 说明 | 处理 | | ||
| 472 | +|--------|------|------| | ||
| 473 | +| 402 | 未授权/登录失效 | 跳转登录页,show=false | | ||
| 474 | +| 其他 | 业务错误 | 显示错误提示 | | ||
| 475 | + | ||
| 476 | +### 402 处理示例 | ||
| 477 | + | ||
| 478 | +```javascript | ||
| 479 | +if (response.data.code === 402) { | ||
| 480 | + response.data.show = false; // 不显示默认错误 | ||
| 481 | + showToast({ | ||
| 482 | + message: '登录失效!将跳转到登录页面', | ||
| 483 | + duration: 1500, | ||
| 484 | + onClose: () => { | ||
| 485 | + window.location.href = location.origin + '/admin/'; | ||
| 486 | + } | ||
| 487 | + }) | ||
| 488 | +} | ||
| 489 | +``` |
docs/agent/04-示例数据.md
0 → 100644
| 1 | +# 示例数据 | ||
| 2 | + | ||
| 3 | +## 完整表单配置示例 | ||
| 4 | + | ||
| 5 | +### 示例 1:用户信息表单 | ||
| 6 | + | ||
| 7 | +```javascript | ||
| 8 | +{ | ||
| 9 | + key: "field_1", | ||
| 10 | + value: "", | ||
| 11 | + component_props: { | ||
| 12 | + tag: "input", | ||
| 13 | + name: "name", | ||
| 14 | + label: "姓名", | ||
| 15 | + placeholder: "请输入姓名", | ||
| 16 | + required: true, | ||
| 17 | + default: "" | ||
| 18 | + } | ||
| 19 | +} | ||
| 20 | +``` | ||
| 21 | + | ||
| 22 | +### 示例 2:性别选择 | ||
| 23 | + | ||
| 24 | +```javascript | ||
| 25 | +{ | ||
| 26 | + key: "field_2", | ||
| 27 | + value: "", | ||
| 28 | + component_props: { | ||
| 29 | + tag: "gender", | ||
| 30 | + name: "gender", | ||
| 31 | + label: "性别", | ||
| 32 | + required: true, | ||
| 33 | + default: "", | ||
| 34 | + options: [ | ||
| 35 | + { | ||
| 36 | + title: "男", | ||
| 37 | + value: "男", | ||
| 38 | + checked: false | ||
| 39 | + }, | ||
| 40 | + { | ||
| 41 | + title: "女", | ||
| 42 | + value: "女", | ||
| 43 | + checked: false | ||
| 44 | + } | ||
| 45 | + ] | ||
| 46 | + } | ||
| 47 | +} | ||
| 48 | +``` | ||
| 49 | + | ||
| 50 | +### 示例 3:手机号输入 | ||
| 51 | + | ||
| 52 | +```javascript | ||
| 53 | +{ | ||
| 54 | + key: "field_3", | ||
| 55 | + value: "", | ||
| 56 | + component_props: { | ||
| 57 | + tag: "phone", | ||
| 58 | + name: "phone", | ||
| 59 | + label: "手机号", | ||
| 60 | + placeholder: "请输入手机号", | ||
| 61 | + required: true, | ||
| 62 | + default: "" | ||
| 63 | + } | ||
| 64 | +} | ||
| 65 | +``` | ||
| 66 | + | ||
| 67 | +### 示例 4:单项选择(带补充信息) | ||
| 68 | + | ||
| 69 | +```javascript | ||
| 70 | +{ | ||
| 71 | + key: "field_4", | ||
| 72 | + value: "", | ||
| 73 | + component_props: { | ||
| 74 | + tag: "radio", | ||
| 75 | + name: "category", | ||
| 76 | + label: "报名类型", | ||
| 77 | + required: true, | ||
| 78 | + direction: "vertical", | ||
| 79 | + default: "", | ||
| 80 | + options: [ | ||
| 81 | + { | ||
| 82 | + title: "个人报名", | ||
| 83 | + value: "personal", | ||
| 84 | + checked: true, | ||
| 85 | + color: "#1989fa" | ||
| 86 | + }, | ||
| 87 | + { | ||
| 88 | + title: "团队报名", | ||
| 89 | + value: "team", | ||
| 90 | + checked: false, | ||
| 91 | + color: "#ff976a" | ||
| 92 | + }, | ||
| 93 | + { | ||
| 94 | + title: "其他", | ||
| 95 | + value: "other", | ||
| 96 | + checked: false, | ||
| 97 | + is_input: true, // 启用补充输入 | ||
| 98 | + input_required: true, // 补充信息必填 | ||
| 99 | + input_placeholder: "请说明具体类型", | ||
| 100 | + desc_text: "请选择最符合的报名类型", | ||
| 101 | + desc_type: "text", | ||
| 102 | + desc_btn_name: "查看说明" | ||
| 103 | + } | ||
| 104 | + ] | ||
| 105 | + } | ||
| 106 | +} | ||
| 107 | +``` | ||
| 108 | + | ||
| 109 | +### 示例 5:多项选择 | ||
| 110 | + | ||
| 111 | +```javascript | ||
| 112 | +{ | ||
| 113 | + key: "field_5", | ||
| 114 | + value: [], | ||
| 115 | + component_props: { | ||
| 116 | + tag: "checkbox", | ||
| 117 | + name: "hobbies", | ||
| 118 | + label: "兴趣爱好", | ||
| 119 | + required: false, | ||
| 120 | + direction: "vertical", | ||
| 121 | + options: [ | ||
| 122 | + { | ||
| 123 | + title: "运动", | ||
| 124 | + value: "sport", | ||
| 125 | + checked: false, | ||
| 126 | + background_color: "#f0f9ff" | ||
| 127 | + }, | ||
| 128 | + { | ||
| 129 | + title: "阅读", | ||
| 130 | + value: "reading", | ||
| 131 | + checked: false, | ||
| 132 | + background_color: "#fff0f0" | ||
| 133 | + }, | ||
| 134 | + { | ||
| 135 | + title: "音乐", | ||
| 136 | + value: "music", | ||
| 137 | + checked: false, | ||
| 138 | + background_color: "#f0fff0" | ||
| 139 | + }, | ||
| 140 | + { | ||
| 141 | + title: "旅游", | ||
| 142 | + value: "travel", | ||
| 143 | + checked: false, | ||
| 144 | + background_color: "#fffaf0" | ||
| 145 | + } | ||
| 146 | + ] | ||
| 147 | + } | ||
| 148 | +} | ||
| 149 | +``` | ||
| 150 | + | ||
| 151 | +### 示例 6:下拉选择 | ||
| 152 | + | ||
| 153 | +```javascript | ||
| 154 | +{ | ||
| 155 | + key: "field_6", | ||
| 156 | + value: "", | ||
| 157 | + component_props: { | ||
| 158 | + tag: "select", | ||
| 159 | + name: "city", | ||
| 160 | + label: "所在城市", | ||
| 161 | + placeholder: "请选择城市", | ||
| 162 | + required: true, | ||
| 163 | + options: [ | ||
| 164 | + { text: "北京", value: "beijing" }, | ||
| 165 | + { text: "上海", value: "shanghai" }, | ||
| 166 | + { text: "广州", value: "guangzhou" }, | ||
| 167 | + { text: "深圳", value: "shenzhen" } | ||
| 168 | + ] | ||
| 169 | + } | ||
| 170 | +} | ||
| 171 | +``` | ||
| 172 | + | ||
| 173 | +### 示例 7:地址选择 | ||
| 174 | + | ||
| 175 | +```javascript | ||
| 176 | +{ | ||
| 177 | + key: "field_7", | ||
| 178 | + value: "", | ||
| 179 | + component_props: { | ||
| 180 | + tag: "address", | ||
| 181 | + name: "address", | ||
| 182 | + label: "详细地址", | ||
| 183 | + placeholder: "请选择省市区", | ||
| 184 | + required: true | ||
| 185 | + } | ||
| 186 | +} | ||
| 187 | +``` | ||
| 188 | + | ||
| 189 | +### 示例 8:日期选择 | ||
| 190 | + | ||
| 191 | +```javascript | ||
| 192 | +{ | ||
| 193 | + key: "field_8", | ||
| 194 | + value: "", | ||
| 195 | + component_props: { | ||
| 196 | + tag: "date", | ||
| 197 | + name: "birthday", | ||
| 198 | + label: "出生日期", | ||
| 199 | + placeholder: "请选择日期", | ||
| 200 | + required: true | ||
| 201 | + } | ||
| 202 | +} | ||
| 203 | +``` | ||
| 204 | + | ||
| 205 | +### 示例 9:图片上传 | ||
| 206 | + | ||
| 207 | +```javascript | ||
| 208 | +{ | ||
| 209 | + key: "field_9", | ||
| 210 | + value: [], | ||
| 211 | + component_props: { | ||
| 212 | + tag: "image_uploader", | ||
| 213 | + name: "photos", | ||
| 214 | + label: "上传照片", | ||
| 215 | + required: true, | ||
| 216 | + max_count: 3, // 最多3张 | ||
| 217 | + max_size: 5, // 最大5MB | ||
| 218 | + default: [] | ||
| 219 | + } | ||
| 220 | +} | ||
| 221 | +``` | ||
| 222 | + | ||
| 223 | +### 示例 10:多行文本 | ||
| 224 | + | ||
| 225 | +```javascript | ||
| 226 | +{ | ||
| 227 | + key: "field_10", | ||
| 228 | + value: "", | ||
| 229 | + component_props: { | ||
| 230 | + tag: "textarea", | ||
| 231 | + name: "description", | ||
| 232 | + label: "个人简介", | ||
| 233 | + placeholder: "请输入个人简介", | ||
| 234 | + required: false, | ||
| 235 | + default: "" | ||
| 236 | + } | ||
| 237 | +} | ||
| 238 | +``` | ||
| 239 | + | ||
| 240 | +### 示例 11:电子签名 | ||
| 241 | + | ||
| 242 | +```javascript | ||
| 243 | +{ | ||
| 244 | + key: "field_11", | ||
| 245 | + value: "", | ||
| 246 | + component_props: { | ||
| 247 | + tag: "sign", | ||
| 248 | + name: "signature", | ||
| 249 | + label: "本人签名", | ||
| 250 | + required: true, | ||
| 251 | + default: "" | ||
| 252 | + } | ||
| 253 | +} | ||
| 254 | +``` | ||
| 255 | + | ||
| 256 | +### 示例 12:评分 | ||
| 257 | + | ||
| 258 | +```javascript | ||
| 259 | +{ | ||
| 260 | + key: "field_12", | ||
| 261 | + value: "", | ||
| 262 | + component_props: { | ||
| 263 | + tag: "rate", | ||
| 264 | + name: "rating", | ||
| 265 | + label: "活动评分", | ||
| 266 | + required: true, | ||
| 267 | + x_score: 5, // 默认5分 | ||
| 268 | + default: "" | ||
| 269 | + } | ||
| 270 | +} | ||
| 271 | +``` | ||
| 272 | + | ||
| 273 | +### 示例 13:身份证号 | ||
| 274 | + | ||
| 275 | +```javascript | ||
| 276 | +{ | ||
| 277 | + key: "field_13", | ||
| 278 | + value: "", | ||
| 279 | + component_props: { | ||
| 280 | + tag: "id_card", | ||
| 281 | + name: "id_card", | ||
| 282 | + label: "身份证号", | ||
| 283 | + placeholder: "请输入身份证号", | ||
| 284 | + required: true | ||
| 285 | + } | ||
| 286 | +} | ||
| 287 | +``` | ||
| 288 | + | ||
| 289 | +### 示例 14:邮箱 | ||
| 290 | + | ||
| 291 | +```javascript | ||
| 292 | +{ | ||
| 293 | + key: "field_14", | ||
| 294 | + value: "", | ||
| 295 | + component_props: { | ||
| 296 | + tag: "email", | ||
| 297 | + name: "email", | ||
| 298 | + label: "电子邮箱", | ||
| 299 | + placeholder: "请输入邮箱地址", | ||
| 300 | + required: false | ||
| 301 | + } | ||
| 302 | +} | ||
| 303 | +``` | ||
| 304 | + | ||
| 305 | +### 示例 15:预约控件 | ||
| 306 | + | ||
| 307 | +```javascript | ||
| 308 | +{ | ||
| 309 | + key: "field_15", | ||
| 310 | + value: "", | ||
| 311 | + component_props: { | ||
| 312 | + tag: "appointment", | ||
| 313 | + name: "appointment_time", | ||
| 314 | + label: "预约时间", | ||
| 315 | + required: true, | ||
| 316 | + appointment_title: "选择预约时间段", | ||
| 317 | + options: [ | ||
| 318 | + { | ||
| 319 | + title: "03月27日", | ||
| 320 | + placeholder: "剩余余量 98", | ||
| 321 | + disabled: false, | ||
| 322 | + columns: [ | ||
| 323 | + { | ||
| 324 | + checked: false, | ||
| 325 | + disabled: false, | ||
| 326 | + value: "1", | ||
| 327 | + text: "09:00-10:30 余98" | ||
| 328 | + }, | ||
| 329 | + { | ||
| 330 | + checked: false, | ||
| 331 | + disabled: false, | ||
| 332 | + value: "2", | ||
| 333 | + text: "14:00-15:30 余50" | ||
| 334 | + }, | ||
| 335 | + { | ||
| 336 | + checked: false, | ||
| 337 | + disabled: true, | ||
| 338 | + value: "3", | ||
| 339 | + text: "16:00-17:30 余0" | ||
| 340 | + } | ||
| 341 | + ] | ||
| 342 | + }, | ||
| 343 | + { | ||
| 344 | + title: "03月28日", | ||
| 345 | + placeholder: "剩余余量 120", | ||
| 346 | + disabled: false, | ||
| 347 | + columns: [ | ||
| 348 | + { | ||
| 349 | + checked: false, | ||
| 350 | + disabled: false, | ||
| 351 | + value: "4", | ||
| 352 | + text: "09:00-10:30 余120" | ||
| 353 | + }, | ||
| 354 | + { | ||
| 355 | + checked: false, | ||
| 356 | + disabled: false, | ||
| 357 | + value: "5", | ||
| 358 | + text: "14:00-15:30 余80" | ||
| 359 | + } | ||
| 360 | + ] | ||
| 361 | + } | ||
| 362 | + ] | ||
| 363 | + } | ||
| 364 | +} | ||
| 365 | +``` | ||
| 366 | + | ||
| 367 | +### 示例 16:表格编辑 | ||
| 368 | + | ||
| 369 | +```javascript | ||
| 370 | +{ | ||
| 371 | + key: "field_16", | ||
| 372 | + value: "", | ||
| 373 | + component_props: { | ||
| 374 | + tag: "table_editor", | ||
| 375 | + name: "table_data", | ||
| 376 | + label: "物品清单", | ||
| 377 | + default: "<table><tr><th>名称</th><th>数量</th></tr><tr><td>物品A</td><td>10</td></tr></table>" | ||
| 378 | + } | ||
| 379 | +} | ||
| 380 | +``` | ||
| 381 | + | ||
| 382 | +### 示例 17:集合组 | ||
| 383 | + | ||
| 384 | +```javascript | ||
| 385 | +{ | ||
| 386 | + key: "field_17", | ||
| 387 | + value: "", | ||
| 388 | + component_props: { | ||
| 389 | + tag: "group", | ||
| 390 | + name: "group_info", | ||
| 391 | + label: "物品信息", | ||
| 392 | + field_groups: [ | ||
| 393 | + { | ||
| 394 | + tag: "input", | ||
| 395 | + name: "item_name", | ||
| 396 | + label: "物品名称", | ||
| 397 | + field_name: "field_18", | ||
| 398 | + group_field_name: "field_17", | ||
| 399 | + placeholder: "请输入物品名称", | ||
| 400 | + required: true | ||
| 401 | + }, | ||
| 402 | + { | ||
| 403 | + tag: "number", | ||
| 404 | + name: "item_count", | ||
| 405 | + label: "数量", | ||
| 406 | + field_name: "field_19", | ||
| 407 | + group_field_name: "field_17", | ||
| 408 | + placeholder: "请输入数量", | ||
| 409 | + required: true | ||
| 410 | + } | ||
| 411 | + ] | ||
| 412 | + } | ||
| 413 | +} | ||
| 414 | +``` | ||
| 415 | + | ||
| 416 | +### 示例 18:规则说明 | ||
| 417 | + | ||
| 418 | +```javascript | ||
| 419 | +{ | ||
| 420 | + key: "field_20", | ||
| 421 | + value: "", | ||
| 422 | + component_props: { | ||
| 423 | + tag: "rule", | ||
| 424 | + name: "rule_info", | ||
| 425 | + label: "活动规则", | ||
| 426 | + default: "", | ||
| 427 | + desc_text: "1. 活动时间:2024年3月1日-3月31日\n2. 参与资格:18岁以上\n3. 每人限参与一次", | ||
| 428 | + desc_type: "text", | ||
| 429 | + desc_btn_name: "查看完整规则" | ||
| 430 | + } | ||
| 431 | +} | ||
| 432 | +``` | ||
| 433 | + | ||
| 434 | +### 示例 19:只读字段 | ||
| 435 | + | ||
| 436 | +```javascript | ||
| 437 | +{ | ||
| 438 | + key: "field_21", | ||
| 439 | + value: "系统自动生成", | ||
| 440 | + component_props: { | ||
| 441 | + tag: "input", | ||
| 442 | + name: "readonly_field", | ||
| 443 | + label: "申请编号", | ||
| 444 | + readonly: true, // 只读 | ||
| 445 | + default: "系统自动生成" | ||
| 446 | + } | ||
| 447 | +} | ||
| 448 | +``` | ||
| 449 | + | ||
| 450 | +### 示例 20:带提示的字段 | ||
| 451 | + | ||
| 452 | +```javascript | ||
| 453 | +{ | ||
| 454 | + key: "field_22", | ||
| 455 | + value: "", | ||
| 456 | + component_props: { | ||
| 457 | + tag: "input", | ||
| 458 | + name: "username", | ||
| 459 | + label: "用户名", | ||
| 460 | + placeholder: "请输入用户名", | ||
| 461 | + required: true, | ||
| 462 | + note: "用户名长度为4-16个字符,支持字母、数字、下划线" | ||
| 463 | + } | ||
| 464 | +} | ||
| 465 | +``` | ||
| 466 | + | ||
| 467 | +### 示例 21:带扫码的输入框 | ||
| 468 | + | ||
| 469 | +```javascript | ||
| 470 | +{ | ||
| 471 | + key: "field_23", | ||
| 472 | + value: "", | ||
| 473 | + component_props: { | ||
| 474 | + tag: "input", | ||
| 475 | + name: "qr_code", | ||
| 476 | + label: "二维码", | ||
| 477 | + placeholder: "请输入或扫描二维码", | ||
| 478 | + required: true, | ||
| 479 | + is_camera_scan: true, | ||
| 480 | + camera_scan_type: "QR_CODE" // ALL_CODE | QR_CODE | BAR_CODE | ||
| 481 | + } | ||
| 482 | +} | ||
| 483 | +``` | ||
| 484 | + | ||
| 485 | +### 示例 22:分割线 | ||
| 486 | + | ||
| 487 | +```javascript | ||
| 488 | +{ | ||
| 489 | + key: "field_24", | ||
| 490 | + value: "", | ||
| 491 | + component_props: { | ||
| 492 | + tag: "divider", | ||
| 493 | + name: "divider", | ||
| 494 | + label: "分割线" | ||
| 495 | + } | ||
| 496 | +} | ||
| 497 | +``` | ||
| 498 | + | ||
| 499 | +### 示例 23:富文本说明 | ||
| 500 | + | ||
| 501 | +```javascript | ||
| 502 | +{ | ||
| 503 | + key: "field_25", | ||
| 504 | + value: "", | ||
| 505 | + component_props: { | ||
| 506 | + tag: "note", | ||
| 507 | + name: "rich_text", | ||
| 508 | + label: "活动详情", | ||
| 509 | + default: "<p>这是一段<strong>富文本</strong>内容</p>" | ||
| 510 | + } | ||
| 511 | +} | ||
| 512 | +``` | ||
| 513 | + | ||
| 514 | +## 复杂表单完整示例 | ||
| 515 | + | ||
| 516 | +```javascript | ||
| 517 | +const formConfig = [ | ||
| 518 | + // 基本信息 | ||
| 519 | + { | ||
| 520 | + key: "field_name", | ||
| 521 | + value: "", | ||
| 522 | + component_props: { | ||
| 523 | + tag: "name", | ||
| 524 | + label: "姓名", | ||
| 525 | + required: true, | ||
| 526 | + placeholder: "请输入姓名" | ||
| 527 | + } | ||
| 528 | + }, | ||
| 529 | + { | ||
| 530 | + key: "field_gender", | ||
| 531 | + value: "", | ||
| 532 | + component_props: { | ||
| 533 | + tag: "gender", | ||
| 534 | + label: "性别", | ||
| 535 | + required: true | ||
| 536 | + } | ||
| 537 | + }, | ||
| 538 | + { | ||
| 539 | + key: "field_phone", | ||
| 540 | + value: "", | ||
| 541 | + component_props: { | ||
| 542 | + tag: "phone", | ||
| 543 | + label: "手机号", | ||
| 544 | + required: true, | ||
| 545 | + placeholder: "请输入手机号" | ||
| 546 | + } | ||
| 547 | + }, | ||
| 548 | + | ||
| 549 | + // 报名信息 | ||
| 550 | + { | ||
| 551 | + key: "field_type", | ||
| 552 | + value: "", | ||
| 553 | + component_props: { | ||
| 554 | + tag: "radio", | ||
| 555 | + label: "报名类型", | ||
| 556 | + required: true, | ||
| 557 | + direction: "vertical", | ||
| 558 | + options: [ | ||
| 559 | + { title: "个人报名", value: "personal", checked: true }, | ||
| 560 | + { title: "团队报名", value: "team" }, | ||
| 561 | + { | ||
| 562 | + title: "其他", | ||
| 563 | + value: "other", | ||
| 564 | + is_input: true, | ||
| 565 | + input_placeholder: "请说明具体类型" | ||
| 566 | + } | ||
| 567 | + ] | ||
| 568 | + } | ||
| 569 | + }, | ||
| 570 | + | ||
| 571 | + // 附加信息 | ||
| 572 | + { | ||
| 573 | + key: "field_hobbies", | ||
| 574 | + value: [], | ||
| 575 | + component_props: { | ||
| 576 | + tag: "checkbox", | ||
| 577 | + label: "兴趣爱好", | ||
| 578 | + direction: "vertical", | ||
| 579 | + options: [ | ||
| 580 | + { title: "运动", value: "sport" }, | ||
| 581 | + { title: "阅读", value: "reading" }, | ||
| 582 | + { title: "音乐", value: "music" } | ||
| 583 | + ] | ||
| 584 | + } | ||
| 585 | + }, | ||
| 586 | + | ||
| 587 | + // 时间选择 | ||
| 588 | + { | ||
| 589 | + key: "field_date", | ||
| 590 | + value: "", | ||
| 591 | + component_props: { | ||
| 592 | + tag: "date", | ||
| 593 | + label: "活动日期", | ||
| 594 | + required: true, | ||
| 595 | + placeholder: "请选择日期" | ||
| 596 | + } | ||
| 597 | + }, | ||
| 598 | + | ||
| 599 | + // 图片上传 | ||
| 600 | + { | ||
| 601 | + key: "field_photo", | ||
| 602 | + value: [], | ||
| 603 | + component_props: { | ||
| 604 | + tag: "image_uploader", | ||
| 605 | + label: "上传照片", | ||
| 606 | + required: true, | ||
| 607 | + max_count: 3, | ||
| 608 | + max_size: 5 | ||
| 609 | + } | ||
| 610 | + }, | ||
| 611 | + | ||
| 612 | + // 说明文字 | ||
| 613 | + { | ||
| 614 | + key: "field_note", | ||
| 615 | + value: "", | ||
| 616 | + component_props: { | ||
| 617 | + tag: "note", | ||
| 618 | + label: "注意事项", | ||
| 619 | + default: "<p>请确保所填信息真实有效</p>" | ||
| 620 | + } | ||
| 621 | + }, | ||
| 622 | + | ||
| 623 | + // 电子签名 | ||
| 624 | + { | ||
| 625 | + key: "field_sign", | ||
| 626 | + value: "", | ||
| 627 | + component_props: { | ||
| 628 | + tag: "sign", | ||
| 629 | + label: "本人签名", | ||
| 630 | + required: true | ||
| 631 | + } | ||
| 632 | + } | ||
| 633 | +] | ||
| 634 | +``` | ||
| 635 | + | ||
| 636 | +## 数据提交格式 | ||
| 637 | + | ||
| 638 | +### 提交到后端的格式 | ||
| 639 | + | ||
| 640 | +```javascript | ||
| 641 | +{ | ||
| 642 | + form_code: "form_001", | ||
| 643 | + data: { | ||
| 644 | + field_name: "张三", | ||
| 645 | + field_gender: "男", | ||
| 646 | + field_phone: "13800138000", | ||
| 647 | + field_type: { | ||
| 648 | + key: "field_type", | ||
| 649 | + value: "personal", | ||
| 650 | + type: "radio" | ||
| 651 | + }, | ||
| 652 | + field_hobbies: { | ||
| 653 | + key: "field_hobbies", | ||
| 654 | + value: ["sport", "music"], | ||
| 655 | + type: "checkbox" | ||
| 656 | + }, | ||
| 657 | + field_date: "2024-03-15", | ||
| 658 | + field_photo: { | ||
| 659 | + key: "field_photo", | ||
| 660 | + value: [ | ||
| 661 | + { url: "https://...", name: "photo1.jpg" } | ||
| 662 | + ], | ||
| 663 | + type: "image_uploader" | ||
| 664 | + }, | ||
| 665 | + field_sign: { | ||
| 666 | + key: "field_sign", | ||
| 667 | + value: "data:image/png;base64,...", | ||
| 668 | + type: "sign" | ||
| 669 | + } | ||
| 670 | + } | ||
| 671 | +} | ||
| 672 | +``` | ||
| 673 | + | ||
| 674 | +## LangChain Agent 使用的提示词模板 | ||
| 675 | + | ||
| 676 | +```javascript | ||
| 677 | +const FORM_GENERATION_PROMPT = ` | ||
| 678 | +你是一个表单配置生成专家。根据用户的自然语言描述,生成符合以下规范的表单字段配置。 | ||
| 679 | + | ||
| 680 | +## 组件类型映射 | ||
| 681 | + | ||
| 682 | +用户描述 → 组件类型: | ||
| 683 | +- "姓名/名字" → name | ||
| 684 | +- "性别" → gender | ||
| 685 | +- "手机号/电话" → phone | ||
| 686 | +- "邮箱" → email | ||
| 687 | +- "身份证" → id_card | ||
| 688 | +- "单选/单项选择" → radio | ||
| 689 | +- "多选/多项选择" → checkbox | ||
| 690 | +- "下拉/选择" → select | ||
| 691 | +- "日期" → date | ||
| 692 | +- "时间" → time | ||
| 693 | +- "地址/省市区" → address | ||
| 694 | +- "图片上传" → image_uploader | ||
| 695 | +- "文件上传" → file_uploader | ||
| 696 | +- "多行文本/描述/简介" → textarea | ||
| 697 | +- "数字" → number | ||
| 698 | +- "评分/打分" → rate | ||
| 699 | +- "签名/电子签名" → sign | ||
| 700 | +- "富文本/说明" → note | ||
| 701 | +- "分割线" → divider | ||
| 702 | + | ||
| 703 | +## 必填属性 | ||
| 704 | + | ||
| 705 | +- "必填/必须/一定要" → required: true | ||
| 706 | +- "可选/非必须" → required: false | ||
| 707 | + | ||
| 708 | +## 配置模板 | ||
| 709 | + | ||
| 710 | +### 文本输入 | ||
| 711 | +{ | ||
| 712 | + key: "field_{index}", | ||
| 713 | + value: "", | ||
| 714 | + component_props: { | ||
| 715 | + tag: "input", | ||
| 716 | + name: "{field_name}", | ||
| 717 | + label: "{显示名称}", | ||
| 718 | + placeholder: "请输入{显示名称}", | ||
| 719 | + required: {是否必填} | ||
| 720 | + } | ||
| 721 | +} | ||
| 722 | + | ||
| 723 | +### 单选/多选 | ||
| 724 | +{ | ||
| 725 | + key: "field_{index}", | ||
| 726 | + value: "", | ||
| 727 | + component_props: { | ||
| 728 | + tag: "{radio|checkbox}", | ||
| 729 | + name: "{field_name}", | ||
| 730 | + label: "{显示名称}", | ||
| 731 | + required: {是否必填}, | ||
| 732 | + direction: "vertical", | ||
| 733 | + options: [ | ||
| 734 | + { title: "{选项1}", value: "{value1}" }, | ||
| 735 | + { title: "{选项2}", value: "{value2}" } | ||
| 736 | + ] | ||
| 737 | + } | ||
| 738 | +} | ||
| 739 | + | ||
| 740 | +### 图片上传 | ||
| 741 | +{ | ||
| 742 | + key: "field_{index}", | ||
| 743 | + value: [], | ||
| 744 | + component_props: { | ||
| 745 | + tag: "image_uploader", | ||
| 746 | + name: "{field_name}", | ||
| 747 | + label: "{显示名称}", | ||
| 748 | + required: {是否必填}, | ||
| 749 | + max_count: {数量}, | ||
| 750 | + max_size: {大小MB} | ||
| 751 | + } | ||
| 752 | +} | ||
| 753 | + | ||
| 754 | +请根据用户需求生成对应的表单配置JSON。 | ||
| 755 | +`; | ||
| 756 | +``` |
docs/agent/05-LangChain-Agent-使用指南.md
0 → 100644
| 1 | +# LangChain Agent 使用指南 | ||
| 2 | + | ||
| 3 | +## 概述 | ||
| 4 | + | ||
| 5 | +本文档为使用 LangChain 构建自然语言生成表单的 Agent 提供参考数据和配置指南。 | ||
| 6 | + | ||
| 7 | +## Agent 任务定义 | ||
| 8 | + | ||
| 9 | +**任务**:将用户的自然语言描述转换为表单字段配置 JSON | ||
| 10 | + | ||
| 11 | +**输入**:自然语言描述 | ||
| 12 | +**输出**:表单字段配置数组 | ||
| 13 | + | ||
| 14 | +## 自然语言到组件映射 | ||
| 15 | + | ||
| 16 | +### 基础输入类 | ||
| 17 | + | ||
| 18 | +| 用户关键词 | 组件类型 | tag | 配置要点 | | ||
| 19 | +|-----------|----------|-----|----------| | ||
| 20 | +| 姓名、名字 | NameField | `name` | 必填通常为 true | | ||
| 21 | +| 性别 | GenderField | `gender` | 选项:男/女 | | ||
| 22 | +| 手机号、电话 | PhoneField | `phone` | 自动验证11位 | | ||
| 23 | +| 邮箱 | EmailField | `email` | 自动验证格式 | | ||
| 24 | +| 身份证 | IdentityField | `id_card` | 自动验证格式 | | ||
| 25 | +| 数字、数量 | NumberField | `number` | 整数类型 | | ||
| 26 | +| 单行文本、输入 | TextField | `input` | 最多255字符 | | ||
| 27 | +| 多行文本、描述 | TextareaField | `textarea` | 支持自动高度 | | ||
| 28 | + | ||
| 29 | +### 选择类 | ||
| 30 | + | ||
| 31 | +| 用户关键词 | 组件类型 | tag | 数据结构 | | ||
| 32 | +|-----------|----------|-----|----------| | ||
| 33 | +| 单选、单项选择 | RadioField | `radio` | options 数组 | | ||
| 34 | +| 多选、多项选择 | CheckboxField | `checkbox` | options 数组 | | ||
| 35 | +| 下拉、选择 | PickerField | `select` | options 数组 | | ||
| 36 | +| 省、市、区、地址 | AreaPickerField | `address` | 三级联动 | | ||
| 37 | + | ||
| 38 | +### 日期时间类 | ||
| 39 | + | ||
| 40 | +| 用户关键词 | 组件类型 | tag | 备注 | | ||
| 41 | +|-----------|----------|-----|------| | ||
| 42 | +| 日期、出生日期 | DatePickerField | `date` | - | | ||
| 43 | +| 时间 | TimePickerField | `time` | - | | ||
| 44 | +| 日期时间、开始时间 | DateTimePickerField | `datetime` | - | | ||
| 45 | +| 日历 | CalendarField | `calendar` | 日历形式 | | ||
| 46 | + | ||
| 47 | +### 上传类 | ||
| 48 | + | ||
| 49 | +| 用户关键词 | 组件类型 | tag | 配置参数 | | ||
| 50 | +|-----------|----------|-----|----------| | ||
| 51 | +| 图片、照片、上传图 | ImageUploaderField | `image_uploader` | max_count, max_size | | ||
| 52 | +| 文件、附件、上传 | FileUploaderField | `file_uploader` | max_count, max_size | | ||
| 53 | + | ||
| 54 | +### 特殊功能类 | ||
| 55 | + | ||
| 56 | +| 用户关键词 | 组件类型 | tag | 备注 | | ||
| 57 | +|-----------|----------|-----|------| | ||
| 58 | +| 签名、签字、电子签名 | SignField | `sign` | 手写签名板 | | ||
| 59 | +| 评分、打分、星级 | RatePickerField | `rate` | 支持 x_score 显示 | | ||
| 60 | +| 预约、时间段 | AppointmentField | `appointment` | 复杂配置 | | ||
| 61 | +| 说明、富文本 | NoteField | `note` | HTML 内容 | | ||
| 62 | +| 分割线、分隔 | DividerField | `divider` | - | | ||
| 63 | +| 跑马灯、公告 | MarqueeField | `marquee` | 滚动文字 | | ||
| 64 | +| 规则、说明 | RuleField | `rule` | 支持弹窗 | | ||
| 65 | +| 按钮 | ButtonField | `button` | 自定义按钮 | | ||
| 66 | + | ||
| 67 | +### 高级类 | ||
| 68 | + | ||
| 69 | +| 用户关键词 | 组件类型 | tag | 备注 | | ||
| 70 | +|-----------|----------|-----|------| | ||
| 71 | +| 表格、清单 | TableField | `table_editor` | 动态表格 | | ||
| 72 | +| 分组、集合 | GroupField | `group` | field_groups 数组 | | ||
| 73 | +| 树形选择、组织 | OrgPickerField | `org_picker` | 树结构 | | ||
| 74 | +| 组别、义工组 | VolunteerGroupField | `volunteer_group` | 义工组选择 | | ||
| 75 | + | ||
| 76 | +## 必填识别 | ||
| 77 | + | ||
| 78 | +### 强必填关键词 | ||
| 79 | + | ||
| 80 | +- 必填、必须、一定要、强制 | ||
| 81 | +- 不可缺少、不能为空 | ||
| 82 | +- 必须提供、务必填写 | ||
| 83 | + | ||
| 84 | +### 可选关键词 | ||
| 85 | + | ||
| 86 | +- 可选、非必须、非强制 | ||
| 87 | +- 选填、可以不填 | ||
| 88 | +- 如果有、尽量填写 | ||
| 89 | + | ||
| 90 | +### 默认规则 | ||
| 91 | + | ||
| 92 | +- 姓名通常必填 | ||
| 93 | +- 手机号通常必填 | ||
| 94 | +- 附件类通常选填 | ||
| 95 | +- 说明文字通常选填 | ||
| 96 | + | ||
| 97 | +## 数量识别 | ||
| 98 | + | ||
| 99 | +### 图片上传数量 | ||
| 100 | + | ||
| 101 | +- "一张图"、"1张" → max_count: 1 | ||
| 102 | +- "三张图"、"3张" → max_count: 3 | ||
| 103 | +- "最多5张" → max_count: 5 | ||
| 104 | +- "多张"、"若干" → max_count: 9(默认) | ||
| 105 | + | ||
| 106 | +### 文件大小限制 | ||
| 107 | + | ||
| 108 | +- "5MB以内"、"小于5M" → max_size: 5 | ||
| 109 | +- "10MB" → max_size: 10 | ||
| 110 | + | ||
| 111 | +## 选项提取 | ||
| 112 | + | ||
| 113 | +### 单选/多选选项提取 | ||
| 114 | + | ||
| 115 | +**用户输入**:"性别:男、女、其他" | ||
| 116 | + | ||
| 117 | +**提取结果**: | ||
| 118 | +```javascript | ||
| 119 | +options: [ | ||
| 120 | + { title: "男", value: "男" }, | ||
| 121 | + { title: "女", value: "女" }, | ||
| 122 | + { title: "其他", value: "其他" } | ||
| 123 | +] | ||
| 124 | +``` | ||
| 125 | + | ||
| 126 | +### 带描述的选项 | ||
| 127 | + | ||
| 128 | +**用户输入**:"同意(详见规则)、不同意" | ||
| 129 | + | ||
| 130 | +**提取结果**: | ||
| 131 | +```javascript | ||
| 132 | +options: [ | ||
| 133 | + { | ||
| 134 | + title: "同意", | ||
| 135 | + value: "agree", | ||
| 136 | + desc_text: "点击查看详细规则", | ||
| 137 | + desc_type: "text", | ||
| 138 | + desc_btn_name: "详见规则" | ||
| 139 | + }, | ||
| 140 | + { | ||
| 141 | + title: "不同意", | ||
| 142 | + value: "disagree" | ||
| 143 | + } | ||
| 144 | +] | ||
| 145 | +``` | ||
| 146 | + | ||
| 147 | +### 带补充输入的选项 | ||
| 148 | + | ||
| 149 | +**用户输入**:"其他(需说明)" | ||
| 150 | + | ||
| 151 | +**提取结果**: | ||
| 152 | +```javascript | ||
| 153 | +options: [ | ||
| 154 | + { | ||
| 155 | + title: "其他", | ||
| 156 | + value: "other", | ||
| 157 | + is_input: true, | ||
| 158 | + input_required: true, | ||
| 159 | + input_placeholder: "请说明具体情况" | ||
| 160 | + } | ||
| 161 | +] | ||
| 162 | +``` | ||
| 163 | + | ||
| 164 | +## 复杂需求处理 | ||
| 165 | + | ||
| 166 | +### 分组需求 | ||
| 167 | + | ||
| 168 | +**用户输入**:"物品信息(包含物品名称和数量)" | ||
| 169 | + | ||
| 170 | +**处理方式**: | ||
| 171 | +1. 识别为 group 类型 | ||
| 172 | +2. 创建 field_groups 数组 | ||
| 173 | +3. 每个子项作为独立字段 | ||
| 174 | + | ||
| 175 | +```javascript | ||
| 176 | +{ | ||
| 177 | + key: "field_1", | ||
| 178 | + value: "", | ||
| 179 | + component_props: { | ||
| 180 | + tag: "group", | ||
| 181 | + label: "物品信息", | ||
| 182 | + field_groups: [ | ||
| 183 | + { | ||
| 184 | + tag: "input", | ||
| 185 | + label: "物品名称", | ||
| 186 | + field_name: "field_1_1", | ||
| 187 | + group_field_name: "field_1" | ||
| 188 | + }, | ||
| 189 | + { | ||
| 190 | + tag: "number", | ||
| 191 | + label: "数量", | ||
| 192 | + field_name: "field_1_2", | ||
| 193 | + group_field_name: "field_1" | ||
| 194 | + } | ||
| 195 | + ] | ||
| 196 | + } | ||
| 197 | +} | ||
| 198 | +``` | ||
| 199 | + | ||
| 200 | +### 选项依赖 | ||
| 201 | + | ||
| 202 | +**用户输入**:"选择'其他'时需要输入补充信息" | ||
| 203 | + | ||
| 204 | +**处理方式**: | ||
| 205 | +- 在对应选项设置 `is_input: true` | ||
| 206 | +- 设置 `input_required` 根据上下文判断 | ||
| 207 | + | ||
| 208 | +### 提示信息 | ||
| 209 | + | ||
| 210 | +**用户输入**:"用户名(4-16个字符,字母数字)" | ||
| 211 | + | ||
| 212 | +**处理方式**: | ||
| 213 | +- label: "用户名" | ||
| 214 | +- note: "4-16个字符,支持字母、数字、下划线" | ||
| 215 | + | ||
| 216 | +## Prompt 模板 | ||
| 217 | + | ||
| 218 | +### 系统提示词 | ||
| 219 | + | ||
| 220 | +```python | ||
| 221 | +FORM_BUILDER_SYSTEM_PROMPT = """ | ||
| 222 | +你是一个表单配置生成专家。你的任务是将用户的自然语言描述转换为符合规范的表单字段配置JSON。 | ||
| 223 | + | ||
| 224 | +## 输出格式 | ||
| 225 | + | ||
| 226 | +返回一个JSON数组,每个元素代表一个表单字段。 | ||
| 227 | + | ||
| 228 | +## 字段结构 | ||
| 229 | + | ||
| 230 | +每个字段必须包含: | ||
| 231 | +- key: 字段唯一标识(格式:field_序号) | ||
| 232 | +- value: 初始值 | ||
| 233 | +- component_props: 组件属性对象 | ||
| 234 | + - tag: 组件类型 | ||
| 235 | + - label: 显示名称 | ||
| 236 | + - required: 是否必填 | ||
| 237 | + - 其他属性根据组件类型而定 | ||
| 238 | + | ||
| 239 | +## 组件类型选择规则 | ||
| 240 | + | ||
| 241 | +根据用户描述选择最合适的组件类型: | ||
| 242 | +- 文本输入:input(单行)、textarea(多行)、number(数字) | ||
| 243 | +- 选择类:radio(单选)、checkbox(多选)、select(下拉) | ||
| 244 | +- 日期时间:date、time、datetime | ||
| 245 | +- 上传类:image_uploader、file_uploader | ||
| 246 | +- 特殊:name、gender、phone、email、id_card、sign、rate等 | ||
| 247 | + | ||
| 248 | +## 选项提取规则 | ||
| 249 | + | ||
| 250 | +当用户列出选项时: | ||
| 251 | +1. 识别是单选还是多选 | ||
| 252 | +2. 提取每个选项的标题和值 | ||
| 253 | +3. 检测是否有补充信息需求 | ||
| 254 | +4. 检测是否有描述信息 | ||
| 255 | + | ||
| 256 | +## 必填识别规则 | ||
| 257 | + | ||
| 258 | +- "必填、必须、一定要" → required: true | ||
| 259 | +- "可选、选填" → required: false | ||
| 260 | +- 姓名、手机号等基础信息通常必填 | ||
| 261 | +- 说明、附件类通常选填 | ||
| 262 | + | ||
| 263 | +请根据用户输入生成相应的表单配置。 | ||
| 264 | +""" | ||
| 265 | +``` | ||
| 266 | + | ||
| 267 | +### 用户输入示例 | ||
| 268 | + | ||
| 269 | +```python | ||
| 270 | +# 示例1:简单表单 | ||
| 271 | +user_input = "创建一个报名表单,包含姓名(必填)、性别(必填,男/女)、手机号(必填)" | ||
| 272 | + | ||
| 273 | +# 示例2:带选项 | ||
| 274 | +user_input = "报名类型,单选,必填,选项:个人报名、团队报名" | ||
| 275 | + | ||
| 276 | +# 示例3:图片上传 | ||
| 277 | +user_input = "上传证件照,最多3张,每张不超过5MB,必填" | ||
| 278 | + | ||
| 279 | +# 示例4:分组 | ||
| 280 | +user_input = "物品清单,包含物品名称(必填)和数量(必填)" | ||
| 281 | + | ||
| 282 | +# 示例5:复杂需求 | ||
| 283 | +user_input = "活动报名表,包含:姓名(必填)、性别(男/女/其他,其他需说明)、手机号(必填)、兴趣爱好(多选:运动、阅读、音乐、旅游)、活动日期(必填)、上传照片(最多3张)、本人签名(必填)" | ||
| 284 | +``` | ||
| 285 | + | ||
| 286 | +## LangChain 工具调用 | ||
| 287 | + | ||
| 288 | +### 推荐使用 LangChain 的工具 | ||
| 289 | + | ||
| 290 | +1. **Structured Output** - 确保输出格式正确 | ||
| 291 | +2. **Few-shot Prompting** - 提供示例 | ||
| 292 | +3. **Output Parser** - 解析 JSON 输出 | ||
| 293 | + | ||
| 294 | +### 代码示例 | ||
| 295 | + | ||
| 296 | +```python | ||
| 297 | +from langchain.output_parsers import PydanticOutputParser | ||
| 298 | +from langchain_core.prompts import ChatPromptTemplate | ||
| 299 | +from pydantic import BaseModel, Field | ||
| 300 | +from typing import List, Optional | ||
| 301 | + | ||
| 302 | +class FormField(BaseModel): | ||
| 303 | + key: str = Field(description="字段唯一标识") | ||
| 304 | + tag: str = Field(description="组件类型") | ||
| 305 | + label: str = Field(description="显示名称") | ||
| 306 | + required: bool = Field(description="是否必填") | ||
| 307 | + placeholder: Optional[str] = Field(default="", description="占位符") | ||
| 308 | + options: Optional[List[dict]] = Field(default=None, description="选项列表") | ||
| 309 | + max_count: Optional[int] = Field(default=None, description="最大上传数量") | ||
| 310 | + max_size: Optional[int] = Field(default=None, description="最大文件大小") | ||
| 311 | + | ||
| 312 | +class FormConfiguration(BaseModel): | ||
| 313 | + fields: List[FormField] = Field(description="表单字段列表") | ||
| 314 | + | ||
| 315 | +# 创建解析器 | ||
| 316 | +parser = PydanticOutputParser(pydantic_object=FormConfiguration) | ||
| 317 | + | ||
| 318 | +# 创建提示模板 | ||
| 319 | +prompt = ChatPromptTemplate.from_messages([ | ||
| 320 | + ("system", FORM_BUILDER_SYSTEM_PROMPT), | ||
| 321 | + ("user", "{user_input}") | ||
| 322 | +]) | ||
| 323 | + | ||
| 324 | +# 创建链 | ||
| 325 | +chain = prompt | llm | parser | ||
| 326 | + | ||
| 327 | +# 调用 | ||
| 328 | +result = chain.invoke({"user_input": "创建一个用户信息表单..."}) | ||
| 329 | +``` | ||
| 330 | + | ||
| 331 | +## 验证和错误处理 | ||
| 332 | + | ||
| 333 | +### 输出验证 | ||
| 334 | + | ||
| 335 | +生成的 JSON 需要验证: | ||
| 336 | + | ||
| 337 | +1. **结构验证** | ||
| 338 | + - 是否是有效的 JSON 数组 | ||
| 339 | + - 每个字段是否包含必需属性 | ||
| 340 | + | ||
| 341 | +2. **类型验证** | ||
| 342 | + - tag 值是否在支持的组件列表中 | ||
| 343 | + - required 是否为布尔值 | ||
| 344 | + - options 是否为数组 | ||
| 345 | + | ||
| 346 | +3. **业务验证** | ||
| 347 | + - 必填字段是否合理 | ||
| 348 | + - 选项是否为空 | ||
| 349 | + - 数量限制是否合理 | ||
| 350 | + | ||
| 351 | +### 常见错误处理 | ||
| 352 | + | ||
| 353 | +| 错误 | 处理方式 | | ||
| 354 | +|------|----------| | ||
| 355 | +| 无法识别组件类型 | 询问用户具体需求 | | ||
| 356 | +| 选项描述不清晰 | 提供选项模板让用户选择 | | ||
| 357 | +| 必填不明确 | 默认为选填,提示用户确认 | | ||
| 358 | +| 数量限制缺失 | 使用默认值(图片:3,文件:5) | | ||
| 359 | + | ||
| 360 | +## 完整工作流程 | ||
| 361 | + | ||
| 362 | +``` | ||
| 363 | +用户输入 | ||
| 364 | + ↓ | ||
| 365 | +意图识别(新增/修改/查询) | ||
| 366 | + ↓ | ||
| 367 | +实体提取(字段名、组件类型、选项) | ||
| 368 | + ↓ | ||
| 369 | +配置生成(生成 component_props) | ||
| 370 | + ↓ | ||
| 371 | +格式验证(JSON 结构、类型检查) | ||
| 372 | + ↓ | ||
| 373 | +结果输出(表单配置 JSON) | ||
| 374 | +``` | ||
| 375 | + | ||
| 376 | +## 最佳实践 | ||
| 377 | + | ||
| 378 | +1. **逐步确认**:复杂需求分步确认,而非一次性生成 | ||
| 379 | +2. **提供示例**:让用户选择最接近的示例 | ||
| 380 | +3. **默认值策略**:不确定时使用保守的默认值 | ||
| 381 | +4. **错误友好**:错误信息要具体指出问题和解决方案 |
docs/agent/06-规则控制系统.md
0 → 100644
| 1 | +# 规则控制系统 | ||
| 2 | + | ||
| 3 | +> **最后更新**: 2026-03-16 | ||
| 4 | +> **核心文件**: `src/views/index.vue` | ||
| 5 | + | ||
| 6 | +## 📋 概述 | ||
| 7 | + | ||
| 8 | +规则控制系统通过动态配置来实现表单字段的显示/隐藏逻辑,是表单系统的核心功能之一。 | ||
| 9 | + | ||
| 10 | +### 核心特性 | ||
| 11 | + | ||
| 12 | +- ✅ **双模式控制**: 支持 SHOW(显示)和 HIDE(隐藏)两种规则模式 | ||
| 13 | +- ✅ **逻辑运算**: 支持 AND(且)和 OR(或)逻辑操作符 | ||
| 14 | +- ✅ **级联隐藏**: 控制字段被隐藏时,其控制的所有字段也会被隐藏 | ||
| 15 | +- ✅ **多规则支持**: 单个字段可以同时受多条规则控制 | ||
| 16 | +- ✅ **优先级机制**: HIDE 规则优先级高于 SHOW 规则 | ||
| 17 | + | ||
| 18 | +--- | ||
| 19 | + | ||
| 20 | +## 🏗️ 数据结构 | ||
| 21 | + | ||
| 22 | +### rule_list(规则列表) | ||
| 23 | + | ||
| 24 | +规则列表位于 `formInfo.value['rule_list']`,是表单级别配置。 | ||
| 25 | + | ||
| 26 | +```typescript | ||
| 27 | +interface Rule { | ||
| 28 | + field_names: string[]; // 受此规则控制的字段名列表 | ||
| 29 | + mode: 'SHOW' | 'HIDE'; // 规则模式:显示或隐藏 | ||
| 30 | + logical_op: 'AND' | 'OR'; // 逻辑操作符 | ||
| 31 | + expr_list: RuleExpr[]; // 规则表达式列表 | ||
| 32 | + is_invalid?: boolean; // 规则是否无效(可选) | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +interface RuleExpr { | ||
| 36 | + field_name: string; // 控制字段名 | ||
| 37 | + values: string[]; // 匹配值列表 | ||
| 38 | +} | ||
| 39 | +``` | ||
| 40 | + | ||
| 41 | +### 规则流程图 | ||
| 42 | + | ||
| 43 | +``` | ||
| 44 | +┌─────────────────────────────────────────────────────────────┐ | ||
| 45 | +│ 规则控制系统架构 │ | ||
| 46 | +├─────────────────────────────────────────────────────────────┤ | ||
| 47 | +│ │ | ||
| 48 | +│ formInfo.rule_list │ | ||
| 49 | +│ ↓ │ | ||
| 50 | +│ ┌─────────────────────────────────────────────┐ │ | ||
| 51 | +│ │ checkRules() - 规则评估入口 │ │ | ||
| 52 | +│ └─────────────────────────────────────────────┘ │ | ||
| 53 | +│ ↓ │ | ||
| 54 | +│ ┌─────────────────────────────────────────────┐ │ | ||
| 55 | +│ │ 1. 收集规则涉及的所有字段 │ │ | ||
| 56 | +│ │ 2. 初始化字段状态(disabled=false) │ │ | ||
| 57 | +│ │ 3. 为每个字段分配规则(x_rules) │ │ | ||
| 58 | +│ │ 4. 合并重复规则 │ │ | ||
| 59 | +│ │ 5. 评估规则并设置 disabled 状态 │ │ | ||
| 60 | +│ └─────────────────────────────────────────────┘ │ | ||
| 61 | +│ ↓ │ | ||
| 62 | +│ ┌─────────────────────────────────────────────┐ │ | ||
| 63 | +│ │ evaluateMultipleRules() - 多规则评估 │ │ | ||
| 64 | +│ │ ↓ │ │ | ||
| 65 | +│ │ 分离 SHOW/HIDE 规则 │ │ | ||
| 66 | +│ │ ↓ │ │ | ||
| 67 | +│ │ SHOW 规则: any 满足 = 显示 │ │ | ||
| 68 | +│ │ HIDE 规则: any 满足 = 隐藏 │ │ | ||
| 69 | +│ │ ↓ │ │ | ||
| 70 | +│ │ HIDE 优先 → 隐藏 │ │ | ||
| 71 | +│ │ 否则 → 根据 SHOW 规则决定 │ │ | ||
| 72 | +│ └─────────────────────────────────────────────┘ │ | ||
| 73 | +│ ↓ │ | ||
| 74 | +│ ┌─────────────────────────────────────────────┐ │ | ||
| 75 | +│ │ handleCascadeHiding() - 级联隐藏 │ │ | ||
| 76 | +│ │ 如果控制字段被隐藏,其控制的所有字段 │ │ | ||
| 77 | +│ │ 也会被隐藏 │ │ | ||
| 78 | +│ └─────────────────────────────────────────────┘ │ | ||
| 79 | +│ │ | ||
| 80 | +└─────────────────────────────────────────────────────────────┘ | ||
| 81 | +``` | ||
| 82 | + | ||
| 83 | +--- | ||
| 84 | + | ||
| 85 | +## 🔧 核心函数 | ||
| 86 | + | ||
| 87 | +### 1. checkRules() | ||
| 88 | + | ||
| 89 | +规则评估的主入口函数,负责初始化和协调整个规则评估流程。 | ||
| 90 | + | ||
| 91 | +```javascript | ||
| 92 | +const checkRules = () => { | ||
| 93 | + const rule_list = formInfo.value['rule_list'] ? [...formInfo.value['rule_list']] : []; | ||
| 94 | + | ||
| 95 | + // 1. 收集所有规则中涉及的字段 | ||
| 96 | + const fieldsInRules = new Set(); | ||
| 97 | + rule_list.forEach(rule => { | ||
| 98 | + if (rule.field_names && Array.isArray(rule.field_names)) { | ||
| 99 | + rule.field_names.forEach(fieldName => { | ||
| 100 | + fieldsInRules.add(fieldName); | ||
| 101 | + }); | ||
| 102 | + } | ||
| 103 | + }); | ||
| 104 | + | ||
| 105 | + // 2. 初始化字段规则,只重置在规则中出现过的字段 | ||
| 106 | + formData.value.forEach(item => { | ||
| 107 | + item.x_rules = []; | ||
| 108 | + if (fieldsInRules.has(item.key) && item.component_props) { | ||
| 109 | + item.component_props.disabled = false; | ||
| 110 | + } | ||
| 111 | + }); | ||
| 112 | + | ||
| 113 | + // 3. 收集每个字段的规则 | ||
| 114 | + rule_list.forEach(rule => { | ||
| 115 | + formData.value.forEach(item => { | ||
| 116 | + if (rule.field_names?.includes(item.key) && !rule.is_invalid) { | ||
| 117 | + item.x_rules.push({ | ||
| 118 | + mode: rule.mode, | ||
| 119 | + logical_op: rule.logical_op, | ||
| 120 | + expr_list: rule.expr_list, | ||
| 121 | + }); | ||
| 122 | + } | ||
| 123 | + }); | ||
| 124 | + }); | ||
| 125 | + | ||
| 126 | + // 4. 合并规则 | ||
| 127 | + formData.value.forEach(item => { | ||
| 128 | + const mergedRules = mergeAndDeduplicate(item.x_rules); | ||
| 129 | + item.field_rules = mergedRules; | ||
| 130 | + }); | ||
| 131 | + | ||
| 132 | + // 5. 处理规则逻辑 - 支持多条规则 | ||
| 133 | + formData.value.forEach(item => { | ||
| 134 | + if (item.field_rules && item.field_rules.length > 0 && item.component_props) { | ||
| 135 | + const finalDisabledState = evaluateMultipleRules(item.field_rules); | ||
| 136 | + item.component_props.disabled = finalDisabledState; | ||
| 137 | + } | ||
| 138 | + }); | ||
| 139 | + | ||
| 140 | + // 6. 处理级联隐藏 | ||
| 141 | + handleCascadeHiding(); | ||
| 142 | +}; | ||
| 143 | +``` | ||
| 144 | + | ||
| 145 | +### 2. evaluateMultipleRules() | ||
| 146 | + | ||
| 147 | +评估字段的所有规则,确定最终的显示/隐藏状态。 | ||
| 148 | + | ||
| 149 | +**核心逻辑**: | ||
| 150 | +- SHOW 规则:任一满足即显示(some) | ||
| 151 | +- HIDE 规则:任一满足即隐藏(some) | ||
| 152 | +- HIDE 规则优先级更高 | ||
| 153 | + | ||
| 154 | +```javascript | ||
| 155 | +const evaluateMultipleRules = (rulesList) => { | ||
| 156 | + if (!rulesList || rulesList.length === 0) { | ||
| 157 | + return false; // 没有规则时默认显示 | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + let showRules = []; | ||
| 161 | + let hideRules = []; | ||
| 162 | + | ||
| 163 | + // 分离SHOW和HIDE规则 | ||
| 164 | + rulesList.forEach(rule => { | ||
| 165 | + if (rule.mode === 'SHOW') { | ||
| 166 | + showRules.push(rule); | ||
| 167 | + } else if (rule.mode === 'HIDE') { | ||
| 168 | + hideRules.push(rule); | ||
| 169 | + } | ||
| 170 | + }); | ||
| 171 | + | ||
| 172 | + // 评估SHOW规则 | ||
| 173 | + let showResult = true; // 默认显示 | ||
| 174 | + if (showRules.length > 0) { | ||
| 175 | + // 如果有SHOW规则,需要至少一个SHOW规则条件满足才显示 | ||
| 176 | + showResult = showRules.some(rule => evaluateRuleCondition(rule)); | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + // 评估HIDE规则 | ||
| 180 | + let hideResult = false; // 默认不隐藏 | ||
| 181 | + if (hideRules.length > 0) { | ||
| 182 | + // 如果有HIDE规则,任何一个HIDE规则条件满足就隐藏 | ||
| 183 | + hideResult = hideRules.some(rule => evaluateRuleCondition(rule)); | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + // 最终逻辑:HIDE规则优先级更高 | ||
| 187 | + if (hideResult) { | ||
| 188 | + return true; // 隐藏 | ||
| 189 | + } else { | ||
| 190 | + return !showResult; // SHOW规则不满足时隐藏 | ||
| 191 | + } | ||
| 192 | +}; | ||
| 193 | +``` | ||
| 194 | + | ||
| 195 | +### 3. evaluateRuleCondition() | ||
| 196 | + | ||
| 197 | +评估单条规则的条件是否满足。 | ||
| 198 | + | ||
| 199 | +**处理逻辑**: | ||
| 200 | +1. 遍历规则表达式列表 | ||
| 201 | +2. 从 `postData.value` 获取表单提交值 | ||
| 202 | +3. 处理字符串类型(单选、下拉):清理冒号前缀后匹配 | ||
| 203 | +4. 处理数组类型(多选):使用 lodash intersection 取交集 | ||
| 204 | +5. 根据逻辑操作符(AND/OR)计算最终结果 | ||
| 205 | + | ||
| 206 | +```javascript | ||
| 207 | +const evaluateRuleCondition = (fieldRules) => { | ||
| 208 | + if (!fieldRules || !fieldRules.expr_list || fieldRules.expr_list.length === 0) { | ||
| 209 | + return false; | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | + const results = []; | ||
| 213 | + | ||
| 214 | + fieldRules.expr_list.forEach(expr => { | ||
| 215 | + let form_submission_value = postData.value[expr.field_name]; | ||
| 216 | + const rule_matching_value = expr.values || []; | ||
| 217 | + | ||
| 218 | + // 处理空值情况 | ||
| 219 | + if (form_submission_value === null || form_submission_value === undefined) { | ||
| 220 | + results.push(false); | ||
| 221 | + return; | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + let matchResult = false; | ||
| 225 | + | ||
| 226 | + if (typeof form_submission_value === 'string') { | ||
| 227 | + // 处理字符串类型(单选,下拉) | ||
| 228 | + let cleanValue = form_submission_value; | ||
| 229 | + if (form_submission_value.indexOf(':') !== -1) { | ||
| 230 | + cleanValue = form_submission_value.split(':')[0]; | ||
| 231 | + } | ||
| 232 | + matchResult = rule_matching_value.includes(cleanValue); | ||
| 233 | + } else if (Array.isArray(form_submission_value)) { | ||
| 234 | + // 处理数组类型(多选) | ||
| 235 | + const cleanValues = form_submission_value.map(item => { | ||
| 236 | + if (typeof item === 'string' && item.includes(':')) { | ||
| 237 | + return item.split(':')[0].trim(); | ||
| 238 | + } | ||
| 239 | + return item; | ||
| 240 | + }); | ||
| 241 | + matchResult = _.intersection(rule_matching_value, cleanValues).length > 0; | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + results.push(matchResult); | ||
| 245 | + }); | ||
| 246 | + | ||
| 247 | + // 根据逻辑操作符计算最终结果 | ||
| 248 | + if (fieldRules.logical_op === 'AND') { | ||
| 249 | + return results.every(result => result === true); | ||
| 250 | + } else { // OR | ||
| 251 | + return results.some(result => result === true); | ||
| 252 | + } | ||
| 253 | +}; | ||
| 254 | +``` | ||
| 255 | + | ||
| 256 | +### 4. handleCascadeHiding() | ||
| 257 | + | ||
| 258 | +处理级联隐藏逻辑,确保当控制字段被隐藏时,其控制的所有字段也会被隐藏。 | ||
| 259 | + | ||
| 260 | +```javascript | ||
| 261 | +const handleCascadeHiding = () => { | ||
| 262 | + const rule_list = formInfo.value['rule_list'] || []; | ||
| 263 | + | ||
| 264 | + // 获取所有规则控制字段的映射 | ||
| 265 | + const ruleControlMap = new Map(); | ||
| 266 | + rule_list.forEach(rule => { | ||
| 267 | + if (rule.expr_list && rule.expr_list.length > 0) { | ||
| 268 | + const controlField = rule.expr_list[0].field_name; | ||
| 269 | + if (!ruleControlMap.has(controlField)) { | ||
| 270 | + ruleControlMap.set(controlField, []); | ||
| 271 | + } | ||
| 272 | + ruleControlMap.get(controlField).push({ | ||
| 273 | + field_names: rule.field_names || [], | ||
| 274 | + mode: rule.mode | ||
| 275 | + }); | ||
| 276 | + } | ||
| 277 | + }); | ||
| 278 | + | ||
| 279 | + // 检查级联隐藏 | ||
| 280 | + formData.value.forEach(item => { | ||
| 281 | + if (ruleControlMap.has(item.key) && item.component_props && item.component_props.disabled) { | ||
| 282 | + // 如果控制字段被隐藏,则隐藏其控制的所有字段 | ||
| 283 | + const controlledRules = ruleControlMap.get(item.key); | ||
| 284 | + controlledRules.forEach(rule => { | ||
| 285 | + rule.field_names.forEach(fieldName => { | ||
| 286 | + const targetField = formData.value.find(field => field.key === fieldName); | ||
| 287 | + if (targetField && targetField.component_props) { | ||
| 288 | + targetField.component_props.disabled = true; | ||
| 289 | + } | ||
| 290 | + }); | ||
| 291 | + }); | ||
| 292 | + } | ||
| 293 | + }); | ||
| 294 | +}; | ||
| 295 | +``` | ||
| 296 | + | ||
| 297 | +--- | ||
| 298 | + | ||
| 299 | +## 🔄 触发机制 | ||
| 300 | + | ||
| 301 | +规则评估在以下时机触发: | ||
| 302 | + | ||
| 303 | +### 1. 表单初始化时 | ||
| 304 | + | ||
| 305 | +表单数据加载完成后,调用 `checkRules()` 初始化所有字段的显示状态。 | ||
| 306 | + | ||
| 307 | +### 2. 字段值变化时 | ||
| 308 | + | ||
| 309 | +当用户修改表单字段值时,通过 `@active` 事件触发规则重新评估: | ||
| 310 | + | ||
| 311 | +```vue | ||
| 312 | +<component | ||
| 313 | + v-for="item in formData" | ||
| 314 | + :is="item.component_props.tag" | ||
| 315 | + v-model="postData[item.key]" | ||
| 316 | + @active="checkRules" | ||
| 317 | +/> | ||
| 318 | +``` | ||
| 319 | + | ||
| 320 | +### 3. 数据结构 | ||
| 321 | + | ||
| 322 | +- **formData**: 表单字段配置数组 | ||
| 323 | +- **postData**: 表单实际提交的数据 | ||
| 324 | +- **formInfo**: 表单元数据(包含 rule_list) | ||
| 325 | + | ||
| 326 | +--- | ||
| 327 | + | ||
| 328 | +## 📊 实际示例 | ||
| 329 | + | ||
| 330 | +### 示例 1:简单 SHOW 规则 | ||
| 331 | + | ||
| 332 | +**场景**:只有当"用户类型"选择"企业用户"时,才显示"企业名称"字段。 | ||
| 333 | + | ||
| 334 | +```json | ||
| 335 | +{ | ||
| 336 | + "rule_list": [ | ||
| 337 | + { | ||
| 338 | + "field_names": ["company_name"], | ||
| 339 | + "mode": "SHOW", | ||
| 340 | + "logical_op": "OR", | ||
| 341 | + "expr_list": [ | ||
| 342 | + { | ||
| 343 | + "field_name": "user_type", | ||
| 344 | + "values": ["enterprise"] | ||
| 345 | + } | ||
| 346 | + ] | ||
| 347 | + } | ||
| 348 | + ] | ||
| 349 | +} | ||
| 350 | +``` | ||
| 351 | + | ||
| 352 | +### 示例 2:HIDE 规则 | ||
| 353 | + | ||
| 354 | +**场景**:当"居住类型"选择"租房"时,隐藏"房产证号"字段。 | ||
| 355 | + | ||
| 356 | +```json | ||
| 357 | +{ | ||
| 358 | + "rule_list": [ | ||
| 359 | + { | ||
| 360 | + "field_names": ["property_cert_no"], | ||
| 361 | + "mode": "HIDE", | ||
| 362 | + "logical_op": "OR", | ||
| 363 | + "expr_list": [ | ||
| 364 | + { | ||
| 365 | + "field_name": "residence_type", | ||
| 366 | + "values": ["rent"] | ||
| 367 | + } | ||
| 368 | + ] | ||
| 369 | + } | ||
| 370 | + ] | ||
| 371 | +} | ||
| 372 | +``` | ||
| 373 | + | ||
| 374 | +### 示例 3:AND 逻辑 | ||
| 375 | + | ||
| 376 | +**场景**:同时满足"年龄大于18"且"有收入证明"时,显示"信用卡申请"字段。 | ||
| 377 | + | ||
| 378 | +```json | ||
| 379 | +{ | ||
| 380 | + "rule_list": [ | ||
| 381 | + { | ||
| 382 | + "field_names": ["credit_card_application"], | ||
| 383 | + "mode": "SHOW", | ||
| 384 | + "logical_op": "AND", | ||
| 385 | + "expr_list": [ | ||
| 386 | + { | ||
| 387 | + "field_name": "age", | ||
| 388 | + "values": ["adult", "senior"] | ||
| 389 | + }, | ||
| 390 | + { | ||
| 391 | + "field_name": "income_proof", | ||
| 392 | + "values": ["yes"] | ||
| 393 | + } | ||
| 394 | + ] | ||
| 395 | + } | ||
| 396 | + ] | ||
| 397 | +} | ||
| 398 | +``` | ||
| 399 | + | ||
| 400 | +### 示例 4:OR 逻辑 | ||
| 401 | + | ||
| 402 | +**场景**:选择"VIP用户"或"企业用户"任一条件时,显示"专属客服"字段。 | ||
| 403 | + | ||
| 404 | +```json | ||
| 405 | +{ | ||
| 406 | + "rule_list": [ | ||
| 407 | + { | ||
| 408 | + "field_names": ["exclusive_service"], | ||
| 409 | + "mode": "SHOW", | ||
| 410 | + "logical_op": "OR", | ||
| 411 | + "expr_list": [ | ||
| 412 | + { | ||
| 413 | + "field_name": "user_type", | ||
| 414 | + "values": ["vip"] | ||
| 415 | + }, | ||
| 416 | + { | ||
| 417 | + "field_name": "user_type", | ||
| 418 | + "values": ["enterprise"] | ||
| 419 | + } | ||
| 420 | + ] | ||
| 421 | + } | ||
| 422 | + ] | ||
| 423 | +} | ||
| 424 | +``` | ||
| 425 | + | ||
| 426 | +### 示例 5:多规则控制 | ||
| 427 | + | ||
| 428 | +**场景**:字段受多条规则控制,HIDE 规则优先。 | ||
| 429 | + | ||
| 430 | +```json | ||
| 431 | +{ | ||
| 432 | + "rule_list": [ | ||
| 433 | + { | ||
| 434 | + "field_names": ["special_discount"], | ||
| 435 | + "mode": "SHOW", | ||
| 436 | + "logical_op": "OR", | ||
| 437 | + "expr_list": [ | ||
| 438 | + { | ||
| 439 | + "field_name": "membership_level", | ||
| 440 | + "values": ["gold", "platinum"] | ||
| 441 | + } | ||
| 442 | + ] | ||
| 443 | + }, | ||
| 444 | + { | ||
| 445 | + "field_names": ["special_discount"], | ||
| 446 | + "mode": "HIDE", | ||
| 447 | + "logical_op": "OR", | ||
| 448 | + "expr_list": [ | ||
| 449 | + { | ||
| 450 | + "field_name": "account_status", | ||
| 451 | + "values": ["suspended", "banned"] | ||
| 452 | + } | ||
| 453 | + ] | ||
| 454 | + } | ||
| 455 | + ] | ||
| 456 | +} | ||
| 457 | +``` | ||
| 458 | + | ||
| 459 | +**结果**:即使满足 VIP 条件,如果账户被暂停,也不会显示特殊折扣字段。 | ||
| 460 | + | ||
| 461 | +### 示例 6:级联隐藏 | ||
| 462 | + | ||
| 463 | +**场景**: | ||
| 464 | +- 字段 A 控制字段 B 的显示 | ||
| 465 | +- 字段 B 控制字段 C 的显示 | ||
| 466 | +- 当字段 A 被隐藏时,字段 B 和 C 都应该被隐藏 | ||
| 467 | + | ||
| 468 | +```json | ||
| 469 | +{ | ||
| 470 | + "rule_list": [ | ||
| 471 | + { | ||
| 472 | + "field_names": ["field_b"], | ||
| 473 | + "mode": "SHOW", | ||
| 474 | + "logical_op": "OR", | ||
| 475 | + "expr_list": [ | ||
| 476 | + { | ||
| 477 | + "field_name": "field_a", | ||
| 478 | + "values": ["show_b"] | ||
| 479 | + } | ||
| 480 | + ] | ||
| 481 | + }, | ||
| 482 | + { | ||
| 483 | + "field_names": ["field_c"], | ||
| 484 | + "mode": "SHOW", | ||
| 485 | + "logical_op": "OR", | ||
| 486 | + "expr_list": [ | ||
| 487 | + { | ||
| 488 | + "field_name": "field_b", | ||
| 489 | + "values": ["show_c"] | ||
| 490 | + } | ||
| 491 | + ] | ||
| 492 | + } | ||
| 493 | + ] | ||
| 494 | +} | ||
| 495 | +``` | ||
| 496 | + | ||
| 497 | +--- | ||
| 498 | + | ||
| 499 | +## 🎯 LangChain Agent 集成要点 | ||
| 500 | + | ||
| 501 | +### 自然语言到规则的映射 | ||
| 502 | + | ||
| 503 | +当用户用自然语言描述规则时,Agent 需要将其转换为规则配置: | ||
| 504 | + | ||
| 505 | +| 用户描述 | mode | logical_op | | ||
| 506 | +|---------|------|------------| | ||
| 507 | +| "当...时显示" | SHOW | OR | | ||
| 508 | +| "只有...才显示" | SHOW | AND | | ||
| 509 | +| "当...时隐藏" | HIDE | OR | | ||
| 510 | +| "只要...就隐藏" | HIDE | OR | | ||
| 511 | + | ||
| 512 | +### Prompt 模板 | ||
| 513 | + | ||
| 514 | +```python | ||
| 515 | +RULE_GENERATION_TEMPLATE = """ | ||
| 516 | +你是一个表单规则配置专家。根据用户的自然语言描述,生成规则配置。 | ||
| 517 | + | ||
| 518 | +用户描述:{user_description} | ||
| 519 | + | ||
| 520 | +可用的字段: | ||
| 521 | +{available_fields} | ||
| 522 | + | ||
| 523 | +请生成规则配置,格式如下: | ||
| 524 | +```json | ||
| 525 | +{{ | ||
| 526 | + "rule_list": [ | ||
| 527 | + {{ | ||
| 528 | + "field_names": ["受控制的字段名"], | ||
| 529 | + "mode": "SHOW" | "HIDE", | ||
| 530 | + "logical_op": "AND" | "OR", | ||
| 531 | + "expr_list": [ | ||
| 532 | + {{ | ||
| 533 | + "field_name": "控制字段名", | ||
| 534 | + "values": ["值1", "值2"] | ||
| 535 | + }} | ||
| 536 | + ] | ||
| 537 | + }} | ||
| 538 | + ] | ||
| 539 | +}} | ||
| 540 | +``` | ||
| 541 | + | ||
| 542 | +规则说明: | ||
| 543 | +1. mode: "SHOW" 表示满足条件时显示,"HIDE" 表示满足条件时隐藏 | ||
| 544 | +2. logical_op: "AND" 表示所有条件都要满足,"OR" 表示任一条件满足即可 | ||
| 545 | +3. HIDE 规则优先级高于 SHOW 规则 | ||
| 546 | +""" | ||
| 547 | +``` | ||
| 548 | + | ||
| 549 | +### 示例对话 | ||
| 550 | + | ||
| 551 | +**用户输入**: | ||
| 552 | +``` | ||
| 553 | +"当用户类型是企业时,显示企业名称和统一社会信用代码字段" | ||
| 554 | +``` | ||
| 555 | + | ||
| 556 | +**Agent 输出**: | ||
| 557 | +```json | ||
| 558 | +{ | ||
| 559 | + "rule_list": [ | ||
| 560 | + { | ||
| 561 | + "field_names": ["company_name", "credit_code"], | ||
| 562 | + "mode": "SHOW", | ||
| 563 | + "logical_op": "OR", | ||
| 564 | + "expr_list": [ | ||
| 565 | + { | ||
| 566 | + "field_name": "user_type", | ||
| 567 | + "values": ["enterprise", "company"] | ||
| 568 | + } | ||
| 569 | + ] | ||
| 570 | + } | ||
| 571 | + ] | ||
| 572 | +} | ||
| 573 | +``` | ||
| 574 | + | ||
| 575 | +--- | ||
| 576 | + | ||
| 577 | +## ⚠️ 注意事项 | ||
| 578 | + | ||
| 579 | +### 1. 值格式处理 | ||
| 580 | + | ||
| 581 | +系统会自动处理带冒号的值(如 `"option1:选项1"`),只匹配冒号前的部分。 | ||
| 582 | + | ||
| 583 | +### 2. 空值处理 | ||
| 584 | + | ||
| 585 | +当控制字段的值为 `null` 或 `undefined` 时,规则匹配结果为 `false`。 | ||
| 586 | + | ||
| 587 | +### 3. 多选字段 | ||
| 588 | + | ||
| 589 | +多选字段(checkbox)的值是数组,使用 lodash `intersection` 检查是否有交集。 | ||
| 590 | + | ||
| 591 | +### 4. 规则优先级 | ||
| 592 | + | ||
| 593 | +- HIDE 规则优先级高于 SHOW 规则 | ||
| 594 | +- 同类型规则之间使用 OR 逻辑(任一满足即可) | ||
| 595 | + | ||
| 596 | +### 5. 性能考虑 | ||
| 597 | + | ||
| 598 | +- 每次字段值变化都会触发所有规则的重新评估 | ||
| 599 | +- 对于复杂表单,建议优化规则数量和复杂度 | ||
| 600 | + | ||
| 601 | +--- | ||
| 602 | + | ||
| 603 | +## 🔗 相关文档 | ||
| 604 | + | ||
| 605 | +- [00-数据结构总览.md](./00-数据结构总览.md) | ||
| 606 | +- [02-component_props-配置规范.md](./02-component_props-配置规范.md) | ||
| 607 | +- [05-LangChain-Agent-使用指南.md](./05-LangChain-Agent-使用指南.md) |
docs/agent/07-页面数据提取指南.md
0 → 100644
| 1 | +# 页面数据提取指南 | ||
| 2 | + | ||
| 3 | +> **最后更新**: 2026-03-16 | ||
| 4 | +> **用途**: 从实际运行的表单页面中提取配置数据 | ||
| 5 | + | ||
| 6 | +## 📋 概述 | ||
| 7 | + | ||
| 8 | +当用户提供一个表单 URL(如 `https://oa-dev.onwall.cn/f/custom_form/front/index.html#/?code=nxqkbf`)时,需要从页面中提取完整的表单配置数据。 | ||
| 9 | + | ||
| 10 | +--- | ||
| 11 | + | ||
| 12 | +## 🏗️ 数据存储结构 | ||
| 13 | + | ||
| 14 | +### Pinia Store | ||
| 15 | + | ||
| 16 | +表单数据存储在 Pinia store 中: | ||
| 17 | + | ||
| 18 | +```javascript | ||
| 19 | +// Store 名称: 'main' | ||
| 20 | +// Store 定义: src/store/index.js | ||
| 21 | + | ||
| 22 | +{ | ||
| 23 | + formInfo: {}, // 表单完整信息(包含字段列表、规则等) | ||
| 24 | + formSetting: {}, // 表单数据收集设置 | ||
| 25 | + successInfo: {}, // 表单提交返回值 | ||
| 26 | +} | ||
| 27 | +``` | ||
| 28 | + | ||
| 29 | +### formInfo 数据结构 | ||
| 30 | + | ||
| 31 | +```typescript | ||
| 32 | +interface FormInfo { | ||
| 33 | + name: string; // 表单名称 | ||
| 34 | + field_list: FieldItem[]; // 字段列表 | ||
| 35 | + rule_list?: Rule[]; // 规则列表(可选) | ||
| 36 | + // ... 其他属性 | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +interface FieldItem { | ||
| 40 | + tag: string; // 组件类型 | ||
| 41 | + field_name: string; // 字段名 | ||
| 42 | + label: string; // 显示标签 | ||
| 43 | + required: boolean; // 是否必填 | ||
| 44 | + data_type: string; // 数据类型 | ||
| 45 | + default?: any; // 默认值 | ||
| 46 | + options?: Option[]; // 选项列表(选择类组件) | ||
| 47 | + disabled?: boolean; // 是否禁用 | ||
| 48 | + readonly?: boolean; // 是否只读 | ||
| 49 | + placeholder?: string; // 占位符 | ||
| 50 | + // ... 其他属性 | ||
| 51 | +} | ||
| 52 | +``` | ||
| 53 | + | ||
| 54 | +--- | ||
| 55 | + | ||
| 56 | +## 🌐 API 数据结构详解 | ||
| 57 | + | ||
| 58 | +### 核心 API 接口 | ||
| 59 | + | ||
| 60 | +表单系统有两个核心 API 接口,分别获取不同维度的数据: | ||
| 61 | + | ||
| 62 | +| API 接口 | 获取内容 | 主要用途 | | ||
| 63 | +|---------|---------|----------| | ||
| 64 | +| `query_form_all_field` | 字段列表、规则列表 | 渲染表单结构 | | ||
| 65 | +| `query_form_setting` | 表单级配置 | 获取表单属性 | | ||
| 66 | + | ||
| 67 | +### API 1: query_form_all_field - 字段和规则 | ||
| 68 | + | ||
| 69 | +**请求**: | ||
| 70 | +```bash | ||
| 71 | +GET https://oa-dev.onwall.cn/srv/?a=query_form_all_field&f=custom_form&form_code=nxqkbf | ||
| 72 | +``` | ||
| 73 | + | ||
| 74 | +**响应结构**: | ||
| 75 | +```json | ||
| 76 | +{ | ||
| 77 | + "code": 1, | ||
| 78 | + "msg": "OK", | ||
| 79 | + "data": { | ||
| 80 | + "id": 835950, | ||
| 81 | + "code": "nxqkbf", | ||
| 82 | + "name": "测试LangChain", | ||
| 83 | + "short_name": "customize_35697_nxqkbf", | ||
| 84 | + "table_name": "customize_35697_nxqkbf", | ||
| 85 | + "max_field_num": 3, | ||
| 86 | + "description": null, | ||
| 87 | + "rule_list": [], | ||
| 88 | + "field_list": [...] | ||
| 89 | + }, | ||
| 90 | + "flow_process_list": null | ||
| 91 | +} | ||
| 92 | +``` | ||
| 93 | + | ||
| 94 | +**field_list 字段类型详解**: | ||
| 95 | + | ||
| 96 | +```typescript | ||
| 97 | +// 1. 页面头部 (page_header) | ||
| 98 | +{ | ||
| 99 | + tag: "page_header", | ||
| 100 | + field_name: "object_1", | ||
| 101 | + label: "测试LangChain", | ||
| 102 | + index: 0, | ||
| 103 | + banner: { | ||
| 104 | + ext: "png", | ||
| 105 | + src: "https://cdn.ipadbiz.cn/...", | ||
| 106 | + name: "" | ||
| 107 | + }, | ||
| 108 | + banner_type: "image", | ||
| 109 | + interaction_type: "h5show" // 仅展示,不可编辑 | ||
| 110 | +} | ||
| 111 | + | ||
| 112 | +// 2. 输入框 (input) | ||
| 113 | +{ | ||
| 114 | + tag: "input", | ||
| 115 | + field_name: "field_2", | ||
| 116 | + label: "标题", | ||
| 117 | + index: 2, | ||
| 118 | + required: false, | ||
| 119 | + data_type: "text", | ||
| 120 | + placeholder: "请输入", | ||
| 121 | + disabled: false, | ||
| 122 | + readonly: false, | ||
| 123 | + default: "", | ||
| 124 | + unique: false, | ||
| 125 | + interaction_type: "h5edit" // 可编辑 | ||
| 126 | +} | ||
| 127 | + | ||
| 128 | +// 3. 提交按钮 (page_commit) | ||
| 129 | +{ | ||
| 130 | + tag: "page_commit", | ||
| 131 | + field_name: "object_3", | ||
| 132 | + text: "提交", | ||
| 133 | + index: 1, | ||
| 134 | + is_back: false, | ||
| 135 | + back_title: "上一页", | ||
| 136 | + interaction_type: "h5show" | ||
| 137 | +} | ||
| 138 | +``` | ||
| 139 | + | ||
| 140 | +### API 2: query_form_setting - 表单配置 | ||
| 141 | + | ||
| 142 | +**请求**: | ||
| 143 | +```bash | ||
| 144 | +GET https://oa-dev.onwall.cn/srv/?a=query_form_setting&f=custom_form&form_code=nxqkbf | ||
| 145 | +``` | ||
| 146 | + | ||
| 147 | +**响应结构**: | ||
| 148 | +```json | ||
| 149 | +{ | ||
| 150 | + "code": 1, | ||
| 151 | + "msg": "OK", | ||
| 152 | + "data": [{ | ||
| 153 | + "id": 835950, | ||
| 154 | + "code": "nxqkbf", | ||
| 155 | + "name": "测试LangChain", | ||
| 156 | + "max_field_num": 3, | ||
| 157 | + "data_count": 7, | ||
| 158 | + "client_id": 35697, | ||
| 159 | + "extend": { | ||
| 160 | + "server_time": "2026-03-16 17:15:40", | ||
| 161 | + "is_back_user": false | ||
| 162 | + }, | ||
| 163 | + "property_list": { | ||
| 164 | + "sjsj_enable": 1, | ||
| 165 | + "commit_action": "text", | ||
| 166 | + "commit_text_type": "default", | ||
| 167 | + "commit_text_template": "提交成功", | ||
| 168 | + "edit_commit_action": "text", | ||
| 169 | + "edit_commit_text_type": "default", | ||
| 170 | + "edit_commit_text_template": "提交成功" | ||
| 171 | + } | ||
| 172 | + }] | ||
| 173 | +} | ||
| 174 | +``` | ||
| 175 | + | ||
| 176 | +**property_list 详解**: | ||
| 177 | + | ||
| 178 | +| 属性 | 类型 | 说明 | | ||
| 179 | +|------|------|------| | ||
| 180 | +| `sjsj_enable` | number | 是否启用数据收集(0=关闭,1=开启) | | ||
| 181 | +| `commit_action` | string | 提交动作类型(text=显示文本) | | ||
| 182 | +| `commit_text_template` | string | 提交成功后显示的文本 | | ||
| 183 | +| `edit_commit_action` | string | 编辑提交动作 | | ||
| 184 | +| `edit_commit_text_template` | string | 编辑提交成功文本 | | ||
| 185 | + | ||
| 186 | +### 完整数据关系图 | ||
| 187 | + | ||
| 188 | +``` | ||
| 189 | +┌─────────────────────────────────────────────────────────────┐ | ||
| 190 | +│ 表单数据完整结构 │ | ||
| 191 | +├─────────────────────────────────────────────────────────────┤ | ||
| 192 | +│ │ | ||
| 193 | +│ 表单 URL │ | ||
| 194 | +│ https://oa-dev.onwall.cn/f/custom_form/front/#/?code=xxx │ | ||
| 195 | +│ ↓ │ | ||
| 196 | +│ 提取 form_code │ | ||
| 197 | +│ ───────────────────────────────────────────────────────── │ | ||
| 198 | +│ ↓ │ | ||
| 199 | +│ ┌─────────────────────────────────────────────────────┐ │ | ||
| 200 | +│ │ API 1: query_form_all_field │ │ | ||
| 201 | +│ │ → 字段列表 (field_list) │ │ | ||
| 202 | +│ │ → 规则列表 (rule_list) │ │ | ||
| 203 | +│ └─────────────────────────────────────────────────────┘ │ | ||
| 204 | +│ ↓ │ | ||
| 205 | +│ ┌─────────────────────────────────────────────────────┐ │ | ||
| 206 | +│ │ API 2: query_form_setting │ │ | ||
| 207 | +│ │ → 表单配置 (property_list) │ │ | ||
| 208 | +│ │ → 扩展信息 (extend) │ │ | ||
| 209 | +│ └─────────────────────────────────────────────────────┘ │ | ||
| 210 | +│ ↓ │ | ||
| 211 | +│ 合并数据 → LangChain Agent 可用的完整表单配置 │ | ||
| 212 | +│ │ | ||
| 213 | +└─────────────────────────────────────────────────────────────┘ | ||
| 214 | +``` | ||
| 215 | + | ||
| 216 | +--- | ||
| 217 | + | ||
| 218 | +## 🔧 数据提取方法 | ||
| 219 | + | ||
| 220 | +### 方法 1: 直接 API 调用(推荐) | ||
| 221 | + | ||
| 222 | +**核心原理**:直接调用后端 API 接口获取表单配置数据 | ||
| 223 | + | ||
| 224 | +**API 端点**: | ||
| 225 | +``` | ||
| 226 | +GET https://oa-dev.onwall.cn/srv/?a=query_form_all_field | ||
| 227 | +``` | ||
| 228 | + | ||
| 229 | +**请求参数**: | ||
| 230 | +```javascript | ||
| 231 | +{ | ||
| 232 | + f: "custom_form", // 固定参数 | ||
| 233 | + form_code: "nxqkbf", // 从 URL 参数中获取(必填) | ||
| 234 | + page_type: "add", // 页面类型:add/edit/view(可选) | ||
| 235 | + data_id: null, // 数据ID(编辑时使用) | ||
| 236 | + flow_node_code: "", // 流程节点代码(流程表单使用) | ||
| 237 | + force_back: "" // 强制后台模式标识 | ||
| 238 | +} | ||
| 239 | +``` | ||
| 240 | + | ||
| 241 | +**✅ 重要**:此 API **不需要特殊认证**,可以直接通过 curl 或 HTTP 请求调用! | ||
| 242 | + | ||
| 243 | +**调用方式**: | ||
| 244 | + | ||
| 245 | +```bash | ||
| 246 | +# 使用 curl 直接调用 | ||
| 247 | +curl "https://oa-dev.onwall.cn/srv/?a=query_form_all_field&f=custom_form&form_code=nxqkbf" | ||
| 248 | +``` | ||
| 249 | + | ||
| 250 | +```javascript | ||
| 251 | +// 使用 fetch/axios | ||
| 252 | +const response = await fetch('https://oa-dev.onwall.cn/srv/?a=query_form_all_field&f=custom_form&form_code=nxqkbf'); | ||
| 253 | +const data = await response.json(); | ||
| 254 | + | ||
| 255 | +// 或使用项目内部的 API 函数 | ||
| 256 | +import { queryFormAPI } from '@/api/form'; | ||
| 257 | +const { data } = await queryFormAPI({ form_code: 'nxqkbf' }); | ||
| 258 | +``` | ||
| 259 | + | ||
| 260 | +**完整 API 响应结构**: | ||
| 261 | +```json | ||
| 262 | +{ | ||
| 263 | + "code": 1, | ||
| 264 | + "msg": "OK", | ||
| 265 | + "data": { | ||
| 266 | + "id": 835950, | ||
| 267 | + "code": "nxqkbf", | ||
| 268 | + "name": "表单名称", | ||
| 269 | + "field_list": [ | ||
| 270 | + { | ||
| 271 | + "tag": "input", | ||
| 272 | + "field_name": "field_1", | ||
| 273 | + "label": "姓名", | ||
| 274 | + "required": true, | ||
| 275 | + "data_type": "text" | ||
| 276 | + } | ||
| 277 | + ], | ||
| 278 | + "rule_list": [] | ||
| 279 | + } | ||
| 280 | +} | ||
| 281 | +``` | ||
| 282 | + | ||
| 283 | +--- | ||
| 284 | + | ||
| 285 | +### 方法 2: Chrome DevTools MCP(需要登录) | ||
| 286 | + | ||
| 287 | +**前提条件**:已使用浏览器登录系统 | ||
| 288 | + | ||
| 289 | +使用 Chrome DevTools MCP 工具直接从页面提取数据: | ||
| 290 | + | ||
| 291 | +```javascript | ||
| 292 | +// 在页面中执行以下脚本获取表单数据 | ||
| 293 | +const app = document.querySelector('#app').__vueParentComponent.appContext.app; | ||
| 294 | +const pinia = app.config.globalProperties.$pinia; | ||
| 295 | +const store = pinia.state.value.main; | ||
| 296 | + | ||
| 297 | +// 获取表单信息 | ||
| 298 | +const formInfo = store.formInfo; | ||
| 299 | + | ||
| 300 | +// 返回结果 | ||
| 301 | +JSON.stringify(formInfo, null, 2); | ||
| 302 | +``` | ||
| 303 | + | ||
| 304 | +--- | ||
| 305 | + | ||
| 306 | +### 方法 3: Vue DevTools API(需要登录) | ||
| 307 | + | ||
| 308 | +通过 Vue DevTools 获取组件状态: | ||
| 309 | + | ||
| 310 | +```javascript | ||
| 311 | +// 获取根组件 | ||
| 312 | +const rootComponent = document.querySelector('#app').__vueParentComponent; | ||
| 313 | + | ||
| 314 | +// 获取 formInfo | ||
| 315 | +const formInfo = rootComponent.ctx.formInfo; | ||
| 316 | + | ||
| 317 | +// 返回结果 | ||
| 318 | +JSON.stringify(formInfo, null, 2); | ||
| 319 | +``` | ||
| 320 | + | ||
| 321 | +--- | ||
| 322 | + | ||
| 323 | +## 📝 完整提取流程 | ||
| 324 | + | ||
| 325 | +### 方法 A: 直接 API 调用(需要登录态) | ||
| 326 | + | ||
| 327 | +**适用场景**:在已登录环境下,需要批量获取表单配置 | ||
| 328 | + | ||
| 329 | +**步骤 1**: 解析 URL 获取 form_code | ||
| 330 | + | ||
| 331 | +```javascript | ||
| 332 | +// 从 URL 中提取 form_code | ||
| 333 | +// URL: https://oa-dev.onwall.cn/f/custom_form/front/index.html#/?code=nxqkbf | ||
| 334 | +const url = new URL('https://oa-dev.onwall.cn/f/custom_form/front/index.html'); | ||
| 335 | +const formCode = 'nxqkbf'; // 从 URL 参数 code 获取 | ||
| 336 | +``` | ||
| 337 | + | ||
| 338 | +**步骤 2**: 调用查询 API | ||
| 339 | + | ||
| 340 | +```javascript | ||
| 341 | +// 使用项目 API 函数 | ||
| 342 | +import { queryFormAPI } from '@/api/form'; | ||
| 343 | + | ||
| 344 | +async function getFormConfig(formCode) { | ||
| 345 | + try { | ||
| 346 | + const response = await queryFormAPI({ | ||
| 347 | + form_code: formCode, | ||
| 348 | + page_type: 'add', | ||
| 349 | + data_id: null, | ||
| 350 | + flow_node_code: '', | ||
| 351 | + force_back: '' | ||
| 352 | + }); | ||
| 353 | + | ||
| 354 | + if (response && response.code === 1) { | ||
| 355 | + return { | ||
| 356 | + formName: response.data.name, | ||
| 357 | + fieldList: response.data.field_list, | ||
| 358 | + ruleList: response.data.rule_list || [], | ||
| 359 | + bannerConfig: response.data.banner_config, | ||
| 360 | + submitConfig: response.data.submit_config | ||
| 361 | + }; | ||
| 362 | + } | ||
| 363 | + } catch (error) { | ||
| 364 | + console.error('获取表单配置失败:', error); | ||
| 365 | + throw error; | ||
| 366 | + } | ||
| 367 | +} | ||
| 368 | +``` | ||
| 369 | + | ||
| 370 | +**步骤 3**: 数据验证 | ||
| 371 | + | ||
| 372 | +```javascript | ||
| 373 | +function validateFormConfig(data) { | ||
| 374 | + const required = ['formName', 'fieldList']; | ||
| 375 | + const missing = required.filter(key => !data[key]); | ||
| 376 | + | ||
| 377 | + if (missing.length > 0) { | ||
| 378 | + throw new Error(`缺少必要字段: ${missing.join(', ')}`); | ||
| 379 | + } | ||
| 380 | + | ||
| 381 | + if (!Array.isArray(data.fieldList) || data.fieldList.length === 0) { | ||
| 382 | + throw new Error('字段列表为空或格式错误'); | ||
| 383 | + } | ||
| 384 | + | ||
| 385 | + return true; | ||
| 386 | +} | ||
| 387 | +``` | ||
| 388 | + | ||
| 389 | +--- | ||
| 390 | + | ||
| 391 | +### 方法 B: 浏览器环境提取(Chrome DevTools) | ||
| 392 | + | ||
| 393 | +**步骤 1**: 打开页面并登录 | ||
| 394 | + | ||
| 395 | +使用 Chrome DevTools MCP 打开 URL 并确保已登录: | ||
| 396 | + | ||
| 397 | +```javascript | ||
| 398 | +await mcp__chrome_devtools__navigate_page({ | ||
| 399 | + type: 'url', | ||
| 400 | + url: 'https://oa-dev.onwall.cn/f/custom_form/front/index.html#/?code=nxqkbf', | ||
| 401 | + timeout: 30000 | ||
| 402 | +}); | ||
| 403 | +``` | ||
| 404 | + | ||
| 405 | +**步骤 2**: 等待页面加载 | ||
| 406 | + | ||
| 407 | +等待数据加载完成: | ||
| 408 | + | ||
| 409 | +```javascript | ||
| 410 | +await mcp__chrome_devtools__wait_for({ | ||
| 411 | + text: '提交', // 等待提交按钮出现 | ||
| 412 | + timeout: 10000 | ||
| 413 | +}); | ||
| 414 | +``` | ||
| 415 | + | ||
| 416 | +**步骤 3**: 提取数据 | ||
| 417 | + | ||
| 418 | +执行脚本提取 formInfo: | ||
| 419 | + | ||
| 420 | +```javascript | ||
| 421 | +const result = await mcp__chrome_devtools__evaluate_script({ | ||
| 422 | + function: `() => { | ||
| 423 | + try { | ||
| 424 | + // 尝试从 Pinia store 获取 | ||
| 425 | + const app = document.querySelector('#app').__vueParentComponent?.appContext?.app; | ||
| 426 | + if (app?.config?.globalProperties?.$pinia) { | ||
| 427 | + const pinia = app.config.globalProperties.$pinia; | ||
| 428 | + const store = pinia.state.value.main; | ||
| 429 | + return { | ||
| 430 | + success: true, | ||
| 431 | + source: 'pinia', | ||
| 432 | + data: store.formInfo | ||
| 433 | + }; | ||
| 434 | + } | ||
| 435 | + | ||
| 436 | + // 尝试从组件直接获取 | ||
| 437 | + const rootComponent = document.querySelector('#app').__vueParentComponent; | ||
| 438 | + if (rootComponent?.ctx?.formInfo) { | ||
| 439 | + return { | ||
| 440 | + success: true, | ||
| 441 | + source: 'component', | ||
| 442 | + data: rootComponent.ctx.formInfo | ||
| 443 | + }; | ||
| 444 | + } | ||
| 445 | + | ||
| 446 | + return { | ||
| 447 | + success: false, | ||
| 448 | + error: '无法找到表单数据' | ||
| 449 | + }; | ||
| 450 | + } catch (error) { | ||
| 451 | + return { | ||
| 452 | + success: false, | ||
| 453 | + error: error.message | ||
| 454 | + }; | ||
| 455 | + } | ||
| 456 | + }` | ||
| 457 | +}); | ||
| 458 | +``` | ||
| 459 | + | ||
| 460 | +**步骤 4**: 解析数据 | ||
| 461 | + | ||
| 462 | +根据提取的数据,解析出: | ||
| 463 | + | ||
| 464 | +1. **表单基本信息**: 表单名称、描述 | ||
| 465 | +2. **字段列表**: 所有字段的配置 | ||
| 466 | +3. **规则列表**: 字段显示/隐藏规则 | ||
| 467 | +4. **页眉配置**: banner、标题等 | ||
| 468 | +5. **提交配置**: 提交按钮配置 | ||
| 469 | + | ||
| 470 | +--- | ||
| 471 | + | ||
| 472 | +## 🎯 数据提取模板 | ||
| 473 | + | ||
| 474 | +```javascript | ||
| 475 | +/** | ||
| 476 | + * 从表单页面提取完整配置 | ||
| 477 | + */ | ||
| 478 | +async function extractFormConfig(pageUrl) { | ||
| 479 | + // 1. 打开页面 | ||
| 480 | + await mcp__chrome_devtools__navigate_page({ | ||
| 481 | + type: 'url', | ||
| 482 | + url: pageUrl, | ||
| 483 | + timeout: 30000 | ||
| 484 | + }); | ||
| 485 | + | ||
| 486 | + // 2. 等待页面加载 | ||
| 487 | + await mcp__chrome_devtools__wait_for({ | ||
| 488 | + text: '提交', | ||
| 489 | + timeout: 10000 | ||
| 490 | + }); | ||
| 491 | + | ||
| 492 | + // 3. 提取数据 | ||
| 493 | + const result = await mcp__chrome_devtools__evaluate_script({ | ||
| 494 | + function: `() => { | ||
| 495 | + const app = document.querySelector('#app').__vueParentComponent?.appContext?.app; | ||
| 496 | + const pinia = app?.config?.globalProperties?.$pinia; | ||
| 497 | + return pinia ? pinia.state.value.main.formInfo : null; | ||
| 498 | + }` | ||
| 499 | + }); | ||
| 500 | + | ||
| 501 | + // 4. 解析配置 | ||
| 502 | + if (result) { | ||
| 503 | + return { | ||
| 504 | + formName: result.name, | ||
| 505 | + fieldList: result.field_list, | ||
| 506 | + ruleList: result.rule_list || [], | ||
| 507 | + metadata: { | ||
| 508 | + extractedAt: new Date().toISOString(), | ||
| 509 | + source: pageUrl | ||
| 510 | + } | ||
| 511 | + }; | ||
| 512 | + } | ||
| 513 | + | ||
| 514 | + throw new Error('无法提取表单数据'); | ||
| 515 | +} | ||
| 516 | +``` | ||
| 517 | + | ||
| 518 | +--- | ||
| 519 | + | ||
| 520 | +## 📊 真实 API 返回数据示例 | ||
| 521 | + | ||
| 522 | +### 测试表单: `nxqkbf` | ||
| 523 | + | ||
| 524 | +**API 1: query_form_all_field 返回** | ||
| 525 | + | ||
| 526 | +```json | ||
| 527 | +{ | ||
| 528 | + "code": 1, | ||
| 529 | + "msg": "OK", | ||
| 530 | + "data": { | ||
| 531 | + "id": 835950, | ||
| 532 | + "code": "nxqkbf", | ||
| 533 | + "name": "测试LangChain", | ||
| 534 | + "short_name": "customize_35697_nxqkbf", | ||
| 535 | + "table_name": "customize_35697_nxqkbf", | ||
| 536 | + "max_field_num": 3, | ||
| 537 | + "description": null, | ||
| 538 | + "rule_list": [], | ||
| 539 | + "field_list": [ | ||
| 540 | + { | ||
| 541 | + "tag": "page_header", | ||
| 542 | + "name": "page_header_0", | ||
| 543 | + "index": 0, | ||
| 544 | + "label": "测试LangChain", | ||
| 545 | + "banner": { | ||
| 546 | + "ext": "png", | ||
| 547 | + "src": "https://cdn.ipadbiz.cn/space/FlBDc7PgmmN0fD4GdMW_xUCFgs5T.png" | ||
| 548 | + }, | ||
| 549 | + "field_id": 835961, | ||
| 550 | + "invisible": false, | ||
| 551 | + "field_name": "object_1", | ||
| 552 | + "banner_type": "image", | ||
| 553 | + "interaction_type": "h5show" | ||
| 554 | + }, | ||
| 555 | + { | ||
| 556 | + "tag": "input", | ||
| 557 | + "name": "input_2", | ||
| 558 | + "index": 2, | ||
| 559 | + "label": "标题", | ||
| 560 | + "unique": false, | ||
| 561 | + "default": "", | ||
| 562 | + "disabled": false, | ||
| 563 | + "field_id": 835962, | ||
| 564 | + "readonly": false, | ||
| 565 | + "required": false, | ||
| 566 | + "data_type": "text", | ||
| 567 | + "field_name": "field_2", | ||
| 568 | + "is_encrypt": false, | ||
| 569 | + "placeholder": "请输入", | ||
| 570 | + "interaction_type": "h5edit" | ||
| 571 | + }, | ||
| 572 | + { | ||
| 573 | + "tag": "page_commit", | ||
| 574 | + "name": "page_commit_1", | ||
| 575 | + "text": "提交", | ||
| 576 | + "index": 1, | ||
| 577 | + "is_back": false, | ||
| 578 | + "field_id": 835964, | ||
| 579 | + "invisible": false, | ||
| 580 | + "back_title": "上一页", | ||
| 581 | + "field_name": "object_3", | ||
| 582 | + "interaction_type": "h5show" | ||
| 583 | + } | ||
| 584 | + ] | ||
| 585 | + } | ||
| 586 | +} | ||
| 587 | +``` | ||
| 588 | + | ||
| 589 | +**API 2: query_form_setting 返回** | ||
| 590 | + | ||
| 591 | +```json | ||
| 592 | +{ | ||
| 593 | + "code": 1, | ||
| 594 | + "msg": "OK", | ||
| 595 | + "data": [{ | ||
| 596 | + "id": 835950, | ||
| 597 | + "code": "nxqkbf", | ||
| 598 | + "name": "测试LangChain", | ||
| 599 | + "max_field_num": 3, | ||
| 600 | + "data_count": 7, | ||
| 601 | + "client_id": 35697, | ||
| 602 | + "extend": { | ||
| 603 | + "server_time": "2026-03-16 17:15:40", | ||
| 604 | + "is_back_user": false | ||
| 605 | + }, | ||
| 606 | + "property_list": { | ||
| 607 | + "sjsj_enable": 1, | ||
| 608 | + "commit_action": "text", | ||
| 609 | + "commit_text_type": "default", | ||
| 610 | + "commit_text_template": "提交成功", | ||
| 611 | + "edit_commit_action": "text", | ||
| 612 | + "edit_commit_text_type": "default", | ||
| 613 | + "edit_commit_text_template": "提交成功" | ||
| 614 | + } | ||
| 615 | + }] | ||
| 616 | +} | ||
| 617 | +``` | ||
| 618 | + | ||
| 619 | +### 数据解析 | ||
| 620 | + | ||
| 621 | +从以上真实数据可以得出: | ||
| 622 | + | ||
| 623 | +| 字段类型 | tag | field_name | 说明 | | ||
| 624 | +|---------|-----|------------|------| | ||
| 625 | +| 页面头部 | page_header | object_1 | 显示 banner 和标题 | | ||
| 626 | +| 输入框 | input | field_2 | 用户可编辑的输入字段 | | ||
| 627 | +| 提交按钮 | page_commit | object_3 | 表单提交按钮 | | ||
| 628 | + | ||
| 629 | +**关键字段说明**: | ||
| 630 | +- `interaction_type: "h5show"` - 仅展示,不可编辑(如 banner、提交按钮) | ||
| 631 | +- `interaction_type: "h5edit"` - 可编辑(如输入框) | ||
| 632 | +- `field_name` - 数据提交时的字段名 | ||
| 633 | +- `required` - 是否必填 | ||
| 634 | + | ||
| 635 | +--- | ||
| 636 | + | ||
| 637 | +## 🎯 数据提取示例 | ||
| 638 | + | ||
| 639 | +### 输入 URL | ||
| 640 | + | ||
| 641 | +``` | ||
| 642 | +https://oa-dev.onwall.cn/f/custom_form/front/index.html#/?code=nxqkbf | ||
| 643 | +``` | ||
| 644 | + | ||
| 645 | +### 提取的数据结构 | ||
| 646 | + | ||
| 647 | +```json | ||
| 648 | +{ | ||
| 649 | + "name": "用户信息采集表", | ||
| 650 | + "field_list": [ | ||
| 651 | + { | ||
| 652 | + "tag": "input", | ||
| 653 | + "field_name": "field_1", | ||
| 654 | + "label": "姓名", | ||
| 655 | + "required": true, | ||
| 656 | + "data_type": "text", | ||
| 657 | + "placeholder": "请输入姓名", | ||
| 658 | + "disabled": false, | ||
| 659 | + "readonly": false | ||
| 660 | + }, | ||
| 661 | + { | ||
| 662 | + "tag": "gender", | ||
| 663 | + "field_name": "field_2", | ||
| 664 | + "label": "性别", | ||
| 665 | + "required": false, | ||
| 666 | + "data_type": "text", | ||
| 667 | + "options": [ | ||
| 668 | + { "title": "男", "value": "男" }, | ||
| 669 | + { "title": "女", "value": "女" } | ||
| 670 | + ] | ||
| 671 | + } | ||
| 672 | + ], | ||
| 673 | + "rule_list": [ | ||
| 674 | + { | ||
| 675 | + "field_names": ["field_3"], | ||
| 676 | + "mode": "SHOW", | ||
| 677 | + "logical_op": "OR", | ||
| 678 | + "expr_list": [ | ||
| 679 | + { | ||
| 680 | + "field_name": "field_1", | ||
| 681 | + "values": ["VIP用户"] | ||
| 682 | + } | ||
| 683 | + ] | ||
| 684 | + } | ||
| 685 | + ] | ||
| 686 | +} | ||
| 687 | +``` | ||
| 688 | + | ||
| 689 | +--- | ||
| 690 | + | ||
| 691 | +## 🔄 数据转换 | ||
| 692 | + | ||
| 693 | +### 将页面数据转换为标准格式 | ||
| 694 | + | ||
| 695 | +提取的数据需要转换为 LangChain Agent 可理解的标准格式: | ||
| 696 | + | ||
| 697 | +```javascript | ||
| 698 | +function convertToStandardFormat(extractedData) { | ||
| 699 | + return { | ||
| 700 | + formName: extractedData.name, | ||
| 701 | + fields: extractedData.field_list.map(field => ({ | ||
| 702 | + key: field.field_name, | ||
| 703 | + component_props: { | ||
| 704 | + tag: field.tag, | ||
| 705 | + label: field.label, | ||
| 706 | + required: field.required, | ||
| 707 | + placeholder: field.placeholder || '', | ||
| 708 | + options: field.options || [], | ||
| 709 | + disabled: field.disabled || false, | ||
| 710 | + readonly: field.readonly || false | ||
| 711 | + } | ||
| 712 | + })), | ||
| 713 | + rules: extractedData.rule_list || [] | ||
| 714 | + }; | ||
| 715 | +} | ||
| 716 | +``` | ||
| 717 | + | ||
| 718 | +--- | ||
| 719 | + | ||
| 720 | +## ⚠️ 注意事项 | ||
| 721 | + | ||
| 722 | +### 1. API 访问说明 | ||
| 723 | + | ||
| 724 | +**表单查询 API 可以直接访问,无需特殊认证!** | ||
| 725 | + | ||
| 726 | +```bash | ||
| 727 | +# 最简单的调用方式 | ||
| 728 | +curl "https://oa-dev.onwall.cn/srv/?a=query_form_all_field&f=custom_form&form_code=nxqkbf" | ||
| 729 | +``` | ||
| 730 | + | ||
| 731 | +**完整 URL 格式**: | ||
| 732 | +``` | ||
| 733 | +https://oa-dev.onwall.cn/srv/?a=query_form_all_field&f=custom_form&form_code={form_code} | ||
| 734 | +``` | ||
| 735 | + | ||
| 736 | +### 2. 数据验证 | ||
| 737 | + | ||
| 738 | +提取后需要验证数据完整性: | ||
| 739 | + | ||
| 740 | +```javascript | ||
| 741 | +function validateExtractedData(data) { | ||
| 742 | + const required = ['name', 'field_list']; | ||
| 743 | + const missing = required.filter(key => !data[key]); | ||
| 744 | + | ||
| 745 | + if (missing.length > 0) { | ||
| 746 | + throw new Error(`缺少必要字段: ${missing.join(', ')}`); | ||
| 747 | + } | ||
| 748 | + | ||
| 749 | + // 验证字段列表 | ||
| 750 | + if (!Array.isArray(data.field_list) || data.field_list.length === 0) { | ||
| 751 | + throw new Error('字段列表为空或格式错误'); | ||
| 752 | + } | ||
| 753 | + | ||
| 754 | + return true; | ||
| 755 | +} | ||
| 756 | +``` | ||
| 757 | + | ||
| 758 | +### 3. 错误处理 | ||
| 759 | + | ||
| 760 | +```javascript | ||
| 761 | +try { | ||
| 762 | + const config = await extractFormConfig(url); | ||
| 763 | + validateExtractedData(config); | ||
| 764 | + return convertToStandardFormat(config); | ||
| 765 | +} catch (error) { | ||
| 766 | + console.error('数据提取失败:', error.message); | ||
| 767 | + // 返回错误信息 | ||
| 768 | + return { | ||
| 769 | + success: false, | ||
| 770 | + error: error.message, | ||
| 771 | + url: url | ||
| 772 | + }; | ||
| 773 | +} | ||
| 774 | +``` | ||
| 775 | + | ||
| 776 | +### 4. URL 解析 | ||
| 777 | + | ||
| 778 | +从用户提供的表单 URL 中提取参数并构建 API 请求: | ||
| 779 | + | ||
| 780 | +```javascript | ||
| 781 | +// 示例 URL: https://oa-dev.onwall.cn/f/custom_form/front/index.html#/?code=nxqkbf | ||
| 782 | +function parseFormUrl(url) { | ||
| 783 | + const params = new URLSearchParams(url.split('?')[1]); | ||
| 784 | + | ||
| 785 | + return { | ||
| 786 | + // 基础参数 | ||
| 787 | + form_code: params.get('code'), | ||
| 788 | + model: params.get('model'), // 预览模式 | ||
| 789 | + data_id: params.get('data_id'), // 数据 ID(编辑时) | ||
| 790 | + page_type: params.get('page_type'), // add/edit/info/flow | ||
| 791 | + flow_node_code: params.get('flow_node_code'), // 流程节点 | ||
| 792 | + force_back: params.get('force_back'), // 强制后台模式 | ||
| 793 | + x_cycle: params.get('x_cycle'), // 周期 ID | ||
| 794 | + volunteer_source: params.get('volunteer_source'), // 义工来源 | ||
| 795 | + openid: params.get('openid'), // 微信 openid | ||
| 796 | + | ||
| 797 | + }; | ||
| 798 | +} | ||
| 799 | + | ||
| 800 | +// 使用示例 | ||
| 801 | +const url = 'https://oa-dev.onwall.cn/f/custom_form/front/index.html#/?code=nxqkbf&page_type=add'; | ||
| 802 | +const params = parseFormUrl(url); | ||
| 803 | + | ||
| 804 | +// 构建完整的 API 请求 | ||
| 805 | +const apiParams = { | ||
| 806 | + f: 'custom_form', | ||
| 807 | + form_code: params.form_code, | ||
| 808 | + page_type: params.page_type || 'add', | ||
| 809 | + data_id: params.data_id || null, | ||
| 810 | + flow_node_code: params.flow_node_code || '', | ||
| 811 | + force_back: params.force_back || '', | ||
| 812 | + x_cycle: params.x_cycle || '', | ||
| 813 | + volunteer_source: params.volunteer_source || '' | ||
| 814 | +}; | ||
| 815 | +``` | ||
| 816 | + | ||
| 817 | +**URL 参数说明**: | ||
| 818 | + | ||
| 819 | +| 参数 | 说明 | 示例值 | 必填 | | ||
| 820 | +|------|------|--------|------| | ||
| 821 | +| `code` | 表单代码 | `nxqkbf` | ✅ | | ||
| 822 | +| `model` | 模式 | `preview` | ❌ | | ||
| 823 | +| `page_type` | 页面类型 | `add`/`edit`/`info`/`flow` | ❌ | | ||
| 824 | +| `data_id` | 数据 ID | `12345` | ❌ | | ||
| 825 | +| `flow_node_code` | 流程节点代码 | `node_001` | ❌ | | ||
| 826 | +| `force_back` | 强制后台模式 | `1` | ❌ | | ||
| 827 | +| `x_cycle` | 周期 ID | `cycle_001` | ❌ | | ||
| 828 | +| `volunteer_source` | 义工来源 | `self`/`leader` | ❌ | | ||
| 829 | +| `openid` | 微信 openid | `oxxxxx` | ❌ | | ||
| 830 | + | ||
| 831 | +**简化的 API 调用**: | ||
| 832 | + | ||
| 833 | +如果只需要获取表单结构,可以只传递必要的参数: | ||
| 834 | + | ||
| 835 | +```bash | ||
| 836 | +# 最小化调用(只需要 form_code) | ||
| 837 | +curl "https://oa-dev.onwall.cn/srv/?a=query_form_all_field&f=custom_form&form_code=nxqkbf" | ||
| 838 | + | ||
| 839 | +# 完整调用(包含所有 URL 参数) | ||
| 840 | +curl "https://oa-dev.onwall.cn/srv/?a=query_form_all_field&f=custom_form&form_code=nxqkbf&page_type=add&data_id=null&flow_node_code=&force_back=" | ||
| 841 | +``` | ||
| 842 | + | ||
| 843 | +--- | ||
| 844 | + | ||
| 845 | +## 🔗 相关文档 | ||
| 846 | + | ||
| 847 | +- [00-数据结构总览.md](./00-数据结构总览.md) | ||
| 848 | +- [01-表单字段组件类型.md](./01-表单字段组件类型.md) | ||
| 849 | +- [06-规则控制系统.md](./06-规则控制系统.md) | ||
| 850 | +- [03-API-接口文档.md](./03-API-接口文档.md) |
docs/agent/README.md
0 → 100644
| 1 | +# docs 文档索引 | ||
| 2 | + | ||
| 3 | +本文档目录为 LangChain Agent 设计表单生成功能提供完整的项目架构和数据结构参考。 | ||
| 4 | + | ||
| 5 | +## 文档列表 | ||
| 6 | + | ||
| 7 | +### 00-数据结构总览.md | ||
| 8 | +**用途**:了解项目的核心数据结构 | ||
| 9 | +**内容**: | ||
| 10 | +- 表单字段结构 (FormField) | ||
| 11 | +- 组件属性结构 (ComponentProps) | ||
| 12 | +- 选项结构 (Option) | ||
| 13 | +- API 响应结构 | ||
| 14 | +- 数据流转流程 | ||
| 15 | + | ||
| 16 | +**适合**:Agent 需要理解整体数据模型时 | ||
| 17 | + | ||
| 18 | +--- | ||
| 19 | + | ||
| 20 | +### 01-表单字段组件类型.md | ||
| 21 | +**用途**:了解所有支持的组件类型 | ||
| 22 | +**内容**: | ||
| 23 | +- 30+ 种组件类型完整列表 | ||
| 24 | +- 每种组件的用途和配置要点 | ||
| 25 | +- 组件注册位置 | ||
| 26 | +- 新增组件流程 | ||
| 27 | + | ||
| 28 | +**适合**:Agent 需要选择合适的组件类型时 | ||
| 29 | + | ||
| 30 | +--- | ||
| 31 | + | ||
| 32 | +### 02-component_props-配置规范.md | ||
| 33 | +**用途**:了解组件属性的详细配置 | ||
| 34 | +**内容**: | ||
| 35 | +- 通用属性(所有组件) | ||
| 36 | +- 各类组件专属属性 | ||
| 37 | +- Option 结构详解 | ||
| 38 | +- 数据提交格式 | ||
| 39 | +- 样式属性 | ||
| 40 | + | ||
| 41 | +**适合**:Agent 生成具体组件配置时 | ||
| 42 | + | ||
| 43 | +--- | ||
| 44 | + | ||
| 45 | +### 03-API-接口文档.md | ||
| 46 | +**用途**:了解后端 API 接口 | ||
| 47 | +**内容**: | ||
| 48 | +- 表单管理接口(增删改查) | ||
| 49 | +- 数据管理接口 | ||
| 50 | +- 组件接口 | ||
| 51 | +- 通用接口(上传、验证码等) | ||
| 52 | +- HTTP 缓存控制 | ||
| 53 | + | ||
| 54 | +**适合**:Agent 需要与后端交互时 | ||
| 55 | + | ||
| 56 | +--- | ||
| 57 | + | ||
| 58 | +### 04-示例数据.md | ||
| 59 | +**用途**:提供各类组件的配置示例 | ||
| 60 | +**内容**: | ||
| 61 | +- 20+ 个真实配置示例 | ||
| 62 | +- 完整表单配置示例 | ||
| 63 | +- 数据提交格式示例 | ||
| 64 | +- LangChain Prompt 模板 | ||
| 65 | + | ||
| 66 | +**适合**:Few-shot Learning、Prompt 模板构建 | ||
| 67 | + | ||
| 68 | +--- | ||
| 69 | + | ||
| 70 | +### 05-LangChain-Agent-使用指南.md | ||
| 71 | +**用途**:Agent 开发指南 | ||
| 72 | +**内容**: | ||
| 73 | +- 自然语言到组件映射表 | ||
| 74 | +- 必填/数量/选项识别规则 | ||
| 75 | +- 复杂需求处理 | ||
| 76 | +- Prompt 模板 | ||
| 77 | +- LangChain 代码示例 | ||
| 78 | +- 验证和错误处理 | ||
| 79 | + | ||
| 80 | +**适合**:**开发 LangChain Agent 的主要参考文档** | ||
| 81 | + | ||
| 82 | +--- | ||
| 83 | + | ||
| 84 | +### 06-规则控制系统.md | ||
| 85 | +**用途**:表单字段显示/隐藏规则系统 | ||
| 86 | +**内容**: | ||
| 87 | +- 规则系统概述(SHOW/HIDE 模式、AND/OR 逻辑) | ||
| 88 | +- 规则数据结构(rule_list、Rule、RuleExpr) | ||
| 89 | +- 核心函数分析(checkRules、evaluateMultipleRules、evaluateRuleCondition、handleCascadeHiding) | ||
| 90 | +- 触发机制(@active 事件) | ||
| 91 | +- 实际示例(简单/复杂/多规则/级联隐藏) | ||
| 92 | +- LangChain Agent 集成要点 | ||
| 93 | + | ||
| 94 | +**适合**:Agent 需要生成规则配置或理解字段间依赖关系时 | ||
| 95 | + | ||
| 96 | +--- | ||
| 97 | + | ||
| 98 | +### 07-页面数据提取指南.md | ||
| 99 | +**用途**:从实际运行的表单页面中提取配置数据 | ||
| 100 | +**内容**: | ||
| 101 | +- Pinia Store 数据存储结构 | ||
| 102 | +- 数据提取方法(Chrome DevTools MCP / Vue DevTools API / 直接 API) | ||
| 103 | +- 完整提取流程(打开页面 → 等待加载 → 提取数据 → 解析配置) | ||
| 104 | +- 数据提取模板和代码示例 | ||
| 105 | +- 数据转换和验证 | ||
| 106 | + | ||
| 107 | +**适合**:用户提供表单 URL 时,需要从页面提取完整配置 | ||
| 108 | + | ||
| 109 | +--- | ||
| 110 | + | ||
| 111 | +## 快速查找指南 | ||
| 112 | + | ||
| 113 | +### 按场景查找 | ||
| 114 | + | ||
| 115 | +| 场景 | 推荐文档 | | ||
| 116 | +|------|----------| | ||
| 117 | +| 理解项目架构 | 00-数据结构总览 | | ||
| 118 | +| 选择组件类型 | 01-表单字段组件类型、05-LangChain-Agent-使用指南 | | ||
| 119 | +| 生成配置 | 02-component_props-配置规范、04-示例数据 | | ||
| 120 | +| Few-shot 示例 | 04-示例数据 | | ||
| 121 | +| 开发 Agent | 05-LangChain-Agent-使用指南 | | ||
| 122 | +| 生成规则配置 | 06-规则控制系统 | | ||
| 123 | +| 理解字段依赖 | 06-规则控制系统 | | ||
| 124 | +| **从 URL 提取表单** | **07-页面数据提取指南** | | ||
| 125 | + | ||
| 126 | +### 按组件类型查找 | ||
| 127 | + | ||
| 128 | +| 组件类别 | 文档位置 | | ||
| 129 | +|----------|----------| | ||
| 130 | +| 文本输入类 | 01-表单字段组件类型(文档输入类) | | ||
| 131 | +| 选择类 | 01-表单字段组件类型(选择类)、04-示例数据(示例4-6) | | ||
| 132 | +| 日期时间类 | 01-表单字段组件类型(日期时间类)、04-示例数据(示例8) | | ||
| 133 | +| 上传类 | 01-表单字段组件类型(上传类)、04-示例数据(示例9) | | ||
| 134 | +| 特殊功能类 | 01-表单字段组件类型(特殊功能类)、04-示例数据(示例11-20) | | ||
| 135 | + | ||
| 136 | +### 按属性查找 | ||
| 137 | + | ||
| 138 | +| 属性 | 文档位置 | | ||
| 139 | +|------|----------| | ||
| 140 | +| 通用属性 | 02-component_props-配置规范(通用属性) | | ||
| 141 | +| options 配置 | 02-component_props-配置规范(选项类组件属性) | | ||
| 142 | +| 图片上传配置 | 02-component_props-配置规范(上传类属性) | | ||
| 143 | +| 样式属性 | 02-component_props-配置规范(样式属性) | | ||
| 144 | +| 规则配置 | 06-规则控制系统(数据结构、触发机制) | | ||
| 145 | +| 字段显示/隐藏 | 06-规则控制系统(SHOW/HIDE 模式) | | ||
| 146 | +| 级联隐藏 | 06-规则控制系统(级联隐藏逻辑) | | ||
| 147 | + | ||
| 148 | +## Agent 开发建议 | ||
| 149 | + | ||
| 150 | +### 1. 先读顺序 | ||
| 151 | + | ||
| 152 | +1. **05-LangChain-Agent-使用指南** - 了解 Agent 设计要点 | ||
| 153 | +2. **01-表单字段组件类型** - 了解可用的组件 | ||
| 154 | +3. **04-示例数据** - 获取 Few-shot 示例 | ||
| 155 | +4. **02-component_props-配置规范** - 深入了解配置细节 | ||
| 156 | +5. **06-规则控制系统** - 了解字段显示/隐藏规则(如需动态表单) | ||
| 157 | + | ||
| 158 | +### 2. 关键数据结构 | ||
| 159 | + | ||
| 160 | +Agent 必须正确理解的核心结构: | ||
| 161 | + | ||
| 162 | +```typescript | ||
| 163 | +// 最核心的结构 | ||
| 164 | +FormField { | ||
| 165 | + key: string | ||
| 166 | + value: any | ||
| 167 | + component_props: { | ||
| 168 | + tag: string // 决定组件类型 | ||
| 169 | + label: string // 显示名称 | ||
| 170 | + required: boolean | ||
| 171 | + // ... 其他属性 | ||
| 172 | + } | ||
| 173 | +} | ||
| 174 | +``` | ||
| 175 | + | ||
| 176 | +### 3. 组件类型映射表 | ||
| 177 | + | ||
| 178 | +直接参考 `05-LangChain-Agent-使用指南` 中的映射表,建立用户描述 → 组件类型的映射。 | ||
| 179 | + | ||
| 180 | +### 4. Few-shot 示例使用 | ||
| 181 | + | ||
| 182 | +从 `04-示例数据.md` 中提取典型示例作为 Prompt 的一部分,提高输出质量。 | ||
| 183 | + | ||
| 184 | +### 5. 验证策略 | ||
| 185 | + | ||
| 186 | +生成配置后,验证以下内容: | ||
| 187 | +- [ ] tag 值是否有效(参考 01 文档的组件列表) | ||
| 188 | +- [ ] required 是否为布尔值 | ||
| 189 | +- [ ] 选项类组件是否有 options 数组 | ||
| 190 | +- [ ] 上传类组件是否有合理的数量限制 | ||
| 191 | + | ||
| 192 | +## 数据流转图 | ||
| 193 | + | ||
| 194 | +``` | ||
| 195 | +用户自然语言 | ||
| 196 | + ↓ | ||
| 197 | + [Agent 解析] | ||
| 198 | + ↓ | ||
| 199 | + 意图识别 + 实体提取 | ||
| 200 | + ↓ | ||
| 201 | + 组件类型选择 + 配置生成 | ||
| 202 | + ↓ | ||
| 203 | + [验证输出] | ||
| 204 | + ↓ | ||
| 205 | +表单字段配置 JSON | ||
| 206 | + ↓ | ||
| 207 | + createComponentType() | ||
| 208 | + ↓ | ||
| 209 | + 动态表单渲染 | ||
| 210 | +``` | ||
| 211 | + | ||
| 212 | +## 联系方式 | ||
| 213 | + | ||
| 214 | +如有问题或需要补充文档,请查阅: | ||
| 215 | +- 项目源码:`src/hooks/useComponentType.js` | ||
| 216 | +- 组件目录:`src/components/` | ||
| 217 | +- API 目录:`src/api/` |
-
Please register or login to post a comment