Skip to content

[app-builder] 新增模型配置表单 #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app-builder/builtin/form/model-config-form/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package-lock.json
node_modules/
output/
3 changes: 3 additions & 0 deletions app-builder/builtin/form/model-config-form/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
strict-ssl=false
package-lock=true
registry=https://registry.npmjs.org/
173 changes: 173 additions & 0 deletions app-builder/builtin/form/model-config-form/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# 画布 # 自定义组件开发说明

## 前提条件

* 开发工具建议使用 VSCode

* 基础环境: Node.js 版本 >= 18, npm 版本 >= 10

* React 组件建议使用 Ant Design (版本: 4.24.13)

## 操作步骤

### 约束条件

上传的组件包必须是 zip 压缩包,解压后文件大小不得超过 5M,且必须包含三部分:

* build 文件夹: 表单代码打包后的静态资源

* config.json: 表单的输入输出参配置文件

* form.jpg/png/jpeg: 表单预览图,大小不得超过 1M

## 开发组件代码

### 创建文件

* 在 `/src/components` 目录下创建 `.tsx` 类型的组件文件

### 表单获取流程数据

用于初始化表单数据:

```tsx
const { data, terminateClick, resumingClick, restartClick } = useContext(DataContext);
```

`data` 为 json 数据,结构与 config.json 的输入参配置一致

### 表单调用内置接口

**1. 终止对话 `terminateClick()`**

```tsx
<Button onClick={onTerminateClick}>终止对话</Button>

const onTerminateClick = () => {
terminateClick({ content: "终止会话" });
}
```

**注意:结束节点不能调用 `terminateClick`**

**2. 继续对话 `resumingClick()`**

```tsx
<Button onClick={onResumeClick}>继续对话</Button>

const onResumeClick = () => {
resumingClick({ params: { a: "hello", b: 1 } });
}
```

**注意:结束节点不能调用 `resumingClick`**

**3. 重新对话 `restartClick()`**

```tsx
<Button onClick={onRestartClick}>重新对话</Button>

const onRestartClick = () => {
restartClick({ params: { a: "hello", b: 1 } });
}
```

**注意:如果在智能表单节点使用,需先调 `terminateClick` 再 `restartClick`**

### 调用外部接口

* 要求接口支持跨域

### 使用图片

* 图片文件放在 `/src/assets/images`

* 路径: `./src/assets/images/xxx.png`

```tsx
<img src="./src/assets/images/empty.png" alt="" height="100px" width="100px"/>
```

### 表单样式文件

* 可以在 `/src/styles` 目录下添加 `.scss` 样式文件

### 调试表单

```bash
npm install
npm start
```

* 模拟数据 `app.tsx`:

```ts
receiveData: {
data: { a: "你好", b: "Demo1" },
uniqueId: 10,
origin: "http://127.0.0.1:3350",
tenantId: "fh47kl"
}
```

### 打包

```bash
npm run build
```

## 表单输入输出参 config.json

### 基础规范

* 格式需符合[json schema规范](https://json-schema.apifox.cn/)

* 格式示例:

```json
{
"schema": {
"parameters": {
"type": "object",
"required": ["a", "b"],
"properties": {
"a": { "type": "string", "default": "haha" },
"b": { "type": "string", "default": "heihei" }
}
},
"return": {
"type": "object",
"properties": {
"a": { "type": "string" },
"b": { "type": "string" }
}
}
}
}
```

* 最外层 `parameters` 字段是入参,入参第一层必须 `type` 为 `object`。

* 必须包含 `name`,支持中文、英文、数字、空格、中划线、下划线组合。

* 可以包含 `description`,对参数进行描述。

* 必须包含 `parameters`。

* 必须包含 `required`,内容不可以为 `properties` 下参数名之外的参数名。

* 可以包含 `order`,若写必须为 `properties` 下所有参数名的列表;若不写,则默认按照 `properties` 下所有参数名的顺序。

* 必须包含 `return`,`return` 字段是出参。

## 表单预览图

* 名称: form.jpg/png/jpeg

* 大小: 不超过 1M

## 打包规则

* 包含 build/、config.json、form.png

* 将build文件夹、config.json、form.png打成zip压缩包,压缩包名称支持大小写英文、中文和数字的字符串,可以包含中划线(-)和下划线(_),但不能以中划线(-)和下划线(_)开头或结尾。
48 changes: 48 additions & 0 deletions app-builder/builtin/form/model-config-form/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"schema": {
"name": "模型管理表单",
"parameters": {
"type": "object",
"required": ["models"],
"properties": {
"models": {
"type": "array",
"items": {
"type": "object",
"properties": {
"createdAt": { "type": "string" },
"modelName": { "type": "string" },
"modelId": { "type": "string" },
"baseUrl": { "type": "string" },
"isDefault": { "type": "integer" },
"userId": { "type": "string" }
},
"required": ["modelId", "isDefault", "userId"]
}
}
}
},
"return": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["add", "delete", "switch", "quit"]
},
"info": {
"type": "object",
"properties": {
"modelName": { "type": "string" },
"modelId": { "type": "string" },
"baseUrl": { "type": "string" },
"isDefault": { "type": "integer" },
"userId": { "type": "string" },
"apiKey": { "type": "string" }
},
"required": ["modelName", "modelId", "baseUrl", "isDefault", "userId", "apiKey"]
}
},
"required": ["action", "info"]
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions app-builder/builtin/form/model-config-form/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "remote-component",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack serve --progress --profile --mode development --host 127.0.0.1 --port 3351 --config webpack.dev.js",
"build": "webpack --mode production --config webpack.prod.js"
},
"license": "ISC",
"devDependencies": {
"@ant-design/icons": "4.8.3",
"@babel/core": "^7.20.12",
"@babel/plugin-transform-runtime": "^7.12.17",
"@babel/preset-env": "^7.12.13",
"@babel/preset-react": "^7.12.13",
"@babel/preset-typescript": "^7.24.7",
"@types/node": "^20.12.12",
"@types/react": "^18.2.74",
"@types/react-dom": "^16.9.2",
"babel-loader": "^8.2.2",
"babel-plugin-dynamic-import-webpack": "^1.1.0",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^10.2.0",
"css-loader": "^6.8.1",
"cssnano": "^5.1.15",
"eslint": "^7.32.0",
"file-loader": "^6.2.0",
"happypack": "^5.0.1",
"html-webpack-plugin": "^5.5.0",
"less": "4.2.0",
"less-loader": "12.2.0",
"lodash": "4.17.21",
"mini-css-extract-plugin": "^1.6.2",
"postcss-import": "^14.0.0",
"postcss-loader": "^4.0.4",
"prettier": "3.2.5",
"sass": "^1.69.5",
"sass-loader": "^13.3.2",
"style-loader": "^2.0.0",
"typescript": "^5.4.5",
"uglifyjs-webpack-plugin": "^2.2.0",
"url-loader": "^4.1.1",
"webpack": "5.89.0",
"webpack-cli": "5.1.4",
"webpack-dev-server": "4.15.1",
"webpack-merge": "5.10.0",
"webpack-subresource-integrity": "5.1.0"
},
"dependencies": {
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"antd": "4.24.13",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-i18next": "^11.8.13",
"uuid": "^11.1.0"
}
}
71 changes: 71 additions & 0 deletions app-builder/builtin/form/model-config-form/src/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*************************************************请勿修改或删除该文件**************************************************/
import React, { useState, useEffect, useRef } from 'react';
import { inIframe, getQueryParams } from './utils/index';
import { DataContext } from './context';
import Form from './components/form';

export default function App() {
const [receiveData, setReceiveData] = useState<any>({});
const uniqueId = getQueryParams(window.location.href);
const formRef = useRef<HTMLDivElement>(null);

const handleMessage = (event: any) => {
setReceiveData(event.data);
};

const terminateClick = (params: any) => {
window.parent.postMessage({ type: 'app-engine-form-terminate', ...params, uniqueId }, receiveData.origin);
};

const resumingClick = (params: any) => {
window.parent.postMessage({ type: 'app-engine-form-resuming', ...params, uniqueId }, receiveData.origin);
};

const restartClick = (params: any) => {
window.parent.postMessage({ type: 'app-engine-form-restart', ...params, uniqueId }, receiveData.origin);
};

useEffect(() => {
if (inIframe()) {
window.addEventListener('message', handleMessage);
window.parent.postMessage({
type: 'app-engine-form-ready',
uniqueId
}, '*');
}

const ro = new ResizeObserver(entries => {
entries.forEach(entry => {
const height = entry.contentRect.height;
window.parent.postMessage({ type: 'app-engine-form-resize', height, uniqueId }, "*");
});
});

if (formRef.current) {
ro.observe(formRef.current);
}

return () => {
if (inIframe()) {
window.removeEventListener('message', handleMessage);
}

if (formRef.current) {
ro.unobserve(formRef.current);
}
ro.disconnect();
};
}, []);

return (
<div
className="form-wrap"
id="custom-smart-form"
ref={formRef}
>
<DataContext.Provider value={{ ...receiveData, terminateClick, resumingClick, restartClick }}>
<Form />
</DataContext.Provider>
</div>
);
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading