@hr-components-dev/cli 1.1.5 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -4
- package/src/amis/components/hr-editor/index.ts +126 -0
- package/src/amis/components/hr-form-editor/index.ts +53 -0
- package/src/amis/components/utils/evalScope.ts +141 -0
- package/src/amis/components/utils/index.ts +4 -0
- package/src/amis/components/utils/registerAmisComponent.ts +27 -0
- package/src/amis/components/utils/setupAmisConfig.ts +25 -0
- package/src/main.ts +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hr-components-dev/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -32,9 +32,7 @@
|
|
|
32
32
|
"vite.config.ts",
|
|
33
33
|
"index.html",
|
|
34
34
|
"tsconfig.build.json",
|
|
35
|
-
"
|
|
36
|
-
"!**/*.tsx",
|
|
37
|
-
"!scripts/**/*.ts",
|
|
35
|
+
"!src/scripts/**/*.ts",
|
|
38
36
|
"!**/*.test.js",
|
|
39
37
|
"!**/*.spec.js"
|
|
40
38
|
],
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { FormControlProps } from 'amis';
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 表单校验 组件 FormItem
|
|
6
|
+
* @param props
|
|
7
|
+
* @returns
|
|
8
|
+
// */
|
|
9
|
+
const EditorComponent = (_p: amis.AmisComponentPropsType) => {
|
|
10
|
+
const throttledSuccessMessage = _.throttle(() =>
|
|
11
|
+
_p.amisUI.toast.success('hr-editor 代码校验完成!')
|
|
12
|
+
, 3000);
|
|
13
|
+
// 修改节流函数,接受错误对象作为参数
|
|
14
|
+
const throttledFailedMessage = _.throttle((o: any, title: string) => {
|
|
15
|
+
_p.amisUI.toast.error(
|
|
16
|
+
`${o.startLineNumber}行${o.startColumn}列,【${o.owner}】错误`,
|
|
17
|
+
{
|
|
18
|
+
body: `错误: ${o.message}\n\n${title}\n${o.label}`,
|
|
19
|
+
timeout: 5000,
|
|
20
|
+
position: "top-right"
|
|
21
|
+
});
|
|
22
|
+
}, 1000);
|
|
23
|
+
const $EditorList: any = {};
|
|
24
|
+
const $MonacoList: any = {};
|
|
25
|
+
|
|
26
|
+
return (p: FormControlProps) => {
|
|
27
|
+
const [errors, setError] = _p.react.useState<any>([]);
|
|
28
|
+
const [name, setName] = _p.react.useState<any>(p.name);
|
|
29
|
+
const [label, setLabel] = _p.react.useState<any>(p.label);
|
|
30
|
+
const [editorOncahnge, setEditorOnchange] = _p.react.useState<any>(false);
|
|
31
|
+
|
|
32
|
+
const get_peditor = () => $EditorList[name];
|
|
33
|
+
const get_pmonaco = () => $MonacoList[name];
|
|
34
|
+
|
|
35
|
+
_p.amislib.addRule(
|
|
36
|
+
`Validat-${p.name}`, // 校验名
|
|
37
|
+
(_values: any, _value: string) => {
|
|
38
|
+
// 查找value对应的key
|
|
39
|
+
|
|
40
|
+
// 校验函数,values 是表单里所有表单项的值,可用于做联合校验;value 是当前表单项的值
|
|
41
|
+
const markers: Array<any> = get_pmonaco()?.editor?.getModelMarkers({ resource: get_peditor().getModel().uri })
|
|
42
|
+
.filter((marker: { severity: any }) => marker.severity === get_pmonaco().MarkerSeverity.Error);
|
|
43
|
+
setError(markers);
|
|
44
|
+
return markers?.length === 0;
|
|
45
|
+
},
|
|
46
|
+
`语法共有${errors?.length}处错误,例: ${errors?.at(0)?.message ?? ''} ,请检查` // 出错时的报错信息
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
_p.react.useEffect(() => {
|
|
50
|
+
if (errors?.length > 0) {
|
|
51
|
+
errors?.forEach((o: any, _i: number) => {
|
|
52
|
+
// 调用节流函数时传递错误对象参数
|
|
53
|
+
throttledFailedMessage({ ...o, label }, `共:${errors.length}处`);
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
throttledSuccessMessage();
|
|
57
|
+
}
|
|
58
|
+
}, [errors]);
|
|
59
|
+
|
|
60
|
+
return p.render(
|
|
61
|
+
'body',
|
|
62
|
+
{
|
|
63
|
+
required: true,
|
|
64
|
+
allowFullscreen: true,
|
|
65
|
+
disabled: false,
|
|
66
|
+
language: 'json',
|
|
67
|
+
autoParseJSON: true,
|
|
68
|
+
options: {
|
|
69
|
+
automaticLayout: true,
|
|
70
|
+
disableLayerHinting: true,
|
|
71
|
+
formatOnPaste: true,
|
|
72
|
+
minimap: {
|
|
73
|
+
enabled: true
|
|
74
|
+
},
|
|
75
|
+
renderFinalNewline: true,
|
|
76
|
+
lineNumbersMinChars: 1, // 行号最小宽度
|
|
77
|
+
glyphMargin: true, // 显示glyph margin
|
|
78
|
+
renderLineHighlight: 'all',
|
|
79
|
+
renderSideBySide: true,
|
|
80
|
+
scrollBeyondLastLine: false,
|
|
81
|
+
selectOnLineNumbers: true,
|
|
82
|
+
theme: 'vs',
|
|
83
|
+
wordWrapBreakAfterCharacters: ',',
|
|
84
|
+
wordWrapBreakBeforeCharacters: ',',
|
|
85
|
+
// 新增配置项
|
|
86
|
+
fontSize: 19,
|
|
87
|
+
fontFamily: '微软雅黑',
|
|
88
|
+
cursorStyle: 'line', // 光标样式: 'line', 'block', 'underline'
|
|
89
|
+
cursorBlinking: 'smooth', // 光标闪烁: 'blink', 'smooth', 'phase', 'expand', 'solid'
|
|
90
|
+
cursorSmoothCaretAnimation: true // 平滑插入动画
|
|
91
|
+
},
|
|
92
|
+
...p.$schema,
|
|
93
|
+
editorDidMount: (editor: any, monaco: any) => {
|
|
94
|
+
setEditorOnchange(true);
|
|
95
|
+
const changeListener = editor.onDidChangeModelContent(() => {
|
|
96
|
+
setLabel(`字段: ${p.label.split(' ').slice(0, 2).join(' ')}`);
|
|
97
|
+
setName(p.name);
|
|
98
|
+
});
|
|
99
|
+
$EditorList[p.name!] = editor;
|
|
100
|
+
$MonacoList[p.name!] = monaco;
|
|
101
|
+
|
|
102
|
+
// eslint-disable-next-line no-bitwise
|
|
103
|
+
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
|
|
104
|
+
editor.trigger('keyboard', 'editor.action.formatDocument');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return () => {
|
|
108
|
+
changeListener.dispose();
|
|
109
|
+
// 清除残留的节流调用
|
|
110
|
+
throttledSuccessMessage.cancel();
|
|
111
|
+
throttledFailedMessage.cancel();
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
validateOnChange: editorOncahnge,
|
|
115
|
+
validations: {
|
|
116
|
+
[`Validat-${p.name}`]: true
|
|
117
|
+
},
|
|
118
|
+
type: 'editor'
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
// props: p
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
export default EditorComponent;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { FormControlProps } from 'amis';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 表单校验 组件 FormItem
|
|
7
|
+
* @param props
|
|
8
|
+
* @returns
|
|
9
|
+
// */
|
|
10
|
+
const EditorFormItemComponent = (_p: amis.AmisComponentPropsType) => {
|
|
11
|
+
const { useRef } = _p.react;
|
|
12
|
+
return (p: FormControlProps) => {
|
|
13
|
+
const _dom: any = useRef(null);
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
15
|
+
const { name, type, label, ...other } = p.$schema;
|
|
16
|
+
return p.render(
|
|
17
|
+
'body',
|
|
18
|
+
{
|
|
19
|
+
type: 'button',
|
|
20
|
+
label,
|
|
21
|
+
actionType: 'dialog',
|
|
22
|
+
dialog: {
|
|
23
|
+
onEvent: {
|
|
24
|
+
// confirm: {
|
|
25
|
+
// actions: [
|
|
26
|
+
// {
|
|
27
|
+
// actionType: 'custom',
|
|
28
|
+
// script: (_ctx: any, _act: any, e: { parentDefault: () => void }) => {
|
|
29
|
+
// e.parentDefault();
|
|
30
|
+
// }
|
|
31
|
+
// }
|
|
32
|
+
// ]
|
|
33
|
+
// }
|
|
34
|
+
},
|
|
35
|
+
title: "编辑器",
|
|
36
|
+
size: 'full',
|
|
37
|
+
body: {
|
|
38
|
+
type: 'hr-editor',
|
|
39
|
+
onChange: p.onChange,
|
|
40
|
+
onBulkChange: p.onBulkChange,
|
|
41
|
+
name: p.name,
|
|
42
|
+
...other
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
// props: p
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default EditorFormItemComponent;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { AxiosResponse } from 'axios';
|
|
2
|
+
import dayjs from 'dayjs';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import consola from 'consola';
|
|
5
|
+
import { disAutoConnect, autoConnect, hiprint } from '@sv-print/hiprint';
|
|
6
|
+
import type { IScopedContext } from 'amis';
|
|
7
|
+
import { loadAmisSDK } from '@maita/amis-tools';
|
|
8
|
+
import axios from 'axios';
|
|
9
|
+
disAutoConnect();
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 动态执行给定的作用域表达式,并返回处理后的上下文和数据。
|
|
17
|
+
*
|
|
18
|
+
* @param scope - 要执行的动态表达式字符串。
|
|
19
|
+
* @returns 包含 `context` 和 `data` 的对象。如果 `scope` 为空,则返回空对象。
|
|
20
|
+
*/
|
|
21
|
+
export const evalFc = async (
|
|
22
|
+
scopeStr: string,
|
|
23
|
+
instance?: IScopedContext & amis.TypeEmbed
|
|
24
|
+
): Promise<{
|
|
25
|
+
data?: Record<string, string | number | boolean | null | undefined>;
|
|
26
|
+
context?: Record<string, any>;
|
|
27
|
+
}> => {
|
|
28
|
+
const getAmis = async () => {
|
|
29
|
+
if (!window.amisRequire) await loadAmisSDK();
|
|
30
|
+
return new Promise((res, rej) => {
|
|
31
|
+
try {
|
|
32
|
+
window.amisRequire(['amis-ui', 'amis', 'amis-formula', 'react', 'amis-core'], (...args: any[]) => {
|
|
33
|
+
const [ui, lib, formula, react, core] = args;
|
|
34
|
+
res({ ui, lib, formula, react, core });
|
|
35
|
+
});
|
|
36
|
+
} catch (error) {
|
|
37
|
+
consola.error('amisRequire 加载失败,部分功能可能无法使用', error);
|
|
38
|
+
rej(error);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const eval2 = (express: string) => {
|
|
44
|
+
// eslint-disable-next-line no-new-func
|
|
45
|
+
return new Function('instance', '_', 'axios', 'hiprint', 'hiprintConnect', 'dayjs', 'amis', `return ${express}`);
|
|
46
|
+
};
|
|
47
|
+
const dynamicCode = eval2(`(${scopeStr})`)(
|
|
48
|
+
instance,
|
|
49
|
+
_,
|
|
50
|
+
axios,
|
|
51
|
+
hiprint.PrintTemplate,
|
|
52
|
+
autoConnect,
|
|
53
|
+
dayjs,
|
|
54
|
+
await getAmis()
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const Scope: {
|
|
58
|
+
data?: Record<string, string | number | boolean | null | undefined>;
|
|
59
|
+
context?: Record<string, any>;
|
|
60
|
+
} = {
|
|
61
|
+
context: dynamicCode.context,
|
|
62
|
+
data: dynamicCode.data
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return Scope;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 递归转换数组Schema类型的$字符串表达式
|
|
70
|
+
* @param orgobj 含$字符串的Schema表达式的对象
|
|
71
|
+
* @param args Title ,entity,user 参数
|
|
72
|
+
* @returns 计算后的对象
|
|
73
|
+
*/
|
|
74
|
+
export function ConvertSchemaMarkToJSON<T>(orgobj: Record<string, any>, scope: any): T {
|
|
75
|
+
const eval2 = (express: string) => {
|
|
76
|
+
// eslint-disable-next-line no-new-func
|
|
77
|
+
return new Function('scope', `return ${express.replace('{{', '').replace('}}', '')}`);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 递归处理对象
|
|
82
|
+
* @param obj 当前处理的对象
|
|
83
|
+
* @returns 处理后的对象
|
|
84
|
+
*/
|
|
85
|
+
const getObject = (obj: Record<string, any> | string): any => {
|
|
86
|
+
// 处理对象
|
|
87
|
+
const targetObj: Record<string, any> = {};
|
|
88
|
+
if (typeof obj === 'number') {
|
|
89
|
+
return obj;
|
|
90
|
+
} else if (typeof obj === 'string') {
|
|
91
|
+
if (/{{.*}}/.test(obj)) obj = eval2(obj)(scope);
|
|
92
|
+
return obj;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const key in obj) {
|
|
96
|
+
if (Object.hasOwn(obj, key)) {
|
|
97
|
+
const value = obj[key];
|
|
98
|
+
// 递归处理对象或数组
|
|
99
|
+
if (Array.isArray(value)) {
|
|
100
|
+
targetObj[key] = value.map(item => getObject(item));
|
|
101
|
+
} else if (typeof value === 'object') {
|
|
102
|
+
targetObj[key] = getObject(value);
|
|
103
|
+
}
|
|
104
|
+
// 处理包含 {{}} 的字符串
|
|
105
|
+
else if (typeof value === 'string' && /{{.*}}/.test(value)) {
|
|
106
|
+
targetObj[key] = eval2(value)(scope);
|
|
107
|
+
} else targetObj[key] = value;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return targetObj;
|
|
111
|
+
};
|
|
112
|
+
return getObject(orgobj);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 封装response数据为一个文件下载
|
|
117
|
+
* @param response - Axios 响应对象
|
|
118
|
+
* @returns 如果服务端返回的是一个blob 则返回一个文件下载
|
|
119
|
+
*/
|
|
120
|
+
export const responeToDownLoad = (response: AxiosResponse<any>) => {
|
|
121
|
+
let filename = '文件打包.zip';
|
|
122
|
+
const contentDisposition = response.headers['content-disposition'] || response.headers['Content-Disposition'];
|
|
123
|
+
// 解析 Content-Disposition 头以获取文件名
|
|
124
|
+
if (contentDisposition) {
|
|
125
|
+
const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
|
|
126
|
+
if (filenameMatch && filenameMatch[1]) {
|
|
127
|
+
filename = decodeURIComponent(filenameMatch[1].replace(/['"]/g, ''));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const downloadUrl = window.URL.createObjectURL(new Blob([response.data as unknown as BlobPart]));
|
|
132
|
+
const link = document.createElement('a');
|
|
133
|
+
link.style.display = 'none';
|
|
134
|
+
link.href = downloadUrl;
|
|
135
|
+
link.setAttribute('download', filename); // 设置下载的文件名
|
|
136
|
+
document.body.appendChild(link);
|
|
137
|
+
link.click();
|
|
138
|
+
document.body.removeChild(link);
|
|
139
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
140
|
+
return { msg: '下载成功', status: 0, data: {} }; // 不进行 Amis 渲染
|
|
141
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 注册amis 自定义组件
|
|
5
|
+
* @param amislib amisReauire amis库
|
|
6
|
+
* @param react amisReauire react库
|
|
7
|
+
*/
|
|
8
|
+
export const registerAmisComponent = (p: amis.AmisComponentPropsType) => {
|
|
9
|
+
const registerComponent = (
|
|
10
|
+
name: string,
|
|
11
|
+
hook: (props: amis.AmisComponentPropsType) => React.ComponentType<any>,
|
|
12
|
+
isFormItem: boolean = false
|
|
13
|
+
) => {
|
|
14
|
+
if (!p.amislib.getFormItemByName(name.toLocaleLowerCase())) {
|
|
15
|
+
const state = isFormItem
|
|
16
|
+
? p.amislib.FormItem({ type: name.toLocaleLowerCase() })(hook(p)) // 注册 formitem 组件
|
|
17
|
+
: p.amislib.Renderer({ type: name.toLocaleLowerCase() })(hook(p)); // 注册 renderer 组件
|
|
18
|
+
return state;
|
|
19
|
+
}
|
|
20
|
+
return p.amislib.getRendererByName(name.toLocaleLowerCase());
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return registerComponent;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default registerAmisComponent;
|
|
27
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MaitaGlobalConfig, loadAmisSDK } from '@maita/amis-tools';
|
|
2
|
+
|
|
3
|
+
/** 设置Amis配置 */
|
|
4
|
+
export const setupAmisConfig = () => {
|
|
5
|
+
const _cf = new MaitaGlobalConfig();
|
|
6
|
+
(async () => {
|
|
7
|
+
// 定义的通用window方法,供amis设计器使用
|
|
8
|
+
const newJsFunc = {
|
|
9
|
+
/**
|
|
10
|
+
* 浏览器动态列缓存
|
|
11
|
+
*
|
|
12
|
+
* @param ctx amis context上下文
|
|
13
|
+
* @param event amis event事件
|
|
14
|
+
* @param clear 是否清除 默认false
|
|
15
|
+
*/
|
|
16
|
+
// dynimicColumnCache: (_ctx: any, _event: any, _clear: boolean = false) => {},
|
|
17
|
+
// dynimicColumnSave: (_ctx: any, _event: any, _clear: boolean = false) => {}
|
|
18
|
+
};
|
|
19
|
+
// if (!window.amisRequire) {
|
|
20
|
+
// await loadAmisSDK();
|
|
21
|
+
// }
|
|
22
|
+
|
|
23
|
+
Object.assign((window as any).__JSFunc, newJsFunc);
|
|
24
|
+
})();
|
|
25
|
+
};
|