Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 additions & 0 deletions app-builder/builtin/form/model-config-form/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package-lock.json
index.html
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",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

确认是否用到?包超大

"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",
Copy link
Copy Markdown
Member

@wjn1584 wjn1584 May 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个依赖没有用到,并且存在漏洞,删掉吧

"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