Skip to content

Commit 8cba741

Browse files
lizhichao51lizhichao51
andauthored
[app-builder] 新增模型配置表单 (#176)
* [app-builder] 新增模型配置表单 * [app-platform] 模型配置表单修改检视意见,提取行内样式 * [app-platform] 修改readme文件的样式 * [app-platform] 修改readme文件的行内引用样式 * [app-platform] 文件不应该忽略index.html --------- Co-authored-by: lizhichao51 <lizhichao51@noreply.gitcode.com>
1 parent eed68d6 commit 8cba741

File tree

16 files changed

+884
-0
lines changed

16 files changed

+884
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package-lock.json
2+
node_modules/
3+
output/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
strict-ssl=false
2+
package-lock=true
3+
registry=https://registry.npmjs.org/
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# 画布 # 自定义组件开发说明
2+
3+
## 前提条件
4+
5+
* 开发工具建议使用 VSCode
6+
7+
* 基础环境: Node.js 版本 >= 18, npm 版本 >= 10
8+
9+
* React 组件建议使用 Ant Design (版本: 4.24.13)
10+
11+
## 操作步骤
12+
13+
### 约束条件
14+
15+
上传的组件包必须是 zip 压缩包,解压后文件大小不得超过 5M,且必须包含三部分:
16+
17+
* build 文件夹: 表单代码打包后的静态资源
18+
19+
* config.json: 表单的输入输出参配置文件
20+
21+
* form.jpg/png/jpeg: 表单预览图,大小不得超过 1M
22+
23+
## 开发组件代码
24+
25+
### 创建文件
26+
27+
*`/src/components` 目录下创建 `.tsx` 类型的组件文件
28+
29+
### 表单获取流程数据
30+
31+
用于初始化表单数据:
32+
33+
```tsx
34+
const { data, terminateClick, resumingClick, restartClick } = useContext(DataContext);
35+
```
36+
37+
`data` 为 json 数据,结构与 config.json 的输入参配置一致
38+
39+
### 表单调用内置接口
40+
41+
**1. 终止对话 `terminateClick()`**
42+
43+
```tsx
44+
<Button onClick={onTerminateClick}>终止对话</Button>
45+
46+
const onTerminateClick = () => {
47+
terminateClick({ content: "终止会话" });
48+
}
49+
```
50+
51+
**注意:结束节点不能调用 `terminateClick`**
52+
53+
**2. 继续对话 `resumingClick()`**
54+
55+
```tsx
56+
<Button onClick={onResumeClick}>继续对话</Button>
57+
58+
const onResumeClick = () => {
59+
resumingClick({ params: { a: "hello", b: 1 } });
60+
}
61+
```
62+
63+
**注意:结束节点不能调用 `resumingClick`**
64+
65+
**3. 重新对话 `restartClick()`**
66+
67+
```tsx
68+
<Button onClick={onRestartClick}>重新对话</Button>
69+
70+
const onRestartClick = () => {
71+
restartClick({ params: { a: "hello", b: 1 } });
72+
}
73+
```
74+
75+
**注意:如果在智能表单节点使用,需先调 `terminateClick``restartClick`**
76+
77+
### 调用外部接口
78+
79+
* 要求接口支持跨域
80+
81+
### 使用图片
82+
83+
* 图片文件放在 `/src/assets/images`
84+
85+
* 路径: `./src/assets/images/xxx.png`
86+
87+
```tsx
88+
<img src="./src/assets/images/empty.png" alt="" height="100px" width="100px"/>
89+
```
90+
91+
### 表单样式文件
92+
93+
* 可以在 `/src/styles` 目录下添加 `.scss` 样式文件
94+
95+
### 调试表单
96+
97+
```bash
98+
npm install
99+
npm start
100+
```
101+
102+
* 模拟数据 `app.tsx`:
103+
104+
```ts
105+
receiveData: {
106+
data: { a: "你好", b: "Demo1" },
107+
uniqueId: 10,
108+
origin: "http://127.0.0.1:3350",
109+
tenantId: "fh47kl"
110+
}
111+
```
112+
113+
### 打包
114+
115+
```bash
116+
npm run build
117+
```
118+
119+
## 表单输入输出参 config.json
120+
121+
### 基础规范
122+
123+
* 格式需符合[json schema规范](https://json-schema.apifox.cn/)
124+
125+
* 格式示例:
126+
127+
```json
128+
{
129+
"schema": {
130+
"parameters": {
131+
"type": "object",
132+
"required": ["a", "b"],
133+
"properties": {
134+
"a": { "type": "string", "default": "haha" },
135+
"b": { "type": "string", "default": "heihei" }
136+
}
137+
},
138+
"return": {
139+
"type": "object",
140+
"properties": {
141+
"a": { "type": "string" },
142+
"b": { "type": "string" }
143+
}
144+
}
145+
}
146+
}
147+
```
148+
149+
* 最外层 `parameters` 字段是入参,入参第一层必须 `type``object`
150+
151+
* 必须包含 `name`,支持中文、英文、数字、空格、中划线、下划线组合。
152+
153+
* 可以包含 `description`,对参数进行描述。
154+
155+
* 必须包含 `parameters`
156+
157+
* 必须包含 `required`,内容不可以为 `properties` 下参数名之外的参数名。
158+
159+
* 可以包含 `order`,若写必须为 `properties` 下所有参数名的列表;若不写,则默认按照 `properties` 下所有参数名的顺序。
160+
161+
* 必须包含 `return``return` 字段是出参。
162+
163+
## 表单预览图
164+
165+
* 名称: form.jpg/png/jpeg
166+
167+
* 大小: 不超过 1M
168+
169+
## 打包规则
170+
171+
* 包含 build/、config.json、form.png
172+
173+
* 将build文件夹、config.json、form.png打成zip压缩包,压缩包名称支持大小写英文、中文和数字的字符串,可以包含中划线(-)和下划线(_),但不能以中划线(-)和下划线(_)开头或结尾。
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"schema": {
3+
"name": "模型管理表单",
4+
"parameters": {
5+
"type": "object",
6+
"required": ["models"],
7+
"properties": {
8+
"models": {
9+
"type": "array",
10+
"items": {
11+
"type": "object",
12+
"properties": {
13+
"createdAt": { "type": "string" },
14+
"modelName": { "type": "string" },
15+
"modelId": { "type": "string" },
16+
"baseUrl": { "type": "string" },
17+
"isDefault": { "type": "integer" },
18+
"userId": { "type": "string" }
19+
},
20+
"required": ["modelId", "isDefault", "userId"]
21+
}
22+
}
23+
}
24+
},
25+
"return": {
26+
"type": "object",
27+
"properties": {
28+
"action": {
29+
"type": "string",
30+
"enum": ["add", "delete", "switch", "quit"]
31+
},
32+
"info": {
33+
"type": "object",
34+
"properties": {
35+
"modelName": { "type": "string" },
36+
"modelId": { "type": "string" },
37+
"baseUrl": { "type": "string" },
38+
"isDefault": { "type": "integer" },
39+
"userId": { "type": "string" },
40+
"apiKey": { "type": "string" }
41+
},
42+
"required": ["modelName", "modelId", "baseUrl", "isDefault", "userId", "apiKey"]
43+
}
44+
},
45+
"required": ["action", "info"]
46+
}
47+
}
48+
}
50.7 KB
Loading
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"name": "remote-component",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"start": "webpack serve --progress --profile --mode development --host 127.0.0.1 --port 3351 --config webpack.dev.js",
8+
"build": "webpack --mode production --config webpack.prod.js"
9+
},
10+
"license": "ISC",
11+
"devDependencies": {
12+
"@ant-design/icons": "4.8.3",
13+
"@babel/core": "^7.20.12",
14+
"@babel/plugin-transform-runtime": "^7.12.17",
15+
"@babel/preset-env": "^7.12.13",
16+
"@babel/preset-react": "^7.12.13",
17+
"@babel/preset-typescript": "^7.24.7",
18+
"@types/node": "^20.12.12",
19+
"@types/react": "^18.2.74",
20+
"@types/react-dom": "^16.9.2",
21+
"babel-loader": "^8.2.2",
22+
"babel-plugin-dynamic-import-webpack": "^1.1.0",
23+
"clean-webpack-plugin": "^3.0.0",
24+
"copy-webpack-plugin": "^10.2.0",
25+
"css-loader": "^6.8.1",
26+
"cssnano": "^5.1.15",
27+
"eslint": "^7.32.0",
28+
"file-loader": "^6.2.0",
29+
"happypack": "^5.0.1",
30+
"html-webpack-plugin": "^5.5.0",
31+
"less": "4.2.0",
32+
"less-loader": "12.2.0",
33+
"lodash": "4.17.21",
34+
"mini-css-extract-plugin": "^1.6.2",
35+
"postcss-import": "^14.0.0",
36+
"postcss-loader": "^4.0.4",
37+
"prettier": "3.2.5",
38+
"sass": "^1.69.5",
39+
"sass-loader": "^13.3.2",
40+
"style-loader": "^2.0.0",
41+
"typescript": "^5.4.5",
42+
"uglifyjs-webpack-plugin": "^2.2.0",
43+
"url-loader": "^4.1.1",
44+
"webpack": "5.89.0",
45+
"webpack-cli": "5.1.4",
46+
"webpack-dev-server": "4.15.1",
47+
"webpack-merge": "5.10.0",
48+
"webpack-subresource-integrity": "5.1.0"
49+
},
50+
"dependencies": {
51+
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
52+
"antd": "4.24.13",
53+
"react": "^18.1.0",
54+
"react-dom": "^18.1.0",
55+
"react-i18next": "^11.8.13",
56+
"uuid": "^11.1.0"
57+
}
58+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*************************************************请勿修改或删除该文件**************************************************/
2+
import React, { useState, useEffect, useRef } from 'react';
3+
import { inIframe, getQueryParams } from './utils/index';
4+
import { DataContext } from './context';
5+
import Form from './components/form';
6+
7+
export default function App() {
8+
const [receiveData, setReceiveData] = useState<any>({});
9+
const uniqueId = getQueryParams(window.location.href);
10+
const formRef = useRef<HTMLDivElement>(null);
11+
12+
const handleMessage = (event: any) => {
13+
setReceiveData(event.data);
14+
};
15+
16+
const terminateClick = (params: any) => {
17+
window.parent.postMessage({ type: 'app-engine-form-terminate', ...params, uniqueId }, receiveData.origin);
18+
};
19+
20+
const resumingClick = (params: any) => {
21+
window.parent.postMessage({ type: 'app-engine-form-resuming', ...params, uniqueId }, receiveData.origin);
22+
};
23+
24+
const restartClick = (params: any) => {
25+
window.parent.postMessage({ type: 'app-engine-form-restart', ...params, uniqueId }, receiveData.origin);
26+
};
27+
28+
useEffect(() => {
29+
if (inIframe()) {
30+
window.addEventListener('message', handleMessage);
31+
window.parent.postMessage({
32+
type: 'app-engine-form-ready',
33+
uniqueId
34+
}, '*');
35+
}
36+
37+
const ro = new ResizeObserver(entries => {
38+
entries.forEach(entry => {
39+
const height = entry.contentRect.height;
40+
window.parent.postMessage({ type: 'app-engine-form-resize', height, uniqueId }, "*");
41+
});
42+
});
43+
44+
if (formRef.current) {
45+
ro.observe(formRef.current);
46+
}
47+
48+
return () => {
49+
if (inIframe()) {
50+
window.removeEventListener('message', handleMessage);
51+
}
52+
53+
if (formRef.current) {
54+
ro.unobserve(formRef.current);
55+
}
56+
ro.disconnect();
57+
};
58+
}, []);
59+
60+
return (
61+
<div
62+
className="form-wrap"
63+
id="custom-smart-form"
64+
ref={formRef}
65+
>
66+
<DataContext.Provider value={{ ...receiveData, terminateClick, resumingClick, restartClick }}>
67+
<Form />
68+
</DataContext.Provider>
69+
</div>
70+
);
71+
}
3.67 KB
Loading

0 commit comments

Comments
 (0)