Skip to content

Commit 6124190

Browse files
xlorneclaude
andcommitted
feat: 新增 toolbar 按钮列表属性 + 规范化 ToolbarButtonProps 命名
- 新增 ScriptCodeEditorProps.toolbar (ToolbarItem[]) 支持以数组形式声明自定义工具栏按钮 - 将 ToolbarButtonProps 移至 types/index.ts 统一管理并添加中文注释 - 规范化属性命名:bg→backgroundColor、hoverBg→hoverBackgroundColor、color→textColor、border→borderColor - 提取 meta.json 为独立文件,版本号升级至 0.0.4 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 69d86cc commit 6124190

10 files changed

Lines changed: 172 additions & 36 deletions

File tree

apps/app-pc/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@script-example/app-pc",
3-
"version": "0.0.3",
3+
"version": "0.0.4",
44
"private": true,
55
"type": "module",
66
"scripts": {

apps/app-pc/src/pages/home.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { ScriptCodeEditor } from '@coding-script/script-engine';
2-
import type { ScriptMetadata } from '@coding-script/script-engine';
2+
import sampleMetadata from './meta.json';
33
import { message } from 'antd';
44

5-
const sampleMetadata: ScriptMetadata = JSON.parse(`{"binds":[{"dataType":"GroovyBindObject","name":"$request"}],"description":"run 函数是脚本的主入口,由引擎在每次任务触发时自动调用。\\n\\n参数说明:\\n - request: MyScriptRequest 类型,包含本次请求携带的所有业务字段。\\n\\n返回值:Integer 类型,表示本次执行的结果状态码。\\n - 0 表示成功\\n - 1 表示参数校验失败\\n - 2 表示业务逻辑异常\\n\\n注意事项:\\n 1. 函数内部可以通过 $request 访问全局注入对象,获取上下文环境信息(如租户 ID、用户身份等)。\\n 2. 请勿在函数内执行耗时超过 5 秒的同步操作,否则引擎会触发超时中断并记录告警日志。\\n 3. 所有对 request 字段的访问应提前做非空判断,避免 NullPointerException 导致整个任务失败。\\n 4. 若需要调用外部 HTTP 接口,请使用内置的 httpUtil 工具类,而非直接 new URL 连接,以确保连接池复用与超时管控生效。","mainMethod":"run","requests":[{"dataType":"MyScriptRequest","description":"我的测试对象","name":"request"}],"returnType":"Integer","types":{"MyScriptRequest":{"dataType":"MyScriptRequest","description":"我的测试对象","fields":[{"dataType":"int","description":"总数量","name":"count"},{"dataType":"MyTest","description":"test","name":"test"}],"functions":[{"description":"是否匹配","name":"isSupport","parameters":[{"dataType":"int","description":"描述信息","name":"count"}]}]},"Integer":{"dataType":"Integer","fields":[],"functions":[]},"boolean":{"dataType":"boolean","fields":[],"functions":[]},"Long":{"dataType":"Long","fields":[],"functions":[]},"String":{"dataType":"String","fields":[],"functions":[]},"MyTest":{"dataType":"MyTest","description":"test","fields":[{"dataType":"Long","description":"id","name":"id"},{"dataType":"String","description":"name","name":"name"}],"functions":[]},"int":{"dataType":"int","fields":[],"functions":[]}}}`);
65

76
const sampleCode = `def run(request){
87
println($request.count);

apps/app-pc/src/pages/meta.json

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
{
2+
"binds": [
3+
{
4+
"dataType": "GroovyBindObject",
5+
"name": "$request"
6+
}
7+
],
8+
"description": "run 函数是脚本的主入口,由引擎在每次任务触发时自动调用。\\n\\n参数说明:\\n - request: MyScriptRequest 类型,包含本次请求携带的所有业务字段。\\n\\n返回值:Integer 类型,表示本次执行的结果状态码。\\n - 0 表示成功\\n - 1 表示参数校验失败\\n - 2 表示业务逻辑异常\\n\\n注意事项:\\n 1. 函数内部可以通过 $request 访问全局注入对象,获取上下文环境信息(如租户 ID、用户身份等)。\\n 2. 请勿在函数内执行耗时超过 5 秒的同步操作,否则引擎会触发超时中断并记录告警日志。\\n 3. 所有对 request 字段的访问应提前做非空判断,避免 NullPointerException 导致整个任务失败。\\n 4. 若需要调用外部 HTTP 接口,请使用内置的 httpUtil 工具类,而非直接 new URL 连接,以确保连接池复用与超时管控生效。",
9+
"mainMethod": "run",
10+
"requests": [
11+
{
12+
"dataType": "MyScriptRequest",
13+
"description": "我的测试对象",
14+
"name": "request"
15+
}
16+
],
17+
"returnType": "Integer",
18+
"types": {
19+
"MyScriptRequest": {
20+
"dataType": "MyScriptRequest",
21+
"description": "我的测试对象",
22+
"fields": [
23+
{
24+
"dataType": "int",
25+
"description": "总数量",
26+
"name": "get('count')"
27+
},
28+
{
29+
"dataType": "MyTest",
30+
"description": "test",
31+
"name": "test"
32+
}
33+
],
34+
"functions": [
35+
{
36+
"description": "是否匹配",
37+
"name": "isSupport",
38+
"parameters": [
39+
{
40+
"dataType": "int",
41+
"description": "描述信息",
42+
"name": "count"
43+
}
44+
]
45+
}
46+
]
47+
},
48+
"Integer": {
49+
"dataType": "Integer",
50+
"fields": [],
51+
"functions": []
52+
},
53+
"boolean": {
54+
"dataType": "boolean",
55+
"fields": [],
56+
"functions": []
57+
},
58+
"Long": {
59+
"dataType": "Long",
60+
"fields": [],
61+
"functions": []
62+
},
63+
"String": {
64+
"dataType": "String",
65+
"fields": [],
66+
"functions": []
67+
},
68+
"MyTest": {
69+
"dataType": "MyTest",
70+
"description": "test",
71+
"fields": [
72+
{
73+
"dataType": "Long",
74+
"description": "id",
75+
"name": "id"
76+
},
77+
{
78+
"dataType": "String",
79+
"description": "name",
80+
"name": "name"
81+
}
82+
],
83+
"functions": []
84+
},
85+
"int": {
86+
"dataType": "int",
87+
"fields": [],
88+
"functions": []
89+
}
90+
}
91+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@coding-script/root",
3-
"version": "0.0.3",
3+
"version": "0.0.4",
44
"description": "script-engine",
55
"main": "index.js",
66
"scripts": {

packages/script-engine/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@coding-script/script-engine",
3-
"version": "0.0.3",
3+
"version": "0.0.4",
44
"description": "script-engine components",
55
"keywords": [
66
"coding-script",

packages/script-engine/src/components/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export { themes, SCROLL_CLASS, ensureScrollbarStyle } from './theme-colors';
22
export type { ThemeColors } from './theme-colors';
33
export { ToolbarButton } from './toolbar-button';
4-
export type { ToolbarButtonProps } from './toolbar-button';
4+
export type { ToolbarButtonProps } from '../types';
55
export { Toolbar } from './toolbar';
66
export type { ToolbarProps } from './toolbar';
77
export { ExpandSidebarButton } from './expand-sidebar-button';

packages/script-engine/src/components/toolbar-button.tsx

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import React, { useState } from 'react';
2+
import type { ToolbarButtonProps } from '../types';
23

3-
export interface ToolbarButtonProps {
4-
label: React.ReactNode;
5-
title: string;
6-
bg: string;
7-
hoverBg: string;
8-
color: string;
9-
border: string;
10-
onClick: () => void;
11-
}
12-
13-
export const ToolbarButton: React.FC<ToolbarButtonProps> = ({ label, title, bg, hoverBg, color, border, onClick }) => {
4+
export const ToolbarButton: React.FC<ToolbarButtonProps> = ({
5+
label,
6+
title,
7+
backgroundColor,
8+
hoverBackgroundColor,
9+
textColor,
10+
borderColor,
11+
onClick,
12+
}) => {
1413
const [hovered, setHovered] = useState(false);
1514
return (
1615
<button
@@ -21,9 +20,9 @@ export const ToolbarButton: React.FC<ToolbarButtonProps> = ({ label, title, bg,
2120
display: 'inline-flex',
2221
alignItems: 'center',
2322
gap: 4,
24-
background: hovered ? hoverBg : bg,
25-
border: `1px solid ${border}`,
26-
color,
23+
background: hovered ? hoverBackgroundColor : backgroundColor,
24+
border: `1px solid ${borderColor}`,
25+
color: textColor,
2726
cursor: 'pointer',
2827
fontSize: 12,
2928
padding: '4px 10px',

packages/script-engine/src/components/toolbar.tsx

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import { ToolbarButton } from './toolbar-button';
33
import { FormatIcon } from './format-icon';
44
import { MaximizeIcon, MinimizeIcon } from './fullscreen-icon';
5+
import type { ToolbarItem } from '../types';
56

67
// 锤子图标(编译/构建)
78
const HammerIcon: React.FC<{ color: string }> = ({ color }) => (
@@ -42,6 +43,7 @@ export interface ToolbarProps {
4243
enableFullscreen?: boolean;
4344
isFullscreen?: boolean;
4445
onToggleFullscreen?: () => void;
46+
toolbar?: ToolbarItem[];
4547
toolbarExtra?: React.ReactNode;
4648
}
4749

@@ -57,6 +59,7 @@ export const Toolbar: React.FC<ToolbarProps> = ({
5759
enableFullscreen,
5860
isFullscreen,
5961
onToggleFullscreen,
62+
toolbar,
6063
toolbarExtra,
6164
}) => {
6265
const isDark = theme === 'dark';
@@ -105,10 +108,10 @@ export const Toolbar: React.FC<ToolbarProps> = ({
105108
<ToolbarButton
106109
label={isDark ? '🌞 浅色模式' : '🌙 深色模式'}
107110
title={isDark ? '切换到浅色主题' : '切换到深色主题'}
108-
bg={btnBg}
109-
hoverBg={btnHoverBg}
110-
color={toolbarText}
111-
border={borderColor}
111+
backgroundColor={btnBg}
112+
hoverBackgroundColor={btnHoverBg}
113+
textColor={toolbarText}
114+
borderColor={borderColor}
112115
onClick={handleThemeToggle}
113116
/>
114117
)}
@@ -122,10 +125,10 @@ export const Toolbar: React.FC<ToolbarProps> = ({
122125
</>
123126
}
124127
title="格式化代码"
125-
bg={isDark ? '#1e3a5f' : '#e6f4ff'}
126-
hoverBg={isDark ? '#264a73' : '#bae0ff'}
127-
color={isDark ? '#61afef' : '#1677ff'}
128-
border={isDark ? '#1e3a5f' : '#91caff'}
128+
backgroundColor={isDark ? '#1e3a5f' : '#e6f4ff'}
129+
hoverBackgroundColor={isDark ? '#264a73' : '#bae0ff'}
130+
textColor={isDark ? '#61afef' : '#1677ff'}
131+
borderColor={isDark ? '#1e3a5f' : '#91caff'}
129132
onClick={onFormat}
130133
/>
131134
)}
@@ -139,10 +142,10 @@ export const Toolbar: React.FC<ToolbarProps> = ({
139142
</>
140143
}
141144
title="编译并验证脚本"
142-
bg={isDark ? '#2d5a27' : '#e6f4e5'}
143-
hoverBg={isDark ? '#3a7033' : '#d4ecd3'}
144-
color={isDark ? '#98c379' : '#389e0d'}
145-
border={isDark ? '#2d5a27' : '#b7eb8f'}
145+
backgroundColor={isDark ? '#2d5a27' : '#e6f4e5'}
146+
hoverBackgroundColor={isDark ? '#3a7033' : '#d4ecd3'}
147+
textColor={isDark ? '#98c379' : '#389e0d'}
148+
borderColor={isDark ? '#2d5a27' : '#b7eb8f'}
146149
onClick={onCompile}
147150
/>
148151
)}
@@ -160,14 +163,28 @@ export const Toolbar: React.FC<ToolbarProps> = ({
160163
</>
161164
}
162165
title={isFullscreen ? '退出全屏(ESC)' : '全屏显示'}
163-
bg={isDark ? '#3a2d5a' : '#f3e8ff'}
164-
hoverBg={isDark ? '#4a3d6a' : '#e9d5ff'}
165-
color={isDark ? '#c678dd' : '#722ed1'}
166-
border={isDark ? '#3a2d5a' : '#d3adf7'}
166+
backgroundColor={isDark ? '#3a2d5a' : '#f3e8ff'}
167+
hoverBackgroundColor={isDark ? '#4a3d6a' : '#e9d5ff'}
168+
textColor={isDark ? '#c678dd' : '#722ed1'}
169+
borderColor={isDark ? '#3a2d5a' : '#d3adf7'}
167170
onClick={() => onToggleFullscreen?.()}
168171
/>
169172
)}
170173

174+
{/* 自定义工具栏按钮列表 */}
175+
{toolbar?.map((item) => (
176+
<ToolbarButton
177+
key={item.key}
178+
label={item.label}
179+
title={item.title}
180+
backgroundColor={item.backgroundColor}
181+
hoverBackgroundColor={item.hoverBackgroundColor}
182+
textColor={item.textColor}
183+
borderColor={item.borderColor}
184+
onClick={item.onClick}
185+
/>
186+
))}
187+
171188
{/* 自定义工具栏内容 */}
172189
{toolbarExtra}
173190
</div>

packages/script-engine/src/script-code.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ export const ScriptCodeEditor: React.FC<ScriptCodeEditorProps> = (props) => {
171171
enableFormat,
172172
enableCompile,
173173
enableFullscreen,
174+
toolbar,
174175
toolbarExtra,
175176
options = {},
176177
} = props;
@@ -387,6 +388,7 @@ export const ScriptCodeEditor: React.FC<ScriptCodeEditorProps> = (props) => {
387388
enableFullscreen={enableFullscreen}
388389
isFullscreen={isFullscreen}
389390
onToggleFullscreen={() => setIsFullscreen((prev) => !prev)}
391+
toolbar={toolbar}
390392
toolbarExtra={toolbarExtra}
391393
/>
392394

packages/script-engine/src/types/index.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
import type React from 'react';
22

3+
// ── 工具栏按钮 ────────────────────────────────────────────────
4+
5+
/** 工具栏按钮属性 */
6+
export interface ToolbarButtonProps {
7+
/** 按钮内容(支持 ReactNode,可包含图标 + 文字) */
8+
label: React.ReactNode;
9+
/** 鼠标悬停提示文字(原生 title 属性) */
10+
title: string;
11+
/** 按钮背景色 */
12+
backgroundColor: string;
13+
/** 鼠标悬停时的背景色 */
14+
hoverBackgroundColor: string;
15+
/** 文字颜色 */
16+
textColor: string;
17+
/** 边框颜色 */
18+
borderColor: string;
19+
/** 点击回调 */
20+
onClick: () => void;
21+
}
22+
23+
/** 工具栏自定义按钮项(用于 toolbar 数组) */
24+
export interface ToolbarItem extends ToolbarButtonProps {
25+
/** 唯一标识(React key) */
26+
key: string;
27+
}
28+
329
// ── 脚本元数据 Schema ──────────────────────────────────────────
430

531
/** 函数参数信息 */
@@ -121,6 +147,8 @@ export interface ScriptCodeEditorProps {
121147
onCompile?: (code: string) => void;
122148

123149
// ── 自定义工具栏内容 ──────────────────────────────────────
150+
/** 工具栏自定义按钮列表(渲染在内置按钮之后) */
151+
toolbar?: ToolbarItem[];
124152
/** 工具栏额外内容(渲染在内置按钮之后,任意 React 节点) */
125153
toolbarExtra?: React.ReactNode;
126154

0 commit comments

Comments
 (0)