Showing
62 changed files
with
4129 additions
and
111 deletions
Too many changes to show.
To preserve performance only 62 of 410 files are displayed.
... | ... | @@ -5,22 +5,28 @@ |
5 | 5 | "public/resource/tinymce/langs" |
6 | 6 | ], |
7 | 7 | "cSpell.words": [ |
8 | + "ACKS", | |
9 | + "clazz", | |
8 | 10 | "Cmds", |
9 | 11 | "COAP", |
10 | 12 | "echarts", |
11 | 13 | "edrx", |
12 | - "EFENTO", | |
14 | + "EFENTO", | |
13 | 15 | "fingerprintjs", |
14 | 16 | "flvjs", |
15 | - "flvjs", | |
16 | 17 | "inited", |
17 | 18 | "liveui", |
18 | 19 | "MQTT", |
20 | + "noconflict", | |
19 | 21 | "notif", |
20 | 22 | "PROTOBUF", |
23 | + "Rabbitmq", | |
21 | 24 | "rtsp", |
22 | 25 | "SCADA", |
26 | + "SMTPS", | |
23 | 27 | "SNMP", |
28 | + "TSLV", | |
29 | + "UNACK", | |
24 | 30 | "unref", |
25 | 31 | "vben", |
26 | 32 | "videojs", | ... | ... |
build/generate/ruleChain/components.ts
0 → 100644
build/generate/ruleChain/index.ts
0 → 100644
1 | +import { join } from 'path'; | |
2 | +import { pathExists, ensureFile, writeFile } from 'fs-extra'; | |
3 | +import { NodeItemConfigType } from '/@/views/rule/designer/types/node'; | |
4 | +import { camelCase, upperFirst, snakeCase } from 'lodash-es'; | |
5 | +import { components } from './components'; | |
6 | +type GroupNodeType = { [key: string]: NodeItemConfigType[] }; | |
7 | + | |
8 | +const RULE_CHAIN_FILE_PATH = join(process.cwd(), '/src/views/rule/designer'); | |
9 | + | |
10 | +const list: NodeItemConfigType[] = components; | |
11 | + | |
12 | +const getCategoryConfigName = (name: string) => { | |
13 | + return `${upperFirst(camelCase(name))}CategoryConfig`; | |
14 | +}; | |
15 | + | |
16 | +const getNodeConfigName = (name: string) => { | |
17 | + return `${upperFirst(camelCase(name))}Config`; | |
18 | +}; | |
19 | + | |
20 | +const getCagegoryEnumName = (name: string) => { | |
21 | + return `${upperFirst(name.toLowerCase())}CategoryComponentEnum`; | |
22 | +}; | |
23 | + | |
24 | +const getEnumKeyName = (name: string) => { | |
25 | + return snakeCase(name).toUpperCase(); | |
26 | +}; | |
27 | + | |
28 | +const createFile = async (fileName: string, fileContent?: string, replace = false) => { | |
29 | + const path = join(RULE_CHAIN_FILE_PATH, './packages', fileName); | |
30 | + | |
31 | + const flag = await pathExists(path); | |
32 | + | |
33 | + if (flag && !replace) return false; | |
34 | + | |
35 | + await ensureFile(path); | |
36 | + | |
37 | + fileContent && (await writeFile(path, fileContent, { encoding: 'utf-8' })); | |
38 | +}; | |
39 | + | |
40 | +const groupByType = () => { | |
41 | + const group: { [key: string]: NodeItemConfigType[] } = {}; | |
42 | + | |
43 | + list.forEach((item) => { | |
44 | + if (!group[item.type]) group[item.type] = []; | |
45 | + group[item.type].push(item); | |
46 | + }); | |
47 | + | |
48 | + return group; | |
49 | +}; | |
50 | + | |
51 | +const generateCategoryEnumFile = async (data: GroupNodeType) => { | |
52 | + const defaultContent = ` | |
53 | +export enum EntryCategoryComponentEnum { | |
54 | + INPUT = 'Input', | |
55 | +} | |
56 | + `; | |
57 | + | |
58 | + const fileContent = Object.keys(data).reduce((prev, next) => { | |
59 | + const enumName = getCagegoryEnumName(next); | |
60 | + | |
61 | + const enumKeys = data[next].map((item) => getEnumKeyName(item.name)); | |
62 | + | |
63 | + const content = `export enum ${enumName} { | |
64 | + ${enumKeys.map((name) => `${name} = '${upperFirst(camelCase(name))}'`)} | |
65 | + }`; | |
66 | + | |
67 | + return `${prev} \n ${content}`; | |
68 | + }, defaultContent); | |
69 | + | |
70 | + createFile('../enum/category.ts', fileContent, true); | |
71 | + return fileContent; | |
72 | +}; | |
73 | + | |
74 | +const generateRuleNodeEnumFile = async (data: GroupNodeType) => { | |
75 | + const categoryKeys = Object.keys(data).map((type) => type.toUpperCase()); | |
76 | + const filePath = join(RULE_CHAIN_FILE_PATH, './packages/index.type.ts'); | |
77 | + const fileContent = ` | |
78 | +export enum RuleNodeTypeEnum { | |
79 | + ${categoryKeys.map((item) => `${item} = '${item}'`).join(',\n')} | |
80 | +} | |
81 | + `; | |
82 | + | |
83 | + await writeFile(filePath, fileContent, { | |
84 | + encoding: 'utf-8', | |
85 | + }); | |
86 | + | |
87 | + return fileContent; | |
88 | +}; | |
89 | + | |
90 | +const generateCategoryIndexFile = async (type: string, data: NodeItemConfigType[]) => { | |
91 | + const getComponentsName = data.map((temp) => `${upperFirst(camelCase(temp.name))}`); | |
92 | + const importContent = getComponentsName.map( | |
93 | + (name) => `import { ${name}Config } from './${name}';\n` | |
94 | + ); | |
95 | + | |
96 | + const components = getComponentsName.map((item) => `${item}Config`); | |
97 | + | |
98 | + const content = `import type { CategoryConfigType, NodeItemConfigType } from '../../types/node'; | |
99 | +import { RuleNodeTypeEnum } from '../index.type'; | |
100 | +${importContent.join('')} | |
101 | + | |
102 | +export const ${getCategoryConfigName(type)}: CategoryConfigType = { | |
103 | + category: RuleNodeTypeEnum.${type.toUpperCase()}, | |
104 | + title: '${type}', | |
105 | + icon: 'tabler:circuit-ground', | |
106 | + description: '使用配置条件筛选传入消息', | |
107 | +}; | |
108 | + | |
109 | +export const ${upperFirst(type.toLowerCase())}Components: NodeItemConfigType[] = [${components}]; | |
110 | +`; | |
111 | + | |
112 | + createFile(`./${upperFirst(type.toLowerCase())}/index.ts`, content, true); | |
113 | + | |
114 | + return content; | |
115 | +}; | |
116 | + | |
117 | +const generateNodeIndexFile = async (type: string, data: NodeItemConfigType) => { | |
118 | + const categoryEnumName = getCagegoryEnumName(type); | |
119 | + | |
120 | + const nodeConfigName = getNodeConfigName(data.name); | |
121 | + | |
122 | + const content = ` | |
123 | + import { ${categoryEnumName} } from '../../../enum/category'; | |
124 | + import { useCreateNodeKey } from '../../../hook/useCreateNodeKey'; | |
125 | + import type { NodeItemConfigType } from '../../../types/node'; | |
126 | + import { RuleNodeTypeEnum } from '../../index.type'; | |
127 | + | |
128 | + const keys = useCreateNodeKey(${categoryEnumName}.${getEnumKeyName(data.name)}); | |
129 | + | |
130 | + export interface ${upperFirst(camelCase(data.name))}DataType { | |
131 | + someConfiguration?: Recordable | |
132 | + } | |
133 | + | |
134 | + export const ${nodeConfigName}: NodeItemConfigType = { | |
135 | + ...keys, | |
136 | + clazz: '${data.clazz}', | |
137 | + categoryType: RuleNodeTypeEnum.${type.toUpperCase()}, | |
138 | + name: '${data.name}', | |
139 | + configurationDescriptor: ${JSON.stringify(data.configurationDescriptor, null, 2)} | |
140 | + }; | |
141 | + `; | |
142 | + | |
143 | + createFile( | |
144 | + `./${upperFirst(type.toLowerCase())}/${upperFirst(camelCase(data.name))}/index.ts`, | |
145 | + content | |
146 | + ); | |
147 | + | |
148 | + return content; | |
149 | +}; | |
150 | + | |
151 | +const generateNodeVueTemplateFile = async (type: string, data: NodeItemConfigType) => { | |
152 | + const content = ` | |
153 | + <script lang="ts" setup> | |
154 | + import type { CreateModalDefineExposeType } from '../../../types'; | |
155 | + import { BasicForm, useForm } from '/@/components/Form'; | |
156 | + import { formSchemas } from './create.config'; | |
157 | + import { NodeData } from '../../../types/node'; | |
158 | + | |
159 | + defineProps<{ | |
160 | + config: NodeData; | |
161 | + }>(); | |
162 | + | |
163 | + const [register, { validate, getFieldsValue, setFieldsValue, resetFields }] = useForm({ | |
164 | + schemas: formSchemas, | |
165 | + showActionButtonGroup: false, | |
166 | + }); | |
167 | + | |
168 | + const getValue: CreateModalDefineExposeType['getFieldsValue'] = async () => { | |
169 | + await validate(); | |
170 | + const value = getFieldsValue() || {}; | |
171 | + return value; | |
172 | + }; | |
173 | + | |
174 | + const setValue: CreateModalDefineExposeType['setFieldsValue'] = (value) => { | |
175 | + resetFields(); | |
176 | + setFieldsValue(value); | |
177 | + }; | |
178 | + | |
179 | + defineExpose({ | |
180 | + setFieldsValue: setValue, | |
181 | + getFieldsValue: getValue, | |
182 | + } as CreateModalDefineExposeType); | |
183 | + </script> | |
184 | + | |
185 | + <template> | |
186 | + <BasicForm @register="register" /> | |
187 | + </template> | |
188 | + `; | |
189 | + | |
190 | + createFile( | |
191 | + `./${upperFirst(type.toLowerCase())}/${upperFirst(camelCase(data.name))}/create.vue`, | |
192 | + content | |
193 | + ); | |
194 | + return content; | |
195 | +}; | |
196 | + | |
197 | +const generateNodeVueConfigFile = async (type: string, data: NodeItemConfigType) => { | |
198 | + const content = ` | |
199 | + import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node'; | |
200 | + import { FormSchema } from '/@/components/Form'; | |
201 | + | |
202 | + export const formSchemas: FormSchema[] = [ | |
203 | + { | |
204 | + field: NodeBindDataFieldEnum.NAME, | |
205 | + component: 'Input', | |
206 | + label: NodeBindDataFieldNameEnum.NAME, | |
207 | + } | |
208 | + ]; | |
209 | + `; | |
210 | + | |
211 | + createFile( | |
212 | + `./${upperFirst(type.toLowerCase())}/${upperFirst(camelCase(data.name))}/create.config.ts`, | |
213 | + content | |
214 | + ); | |
215 | + return content; | |
216 | +}; | |
217 | + | |
218 | +const generateNodeConfigFile = async (type: string, data: NodeItemConfigType) => { | |
219 | + const nodeConfigName = getNodeConfigName(data.name); | |
220 | + const categoryConfigName = getCategoryConfigName(type); | |
221 | + const content = ` | |
222 | + import { cloneDeep } from 'lodash-es'; | |
223 | + import { PublicNodeItemClass } from '../../../types/node'; | |
224 | + import type { | |
225 | + CategoryConfigType, | |
226 | + CreateComponentType, | |
227 | + NodeItemConfigType, | |
228 | + } from '../../../types/node'; | |
229 | + import { ${categoryConfigName} } from '..'; | |
230 | + import { ${nodeConfigName} } from '.'; | |
231 | + | |
232 | + export class Config extends PublicNodeItemClass implements CreateComponentType { | |
233 | + public config: NodeItemConfigType = cloneDeep(${nodeConfigName}); | |
234 | + | |
235 | + public categoryConfig: CategoryConfigType = cloneDeep(${categoryConfigName}); | |
236 | + | |
237 | + constructor() { | |
238 | + super(); | |
239 | + } | |
240 | + } | |
241 | + `; | |
242 | + | |
243 | + createFile( | |
244 | + `./${upperFirst(type.toLowerCase())}/${upperFirst(camelCase(data.name))}/config.ts`, | |
245 | + content | |
246 | + ); | |
247 | + return content; | |
248 | +}; | |
249 | + | |
250 | +const bootstrap = async () => { | |
251 | + const groupData = groupByType(); | |
252 | + await generateRuleNodeEnumFile(groupData); | |
253 | + await generateCategoryEnumFile(groupData); | |
254 | + for (const type of Object.keys(groupData)) { | |
255 | + const item = groupData[type]; | |
256 | + await generateCategoryIndexFile(type, item); | |
257 | + for (const temp of item) { | |
258 | + await generateNodeConfigFile(type, temp); | |
259 | + await generateNodeIndexFile(type, temp); | |
260 | + await generateNodeVueConfigFile(type, temp); | |
261 | + await generateNodeVueTemplateFile(type, temp); | |
262 | + } | |
263 | + } | |
264 | +}; | |
265 | + | |
266 | +bootstrap(); | ... | ... |
... | ... | @@ -32,13 +32,18 @@ |
32 | 32 | "reinstall": "rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run bootstrap", |
33 | 33 | "prepare": "husky install", |
34 | 34 | "gen:icon": "esno ./build/generate/icon/index.ts", |
35 | - "gen:iconfont": "esno ./build/generate/iconfont/index.ts" | |
35 | + "gen:iconfont": "esno ./build/generate/iconfont/index.ts", | |
36 | + "gen:rule": "esno ./build/generate/ruleChain/index.ts && npx eslint \"src/views/rule/designer/**/*.{vue,ts,tsx}\" --fix" | |
36 | 37 | }, |
37 | 38 | "dependencies": { |
38 | 39 | "@fingerprintjs/fingerprintjs": "^3.4.1", |
39 | 40 | "@iconify/iconify": "^2.0.3", |
40 | 41 | "@logicflow/core": "^0.6.9", |
41 | 42 | "@logicflow/extension": "^0.6.9", |
43 | + "@vue-flow/background": "^1.2.0", | |
44 | + "@vue-flow/controls": "^1.1.0", | |
45 | + "@vue-flow/core": "^1.22.1", | |
46 | + "@vue-flow/node-toolbar": "^1.1.0", | |
42 | 47 | "@vueuse/core": "^10.1.0", |
43 | 48 | "@zxcvbn-ts/core": "^1.0.0-beta.0", |
44 | 49 | "ace-builds": "^1.4.14", |
... | ... | @@ -53,6 +58,7 @@ |
53 | 58 | "flv.js": "^1.6.2", |
54 | 59 | "hls.js": "^1.0.10", |
55 | 60 | "intro.js": "^4.1.0", |
61 | + "js-beautify": "^1.14.9", | |
56 | 62 | "jsoneditor": "^9.7.2", |
57 | 63 | "jwt-decode": "^3.1.2", |
58 | 64 | "lodash-es": "^4.17.21", |
... | ... | @@ -68,7 +74,7 @@ |
68 | 74 | "vditor": "^3.8.6", |
69 | 75 | "video.js": "^7.20.3", |
70 | 76 | "videojs-flvjs-es6": "^1.0.1", |
71 | - "vue": "3.2.31", | |
77 | + "vue": "3.3.4", | |
72 | 78 | "vue-i18n": "9.1.7", |
73 | 79 | "vue-json-pretty": "^2.0.4", |
74 | 80 | "vue-router": "^4.0.11", | ... | ... |
src/api/ruleChainDesigner/index.ts
0 → 100644
1 | +import { DeviceInfoItemType, DeviceTypeItem, PageParams } from './model'; | |
2 | +import { TBPaginationResult } from '/#/axios'; | |
3 | +import { defHttp } from '/@/utils/http/axios'; | |
4 | + | |
5 | +enum Api { | |
6 | + GET_DEVICE_INFOS = '/tenant/deviceInfos', | |
7 | + GET_DEVICE_TYPE = '/device/types', | |
8 | + TENANT_QUEUE = '/tenant/queues', | |
9 | +} | |
10 | + | |
11 | +enum Entity { | |
12 | + DEVICES = '/tenant/devices', | |
13 | + ASSETS = '/tenant/assets', | |
14 | + ENTITY_VIEW = '/tenant/entityViews', | |
15 | + TENANT = '/tenant', | |
16 | + CUSTOMER = '/customers', | |
17 | + DASHBOARD = '/tenant/dashboards', | |
18 | + USER = '/users', | |
19 | + EDGE = '/tenant/edges', | |
20 | +} | |
21 | + | |
22 | +export const getDeviceInfos = () => { | |
23 | + return defHttp.get<TBPaginationResult<DeviceInfoItemType>>( | |
24 | + { | |
25 | + url: Api.GET_DEVICE_INFOS, | |
26 | + }, | |
27 | + { joinPrefix: false } | |
28 | + ); | |
29 | +}; | |
30 | + | |
31 | +export const getDeviceTypes = () => { | |
32 | + return defHttp.get<TBPaginationResult<DeviceTypeItem[]>>( | |
33 | + { | |
34 | + url: Api.GET_DEVICE_TYPE, | |
35 | + }, | |
36 | + { joinPrefix: false } | |
37 | + ); | |
38 | +}; | |
39 | + | |
40 | +export const getTenantQueue = (params: Recordable) => { | |
41 | + return defHttp.get<string[]>( | |
42 | + { | |
43 | + url: Api.TENANT_QUEUE, | |
44 | + params, | |
45 | + }, | |
46 | + { joinPrefix: false } | |
47 | + ); | |
48 | +}; | |
49 | + | |
50 | +export const getEntityDevice = (params: PageParams) => { | |
51 | + return defHttp.get( | |
52 | + { | |
53 | + url: Entity.DEVICES, | |
54 | + params, | |
55 | + }, | |
56 | + { | |
57 | + joinPrefix: false, | |
58 | + } | |
59 | + ); | |
60 | +}; | |
61 | + | |
62 | +export const getEntityAssets = (params: PageParams) => { | |
63 | + return defHttp.get( | |
64 | + { | |
65 | + url: Entity.ASSETS, | |
66 | + params, | |
67 | + }, | |
68 | + { | |
69 | + joinPrefix: false, | |
70 | + } | |
71 | + ); | |
72 | +}; | |
73 | + | |
74 | +export const getEntityViews = (params: PageParams) => { | |
75 | + return defHttp.get( | |
76 | + { | |
77 | + url: Entity.ENTITY_VIEW, | |
78 | + params, | |
79 | + }, | |
80 | + { | |
81 | + joinPrefix: false, | |
82 | + } | |
83 | + ); | |
84 | +}; | |
85 | + | |
86 | +export const getEntityTenant = (params: Record<'tenantId', string>) => { | |
87 | + return defHttp.get( | |
88 | + { | |
89 | + url: `${Entity.TENANT}/${params.tenantId}`, | |
90 | + params, | |
91 | + }, | |
92 | + { | |
93 | + joinPrefix: false, | |
94 | + } | |
95 | + ); | |
96 | +}; | |
97 | + | |
98 | +export const getEntityCustomer = (params: PageParams) => { | |
99 | + return defHttp.get( | |
100 | + { | |
101 | + url: Entity.CUSTOMER, | |
102 | + params, | |
103 | + }, | |
104 | + { | |
105 | + joinPrefix: false, | |
106 | + } | |
107 | + ); | |
108 | +}; | |
109 | + | |
110 | +export const getEntityUser = (params: PageParams) => { | |
111 | + return defHttp.get( | |
112 | + { | |
113 | + url: Entity.USER, | |
114 | + params, | |
115 | + }, | |
116 | + { | |
117 | + joinPrefix: false, | |
118 | + } | |
119 | + ); | |
120 | +}; | |
121 | + | |
122 | +export const getEntityDashboard = (params: PageParams) => { | |
123 | + return defHttp.get( | |
124 | + { | |
125 | + url: Entity.DASHBOARD, | |
126 | + params, | |
127 | + }, | |
128 | + { | |
129 | + joinPrefix: false, | |
130 | + } | |
131 | + ); | |
132 | +}; | |
133 | + | |
134 | +export const getEntityEdge = (params: PageParams) => { | |
135 | + return defHttp.get( | |
136 | + { | |
137 | + url: Entity.EDGE, | |
138 | + params, | |
139 | + }, | |
140 | + { | |
141 | + joinPrefix: false, | |
142 | + } | |
143 | + ); | |
144 | +}; | ... | ... |
src/api/ruleChainDesigner/model/index.ts
0 → 100644
1 | +export interface DeviceInfoItemType { | |
2 | + id: Id; | |
3 | + createdTime: number; | |
4 | + additionalInfo: AdditionalInfo; | |
5 | + tenantId: Id; | |
6 | + customerId: Id; | |
7 | + name: string; | |
8 | + type: string; | |
9 | + label: string; | |
10 | + deviceProfileId: Id; | |
11 | + deviceData: DeviceData; | |
12 | + firmwareId: any; | |
13 | + softwareId: any; | |
14 | + customerTitle: any; | |
15 | + customerIsPublic: boolean; | |
16 | + deviceProfileName: string; | |
17 | +} | |
18 | + | |
19 | +export interface Id { | |
20 | + entityType: string; | |
21 | + id: string; | |
22 | +} | |
23 | + | |
24 | +export interface DeviceData { | |
25 | + configuration: Configuration; | |
26 | + transportConfiguration: TransportConfiguration; | |
27 | +} | |
28 | + | |
29 | +export interface AdditionalInfo { | |
30 | + gateway: boolean; | |
31 | + description: string; | |
32 | + overwriteActivityTime: boolean; | |
33 | +} | |
34 | +export interface Configuration { | |
35 | + type: string; | |
36 | +} | |
37 | + | |
38 | +export interface TransportConfiguration { | |
39 | + type: string; | |
40 | +} | |
41 | + | |
42 | +export interface DeviceTypeItem { | |
43 | + tenantId: Id; | |
44 | + entityType: string; | |
45 | + type: string; | |
46 | +} | |
47 | + | |
48 | +export interface PageParams { | |
49 | + pageSize?: number; | |
50 | + page?: number; | |
51 | + textSearch?: string; | |
52 | + sortProperty?: string; | |
53 | + sortOrder?: string; | |
54 | +} | ... | ... |
src/api/ruleDesigner/index.ts
0 → 100644
1 | +import { RuleChainPaginationItemType } from './model/type'; | |
2 | +import { TBPaginationResult } from '/#/axios'; | |
3 | +import { defHttp } from '/@/utils/http/axios'; | |
4 | +import { RuleChainDetail, RuleChainType } from '/@/views/rule/designer/types/ruleNode'; | |
5 | + | |
6 | +enum Api { | |
7 | + GET_RULE_CHAINS_DETAIL = '/ruleChain', | |
8 | + SAVE = '/ruleChain/metadata', | |
9 | + GET_RULE_CHAINES = '/ruleChains', | |
10 | + GET_RULE_NODE_EVENTS = '/events/RULE_NODE', | |
11 | +} | |
12 | + | |
13 | +export const getRuleChainDetail = (id: string) => { | |
14 | + return defHttp.get<RuleChainDetail>( | |
15 | + { | |
16 | + url: `${Api.GET_RULE_CHAINS_DETAIL}/${id}`, | |
17 | + }, | |
18 | + { joinPrefix: false } | |
19 | + ); | |
20 | +}; | |
21 | + | |
22 | +export const getRuleChainData = (id: string) => { | |
23 | + return defHttp.get<RuleChainType>( | |
24 | + { | |
25 | + url: `/ruleChain/${id}/metadata`, | |
26 | + }, | |
27 | + { joinPrefix: false } | |
28 | + ); | |
29 | +}; | |
30 | + | |
31 | +export const saveRuleChainData = (data: RuleChainType) => { | |
32 | + return defHttp.post( | |
33 | + { | |
34 | + url: Api.SAVE, | |
35 | + data, | |
36 | + }, | |
37 | + { joinPrefix: false } | |
38 | + ); | |
39 | +}; | |
40 | + | |
41 | +export const getRuleChains = (params: Recordable) => { | |
42 | + return defHttp.get<TBPaginationResult<RuleChainPaginationItemType>>( | |
43 | + { | |
44 | + url: Api.GET_RULE_CHAINES, | |
45 | + params, | |
46 | + }, | |
47 | + { | |
48 | + joinPrefix: false, | |
49 | + } | |
50 | + ); | |
51 | +}; | |
52 | + | |
53 | +export const getRuleNodeEventList = ( | |
54 | + ruleNodeId: string, | |
55 | + params: Recordable, | |
56 | + data: Recordable & Record<'eventType', string> | |
57 | +) => { | |
58 | + return defHttp.post<TBPaginationResult>( | |
59 | + { | |
60 | + url: `${Api.GET_RULE_NODE_EVENTS}/${ruleNodeId}`, | |
61 | + params, | |
62 | + data, | |
63 | + }, | |
64 | + { joinPrefix: false } | |
65 | + ); | |
66 | +}; | ... | ... |
src/api/ruleDesigner/model/type.ts
0 → 100644
1 | +export interface RuleChainPaginationItemType { | |
2 | + id: Id; | |
3 | + createdTime: number; | |
4 | + additionalInfo?: AdditionalInfo; | |
5 | + tenantId: Id; | |
6 | + name: string; | |
7 | + type: string; | |
8 | + firstRuleNodeId: Id; | |
9 | + root: boolean; | |
10 | + debugMode: boolean; | |
11 | + configuration: any; | |
12 | +} | |
13 | + | |
14 | +export interface Id { | |
15 | + entityType: string; | |
16 | + id: string; | |
17 | +} | |
18 | + | |
19 | +export interface AdditionalInfo { | |
20 | + description: string; | |
21 | +} | ... | ... |
... | ... | @@ -22,6 +22,8 @@ enum ScreenManagerApi { |
22 | 22 | GET_ATTRBUTELIST = '/device/attributes/', |
23 | 23 | ALARM_PROFILE = '/alarm/profile/', |
24 | 24 | MASTER_GET_DEVICE = '/device/list', |
25 | + RULE_CHAINS = '/ruleChains', | |
26 | + RULE_CHAIN = '/ruleChain', | |
25 | 27 | } |
26 | 28 | |
27 | 29 | /** |
... | ... | @@ -130,3 +132,45 @@ export const byOrganizationIdGetMasterDevice = (params: { |
130 | 132 | }); |
131 | 133 | }; |
132 | 134 | //TODO-fengtao |
135 | + | |
136 | +/** | |
137 | + * 分页查询规则链库 | |
138 | + */ | |
139 | + | |
140 | +export const getRuleChinsList = (params) => { | |
141 | + return defHttp.get( | |
142 | + { | |
143 | + url: `${ScreenManagerApi.RULE_CHAINS}`, | |
144 | + params, | |
145 | + }, | |
146 | + { joinPrefix: false } | |
147 | + ); | |
148 | +}; | |
149 | + | |
150 | +/** | |
151 | + * 新增规则链 | |
152 | + */ | |
153 | + | |
154 | +export const createRuleChine = (params) => { | |
155 | + return defHttp.post( | |
156 | + { | |
157 | + url: `${ScreenManagerApi.RULE_CHAIN}`, | |
158 | + params, | |
159 | + }, | |
160 | + { joinPrefix: false } | |
161 | + ); | |
162 | +}; | |
163 | + | |
164 | +/** | |
165 | + * 删除规则链 | |
166 | + */ | |
167 | + | |
168 | +export const deleteRuleChine = (params) => { | |
169 | + return defHttp.delete( | |
170 | + { | |
171 | + url: `${ScreenManagerApi.RULE_CHAIN}/`, | |
172 | + params, | |
173 | + }, | |
174 | + { joinPrefix: false } | |
175 | + ); | |
176 | +}; | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | - import { ref, watch } from 'vue'; | |
3 | - import JSONEditor, { JSONEditorOptions } from 'jsoneditor'; | |
4 | - import 'jsoneditor/dist/jsoneditor.min.css'; | |
5 | - import { unref } from 'vue'; | |
6 | - import { onMounted } from 'vue'; | |
7 | - import { computed } from '@vue/reactivity'; | |
8 | - import { onUnmounted } from 'vue'; | |
2 | + import { onMounted, computed, onUnmounted, unref, ref, watch } from 'vue'; | |
3 | + import { Tooltip } from 'ant-design-vue'; | |
4 | + import { Icon } from '/@/components/Icon'; | |
5 | + import { useFullscreen } from '@vueuse/core'; | |
6 | + import { isNumber, isObject, isString } from '/@/utils/is'; | |
7 | + import AceEditor, { Ace } from 'ace-builds'; | |
8 | + import workerJsonUrl from 'ace-builds/src-noconflict/worker-json?url'; | |
9 | + import githubTheme from 'ace-builds/src-noconflict/theme-github?url'; | |
10 | + import 'ace-builds/src-noconflict/mode-json'; | |
9 | 11 | |
10 | 12 | enum EventEnum { |
11 | 13 | UPDATE_VALUE = 'update:value', |
... | ... | @@ -16,89 +18,134 @@ |
16 | 18 | |
17 | 19 | const props = withDefaults( |
18 | 20 | defineProps<{ |
19 | - value?: string; | |
20 | - options?: JSONEditorOptions; | |
21 | - height?: number; | |
21 | + value?: string | Recordable; | |
22 | + height?: number | string; | |
23 | + title?: string; | |
24 | + disabled?: boolean; | |
22 | 25 | }>(), |
23 | 26 | { |
24 | - options: () => | |
25 | - ({ | |
26 | - mode: 'code', | |
27 | - mainMenuBar: false, | |
28 | - statusBar: false, | |
29 | - } as JSONEditorOptions), | |
30 | 27 | height: 150, |
31 | 28 | } |
32 | 29 | ); |
33 | 30 | |
34 | 31 | const emit = defineEmits<{ |
35 | - (e: EventEnum.UPDATE_VALUE, value: any, instance?: JSONEditor): void; | |
36 | - (e: EventEnum.CHANGE, value: any, instance?: JSONEditor): void; | |
37 | - (e: EventEnum.BLUR, event: Event, instance?: JSONEditor): void; | |
38 | - (e: EventEnum.FOCUS, event: Event, instance?: JSONEditor): void; | |
32 | + (e: EventEnum.UPDATE_VALUE, value: any, instance?: Ace.Editor): void; | |
33 | + (e: EventEnum.CHANGE, value: any, instance?: Ace.Editor): void; | |
34 | + (e: EventEnum.BLUR, event: Event, instance?: Ace.Editor): void; | |
35 | + (e: EventEnum.FOCUS, event: Event, instance?: Ace.Editor): void; | |
39 | 36 | }>(); |
40 | 37 | |
41 | 38 | const jsonEditorElRef = ref<Nullable<any>>(); |
42 | 39 | |
43 | - const editoreRef = ref<JSONEditor>(); | |
40 | + const editoreRef = ref<Ace.Editor>(); | |
44 | 41 | |
45 | 42 | const isFocus = ref(false); |
46 | 43 | |
47 | - const handleChange = (value: any) => { | |
44 | + const handleOnChange = () => { | |
45 | + const value = get(); | |
48 | 46 | emit(EventEnum.UPDATE_VALUE, value, unref(editoreRef)); |
49 | 47 | emit(EventEnum.CHANGE, value, unref(editoreRef)); |
50 | 48 | }; |
51 | 49 | |
52 | - const handleEmit = (event: Event, key: EventEnum) => { | |
53 | - emit(key as EventEnum[keyof EventEnum], event, unref(editoreRef)); | |
50 | + const handleOnBlur = (event: Event) => { | |
51 | + isFocus.value = false; | |
52 | + emit(EventEnum.BLUR, event, unref(editoreRef)); | |
54 | 53 | }; |
55 | 54 | |
56 | - const getOptions = computed(() => { | |
57 | - const { options } = props; | |
58 | - return { | |
59 | - ...options, | |
60 | - onChangeText: handleChange, | |
61 | - onBlur: (event: Event) => { | |
62 | - isFocus.value = false; | |
63 | - handleEmit(event, EventEnum.BLUR); | |
64 | - }, | |
65 | - onFocus: (event: Event) => { | |
66 | - isFocus.value = true; | |
67 | - handleEmit(event, EventEnum.FOCUS); | |
68 | - }, | |
69 | - } as JSONEditorOptions; | |
70 | - }); | |
55 | + const handleOnFocus = (event: Event) => { | |
56 | + isFocus.value = true; | |
57 | + emit(EventEnum.FOCUS, event, unref(editoreRef)); | |
58 | + }; | |
59 | + | |
60 | + const getFormatValue = (value: Recordable | string = '') => { | |
61 | + return isObject(value) ? JSON.stringify(value, null, 2) : value; | |
62 | + }; | |
71 | 63 | |
72 | 64 | const initialize = () => { |
73 | - editoreRef.value = new JSONEditor(unref(jsonEditorElRef), unref(getOptions)); | |
65 | + AceEditor.config.setModuleUrl('ace/mode/json_worker', workerJsonUrl); | |
66 | + AceEditor.config.setModuleUrl('ace/theme/github', githubTheme); | |
67 | + const editor = AceEditor.edit(unref(jsonEditorElRef)!, { | |
68 | + mode: 'ace/mode/json', | |
69 | + }); | |
70 | + editor.setTheme('ace/theme/github'); | |
71 | + editor.setOptions({ | |
72 | + fontSize: 14, | |
73 | + }); | |
74 | + | |
75 | + editor.on('change', handleOnChange); | |
76 | + editor.on('blur', handleOnBlur); | |
77 | + editor.on('focus', handleOnFocus); | |
78 | + | |
79 | + editoreRef.value = editor; | |
80 | + unref(editoreRef)?.setValue(getFormatValue(props.value), 1); | |
81 | + unref(editoreRef)?.setReadOnly(props.disabled); | |
74 | 82 | }; |
75 | 83 | |
76 | 84 | watch( |
77 | 85 | () => props.value, |
78 | 86 | (target) => { |
87 | + // const position = unref(editoreRef)?.getCursorPosition(); | |
79 | 88 | if (unref(isFocus)) return; |
80 | - unref(editoreRef)?.setText(target || ''); | |
89 | + unref(editoreRef)?.setValue(getFormatValue(target)); | |
90 | + unref(editoreRef)?.clearSelection(); | |
91 | + // position && unref(editoreRef)?.moveCursorToPosition(position!); | |
81 | 92 | }, |
82 | 93 | { |
83 | 94 | immediate: true, |
84 | 95 | } |
85 | 96 | ); |
86 | 97 | |
98 | + watch( | |
99 | + () => props.disabled, | |
100 | + (value) => { | |
101 | + unref(editoreRef)?.setReadOnly(value); | |
102 | + } | |
103 | + ); | |
104 | + | |
87 | 105 | const get = (): string => { |
88 | - return unref(editoreRef)?.getText() || ''; | |
106 | + return unref(editoreRef)?.getValue() || ''; | |
89 | 107 | }; |
90 | 108 | |
91 | 109 | const set = (data: any) => { |
92 | - return unref(editoreRef)?.set(data); | |
110 | + return unref(editoreRef)?.setValue(getFormatValue(data)); | |
93 | 111 | }; |
94 | 112 | |
95 | 113 | onMounted(() => { |
96 | 114 | initialize(); |
97 | - unref(editoreRef)?.setText(props.value || ''); | |
115 | + unref(editoreRef)?.setValue(getFormatValue(props.value)); | |
98 | 116 | }); |
99 | 117 | |
100 | 118 | onUnmounted(() => { |
119 | + unref(editoreRef)?.off('change', handleOnChange); | |
120 | + unref(editoreRef)?.off('blur', handleOnBlur); | |
121 | + unref(editoreRef)?.off('focus', handleOnFocus); | |
101 | 122 | unref(editoreRef)?.destroy(); |
123 | + unref(editoreRef)?.container.remove(); | |
124 | + }); | |
125 | + | |
126 | + const handleFormat = () => { | |
127 | + const value = get(); | |
128 | + if (isString(value) && !value) return; | |
129 | + unref(editoreRef)?.setValue(JSON.stringify(JSON.parse(value), null, 2)); | |
130 | + unref(editoreRef)?.clearSelection(); | |
131 | + }; | |
132 | + | |
133 | + const handleCompress = () => { | |
134 | + const value = get(); | |
135 | + if (isString(value) && !value) return; | |
136 | + unref(editoreRef)?.setValue(JSON.stringify(JSON.parse(value))); | |
137 | + unref(editoreRef)?.clearSelection(); | |
138 | + }; | |
139 | + | |
140 | + const jsonEditorContainerElRef = ref<Nullable<HTMLDivElement>>(); | |
141 | + const { isFullscreen, isSupported, toggle } = useFullscreen(jsonEditorContainerElRef); | |
142 | + const handleFullScreen = () => { | |
143 | + toggle(); | |
144 | + }; | |
145 | + | |
146 | + const getHeight = computed(() => { | |
147 | + const { height } = props; | |
148 | + return isNumber(height) ? `${height}px` : height; | |
102 | 149 | }); |
103 | 150 | |
104 | 151 | defineExpose({ |
... | ... | @@ -108,22 +155,41 @@ |
108 | 155 | </script> |
109 | 156 | |
110 | 157 | <template> |
111 | - <div class="p-2 bg-gray-200" :style="{ height: `${height}px` }"> | |
112 | - <div ref="jsonEditorElRef" class="jsoneditor"></div> | |
158 | + <div | |
159 | + ref="jsonEditorContainerElRef" | |
160 | + class="p-2 bg-gray-200 flex flex-col" | |
161 | + :style="{ height: getHeight }" | |
162 | + > | |
163 | + <div class="w-full h-8 flex justify-between items-center"> | |
164 | + <div> | |
165 | + {{ title }} | |
166 | + </div> | |
167 | + <slot name="header"></slot> | |
168 | + <div class="flex h-8 gap-3 justify-end items-center text-dark-500 svg:text-2xl"> | |
169 | + <slot name="beforeFormat"></slot> | |
170 | + <Tooltip title="整洁"> | |
171 | + <Icon @click="handleFormat" class="cursor-pointer" icon="gg:format-left" /> | |
172 | + </Tooltip> | |
173 | + <slot name="beforeCompress"></slot> | |
174 | + | |
175 | + <Tooltip title="迷你"> | |
176 | + <Icon @click="handleCompress" class="cursor-pointer" icon="material-symbols:compress" /> | |
177 | + </Tooltip> | |
178 | + <slot name="beforeFullScreen"></slot> | |
179 | + | |
180 | + <Tooltip title="全屏"> | |
181 | + <Icon | |
182 | + v-if="isSupported" | |
183 | + class="cursor-pointer" | |
184 | + :icon=" | |
185 | + isFullscreen ? 'material-symbols:fullscreen-exit' : 'material-symbols:fullscreen' | |
186 | + " | |
187 | + @click="handleFullScreen" | |
188 | + /> | |
189 | + </Tooltip> | |
190 | + <slot name="afterFullScreen"></slot> | |
191 | + </div> | |
192 | + </div> | |
193 | + <div ref="jsonEditorElRef" class="flex-auto"></div> | |
113 | 194 | </div> |
114 | 195 | </template> |
115 | - | |
116 | -<style lang="less" scoped> | |
117 | - .jsoneditor { | |
118 | - border: none !important; | |
119 | - | |
120 | - :deep(.jsoneditor) { | |
121 | - border: none !important; | |
122 | - | |
123 | - .ace-jsoneditor, | |
124 | - textarea.jsoneditor-text { | |
125 | - min-height: auto; | |
126 | - } | |
127 | - } | |
128 | - } | |
129 | -</style> | ... | ... |
... | ... | @@ -13,6 +13,7 @@ export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue'; |
13 | 13 | export { default as ApiUpload } from './src/components/ApiUpload.vue'; |
14 | 14 | |
15 | 15 | export { default as StructForm } from './src/externalCompns/components/StructForm/StructForm.vue'; |
16 | +export { default as JavaScriptFunctionEditor } from './src/components/JavaScriptFunctionEditor.vue'; | |
16 | 17 | |
17 | 18 | //注册自定义组件 |
18 | 19 | export { | ... | ... |
... | ... | @@ -14,6 +14,7 @@ |
14 | 14 | import { get, omit } from 'lodash-es'; |
15 | 15 | import { LoadingOutlined } from '@ant-design/icons-vue'; |
16 | 16 | import { useI18n } from '/@/hooks/web/useI18n'; |
17 | + import { useDebounceFn } from '@vueuse/shared'; | |
17 | 18 | |
18 | 19 | const emit = defineEmits(['options-change', 'change']); |
19 | 20 | const props = withDefaults( |
... | ... | @@ -27,6 +28,7 @@ |
27 | 28 | labelField?: string; |
28 | 29 | valueField?: string; |
29 | 30 | immediate?: boolean; |
31 | + searchField?: string; | |
30 | 32 | queryEmptyDataAgin?: boolean; |
31 | 33 | onChangeHook?: ({ options }: OnChangeHookParams) => void; |
32 | 34 | dropdownVisibleChangeHook?: ({ options }: OnChangeHookParams) => void; |
... | ... | @@ -35,6 +37,7 @@ |
35 | 37 | resultField: '', |
36 | 38 | labelField: 'label', |
37 | 39 | valueField: 'value', |
40 | + searchField: 'text', | |
38 | 41 | immediate: true, |
39 | 42 | queryEmptyDataAgin: true, |
40 | 43 | } |
... | ... | @@ -53,17 +56,27 @@ |
53 | 56 | const { labelField, valueField = 'value', numberToString } = props; |
54 | 57 | return unref(options).reduce((prev, next: Recordable) => { |
55 | 58 | if (next) { |
56 | - const value = next[valueField]; | |
59 | + const value = get(next, valueField); | |
60 | + const label = get(next, labelField); | |
57 | 61 | prev.push({ |
58 | - label: next[labelField], | |
59 | - value: numberToString ? `${value}` : value, | |
60 | 62 | ...omit(next, [labelField, valueField]), |
63 | + label, | |
64 | + value: numberToString ? `${value}` : value, | |
61 | 65 | }); |
62 | 66 | } |
63 | 67 | return prev; |
64 | 68 | }, [] as OptionsItem[]); |
65 | 69 | }); |
66 | 70 | |
71 | + const getBindProps = computed(() => { | |
72 | + const { searchApi } = props; | |
73 | + return { | |
74 | + ...attrs, | |
75 | + showSearch: true, | |
76 | + filterOption: !searchApi, | |
77 | + }; | |
78 | + }); | |
79 | + | |
67 | 80 | watchEffect(() => { |
68 | 81 | props.immediate && fetch(); |
69 | 82 | }); |
... | ... | @@ -122,8 +135,9 @@ |
122 | 135 | onChangeHook({ options }); |
123 | 136 | } |
124 | 137 | |
138 | + const debounceSearchFunction = useDebounceFn(handleSearch, 300); | |
125 | 139 | async function handleSearch(params?: string) { |
126 | - let { searchApi, api } = props; | |
140 | + let { searchApi, api, searchField } = props; | |
127 | 141 | if (!searchApi || !isFunction(searchApi)) { |
128 | 142 | if (!api || !isFunction(api)) return; |
129 | 143 | searchApi = api; |
... | ... | @@ -131,7 +145,7 @@ |
131 | 145 | options.value = []; |
132 | 146 | try { |
133 | 147 | loading.value = true; |
134 | - const res = await searchApi({ ...props.params, text: params }); | |
148 | + const res = await searchApi({ ...props.params, [searchField]: params }); | |
135 | 149 | if (Array.isArray(res)) { |
136 | 150 | options.value = res; |
137 | 151 | emitChange(); |
... | ... | @@ -152,11 +166,10 @@ |
152 | 166 | <template> |
153 | 167 | <Select |
154 | 168 | @dropdownVisibleChange="handleFetch" |
155 | - v-bind="attrs" | |
156 | - show-search | |
169 | + v-bind="getBindProps" | |
157 | 170 | @change="handleChange" |
158 | 171 | :options="getOptions" |
159 | - @search="handleSearch" | |
172 | + @search="debounceSearchFunction" | |
160 | 173 | v-model:value="state" |
161 | 174 | > |
162 | 175 | <template #[item]="data" v-for="item in Object.keys($slots)"> | ... | ... |
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | <script lang="ts" setup> |
7 | 7 | import { ref, watchEffect, computed, unref, watch, reactive } from 'vue'; |
8 | 8 | import { Select, Spin } from 'ant-design-vue'; |
9 | - import { isFunction } from '/@/utils/is'; | |
9 | + import { isFunction, isNullAndUnDef } from '/@/utils/is'; | |
10 | 10 | import { useRuleFormItem } from '/@/hooks/component/useFormItem'; |
11 | 11 | import { useAttrs } from '/@/hooks/core/useAttrs'; |
12 | 12 | import { get, omit } from 'lodash-es'; |
... | ... | @@ -30,8 +30,11 @@ |
30 | 30 | labelField?: string; |
31 | 31 | valueField?: string; |
32 | 32 | immediate?: boolean; |
33 | - pagenation?: Pagination; | |
33 | + searchField?: string; | |
34 | + pagination?: Pagination; | |
34 | 35 | queryEmptyDataAgin?: boolean; |
36 | + fetchSearch?: boolean; | |
37 | + filterOption?: (inputValue: string, options: Recordable) => boolean; | |
35 | 38 | }>(), |
36 | 39 | { |
37 | 40 | resultField: '', |
... | ... | @@ -39,14 +42,15 @@ |
39 | 42 | valueField: 'value', |
40 | 43 | immediate: true, |
41 | 44 | queryEmptyDataAgin: true, |
42 | - pagenation: () => ({ page: 1, pageSize: 10 }), | |
45 | + pagination: () => ({ page: 1, pageSize: 10 }), | |
46 | + fetchSearch: false, | |
43 | 47 | } |
44 | 48 | ); |
45 | 49 | |
46 | 50 | const OptionsItem = (_, { attrs }: { attrs: { vNode: any } }) => attrs.vNode; |
47 | 51 | |
48 | 52 | const options = ref<OptionsItem[]>([]); |
49 | - const pagination = reactive(Object.assign({ total: 0, page: 1, pageSize: 10 }, props.pagenation)); | |
53 | + const pagination = reactive<Record<'total' | 'page' | 'pageSize', number>>({} as any); | |
50 | 54 | const scrollLoading = ref(false); |
51 | 55 | const lock = ref(false); |
52 | 56 | const loading = ref(false); |
... | ... | @@ -55,6 +59,13 @@ |
55 | 59 | const attrs = useAttrs(); |
56 | 60 | const { t } = useI18n(); |
57 | 61 | |
62 | + const getPagination = computed(() => { | |
63 | + return { | |
64 | + ...props.pagination, | |
65 | + ...unref(pagination), | |
66 | + }; | |
67 | + }); | |
68 | + | |
58 | 69 | // Embedded in the form, just use the hook binding to perform form verification |
59 | 70 | const [state] = useRuleFormItem(props, 'value', 'change', emitData); |
60 | 71 | |
... | ... | @@ -86,16 +97,18 @@ |
86 | 97 | { deep: true } |
87 | 98 | ); |
88 | 99 | |
89 | - async function fetch() { | |
90 | - const api = props.api; | |
100 | + async function fetch(searchText?: string) { | |
101 | + const { api, searchField, fetchSearch } = props; | |
91 | 102 | if (!api || !isFunction(api)) return; |
103 | + const isFetchSearchFlag = fetchSearch && !isNullAndUnDef(searchText) && searchField; | |
92 | 104 | try { |
93 | 105 | !unref(getOptions).length ? (loading.value = true) : (scrollLoading.value = true); |
94 | 106 | lock.value = true; |
95 | 107 | const { total, items } = await api({ |
96 | 108 | ...props.params, |
97 | - page: pagination.page, | |
98 | - pageSize: pagination.pageSize, | |
109 | + page: unref(getPagination).page, | |
110 | + pageSize: unref(getPagination).pageSize, | |
111 | + ...(isFetchSearchFlag ? { [searchField!]: searchText } : {}), | |
99 | 112 | }); |
100 | 113 | |
101 | 114 | pagination.total = total; |
... | ... | @@ -105,11 +118,13 @@ |
105 | 118 | return; |
106 | 119 | } |
107 | 120 | if (props.resultField) { |
108 | - options.value = [...options.value, ...(get(items, props.resultField) || [])]; | |
121 | + options.value = isFetchSearchFlag | |
122 | + ? get(items, props.resultField) || [] | |
123 | + : [...options.value, ...(get(items, props.resultField) || [])]; | |
109 | 124 | } |
110 | 125 | emitChange(); |
111 | 126 | } catch (error) { |
112 | - pagination.page = Math.ceil(unref(getOptions).length / pagination.pageSize); | |
127 | + pagination.page = Math.ceil(unref(getOptions).length / unref(getPagination).pageSize); | |
113 | 128 | console.warn(error); |
114 | 129 | } finally { |
115 | 130 | isFirstLoad.value = false; |
... | ... | @@ -134,17 +149,39 @@ |
134 | 149 | emitData.value = args; |
135 | 150 | } |
136 | 151 | |
152 | + const sleep = async (number: number) => { | |
153 | + return new Promise((resolve) => { | |
154 | + setTimeout(() => { | |
155 | + resolve(number); | |
156 | + }, number); | |
157 | + }); | |
158 | + }; | |
159 | + | |
137 | 160 | async function handlePopupScroll(event: MouseEvent) { |
138 | 161 | const { scrollHeight, scrollTop, clientHeight } = event.target as HTMLDivElement; |
139 | 162 | if (scrollTop + clientHeight >= scrollHeight) { |
140 | - if (unref(getOptions).length < pagination.total && !unref(lock)) { | |
141 | - pagination.page = pagination.page + 1; | |
163 | + if (unref(getOptions).length < unref(getPagination).total && !unref(lock)) { | |
164 | + pagination.page = unref(getPagination).page + 1; | |
165 | + scrollLoading.value = true; | |
166 | + await sleep(500); | |
142 | 167 | await fetch(); |
143 | 168 | } |
144 | 169 | } |
145 | 170 | } |
146 | 171 | |
147 | 172 | const debounceHandlePopupScroll = useDebounceFn(handlePopupScroll, 100); |
173 | + | |
174 | + const handleFilterOption = async (inputValue: string, option: Recordable) => { | |
175 | + const { filterOption, fetchSearch } = props; | |
176 | + if (filterOption && isFunction(filterOption)) { | |
177 | + filterOption?.(inputValue, option); | |
178 | + return; | |
179 | + } | |
180 | + | |
181 | + if (fetchSearch) { | |
182 | + await fetch(inputValue); | |
183 | + } | |
184 | + }; | |
148 | 185 | </script> |
149 | 186 | |
150 | 187 | <template> |
... | ... | @@ -153,6 +190,8 @@ |
153 | 190 | v-bind="attrs" |
154 | 191 | @change="handleChange" |
155 | 192 | :options="getOptions" |
193 | + :filterOption="handleFilterOption" | |
194 | + :showSearch="true" | |
156 | 195 | v-model:value="state" |
157 | 196 | @popup-scroll="debounceHandlePopupScroll" |
158 | 197 | > | ... | ... |
... | ... | @@ -40,16 +40,19 @@ |
40 | 40 | accept?: string; |
41 | 41 | maxSize?: number; |
42 | 42 | disabled?: boolean; |
43 | - listType?: string; | |
43 | + listType?: 'text' | 'picture-card' | 'picture'; | |
44 | 44 | multiple?: boolean; |
45 | 45 | maxFileLimit?: number; |
46 | - showUploadList?: boolean | { showPreviewIcon?: boolean; showRemoveIcon?: boolean }; | |
46 | + showUploadList?: InstanceType<typeof Upload>['$props']['showUploadList']; | |
47 | 47 | transformFile?: (file: File) => string | Blob | Promise<string | Blob | File>; |
48 | 48 | api: (file: string | Blob | Promise<string | Blob | File>) => Promise<FileItem>; |
49 | + overFileLimitHiddenUploadEntry?: boolean; | |
49 | 50 | }>(), |
50 | 51 | { |
51 | 52 | fileList: () => [], |
52 | 53 | maxSize: 5 * 1024 * 1024, |
54 | + overFileLimitHiddenUploadEntry: true, | |
55 | + listType: 'text', | |
53 | 56 | showUploadList: () => ({ showPreviewIcon: true, showRemoveIcon: true }), |
54 | 57 | } |
55 | 58 | ); |
... | ... | @@ -75,7 +78,7 @@ |
75 | 78 | |
76 | 79 | const getMaxFileLimit = computed(() => { |
77 | 80 | const { maxFileLimit } = props; |
78 | - return isPictureCard.value ? 1 : maxFileLimit; | |
81 | + return isPictureCard.value ? 1 : maxFileLimit || 1; | |
79 | 82 | }); |
80 | 83 | |
81 | 84 | const handleUpload = async (file: File | string | Blob | Promise<string | Blob | File>) => { |
... | ... | @@ -131,11 +134,15 @@ |
131 | 134 | :list-type="props.listType" |
132 | 135 | :disabled="getDisabled" |
133 | 136 | :before-upload="handleBeforeUpload" |
137 | + :show-upload-list="showUploadList" | |
134 | 138 | @preview="handlePreview" |
135 | 139 | @download="handleDownload" |
136 | 140 | :remove="handleRemove" |
137 | 141 | > |
138 | - <Spin v-if="!fileList.length" :spinning="loading"> | |
142 | + <Spin | |
143 | + v-if="!(fileList.length >= getMaxFileLimit) || overFileLimitHiddenUploadEntry" | |
144 | + :spinning="loading" | |
145 | + > | |
139 | 146 | <div class="w-full h-full flex flex-col justify-center content-center"> |
140 | 147 | <Tooltip title="点击上传或拖拽上传"> |
141 | 148 | <InboxOutlined class="text-[3rem] !text-blue-500" /> | ... | ... |
1 | +<script lang="ts" setup> | |
2 | + import { Icon } from '/@/components/Icon'; | |
3 | + import { Tooltip } from 'ant-design-vue'; | |
4 | + import { computed, onMounted, onUnmounted, ref, shallowRef, unref, watch } from 'vue'; | |
5 | + import AceEditor, { Ace } from 'ace-builds'; | |
6 | + import workerJavascriptUrl from 'ace-builds/src-noconflict/worker-javascript?url'; | |
7 | + import githubTheme from 'ace-builds/src-noconflict/theme-github?url'; | |
8 | + import 'ace-builds/src-noconflict/mode-javascript'; | |
9 | + import 'ace-builds/src-noconflict/ext-searchbox'; | |
10 | + import 'ace-builds/src-noconflict/ext-language_tools'; | |
11 | + import 'ace-builds/src-noconflict/snippets/javascript'; | |
12 | + import { useBeautify } from '/@/hooks/business/useBeautify'; | |
13 | + import { useFullscreen } from '@vueuse/core'; | |
14 | + import { isNumber } from '/@/utils/is'; | |
15 | + | |
16 | + const emit = defineEmits(['update:value', 'focus', 'blur']); | |
17 | + const props = withDefaults( | |
18 | + defineProps<{ | |
19 | + functionName?: string; | |
20 | + paramsName?: string[]; | |
21 | + height?: number | string; | |
22 | + value?: string; | |
23 | + disabled?: boolean; | |
24 | + validateStatus?: boolean; | |
25 | + }>(), | |
26 | + { | |
27 | + functionName: 'method', | |
28 | + paramsName: () => [], | |
29 | + height: 200, | |
30 | + value: '', | |
31 | + } | |
32 | + ); | |
33 | + | |
34 | + const getHeight = computed(() => { | |
35 | + const { height } = props; | |
36 | + return isNumber(height) ? `${height}px` : height; | |
37 | + }); | |
38 | + | |
39 | + const javaScriptEditorElRef = ref<Nullable<HTMLDivElement>>(); | |
40 | + const editorInstance = shallowRef<Ace.Editor>(); | |
41 | + const isFocus = ref(false); | |
42 | + | |
43 | + const handleFocus = () => { | |
44 | + isFocus.value = true; | |
45 | + emit('focus', unref(editorInstance)); | |
46 | + }; | |
47 | + | |
48 | + const handleBlur = () => { | |
49 | + isFocus.value = false; | |
50 | + emit('update:value', get()); | |
51 | + emit('blur', unref(editorInstance)); | |
52 | + }; | |
53 | + | |
54 | + const handleChange = () => { | |
55 | + emit('update:value', get()); | |
56 | + }; | |
57 | + | |
58 | + const initEditor = () => { | |
59 | + AceEditor.config.setModuleUrl('ace/mode/javascript_worker', workerJavascriptUrl); | |
60 | + AceEditor.config.setModuleUrl('ace/theme/github', githubTheme); | |
61 | + const editor = AceEditor.edit(unref(javaScriptEditorElRef)!, { | |
62 | + mode: 'ace/mode/javascript', | |
63 | + }); | |
64 | + editor.setTheme('ace/theme/github'); | |
65 | + editor.setOptions({ | |
66 | + fontSize: 14, | |
67 | + enableBasicAutocompletion: true, | |
68 | + enableSnippets: true, | |
69 | + enableLiveAutocompletion: true, | |
70 | + }); | |
71 | + | |
72 | + editor.on('focus', handleFocus); | |
73 | + editor.on('blur', handleBlur); | |
74 | + editor.on('change', handleChange); | |
75 | + editorInstance.value = editor; | |
76 | + editor.setValue(props.value); | |
77 | + editor?.clearSelection(); | |
78 | + unref(editorInstance)?.setReadOnly(props.disabled); | |
79 | + }; | |
80 | + | |
81 | + const get = () => { | |
82 | + return unref(editorInstance)?.getValue(); | |
83 | + }; | |
84 | + | |
85 | + const set = (val: string, cursorPos?: number) => { | |
86 | + return unref(editorInstance)?.setValue(val, cursorPos); | |
87 | + }; | |
88 | + | |
89 | + onMounted(() => { | |
90 | + initEditor(); | |
91 | + }); | |
92 | + | |
93 | + onUnmounted(() => { | |
94 | + unref(editorInstance)?.off('change', handleChange); | |
95 | + unref(editorInstance)?.off('focus', handleFocus); | |
96 | + unref(editorInstance)?.off('blur', handleBlur); | |
97 | + unref(editorInstance)?.destroy(); | |
98 | + unref(editorInstance)?.container.remove(); | |
99 | + }); | |
100 | + | |
101 | + const { beautifyJs } = useBeautify(); | |
102 | + const handleFormatCode = async () => { | |
103 | + const res = await beautifyJs(get() || '', { indent_size: 4, wrap_line_length: 60 }); | |
104 | + set(res || '', -1); | |
105 | + }; | |
106 | + | |
107 | + const jsFunctionContainerElRef = ref<Nullable<HTMLDivElement>>(); | |
108 | + const { isFullscreen, isSupported, toggle } = useFullscreen(jsFunctionContainerElRef); | |
109 | + const handleFullScreen = () => { | |
110 | + toggle(); | |
111 | + }; | |
112 | + | |
113 | + watch( | |
114 | + () => props.value, | |
115 | + (value) => { | |
116 | + // const position = unref(editorInstance)?.getCursorPosition(); | |
117 | + if (unref(isFocus)) return; | |
118 | + set(value); | |
119 | + unref(editorInstance)?.clearSelection(); | |
120 | + // position && unref(editorInstance)?.moveCursorToPosition(position!); | |
121 | + }, | |
122 | + { | |
123 | + immediate: true, | |
124 | + } | |
125 | + ); | |
126 | + | |
127 | + watch( | |
128 | + () => props.disabled, | |
129 | + (value) => { | |
130 | + unref(editorInstance)?.setReadOnly(value); | |
131 | + } | |
132 | + ); | |
133 | + | |
134 | + defineExpose({ | |
135 | + get, | |
136 | + set, | |
137 | + }); | |
138 | +</script> | |
139 | + | |
140 | +<template> | |
141 | + <section | |
142 | + ref="jsFunctionContainerElRef" | |
143 | + class="p-2 bg-gray-200 flex flex-col" | |
144 | + :style="{ height: getHeight }" | |
145 | + > | |
146 | + <head class="flex justify-between h-8 items-center"> | |
147 | + <div class="font-bold"> | |
148 | + <span>function</span> | |
149 | + <span class="ml-1">{{ functionName }}</span> | |
150 | + <span>({{ paramsName.join(',') }})</span> | |
151 | + <span class="ml-1">{</span> | |
152 | + </div> | |
153 | + <div class="flex gap-3 items-center svg:text-2xl"> | |
154 | + <slot name="beforeFormat"></slot> | |
155 | + | |
156 | + <Tooltip title="整洁"> | |
157 | + <Icon class="cursor-pointer" icon="gg:format-left" @click="handleFormatCode" /> | |
158 | + </Tooltip> | |
159 | + <slot name="beforeFullScreen"></slot> | |
160 | + <Tooltip title="全屏"> | |
161 | + <Icon | |
162 | + v-if="isSupported" | |
163 | + class="cursor-pointer" | |
164 | + :icon=" | |
165 | + isFullscreen ? 'material-symbols:fullscreen-exit' : 'material-symbols:fullscreen' | |
166 | + " | |
167 | + @click="handleFullScreen" | |
168 | + /> | |
169 | + </Tooltip> | |
170 | + <slot name="afterFullScreen"></slot> | |
171 | + </div> | |
172 | + </head> | |
173 | + <main ref="javaScriptEditorElRef" class="flex-auto"> </main> | |
174 | + <footer class="font-bold">}</footer> | |
175 | + </section> | |
176 | +</template> | ... | ... |
... | ... | @@ -130,4 +130,11 @@ export type ComponentType = |
130 | 130 | | 'ControlGroup' |
131 | 131 | | 'JSONEditor' |
132 | 132 | | 'OrgTreeSelect' |
133 | - | 'ExtendDesc'; | |
133 | + | 'ExtendDesc' | |
134 | + | 'JavaScriptFunctionEditor' | |
135 | + | 'JavascriptEditorWithTestModal' | |
136 | + | 'AttributeConfiguration' | |
137 | + | 'CorrelationFilters' | |
138 | + | 'RelationsQuery' | |
139 | + | 'CredentialsCard' | |
140 | + | 'ApiComplete'; | ... | ... |
src/enums/alarmEnum.ts
0 → 100644
1 | +export enum AlarmStatus { | |
2 | + CLEARED_UN_ACK = 'CLEARED_UNACK', | |
3 | + ACTIVE_UN_ACK = 'ACTIVE_UNACK', | |
4 | + CLEARED_ACK = 'CLEARED_ACK', | |
5 | + ACTIVE_ACK = 'ACTIVE_ACK', | |
6 | +} | |
7 | + | |
8 | +export enum AlarmStatusMean { | |
9 | + CLEARED_UNACK = '清除未确认', | |
10 | + ACTIVE_UNACK = '激活未确认', | |
11 | + CLEARED_ACK = '清除已确认', | |
12 | + ACTIVE_ACK = '激活已确认', | |
13 | +} | ... | ... |
... | ... | @@ -38,6 +38,11 @@ export const PLATFORM = 'PLATFORM'; |
38 | 38 | export const PLATFORM_INFO_CACHE_KEY = 'PLATFORM_INFO'; |
39 | 39 | |
40 | 40 | export const MENU_LIST = 'MENU_LIST'; |
41 | + | |
42 | +export const RULE_NODE_LOCAL_CACHE_KEY = 'RULE__NODE__KEY__'; | |
43 | + | |
44 | +export const RULE_NODE_KEY = 'RULE_NODE'; | |
45 | + | |
41 | 46 | export enum CacheTypeEnum { |
42 | 47 | SESSION, |
43 | 48 | LOCAL, | ... | ... |
... | ... | @@ -19,4 +19,8 @@ export enum DictEnum { |
19 | 19 | DISABLE_CUSTOMER_AUTH = 'disabled_customer_auth', |
20 | 20 | // 寄存器数据格式 |
21 | 21 | REGISTER_DATA_FORMAT = 'register_data_format', |
22 | + // 消息类型 规则节点 Filter message type switch | |
23 | + MESSAGE_TYPES_FILTER = 'message_types_filter', | |
24 | + // 实体类型 规则节点 Filter originator types switch | |
25 | + ORIGINATOR_TYPES = 'originator_types', | |
22 | 26 | } | ... | ... |
src/hooks/business/useBatchSettingDict.ts
0 → 100644
1 | +import { saveOrEditDictItem } from '/@/api/system/dict'; | |
2 | +import { SysDictItem } from '/@/api/system/model/dictModel'; | |
3 | + | |
4 | +interface BatchSettingParamsType { | |
5 | + dictId: string; | |
6 | + list: any[]; | |
7 | + transformText: (item: any) => any; | |
8 | + transformValue: (item: any) => any; | |
9 | + update?: boolean; | |
10 | +} | |
11 | + | |
12 | +export function useBatchSettingDict() { | |
13 | + const batchSetting = async (options: BatchSettingParamsType) => { | |
14 | + const { dictId, list, transformText, transformValue, update = false } = options; | |
15 | + if (!transformText || !transformValue) return; | |
16 | + let index = 1; | |
17 | + for (const item of list) { | |
18 | + const params: Partial<SysDictItem> & { dictId: string } = { | |
19 | + dictId, | |
20 | + sort: index++, | |
21 | + status: 1, | |
22 | + itemText: transformText(item), | |
23 | + itemValue: transformValue(item), | |
24 | + }; | |
25 | + | |
26 | + await saveOrEditDictItem(params as SysDictItem, update); | |
27 | + } | |
28 | + }; | |
29 | + | |
30 | + const batchDelete = () => {}; | |
31 | + | |
32 | + return { | |
33 | + batchSetting, | |
34 | + batchDelete, | |
35 | + }; | |
36 | +} | ... | ... |
src/hooks/business/useBeautify.ts
0 → 100644
1 | +export function useBeautify() { | |
2 | + let jsBeautifyModule: any; | |
3 | + | |
4 | + async function loadJsBeautify() { | |
5 | + if (jsBeautifyModule) return jsBeautifyModule; | |
6 | + jsBeautifyModule = await import('js-beautify/js/lib/beautifier'); | |
7 | + return jsBeautifyModule; | |
8 | + } | |
9 | + | |
10 | + async function beautifyJs(source: string, options?: any) { | |
11 | + const module = await loadJsBeautify(); | |
12 | + return module.js(source, options); | |
13 | + } | |
14 | + return { beautifyJs }; | |
15 | +} | ... | ... |
src/hooks/business/useJsonParse.ts
0 → 100644
1 | +import { isObject, isString } from '/@/utils/is'; | |
2 | + | |
3 | +export function useJsonParse(value: any, defaultValue = {}) { | |
4 | + let flag = false; | |
5 | + try { | |
6 | + value = JSON.parse(value); | |
7 | + if (isObject(value) || (isString(value) && value.trim() === '')) flag = true; | |
8 | + } catch (error) { | |
9 | + value = defaultValue; | |
10 | + } | |
11 | + return { flag, value }; | |
12 | +} | ... | ... |
... | ... | @@ -3,6 +3,7 @@ import { RouteLocationNormalizedLoaded } from 'vue-router'; |
3 | 3 | const menuMap = new Map(); |
4 | 4 | |
5 | 5 | menuMap.set('/visual/board/detail/:boardId/:boardName?', '/visual/board'); |
6 | +menuMap.set('/rule/chain/:id', '/rule/chain'); | |
6 | 7 | |
7 | 8 | export const useMenuActiveFix = (route: RouteLocationNormalizedLoaded) => { |
8 | 9 | let flag = false; | ... | ... |
... | ... | @@ -3,20 +3,7 @@ import { FormSchema } from '/@/components/Form'; |
3 | 3 | import { BasicColumn } from '/@/components/Table'; |
4 | 4 | import moment from 'moment'; |
5 | 5 | import { findDictItemByCode } from '/@/api/system/dict'; |
6 | - | |
7 | -export enum AlarmStatus { | |
8 | - CLEARED_UN_ACK = 'CLEARED_UNACK', | |
9 | - ACTIVE_UN_ACK = 'ACTIVE_UNACK', | |
10 | - CLEARED_ACK = 'CLEARED_ACK', | |
11 | - ACTIVE_ACK = 'ACTIVE_ACK', | |
12 | -} | |
13 | - | |
14 | -export enum AlarmStatusMean { | |
15 | - CLEARED_UNACK = '清除未确认', | |
16 | - ACTIVE_UNACK = '激活未确认', | |
17 | - CLEARED_ACK = '清除已确认', | |
18 | - ACTIVE_ACK = '激活已确认', | |
19 | -} | |
6 | +import { AlarmStatus, AlarmStatusMean } from '/@/enums/alarmEnum'; | |
20 | 7 | |
21 | 8 | export const alarmSearchSchemas: FormSchema[] = [ |
22 | 9 | { | ... | ... |
1 | -import { AlarmStatus, AlarmStatusMean } from '../config/detail.config'; | |
2 | 1 | import { clearOrAckAlarm, getDeviceAlarm } from '/@/api/device/deviceManager'; |
3 | 2 | import { notification, Button, Tag } from 'ant-design-vue'; |
4 | 3 | import { h, onMounted, onUnmounted } from 'vue'; |
... | ... | @@ -8,6 +7,7 @@ import { RoleEnum } from '/@/enums/roleEnum'; |
8 | 7 | import { usePermission } from '/@/hooks/web/usePermission'; |
9 | 8 | import { useUserStore } from '/@/store/modules/user'; |
10 | 9 | import { useGlobSetting } from '/@/hooks/setting'; |
10 | +import { AlarmStatus, AlarmStatusMean } from '/@/enums/alarmEnum'; | |
11 | 11 | |
12 | 12 | interface UseAlarmNotifyParams { |
13 | 13 | alarmNotifyStatus?: AlarmStatus; | ... | ... |
... | ... | @@ -91,7 +91,7 @@ export const formSchema: FormSchema[] = [ |
91 | 91 | valueField: 'fileList', |
92 | 92 | componentProps: () => { |
93 | 93 | return { |
94 | - listType: 'picture-card', | |
94 | + // listType: 'picture-card', | |
95 | 95 | maxFileLimit: 1, |
96 | 96 | api: async (file: File) => { |
97 | 97 | try { |
... | ... | @@ -110,6 +110,10 @@ export const formSchema: FormSchema[] = [ |
110 | 110 | onPreview: (fileList: FileItem) => { |
111 | 111 | createImgPreview({ imageList: [fileList.url!] }); |
112 | 112 | }, |
113 | + showUploadList: { | |
114 | + showDownloadIcon: true, | |
115 | + showRemoveIcon: true, | |
116 | + }, | |
113 | 117 | }; |
114 | 118 | }, |
115 | 119 | }, | ... | ... |
... | ... | @@ -57,7 +57,7 @@ export const formSchema: FormSchema[] = [ |
57 | 57 | valueField: 'fileList', |
58 | 58 | componentProps: () => { |
59 | 59 | return { |
60 | - listType: 'picture-card', | |
60 | + // listType: 'picture-card', | |
61 | 61 | maxFileLimit: 1, |
62 | 62 | api: async (file: File) => { |
63 | 63 | try { |
... | ... | @@ -73,6 +73,10 @@ export const formSchema: FormSchema[] = [ |
73 | 73 | return {}; |
74 | 74 | } |
75 | 75 | }, |
76 | + showUploadList: true, | |
77 | + onDownload(file) { | |
78 | + console.log(file); | |
79 | + }, | |
76 | 80 | onPreview: (fileList: FileItem) => { |
77 | 81 | createImgPreview({ imageList: [fileList.url!] }); |
78 | 82 | }, | ... | ... |
... | ... | @@ -23,7 +23,7 @@ |
23 | 23 | layout: 'vertical', |
24 | 24 | }); |
25 | 25 | |
26 | - const { genForm } = useGenDynamicForm(); | |
26 | + const { genForm, transformValue } = useGenDynamicForm(); | |
27 | 27 | |
28 | 28 | const keys = ref<string[]>([]); |
29 | 29 | |
... | ... | @@ -159,8 +159,8 @@ |
159 | 159 | |
160 | 160 | sendValue.value = await genModbusCommand(unref(modBUSForm)); |
161 | 161 | } else { |
162 | - const _value = getFieldsValue(); | |
163 | - | |
162 | + await validate(); | |
163 | + const _value = transformValue(getFieldsValue()); | |
164 | 164 | sendValue.value = unref(keys).reduce((prev, next) => { |
165 | 165 | return { ...prev, [next]: _value[next] }; |
166 | 166 | }, {}); | ... | ... |
1 | 1 | import { DataType, Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel'; |
2 | 2 | import { JSONEditor } from '/@/components/CodeEditor'; |
3 | 3 | import { FormSchema, useComponentRegister } from '/@/components/Form'; |
4 | +import { useJsonParse } from '/@/hooks/business/useJsonParse'; | |
4 | 5 | import { DataTypeEnum } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; |
5 | 6 | |
6 | 7 | export interface BasicCreateFormParams { |
... | ... | @@ -106,6 +107,19 @@ export const useGenDynamicForm = () => { |
106 | 107 | field: identifier, |
107 | 108 | label: functionName, |
108 | 109 | component: 'JSONEditor', |
110 | + valueField: 'value', | |
111 | + changeEvent: 'update:value', | |
112 | + rules: [ | |
113 | + { | |
114 | + validator: (_rule, value: any) => { | |
115 | + if (value) { | |
116 | + const { flag } = useJsonParse(value); | |
117 | + if (!flag) return Promise.reject(`${functionName} 不是一个有效的JSON对象`); | |
118 | + } | |
119 | + return Promise.resolve(); | |
120 | + }, | |
121 | + }, | |
122 | + ], | |
109 | 123 | }; |
110 | 124 | }; |
111 | 125 | |
... | ... | @@ -117,11 +131,14 @@ export const useGenDynamicForm = () => { |
117 | 131 | [DataTypeEnum.IS_STRUCT]: createInputJson, |
118 | 132 | }; |
119 | 133 | |
134 | + const fieldTypeMap = new Map<string, DataTypeEnum>(); | |
120 | 135 | const genForm = (schemas: StructJSON[]) => { |
136 | + fieldTypeMap.clear(); | |
121 | 137 | const formSchema = schemas.map((item) => { |
122 | 138 | const { functionName, identifier, dataType } = item; |
123 | 139 | const { type } = dataType || {}; |
124 | 140 | |
141 | + fieldTypeMap.set(identifier!, dataType!.type); | |
125 | 142 | const method = schemaMethod[type!]; |
126 | 143 | |
127 | 144 | const formSchema = method?.({ |
... | ... | @@ -136,5 +153,21 @@ export const useGenDynamicForm = () => { |
136 | 153 | return formSchema.filter(Boolean); |
137 | 154 | }; |
138 | 155 | |
139 | - return { genForm }; | |
156 | + const transformValue = (value: Recordable) => { | |
157 | + return Object.keys(value || {}).reduce((prev, next) => { | |
158 | + const dataType = fieldTypeMap.get(next)!; | |
159 | + | |
160 | + let itemValue = value[next]; | |
161 | + if (dataType === DataTypeEnum.IS_STRUCT) { | |
162 | + const { value } = useJsonParse(itemValue); | |
163 | + itemValue = value; | |
164 | + } | |
165 | + return { | |
166 | + ...prev, | |
167 | + [next]: itemValue, | |
168 | + }; | |
169 | + }, {} as Recordable); | |
170 | + }; | |
171 | + | |
172 | + return { genForm, transformValue }; | |
140 | 173 | }; | ... | ... |
1 | +<template> | |
2 | + <div> | |
3 | + <BasicModal | |
4 | + destroyOnClose | |
5 | + v-bind="$attrs" | |
6 | + width="30rem" | |
7 | + @register="register" | |
8 | + title="添加规则链" | |
9 | + @ok="handleSuccess" | |
10 | + @close="handleClose" | |
11 | + > | |
12 | + <div> | |
13 | + <BasicForm @register="registerForm" /> | |
14 | + </div> | |
15 | + </BasicModal> | |
16 | + </div> | |
17 | +</template> | |
18 | +<script setup lang="ts"> | |
19 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | |
20 | + import { ExecuteReportRecord } from '/@/api/export/model/exportModel'; | |
21 | + import { useForm, BasicForm } from '/@/components/Form'; | |
22 | + import { formSchema } from './config'; | |
23 | + import { createRuleChine } from '/@/api/ruleengine/ruleengineApi'; | |
24 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
25 | + | |
26 | + const emit = defineEmits(['register', 'success']); | |
27 | + | |
28 | + const { createMessage } = useMessage(); | |
29 | + | |
30 | + const [registerForm, { getFieldsValue, validate }] = useForm({ | |
31 | + labelWidth: 120, | |
32 | + schemas: formSchema, | |
33 | + showActionButtonGroup: false, | |
34 | + }); | |
35 | + | |
36 | + const [register, { setModalProps, closeModal }] = useModalInner( | |
37 | + async (data: { record: ExecuteReportRecord }) => { | |
38 | + setModalProps({ loading: true }); | |
39 | + console.log(data, 'record'); | |
40 | + } | |
41 | + ); | |
42 | + | |
43 | + const handleClose = () => { | |
44 | + closeModal(); | |
45 | + }; | |
46 | + | |
47 | + const handleSuccess = async () => { | |
48 | + console.log(1, '1', getFieldsValue()); | |
49 | + await validate(); | |
50 | + const record = getFieldsValue(); | |
51 | + const { description, debugMode, name } = record; | |
52 | + const form = { | |
53 | + additionalInfo: { | |
54 | + description, | |
55 | + }, | |
56 | + debugMode, | |
57 | + name, | |
58 | + type: 'CORE', | |
59 | + }; | |
60 | + | |
61 | + await createRuleChine(form); | |
62 | + createMessage.success('添加成功'); | |
63 | + handleClose(); | |
64 | + emit('success'); | |
65 | + }; | |
66 | +</script> | |
67 | +<style lang="less" scoped></style> | ... | ... |
src/views/rule/chain/component/config.ts
0 → 100644
1 | +import { FormSchema } from '/@/components/Form'; | |
2 | + | |
3 | +export const formSchema: FormSchema[] = [ | |
4 | + { | |
5 | + field: 'name', | |
6 | + label: '名称', | |
7 | + colProps: { span: 16 }, | |
8 | + component: 'Input', | |
9 | + required: true, | |
10 | + componentProps: { | |
11 | + placeholder: '请输入名称', | |
12 | + }, | |
13 | + }, | |
14 | + { | |
15 | + field: 'debugMode', | |
16 | + label: '调试模式', | |
17 | + component: 'Checkbox', | |
18 | + colProps: { span: 8 }, | |
19 | + componentProps: {}, | |
20 | + }, | |
21 | + { | |
22 | + field: 'description', | |
23 | + label: '说明', | |
24 | + component: 'InputTextArea', | |
25 | + }, | |
26 | +]; | ... | ... |
src/views/rule/chain/component/index.ts
0 → 100644
src/views/rule/chain/config/config.data.ts
0 → 100644
1 | +import { BasicColumn, FormSchema } from '/@/components/Table'; | |
2 | +import { transformTime } from '/@/hooks/web/useDateToLocaleString'; | |
3 | + | |
4 | +export const columns: BasicColumn[] = [ | |
5 | + { | |
6 | + title: '创建时间', | |
7 | + dataIndex: 'createdTime', | |
8 | + width: 200, | |
9 | + format: (_text: string, record: Recordable) => { | |
10 | + return transformTime(record.createdTime); | |
11 | + }, | |
12 | + }, | |
13 | + { | |
14 | + title: '名称', | |
15 | + dataIndex: 'name', | |
16 | + width: 200, | |
17 | + }, | |
18 | + { | |
19 | + title: '是否跟链', | |
20 | + dataIndex: 'root', | |
21 | + slots: { | |
22 | + customRender: 'root', | |
23 | + }, | |
24 | + width: 200, | |
25 | + }, | |
26 | +]; | |
27 | + | |
28 | +export const searchFormSchema: FormSchema[] = [ | |
29 | + { | |
30 | + field: 'textSearch', | |
31 | + label: '名称', | |
32 | + component: 'Input', | |
33 | + | |
34 | + colProps: { span: 8 }, | |
35 | + componentProps: { | |
36 | + placeholder: '请输入名称', | |
37 | + }, | |
38 | + }, | |
39 | +]; | |
40 | + | |
41 | +export const encode = (string: string) => { | |
42 | + return encodeURIComponent(string); | |
43 | +}; | ... | ... |
src/views/rule/chain/index.vue
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | + <BasicTable @register="registerTable"> | |
4 | + <template #toolbar> | |
5 | + <Authority> | |
6 | + <a-button type="primary" @click="handleAdd"> 新增规则链 </a-button> | |
7 | + </Authority> | |
8 | + <!-- <Authority> | |
9 | + <Popconfirm | |
10 | + title="您确定要批量删除数据" | |
11 | + ok-text="确定" | |
12 | + cancel-text="取消" | |
13 | + @confirm="handleDeleteOrBatchDelete(null)" | |
14 | + > | |
15 | + <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> | |
16 | + </Popconfirm> | |
17 | + </Authority> --> | |
18 | + </template> | |
19 | + <template #root="{ record }"> | |
20 | + <Tag :color="record.root ? 'green' : 'red'"> {{ record.root ? '是' : '否' }}</Tag> | |
21 | + </template> | |
22 | + <template #action="{ record }"> | |
23 | + <TableAction | |
24 | + :actions="[ | |
25 | + { | |
26 | + label: '查看', | |
27 | + icon: 'ant-design:eye-outlined', | |
28 | + onClick: handleView.bind(null, record), | |
29 | + }, | |
30 | + { | |
31 | + label: '删除', | |
32 | + icon: 'ant-design:delete-outlined', | |
33 | + color: 'error', | |
34 | + ifShow: !record.root, | |
35 | + popConfirm: { | |
36 | + title: '是否确认删除', | |
37 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | |
38 | + }, | |
39 | + }, | |
40 | + ]" | |
41 | + /> | |
42 | + </template> | |
43 | + </BasicTable> | |
44 | + <RuleChainModal @register="registerModal" @success="handleSuccess" /> | |
45 | + </div> | |
46 | +</template> | |
47 | +<script lang="ts" setup> | |
48 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
49 | + import { columns, encode, searchFormSchema } from './config/config.data'; | |
50 | + import { deleteRuleChine, getRuleChinsList } from '/@/api/ruleengine/ruleengineApi'; | |
51 | + import { useModal } from '/@/components/Modal'; | |
52 | + import { Authority } from '/@/components/Authority'; | |
53 | + import { Tag } from 'ant-design-vue'; | |
54 | + import { RuleChainModal } from './component/index'; | |
55 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
56 | + import { usePermission } from '/@/hooks/web/usePermission'; | |
57 | + import { useRouter } from 'vue-router'; | |
58 | + | |
59 | + const [registerTable, { reload, setProps }] = useTable({ | |
60 | + title: '规则链库', | |
61 | + api: getRuleChinsList, | |
62 | + columns, | |
63 | + formConfig: { | |
64 | + labelWidth: 120, | |
65 | + schemas: searchFormSchema, | |
66 | + }, | |
67 | + fetchSetting: { | |
68 | + pageField: 'page', | |
69 | + listField: 'data', | |
70 | + }, | |
71 | + pagination: true, | |
72 | + useSearchForm: true, | |
73 | + showTableSetting: true, | |
74 | + bordered: true, | |
75 | + showIndexColumn: false, | |
76 | + beforeFetch(params) { | |
77 | + Reflect.set(params, 'page', params.page - 1); | |
78 | + Reflect.set(params, 'sortProperty', 'createdTime'); | |
79 | + Reflect.set(params, 'sortOrder', 'DESC'); | |
80 | + return params; | |
81 | + }, | |
82 | + actionColumn: { | |
83 | + width: 200, | |
84 | + title: '操作', | |
85 | + dataIndex: 'action', | |
86 | + slots: { customRender: 'action' }, | |
87 | + fixed: 'right', | |
88 | + }, | |
89 | + }); | |
90 | + | |
91 | + const [registerModal, { openModal }] = useModal(); | |
92 | + | |
93 | + const handleSuccess = () => { | |
94 | + reload(); | |
95 | + }; | |
96 | + | |
97 | + const handleAdd = () => { | |
98 | + openModal(true); | |
99 | + }; | |
100 | + | |
101 | + const { createMessage } = useMessage(); | |
102 | + const { hasPermission } = usePermission(); | |
103 | + const router = useRouter(); | |
104 | + | |
105 | + const handleView = (record: Recordable) => { | |
106 | + const hasDetailPermission = hasPermission('rule:chain:detail'); | |
107 | + if (hasDetailPermission) { | |
108 | + const boardId = encode(record.id.id); | |
109 | + router.push(`/rule/chain/${boardId}`); | |
110 | + } else createMessage.warning('没有权限'); | |
111 | + }; | |
112 | + | |
113 | + const handleDeleteOrBatchDelete = async (record: Recordable) => { | |
114 | + setProps({ | |
115 | + loading: true, | |
116 | + }); | |
117 | + try { | |
118 | + await deleteRuleChine(record.id.id); | |
119 | + createMessage.success('删除成功'); | |
120 | + } finally { | |
121 | + setProps({ | |
122 | + loading: false, | |
123 | + }); | |
124 | + } | |
125 | + reload(); | |
126 | + }; | |
127 | +</script> | ... | ... |
src/views/rule/designer/enum/category.ts
0 → 100644
1 | +export enum EntryCategoryComponentEnum { | |
2 | + INPUT = 'Input', | |
3 | +} | |
4 | + | |
5 | +export enum FlowCategoryComponentEnum { | |
6 | + ACKNOWLEDGE = 'Acknowledge', | |
7 | + CHECKPOINT = 'Checkpoint', | |
8 | + RULE_CHAIN = 'RuleChain', | |
9 | + OUTPUT = 'Output', | |
10 | +} | |
11 | +export enum EnrichmentCategoryComponentEnum { | |
12 | + CUSTOMER_ATTRIBUTES = 'CustomerAttributes', | |
13 | + ORIGINATOR_TELEMETRY = 'OriginatorTelemetry', | |
14 | + ORIGINATOR_FIELDS = 'OriginatorFields', | |
15 | + CALCULATE_DELTA = 'CalculateDelta', | |
16 | + TENANT_ATTRIBUTES = 'TenantAttributes', | |
17 | + RELATED_DEVICE_ATTRIBUTES = 'RelatedDeviceAttributes', | |
18 | + RELATED_ATTRIBUTES = 'RelatedAttributes', | |
19 | + TENANT_DETAILS = 'TenantDetails', | |
20 | + ORIGINATOR_ATTRIBUTES = 'OriginatorAttributes', | |
21 | + CUSTOMER_DETAILS = 'CustomerDetails', | |
22 | +} | |
23 | +export enum ExternalCategoryComponentEnum { | |
24 | + ALARM_NOTICE = 'AlarmNotice', | |
25 | + MQTT = 'Mqtt', | |
26 | + GCP_PUBSUB = 'GcpPubsub', | |
27 | + SEND_SMS = 'SendSms', | |
28 | + AZURE_IOT_HUB = 'AzureIotHub', | |
29 | + REST_API_CALL = 'RestApiCall', | |
30 | + KAFKA = 'Kafka', | |
31 | + AWS_SNS = 'AwsSns', | |
32 | + SEND_EMAIL = 'SendEmail', | |
33 | + RABBITMQ = 'Rabbitmq', | |
34 | + AWS_SQS = 'AwsSqs', | |
35 | +} | |
36 | +export enum ActionCategoryComponentEnum { | |
37 | + CREATE_ALARM = 'CreateAlarm', | |
38 | + PUSH_TO_EDGE = 'PushToEdge', | |
39 | + GENERATOR = 'Generator', | |
40 | + ASSIGN_TO_CUSTOMER = 'AssignToCustomer', | |
41 | + UNASSIGN_FROM_CUSTOMER = 'UnassignFromCustomer', | |
42 | + SAVE_TIMESERIES = 'SaveTimeseries', | |
43 | + GPS_GEOFENCING_EVENTS = 'GpsGeofencingEvents', | |
44 | + DEVICE_PROFILE = 'DeviceProfile', | |
45 | + RPC_CALL_REPLY = 'RpcCallReply', | |
46 | + COPY_TO_VIEW = 'CopyToView', | |
47 | + LOG = 'Log', | |
48 | + SAVE_TO_CUSTOM_TABLE = 'SaveToCustomTable', | |
49 | + CLEAR_ALARM = 'ClearAlarm', | |
50 | + DELETE_RELATION = 'DeleteRelation', | |
51 | + DELAY_DEPRECATED = 'DelayDeprecated', | |
52 | + MESSAGE_COUNT = 'MessageCount', | |
53 | + SAVE_EVENT = 'SaveEvent', | |
54 | + RPC_CALL_REQUEST = 'RpcCallRequest', | |
55 | + SYNCHRONIZATION_START = 'SynchronizationStart', | |
56 | + SYNCHRONIZATION_END = 'SynchronizationEnd', | |
57 | + SAVE_ATTRIBUTES = 'SaveAttributes', | |
58 | + CREATE_RELATION = 'CreateRelation', | |
59 | +} | |
60 | +export enum FilterCategoryComponentEnum { | |
61 | + SCRIPT = 'Script', | |
62 | + SCENE_REACT = 'SceneReact', | |
63 | + CHECK_EXISTENCE_FIELDS = 'CheckExistenceFields', | |
64 | + ORIGINATOR_TYPE_SWITCH = 'OriginatorTypeSwitch', | |
65 | + CHECK_RELATION = 'CheckRelation', | |
66 | + MESSAGE_TYPE = 'MessageType', | |
67 | + ORIGINATOR_TYPE = 'OriginatorType', | |
68 | + MESSAGE_TYPE_SWITCH = 'MessageTypeSwitch', | |
69 | + SWITCH = 'Switch', | |
70 | + GPS_GEOFENCING_FILTER = 'GpsGeofencingFilter', | |
71 | + CHECK_ALARM_STATUS = 'CheckAlarmStatus', | |
72 | +} | |
73 | +export enum TransformationCategoryComponentEnum { | |
74 | + CHANGE_ORIGINATOR = 'ChangeOriginator', | |
75 | + SCRIPT = 'Script', | |
76 | + TO_EMAIL = 'ToEmail', | |
77 | +} | ... | ... |
src/views/rule/designer/enum/entity.ts
0 → 100644
src/views/rule/designer/enum/form.ts
0 → 100644
1 | +/** | |
2 | + * @description 方向 | |
3 | + */ | |
4 | +export enum DirectionEnum { | |
5 | + FROM = 'FROM', | |
6 | + TO = 'TO', | |
7 | +} | |
8 | + | |
9 | +export enum DirectionNameEnum { | |
10 | + FROM = '从', | |
11 | + TO = '到', | |
12 | +} | |
13 | +/** | |
14 | + * @description 关联类型 | |
15 | + */ | |
16 | +export enum RelationTypeEnum { | |
17 | + CONTAINS = 'CONTAINS', | |
18 | + MANAGES = 'MANAGES', | |
19 | +} | |
20 | + | |
21 | +export enum RelationTypeNameEnum { | |
22 | + CONTAINS = 'Contains', | |
23 | + MANAGES = 'Manages', | |
24 | +} | |
25 | + | |
26 | +/** | |
27 | + * @description 类型 | |
28 | + */ | |
29 | +export enum EntityTypeEnum { | |
30 | + DEVICE = 'DEVICE', | |
31 | + ASSET = 'ASSET', | |
32 | + ENTITY_VIEW = 'ENTITY_VIEW', | |
33 | + TENANT = 'TENANT', | |
34 | + CUSTOMER = 'CUSTOMER', | |
35 | + USER = 'USER', | |
36 | + DASHBOARD = 'DASHBOARD', | |
37 | + EDGE = 'EDGE', | |
38 | +} | |
39 | + | |
40 | +export enum EntityTypeNameEnum { | |
41 | + DEVICE = '设备', | |
42 | + ASSET = '资产', | |
43 | + ENTITY_VIEW = '实体视图', | |
44 | + TENANT = '租户', | |
45 | + CUSTOMER = '客户', | |
46 | + USER = '用户', | |
47 | + DASHBOARD = '仪表板', | |
48 | + EDGE = '边缘', | |
49 | +} | |
50 | + | |
51 | +/** | |
52 | + * @description Filter Perimeter type | |
53 | + */ | |
54 | +export enum PerimeterTypeEnum { | |
55 | + POLYGON = 'POLYGON', | |
56 | + CIRCLE = 'CIRCLE', | |
57 | +} | |
58 | + | |
59 | +export enum MessageTypesEnum { | |
60 | + POST_ATTRIBUTES_REQUEST = 'POST_ATTRIBUTES_REQUEST', | |
61 | + POST_TELEMETRY_REQUEST = 'POST_TELEMETRY_REQUEST', | |
62 | + TO_SERVER_RPC_REQUEST = 'TO_SERVER_RPC_REQUEST', | |
63 | + RPC_CALL_FROM_SERVER_TO_DEVICE = 'RPC_CALL_FROM_SERVER_TO_DEVICE', | |
64 | + ACTIVITY_EVENT = 'ACTIVITY_EVENT', | |
65 | + INACTIVITY_EVENT = 'INACTIVITY_EVENT', | |
66 | + CONNECT_EVENT = 'CONNECT_EVENT', | |
67 | + DISCONNECT_EVENT = 'DISCONNECT_EVENT', | |
68 | + ENTITY_CREATED = 'ENTITY_CREATED', | |
69 | + ENTITY_UPDATED = 'ENTITY_UPDATED', | |
70 | + ENTITY_DELETED = 'ENTITY_DELETED', | |
71 | + ENTITY_ASSIGNED = 'ENTITY_ASSIGNED', | |
72 | + ENTITY_UNASSIGNED = 'ENTITY_UNASSIGNED', | |
73 | + ATTRIBUTES_UPDATED = 'ATTRIBUTES_UPDATED', | |
74 | + ATTRIBUTES_DELETED = 'ATTRIBUTES_DELETED', | |
75 | + TIMESERIES_UPDATED = 'TIMESERIES_UPDATED', | |
76 | + TIMESERIES_DELETED = 'TIMESERIES_DELETED', | |
77 | + RPC_QUEUED = 'RPC_QUEUED', | |
78 | + RPC_DELIVERED = 'RPC_DELIVERED', | |
79 | + RPC_SUCCESSFUL = 'RPC_SUCCESSFUL', | |
80 | + RPC_TIMEOUT = 'RPC_TIMEOUT', | |
81 | + RPC_FAILED = 'RPC_FAILED', | |
82 | +} | |
83 | + | |
84 | +export enum MessageTypesNameEnum { | |
85 | + POST_ATTRIBUTES_REQUEST = 'Post attributes', | |
86 | + POST_TELEMETRY_REQUEST = 'Post telemetry', | |
87 | + TO_SERVER_RPC_REQUEST = 'RPC Request from Device', | |
88 | + RPC_CALL_FROM_SERVER_TO_DEVICE = 'RPC Request to Device', | |
89 | + ACTIVITY_EVENT = 'Activity Event', | |
90 | + INACTIVITY_EVENT = 'Inactivity Event', | |
91 | + CONNECT_EVENT = 'Connect Event', | |
92 | + DISCONNECT_EVENT = 'Disconnect Event', | |
93 | + ENTITY_CREATED = 'Entity Created', | |
94 | + ENTITY_UPDATED = 'Entity Updated', | |
95 | + ENTITY_DELETED = 'Entity Deleted', | |
96 | + ENTITY_ASSIGNED = 'Entity Assigned', | |
97 | + ENTITY_UNASSIGNED = 'Entity Unassigned', | |
98 | + ATTRIBUTES_UPDATED = 'Attributes Updated', | |
99 | + ATTRIBUTES_DELETED = 'Attributes Deleted', | |
100 | + TIMESERIES_UPDATED = 'Timeseries Updated', | |
101 | + TIMESERIES_DELETED = 'Timeseries Deleted', | |
102 | + RPC_QUEUED = 'RPC Queued', | |
103 | + RPC_DELIVERED = 'RPC Delivered', | |
104 | + RPC_SUCCESSFUL = 'RPC Successful', | |
105 | + RPC_TIMEOUT = 'RPC Timeout', | |
106 | + RPC_FAILED = 'RPC Failed', | |
107 | +} | |
108 | +/** | |
109 | + * @description Filter Range util | |
110 | + */ | |
111 | +export enum RangeUtilEnum { | |
112 | + METER = 'METER', | |
113 | + KILOMETER = 'KILOMETER', | |
114 | + FOOT = 'FOOT', | |
115 | + MILE = 'MILE', | |
116 | + NAUTICAL_MILE = 'NAUTICAL_MILE', | |
117 | +} | |
118 | + | |
119 | +export enum RangeUtilNameEnum { | |
120 | + METER = 'Meter', | |
121 | + KILOMETER = 'Kilometer', | |
122 | + FOOT = 'Foot', | |
123 | + MILE = 'Mile', | |
124 | + NAUTICAL_MILE = 'Nautical mile', | |
125 | +} | |
126 | + | |
127 | +// Enrichment Customer details | |
128 | +export enum DetailsListEnum { | |
129 | + TITLE = 'TITLE', | |
130 | + COUNTRY = 'COUNTRY', | |
131 | + STATE = 'STATE', | |
132 | + CITY = 'CITY', | |
133 | + ZIP = 'ZIP', | |
134 | + ADDRESS = 'ADDRESS', | |
135 | + ADDRESS_2 = 'ADDRESS_2', | |
136 | + PHONE = 'PHONE', | |
137 | + EMAIL = 'EMAIL', | |
138 | + ADDITIONAL_INFO = 'ADDITIONAL_INFO', | |
139 | +} | |
140 | + | |
141 | +export enum DetailsListNameEnum { | |
142 | + TITLE = 'Title', | |
143 | + COUNTRY = 'Country', | |
144 | + STATE = 'State', | |
145 | + CITY = 'City', | |
146 | + ZIP = 'Zip', | |
147 | + ADDRESS = 'Address', | |
148 | + ADDRESS_2 = 'Address2', | |
149 | + PHONE = 'Phone', | |
150 | + EMAIL = 'Email', | |
151 | + ADDITIONAL_INFO = 'Additional Info', | |
152 | +} | |
153 | + | |
154 | +// Enrichment Originator Telemetry FetchMode | |
155 | +export enum FetchModeEnum { | |
156 | + FIRST = 'FIRST', | |
157 | + LAST = 'LAST', | |
158 | + ALL = 'ALL', | |
159 | +} | |
160 | + | |
161 | +// Enrichment Originator Telemetry Time interval unit | |
162 | +export enum TimeIntervalUnitEnum { | |
163 | + MILLISECONDS = 'MILLISECONDS', | |
164 | + SECONDS = 'SECONDS', | |
165 | + MINUTES = 'MINUTES', | |
166 | + HOURS = 'HOURS', | |
167 | + DAYS = 'DAYS', | |
168 | +} | |
169 | + | |
170 | +export enum TimeIntervalUnitNameEnum { | |
171 | + MILLISECONDS = 'Milliseconds', | |
172 | + SECONDS = 'Seconds', | |
173 | + MINUTES = 'Minutes', | |
174 | + HOURS = 'Hours', | |
175 | + DAYS = 'Days', | |
176 | +} | |
177 | + | |
178 | +// Enrichment Originator Telemetry OrderBy | |
179 | +export enum OrderByEnum { | |
180 | + DESC = 'DESC', | |
181 | + ASC = 'ASC', | |
182 | +} | |
183 | + | |
184 | +// Enrichment Originator Telemetry Aggregation | |
185 | +export enum AggregationEnum { | |
186 | + MIN = 'MIN', | |
187 | + MAX = 'MAX', | |
188 | + AVG = 'AVG', | |
189 | + SUM = 'SUM', | |
190 | + COUNT = 'COUNT', | |
191 | + NONE = 'NONE', | |
192 | +} | |
193 | + | |
194 | +export enum AggregationNameEnum { | |
195 | + MIN = '最少值', | |
196 | + MAX = '最大值', | |
197 | + AVG = '平均值', | |
198 | + SUM = '求和', | |
199 | + COUNT = '计数', | |
200 | + NONE = '空', | |
201 | +} | |
202 | + | |
203 | +// Originator source | |
204 | +export enum OriginatorSourceEnum { | |
205 | + CUSTOMER = 'CUSTOMER', | |
206 | + TENANT = 'TENANT', | |
207 | + RELATED = 'RELATED', | |
208 | + ALARM_ORIGINATOR = 'ALARM_ORIGINATOR', | |
209 | +} | |
210 | + | |
211 | +export enum OriginatorSourceNameEnum { | |
212 | + CUSTOMER = 'Customer', | |
213 | + TENANT = 'Tenant', | |
214 | + RELATED = 'Related', | |
215 | + ALARM_ORIGINATOR = 'Alarm Originator', | |
216 | +} | |
217 | + | |
218 | +// Transformation To Email | |
219 | +export enum MailBodyTypeEnum { | |
220 | + DYNAMIC = 'dynamic', | |
221 | + HTML = 'true', | |
222 | + PLAIN_TEXT = 'false', | |
223 | +} | |
224 | + | |
225 | +export enum MailBodyTypeNameEnum { | |
226 | + DYNAMIC = 'Dynamic', | |
227 | + HTML = 'HTML', | |
228 | + PLAIN_TEXT = 'Plain Text', | |
229 | +} | |
230 | + | |
231 | +// Action Push to edge | |
232 | +export enum ScopeEnum { | |
233 | + SERVER_SCOPE = 'SERVER_SCOPE', | |
234 | + CLIENT_SCOPE = 'CLIENT_SCOPE', | |
235 | + SHARED_SCOPE = 'SHARED_SCOPE', | |
236 | +} | |
237 | + | |
238 | +export enum ScopeNameEnum { | |
239 | + SERVER_SCOPE = '服务端属性', | |
240 | + CLIENT_SCOPE = '客户端属性', | |
241 | + SHARED_SCOPE = '共享属性', | |
242 | +} | |
243 | + | |
244 | +// External Queue type | |
245 | +export enum QueueTypeEnum { | |
246 | + STANDARD = 'STANDARD', | |
247 | + FIFO = 'FIFO', | |
248 | +} | |
249 | + | |
250 | +export enum QueueTypeNameEnum { | |
251 | + STANDARD = 'Standard', | |
252 | + FIFO = 'FIFO', | |
253 | +} | |
254 | + | |
255 | +// Charset encoding | |
256 | +export enum CharsetEncodingEnum { | |
257 | + US_ASCII = 'US_ASCII', | |
258 | + ISO_8859_1 = 'ISO_8859_1', | |
259 | + UTF_8 = 'UTF_8', | |
260 | + UTF_16BE = 'UTF_16BE', | |
261 | + UTF_16LE = 'UTF_16LE', | |
262 | + UTF_16 = 'UTF_16', | |
263 | +} | |
264 | + | |
265 | +export enum CharsetEncodingNameEnum { | |
266 | + US_ASCII = 'US-ASCII', | |
267 | + ISO_8859_1 = 'ISO-8859-1', | |
268 | + UTF_8 = 'UTF-8', | |
269 | + UTF_16BE = 'UTF-16BE', | |
270 | + UTF_16LE = 'UTF-16LE', | |
271 | + UTF_16 = 'UTF-16', | |
272 | +} | |
273 | + | |
274 | +// Rabbitmq Message properties | |
275 | +export enum MessagePropertiesEnum { | |
276 | + BASIC = 'BASIC', | |
277 | + TEXT_PLAIN = 'TEXT_PLAIN', | |
278 | + MINIMAL_BASIC = 'MINIMAL_BASIC', | |
279 | + MINIMAL_PERSISTENT_BASIC = 'MINIMAL_PERSISTENT_BASIC', | |
280 | + PERSISTENT_BASIC = 'PERSISTENT_BASIC', | |
281 | + PERSISTENT_TEXT_PLAIN = 'PERSISTENT_TEXT_PLAIN', | |
282 | +} | |
283 | + | |
284 | +// rest api call Request method | |
285 | +export enum RequestMethodEnum { | |
286 | + GET = 'GET', | |
287 | + POST = 'POST', | |
288 | + PUT = 'PUT', | |
289 | + DELETE = 'DELETE', | |
290 | +} | |
291 | + | |
292 | +export enum ProtocolEnum { | |
293 | + HTTP = 'HTTP', | |
294 | + HTTPS = 'HTTPS', | |
295 | +} | |
296 | + | |
297 | +export enum ProtocolNameEnum { | |
298 | + HTTP = 'http', | |
299 | + HTTPS = 'https', | |
300 | +} | |
301 | + | |
302 | +export enum EmailProtocolEnum { | |
303 | + SMTP = 'SMTP', | |
304 | + SMTPS = 'SMTPS', | |
305 | +} | |
306 | + | |
307 | +export enum EmailProtocolNameEnum { | |
308 | + SMTP = 'smtp', | |
309 | + SMTPS = 'smtps', | |
310 | +} | |
311 | + | |
312 | +export enum TSLVersionEnum { | |
313 | + TSLV1 = 'TSLV1', | |
314 | + TSLV1_1 = 'TSLV1_1', | |
315 | + TSLV1_2 = 'TSLV1_2', | |
316 | + TSLV1_3 = 'TSLV1_3', | |
317 | +} | |
318 | + | |
319 | +export enum TSLVersionNameEnum { | |
320 | + TSLV1 = 'TSLV1', | |
321 | + TSLV1_1 = 'TSLV1.1', | |
322 | + TSLV1_2 = 'TSLV1.2', | |
323 | + TSLV1_3 = 'TSLV1.3', | |
324 | +} | |
325 | + | |
326 | +export enum SMSServiceProviderEnum { | |
327 | + AWS_SNS = 'AWS_SNS', | |
328 | + TWILIO = 'TWILIO', | |
329 | +} | |
330 | + | |
331 | +export enum SMSServiceProviderNameEnum { | |
332 | + AWS_SNS = '亚马逊社交网站', | |
333 | + TWILIO = 'Twilio', | |
334 | +} | ... | ... |
1 | +// Assign to customer | |
2 | +export enum AssignToCustomerFieldsEnum { | |
3 | + CUSTOMER_NAME_PATTERN = 'customerNamePattern', | |
4 | + CREATE_CUSTOMER_IF_NOT_EXISTS = 'createCustomerIfNotExists', | |
5 | + CUSTOMER_CACHE_EXPIRATION = 'customerCacheExpiration', | |
6 | +} | |
7 | + | |
8 | +export enum AssignToCustomerFieldsNameEnum { | |
9 | + CUSTOMER_NAME_PATTERN = 'Customer name pattern', | |
10 | + CREATE_CUSTOMER_IF_NOT_EXISTS = 'Create new customer if not exists', | |
11 | + CUSTOMER_CACHE_EXPIRATION = 'Customers cache expiration time(sec)', | |
12 | +} | |
13 | + | |
14 | +// clear alarm | |
15 | +export enum ClearAlarmFieldsEnum { | |
16 | + ALARM_TYPE = 'alarmType', | |
17 | + ALARM_DETAILS_BUILD_JS = 'alarmDetailsBuildJs', | |
18 | +} | |
19 | + | |
20 | +export enum ClearAlarmFieldsNameEnum { | |
21 | + ALARM_TYPE = 'Alarm type', | |
22 | + ALARM_DETAILS_BUILD_JS = 'Alarm details builder', | |
23 | +} | |
24 | + | |
25 | +// Create alarm | |
26 | +export enum CreateAlarmFieldsEnum { | |
27 | + ALARM_DETAILS_BUILD_JS = 'alarmDetailsBuildJs', | |
28 | + USE_MESSAGE_ALARM_DATA = 'useMessageAlarmData', | |
29 | + OVERWRITE_ALARM_DETAILS = 'overwriteAlarmDetails', | |
30 | + ALARM_TYPE = 'alarmType', | |
31 | + SEVERITY = 'severity', | |
32 | + PROPAGATE = 'propagate', | |
33 | + RELATION_TYPES = 'relationTypes', | |
34 | + PROPAGATE_TO_OWNER = 'propagateToOwner', | |
35 | + PROPAGATE_TO_TENANT = 'propagateToTenant', | |
36 | + DYNAMIC_SEVERITY = 'dynamicSeverity', | |
37 | +} | |
38 | + | |
39 | +export enum CreateAlarmFieldsNameEnum { | |
40 | + ALARM_DETAILS_BUILD_JS = 'Alarm details builder', | |
41 | + USE_MESSAGE_ALARM_DATA = 'Use message alarm data', | |
42 | + OVERWRITE_ALARM_DETAILS = 'Overwrite alarm details', | |
43 | + ALARM_TYPE = 'Alarm type', | |
44 | + SEVERITY = 'Alarm severity pattern', | |
45 | + PROPAGATE = 'Propagate alarm to related entities', | |
46 | + RELATION_TYPES = 'Relation types to propagate', | |
47 | + PROPAGATE_TO_OWNER = 'Propagate alarm to entity owner (Customer or Tenant)', | |
48 | + PROPAGATE_TO_TENANT = 'Propagate alarm to Tenant', | |
49 | + DYNAMIC_SEVERITY = 'Use alarm severity pattern', | |
50 | +} | |
51 | + | |
52 | +// Create relation | |
53 | +export enum CreateRelationFieldsEnum { | |
54 | + DIRECTION = 'direction', | |
55 | + ENTITY_TYPE = 'entityType', | |
56 | + ENTITY_NAME_PATTERN = 'entityNamePattern', | |
57 | + ENTITY_TYPE_PATTERN = 'entityTypePattern', | |
58 | + RELATION_TYPE = 'relationType', | |
59 | + CREATE_ENTITY_IF_NOT_EXISTS = 'createEntityIfNotExists', | |
60 | + REMOVE_CURRENT_RELATIONS = 'removeCurrentRelations', | |
61 | + CHANGE_ORIGINATOR_TO_RELATED_ENTITY = 'changeOriginatorToRelatedEntity', | |
62 | + ENTITY_CACHE_EXPIRATION = 'entityCacheExpiration', | |
63 | +} | |
64 | + | |
65 | +export enum CreateRelationFieldsNameEnum { | |
66 | + DIRECTION = '方向', | |
67 | + ENTITY_TYPE = '类型', | |
68 | + ENTITY_NAME_PATTERN = 'Name pattern', | |
69 | + ENTITY_TYPE_PATTERN = 'Type pattern', | |
70 | + RELATION_TYPE = 'Relation type pattern', | |
71 | + CREATE_ENTITY_IF_NOT_EXISTS = 'Create new entity if not exists', | |
72 | + REMOVE_CURRENT_RELATIONS = 'Remove current relations', | |
73 | + CHANGE_ORIGINATOR_TO_RELATED_ENTITY = 'Change originator to related entity', | |
74 | + ENTITY_CACHE_EXPIRATION = 'Entities cache expiration time(sec)', | |
75 | +} | |
76 | + | |
77 | +// Delay deprecated | |
78 | +export enum DelayDeprecatedFieldsEnum { | |
79 | + USE_METADATA_PERIOD_IN_SECONDS_PATTERNS = 'useMetadataPeriodInSecondsPatterns', | |
80 | + PERIOD_IN_SECONDS = 'periodInSeconds', | |
81 | + PERIOD_IN_SECONDS_PATTERN = 'periodInSecondsPattern', | |
82 | + MAX_PENDING_MSGS = 'maxPendingMsgs', | |
83 | +} | |
84 | + | |
85 | +export enum DelayDeprecatedFieldsNameEnum { | |
86 | + USE_METADATA_PERIOD_IN_SECONDS_PATTERNS = 'Use period in seconds pattern', | |
87 | + PERIOD_IN_SECONDS = 'Period in seconds', | |
88 | + PERIOD_IN_SECONDS_PATTERN = 'Period in seconds pattern', | |
89 | + MAX_PENDING_MSGS = 'Maximum pending messages', | |
90 | +} | |
91 | + | |
92 | +export enum DeleteRelationFieldsEnum { | |
93 | + DELETE_FOR_SINGLE_ENTITY = 'deleteForSingleEntity', | |
94 | + DIRECTION = 'direction', | |
95 | + ENTITY_TYPE = 'entityType', | |
96 | + ENTITY_NAME_PATTERN = 'entityNamePattern', | |
97 | + RELATION_TYPE = 'relationType', | |
98 | + ENTITY_CACHE_EXPIRATION = 'entityCacheExpiration', | |
99 | +} | |
100 | + | |
101 | +export enum DeleteRelationFieldsNameEnum { | |
102 | + DELETE_FOR_SINGLE_ENTITY = 'Delete relation to specific entity', | |
103 | + DIRECTION = '方向', | |
104 | + ENTITY_TYPE = '类型', | |
105 | + ENTITY_NAME_PATTERN = 'Name pattern', | |
106 | + RELATION_TYPE = 'Relation type pattern', | |
107 | + ENTITY_CACHE_EXPIRATION = 'Entities cache expiration time(sec)', | |
108 | +} | |
109 | + | |
110 | +// device profile | |
111 | +export enum DeviceProfileFieldsEnum { | |
112 | + PERSIST_ALARM_RULES_STATE = 'persistAlarmRulesState', | |
113 | + FETCH_ALARM_RULES_STATE_ON_START = 'fetchAlarmRulesStateOnStart', | |
114 | +} | |
115 | + | |
116 | +export enum DeviceProfileFieldsNameEnum { | |
117 | + PERSIST_ALARM_RULES_STATE = 'Persist state of alarm rules', | |
118 | + FETCH_ALARM_RULES_STATE_ON_START = 'Fetch state of alarm rules', | |
119 | +} | |
120 | + | |
121 | +// Generator | |
122 | +export enum GeneratorFieldsEnum { | |
123 | + MSG_COUNT = 'msgCount', | |
124 | + PERIOD_IN_SECONDS = 'periodInSeconds', | |
125 | + JS_SCRIPT = 'jsScript', | |
126 | + ORIGINATOR_ID = 'originatorId', | |
127 | + ORIGINATOR_TYPE = 'originatorType', | |
128 | +} | |
129 | + | |
130 | +export enum GeneratorFieldsNameEnum { | |
131 | + MSG_COUNT = 'Message count(0 - unlimited)', | |
132 | + PERIOD_IN_SECONDS = 'Period in seconds', | |
133 | + JS_SCRIPT = 'Generate', | |
134 | + // ORIGINATOR_ID = '资产', | |
135 | + ORIGINATOR_TYPE = '类型', | |
136 | +} | |
137 | + | |
138 | +// Gps geofencing events | |
139 | +export enum GpsGeofencingEventsFieldsEnum { | |
140 | + LATITUDE_KEY_NAME = 'latitudeKeyName', | |
141 | + LONGITUDE_KEY_NAME = 'longitudeKeyName', | |
142 | + PERIMETER_TYPE = 'perimeterType', | |
143 | + FETCH_PERIMETER_INFO_FROM_MESSAGE_METADATA = 'fetchPerimeterInfoFromMessageMetadata', | |
144 | + PERIMETER_KEY_NAME = 'perimeterKeyName', | |
145 | + CENTER_LATITUDE = 'centerLatitude', | |
146 | + CENTER_LONGITUDE = 'centerLongitude', | |
147 | + RANGE = 'range', | |
148 | + RANGE_UNIT = 'rangeUnit', | |
149 | + POLYGONS_DEFINITION = 'polygonsDefinition', | |
150 | + MIN_INSIDE_DURATION = 'minInsideDuration', | |
151 | + MIN_INSIDE_DURATION_TIME_UNIT = 'minInsideDurationTimeUnit', | |
152 | + MIN_OUTSIDE_DURATION = 'minOutsideDuration', | |
153 | + MIN_OUTSIDE_DURATION_TIME_UNIT = 'minOutsideDurationTimeUnit', | |
154 | +} | |
155 | + | |
156 | +export enum GpsGeofencingEventsFieldsNameEnum { | |
157 | + LATITUDE_KEY_NAME = 'Latitude key name', | |
158 | + LONGITUDE_KEY_NAME = 'longitude key name', | |
159 | + PERIMETER_TYPE = 'Perimeter type', | |
160 | + FETCH_PERIMETER_INFO_FROM_MESSAGE_METADATA = 'Fetch perimeter information from message metadata', | |
161 | + PERIMETER_KEY_NAME = 'Perimeter key name', | |
162 | + CENTER_LATITUDE = 'Center Latitude', | |
163 | + CENTER_LONGITUDE = 'Center Longitude', | |
164 | + RANGE = 'Range', | |
165 | + RANGE_UNIT = 'Range units', | |
166 | + POLYGONS_DEFINITION = 'Polygon definition', | |
167 | + MIN_INSIDE_DURATION = 'Minimal inside duration', | |
168 | + MIN_INSIDE_DURATION_TIME_UNIT = 'Minimal inside duration time unit', | |
169 | + MIN_OUTSIDE_DURATION = 'Minimal outside duration', | |
170 | + MIN_OUTSIDE_DURATION_TIME_UNIT = 'Minimal outside duration time unit', | |
171 | +} | |
172 | + | |
173 | +// Log | |
174 | +export enum LogFieldsEnum { | |
175 | + JS_SCRIPT = 'jsScript', | |
176 | +} | |
177 | + | |
178 | +export enum LogFieldsNameEnum { | |
179 | + JS_SCRIPT = 'To string', | |
180 | +} | |
181 | + | |
182 | +// Message Count | |
183 | +export enum MessageCountFieldsEnum { | |
184 | + INTERVAL = 'interval', | |
185 | + TELEMETRY_PREFIX = 'telemetryPrefix', | |
186 | +} | |
187 | + | |
188 | +export enum MessageCountFieldsNameEnum { | |
189 | + INTERVAL = 'Interval in seconds', | |
190 | + TELEMETRY_PREFIX = 'Output timeseries key prefix', | |
191 | +} | |
192 | + | |
193 | +// Push to edge | |
194 | +export enum PushToEdgeFieldsEnum { | |
195 | + SCOPE = 'scope', | |
196 | +} | |
197 | + | |
198 | +export enum PushToEdgeFieldsNameEnum { | |
199 | + SCOPE = '设备属性范围', | |
200 | +} | |
201 | +// Rpc call reply | |
202 | +export enum RpcCallReplyFieldsEnum { | |
203 | + REQUEST_ID_META_DATA_ATTRIBUTE = 'requestIdMetaDataAttribute', | |
204 | +} | |
205 | + | |
206 | +export enum RpcCallReplyFieldsNameEnum { | |
207 | + REQUEST_ID_META_DATA_ATTRIBUTE = 'Request Id Metadata attribute name', | |
208 | +} | |
209 | + | |
210 | +// Rpc call request | |
211 | +export enum RpcCallRequestFieldsEnum { | |
212 | + TIMEOUT_IN_SECONDS = 'timeoutInSeconds', | |
213 | +} | |
214 | + | |
215 | +export enum RpcCallRequestFieldsNameEnum { | |
216 | + TIMEOUT_IN_SECONDS = 'Timeout in seconds', | |
217 | +} | |
218 | + | |
219 | +// Save attribute | |
220 | +export enum SaveAttributesFieldsEnum { | |
221 | + NOTIFY_DEVICE = 'notifyDevice', | |
222 | + SCOPE = 'scope', | |
223 | +} | |
224 | + | |
225 | +export enum SaveAttributesFieldsNameEnum { | |
226 | + NOTIFY_DEVICE = 'Notify Device', | |
227 | + SCOPE = '设备属性范围', | |
228 | +} | |
229 | + | |
230 | +// Save event | |
231 | +export enum SaveEventFieldsEnum { | |
232 | + CONFIGURATION = 'CONFIGURATION', | |
233 | +} | |
234 | + | |
235 | +export enum SaveEventFieldsNameEnum { | |
236 | + CONFIGURATION = '配置', | |
237 | +} | |
238 | + | |
239 | +// Save timeseries | |
240 | +export enum SaveTimeseriesFieldsEnum { | |
241 | + DEFAULT_TTL = 'defaultTTL', | |
242 | + SKIP_LATEST_PERSISTENCE = 'skipLatestPersistence', | |
243 | + USE_SERVER_TS = 'useServerTs', | |
244 | +} | |
245 | + | |
246 | +export enum SaveTimeseriesFieldsNameEnum { | |
247 | + DEFAULT_TTL = 'Default TTL in seconds', | |
248 | + SKIP_LATEST_PERSISTENCE = 'Skit latest persistence', | |
249 | + USE_SERVER_TS = 'Use server ts', | |
250 | +} | |
251 | + | |
252 | +// save to custom table | |
253 | +export enum SaveToCustomTableFieldsEnum { | |
254 | + FIELDS_MAPPING = 'fieldsMapping', | |
255 | + TABLE_NAME = 'tableName', | |
256 | +} | |
257 | + | |
258 | +export enum SaveToCustomTableFieldsNameEnum { | |
259 | + FIELDS_MAPPING = 'Fields mapping', | |
260 | + TABLE_NAME = 'Custom table name', | |
261 | +} | |
262 | + | |
263 | +// Unassign from customer | |
264 | +export enum UnassignFromCustomerFieldsEnum { | |
265 | + CUSTOMER_NAME_PATTERN = 'customerNamePattern', | |
266 | + CUSTOMER_CACHE_EXPIRATION = 'customerCacheExpiration', | |
267 | +} | |
268 | + | |
269 | +export enum UnassignFromCustomerFieldsNameEnum { | |
270 | + CUSTOMER_NAME_PATTERN = 'Customer name pattern', | |
271 | + CUSTOMER_CACHE_EXPIRATION = 'Customer cache expiration time(sec)', | |
272 | +} | ... | ... |
1 | +export enum CommonFieldsEnum { | |
2 | + NAME = 'name', | |
3 | + DESCRIPTION = 'description', | |
4 | + DEBUG_MODE = 'debugMode', | |
5 | +} | |
6 | + | |
7 | +export enum CommonFieldsNameEnum { | |
8 | + NAME = '名称', | |
9 | + DESCRIPTION = '说明', | |
10 | + DEBUG_MODE = '调试模式', | |
11 | +} | |
12 | + | |
13 | +export const CommonFields = { ...CommonFieldsEnum }; | |
14 | +export const CommonFieldsName = { ...CommonFieldsNameEnum }; | |
15 | +export type CommonFieldsType = typeof CommonFields; | ... | ... |
1 | +// Enrichment Calculate delta | |
2 | +export enum CalculateDeltaFieldsEnum { | |
3 | + INPUT_VALUE_KEY = 'inputValueKey', | |
4 | + OUTPUT_VALUE_KEY = 'outputValueKey', | |
5 | + ROUND = 'round', | |
6 | + USE_CACHE = 'useCache', | |
7 | + TELL_FAILURE_IF_DELTA_IS_NEGATIVE = 'tellFailureIfDeltaIsNegative', | |
8 | + ADD_PERIOD_BETWEEN_MSGS = 'addPeriodBetweenMsgs', | |
9 | + PERIOD_VALUE_KEY = 'periodValueKey', | |
10 | +} | |
11 | + | |
12 | +export enum CalculateDeltaFieldsNameEnum { | |
13 | + INPUT_VALUE_KEY = 'Input value key', | |
14 | + OUTPUT_VALUE_KEY = 'Output value key', | |
15 | + ROUND = 'Decimals', | |
16 | + USE_CACHE = 'Use cache for latest value', | |
17 | + TELL_FAILURE_IF_DELTA_IS_NEGATIVE = 'Tell Failure if delta is negative', | |
18 | + ADD_PERIOD_BETWEEN_MSGS = 'Add period between messages', | |
19 | + PERIOD_VALUE_KEY = 'Period value key', | |
20 | +} | |
21 | + | |
22 | +// Enrichment Customer Attributes | |
23 | +export enum CustomerAttributesFieldsEnum { | |
24 | + ATTR_MAPING = 'attrMapping', | |
25 | + TELEMETRY = 'telemetry', | |
26 | +} | |
27 | + | |
28 | +export enum CustomerAttributesFieldsNameEnum { | |
29 | + ATTR_MAPING = 'Attributes mapping', | |
30 | + TELEMETRY = 'Latest telemetry', | |
31 | +} | |
32 | + | |
33 | +// Enrichment Customer details | |
34 | +export enum CustomerDetailsFieldsEnum { | |
35 | + DETAILS_LIST = 'detailsList', | |
36 | + ADD_TO_METADATA = 'addToMetadata', | |
37 | +} | |
38 | + | |
39 | +export enum CustomerDetailsFieldsNameEnum { | |
40 | + DETAILS_LIST = 'Select entity details', | |
41 | + ADD_TO_METADATA = 'Add selected details to message metadata', | |
42 | +} | |
43 | + | |
44 | +// Enrichment Originator attributes | |
45 | +export enum OriginatorAttributesEnum { | |
46 | + TELL_FAILURE_IF_ABSENT = 'tellFailureIfAbsent', | |
47 | + CLIENT_ATTRIBUTE_NAMES = 'clientAttributeNames', | |
48 | + SHARED_ATTRIBUTE_NAMES = 'sharedAttributeNames', | |
49 | + SERVER_ATTRIBUTE_NAMES = 'serverAttributeNames', | |
50 | + LATEST_TS_KEY_NAMES = 'latestTsKeyNames', | |
51 | + GET_LATEST_VALUE_WITH_TS = 'getLatestValueWithTs', | |
52 | +} | |
53 | + | |
54 | +export enum OriginatorAttributesNameEnum { | |
55 | + TELL_FAILURE_IF_ABSENT = 'Tell Failure', | |
56 | + CLIENT_ATTRIBUTE_NAMES = 'Client attributes', | |
57 | + SHARED_ATTRIBUTE_NAMES = 'Shared attributes', | |
58 | + SERVER_ATTRIBUTE_NAMES = 'Server attributes', | |
59 | + LATEST_TS_KEY_NAMES = 'Latest timeseries', | |
60 | + GET_LATEST_VALUE_WITH_TS = 'Fetch Latest telemetry with Timestamp', | |
61 | +} | |
62 | + | |
63 | +// Enrichment Originator Fields | |
64 | +export enum OriginatorFieldsEnum { | |
65 | + FIELDS_MAPPING = 'fieldsMapping', | |
66 | +} | |
67 | + | |
68 | +export enum OriginatorFieldsNameEnum { | |
69 | + FIELDS_MAPPING = 'Fields mapping', | |
70 | +} | |
71 | + | |
72 | +// Enrichment originator telemetry | |
73 | +export enum OriginatorTelemetryFieldsEnum { | |
74 | + LATEST_TS_KEY_NAMES = 'latestTsKeyNames', | |
75 | + AGGREGATION = 'aggregation', | |
76 | + FETCH_MODE = 'fetchMode', | |
77 | + ORDER_BY = 'orderBy', | |
78 | + LIMIT = 'limit', | |
79 | + USE_METADATA_INTERVAL_PATTERNS = 'useMetadataIntervalPatterns', | |
80 | + START_INTERVAL = 'startInterval', | |
81 | + START_INTERVAL_TIME_UNIT = 'startIntervalTimeUnit', | |
82 | + END_INTERVAL = 'endInterval', | |
83 | + END_INTERVAL_TIME_UNIT = 'endIntervalTimeUnit', | |
84 | + START_INTERVAL_PATTERN = 'startIntervalPattern', | |
85 | + END_INTERVAL_PATTERN = 'endIntervalPattern', | |
86 | +} | |
87 | + | |
88 | +export enum OriginatorTelemetryFieldsNameEnum { | |
89 | + LATEST_TS_KEY_NAMES = 'Latest timeseries', | |
90 | + AGGREGATION = '数据聚合功能', | |
91 | + FETCH_MODE = 'Fetch Mode', | |
92 | + ORDER_BY = 'Order by', | |
93 | + LIMIT = 'Limit', | |
94 | + USE_METADATA_INTERVAL_PATTERNS = 'useMetadataIntervalPatterns', | |
95 | + START_INTERVAL = 'Start Interval', | |
96 | + START_INTERVAL_TIME_UNIT = 'Start Interval Time Unit', | |
97 | + END_INTERVAL = 'End Interval', | |
98 | + END_INTERVAL_TIME_UNIT = 'End Interval Time Unit', | |
99 | + START_INTERVAL_PATTERN = 'startIntervalPattern', | |
100 | + END_INTERVAL_PATTERN = 'endIntervalPattern', | |
101 | +} | |
102 | + | |
103 | +// Enrichment Related attributes | |
104 | +export enum RelatedAttributesFieldsEnum { | |
105 | + RELATIONS_QUERY = 'relationsQuery', | |
106 | + ATTR_MAPPING = 'attrMapping', | |
107 | + TELEMETRY = 'telemetry', | |
108 | +} | |
109 | + | |
110 | +export enum RelatedAttributesFieldsNameEnum { | |
111 | + RELATIONS_QUERY = 'Relations query', | |
112 | + ATTR_MAPPING = 'Attributes mapping', | |
113 | + TELEMETRY = 'Latest telemetry', | |
114 | +} | |
115 | + | |
116 | +// Enrichment Related device Attributes | |
117 | +export enum RelatedDeviceAttributeFieldsEnum { | |
118 | + DEVICE_RELATIONS_QUERY = 'deviceRelationsQuery', | |
119 | + TELL_FAILURE_IF_ABSENT = 'tellFailureIfAbsent', | |
120 | + CLIENT_ATTRIBUTE_NAMES = 'clientAttributeNames', | |
121 | + SHARED_ATTRIBUTE_NAMES = 'sharedAttributeNames', | |
122 | + SERVER_ATTRIBUTE_NAMES = 'serverAttributeNames', | |
123 | + LATEST_TS_KEY_NAMES = 'latestTsKeyNames', | |
124 | + GET_LATEST_VALUE_WITH_TS = 'getLatestValueWithTs', | |
125 | + FETCH_LAST_LEVEL_ONLY = 'fetchLastLevelOnly', | |
126 | + | |
127 | + // DEVICE_RELATIONS_QUERY | |
128 | + DIRECTION = 'direction', | |
129 | + MAX_LEVEL = 'maxLevel', | |
130 | + RELATION_TYPE = 'relationType', | |
131 | + DEVICE_TYPES = 'deviceTypes', | |
132 | +} | |
133 | + | |
134 | +export enum RelatedDeviceAttributeFieldsNameEnum { | |
135 | + DEVICE_RELATIONS_QUERY = 'deviceRelationsQuery', | |
136 | + TELL_FAILURE_IF_ABSENT = 'Tell Failure', | |
137 | + CLIENT_ATTRIBUTE_NAMES = 'Client attributes', | |
138 | + SHARED_ATTRIBUTE_NAMES = 'Shared attributes', | |
139 | + SERVER_ATTRIBUTE_NAMES = 'Server attributes', | |
140 | + LATEST_TS_KEY_NAMES = 'Latest timeseries', | |
141 | + GET_LATEST_VALUE_WITH_TS = 'Fetch Latest telemetry with Timestamp', | |
142 | + FETCH_LAST_LEVEL_ONLY = '仅获取最后一级关联', | |
143 | + | |
144 | + // DEVICE_RELATIONS_QUERY | |
145 | + DIRECTION = '方向', | |
146 | + MAX_LEVEL = 'Max relation level', | |
147 | + RELATION_TYPE = '关联类型', | |
148 | + DEVICE_TYPES = '设备类型', | |
149 | +} | |
150 | + | |
151 | +// Tenant attributes | |
152 | +export enum TenantAttributesFieldsEnum { | |
153 | + ATTR_MAPING = 'attrMapping', | |
154 | + TELEMETRY = 'telemetry', | |
155 | +} | |
156 | + | |
157 | +export enum TenantAttributesFieldsNameEnum { | |
158 | + ATTR_MAPING = 'attrMapping', | |
159 | + TELEMETRY = 'Latest telemetry', | |
160 | +} | |
161 | + | |
162 | +// Enrichment Tenant details | |
163 | +export enum TenantDetailsFieldsEnum { | |
164 | + DETAILS_LIST = 'detailsList', | |
165 | + ADD_TO_METADATA = 'addToMetadata', | |
166 | +} | |
167 | + | |
168 | +export enum TenantDetailsFieldsNameEnum { | |
169 | + DETAILS_LIST = 'Add selected details to message metadata', | |
170 | + ADD_TO_METADATA = 'Select entity details', | |
171 | +} | ... | ... |
1 | +// Alarm notice | |
2 | +export enum AlarmNoticeFieldsEnum { | |
3 | + CONFIGURATION = 'CONFIGURATION', | |
4 | +} | |
5 | + | |
6 | +export enum AlarmNoticeFieldsNameEnum { | |
7 | + CONFIGURATION = '配置', | |
8 | +} | |
9 | + | |
10 | +// aws sns | |
11 | +export enum AwsSnsFieldsEnum { | |
12 | + TOPIC_ARN_PATTERN = 'topicArnPattern', | |
13 | + ACCESS_KEY_ID = 'accessKeyId', | |
14 | + SECRET_ACCESS_KEY = 'secretAccessKey', | |
15 | + REGION = 'region', | |
16 | +} | |
17 | + | |
18 | +export enum AwsSnsFieldsNameEnum { | |
19 | + TOPIC_ARN_PATTERN = 'Topic ARN pattern', | |
20 | + ACCESS_KEY_ID = 'AWS Access Key ID', | |
21 | + SECRET_ACCESS_KEY = 'AWS Secret Access Key', | |
22 | + REGION = 'AWS Region', | |
23 | +} | |
24 | + | |
25 | +// Aws sqs | |
26 | +export enum AwsSqsFieldsEnum { | |
27 | + QUEUE_TYPE = 'queueType', | |
28 | + QUEUE_URL_PATTERN = 'queueUrlPattern', | |
29 | + DELAY_SECONDS = 'delaySeconds', | |
30 | + MESSAGE_ATTRIBUTES = 'messageAttributes', | |
31 | + ACCESS_KEY_ID = 'accessKeyId', | |
32 | + SECRET_ACCESS_KEY = 'secretAccessKey', | |
33 | + REGION = 'region', | |
34 | +} | |
35 | + | |
36 | +export enum AwsSqsFieldsNameEnum { | |
37 | + QUEUE_TYPE = 'Queue type', | |
38 | + QUEUE_URL_PATTERN = 'Queue URL pattern', | |
39 | + DELAY_SECONDS = 'Delay(seconds)', | |
40 | + MESSAGE_ATTRIBUTES = 'Message attributes', | |
41 | + ACCESS_KEY_ID = 'AWS Access Key ID', | |
42 | + SECRET_ACCESS_KEY = 'AWS Secret Access Key', | |
43 | + REGION = 'AWS Region', | |
44 | +} | |
45 | + | |
46 | +// Azure iot hub | |
47 | +export enum AzureIotHubFieldsEnum { | |
48 | + TOPIC_PATTERN = 'topicPattern', | |
49 | + HOST = 'host', | |
50 | + PORT = 'port', | |
51 | + CONNECT_TIMEOUT_SEC = 'connectTimeoutSec', | |
52 | + CLIENT_ID = 'clientId', | |
53 | + CLEAN_SESSION = 'cleanSession', | |
54 | + SSL = 'ssl', | |
55 | + CREDENTIALS = 'credentials', | |
56 | + | |
57 | + TYPE = 'type', | |
58 | + SAS_KEY = 'sasKey', | |
59 | + CA_CERT = 'caCert', | |
60 | + CA_CERT_FILE_NAME = 'caCertFileName', | |
61 | + PRIVATE_KEY = 'privateKey', | |
62 | + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName', | |
63 | + CERT = 'cert', | |
64 | + CERT_FILE_NAME = 'certFileName', | |
65 | + PASSWORD = 'password', | |
66 | +} | |
67 | + | |
68 | +export enum AzureIotHubFieldsNameEnum { | |
69 | + TOPIC_PATTERN = 'Topic', | |
70 | + HOST = 'Hostname', | |
71 | + PORT = 'port', | |
72 | + CONNECT_TIMEOUT_SEC = 'connectTimeoutSec', | |
73 | + CLIENT_ID = 'Device ID', | |
74 | + CLEAN_SESSION = 'cleanSession', | |
75 | + SSL = 'ssl', | |
76 | + CREDENTIALS = 'credentials', | |
77 | + | |
78 | + TYPE = 'Credentials type', | |
79 | + SAS_KEY = 'sasKey', | |
80 | + CA_CERT = 'CA certificate file', | |
81 | + CA_CERT_FILE_NAME = 'caCertFileName', | |
82 | + PRIVATE_KEY = 'Client private key file', | |
83 | + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName', | |
84 | + CERT = 'Client certificate file', | |
85 | + CERT_FILE_NAME = 'certFileName', | |
86 | + PASSWORD = 'Private key password', | |
87 | +} | |
88 | + | |
89 | +// GCP pubsub | |
90 | +export enum GcpPubsubFieldsEnum { | |
91 | + PROJECT_ID = 'projectId', | |
92 | + TOPIC_NAME = 'topicName', | |
93 | + SERVICE_ACCOUNT_KEY = 'serviceAccountKey', | |
94 | + SERVICE_ACCOUNT_KEY_FILE_NAME = 'serviceAccountKeyFileName', | |
95 | + MESSAGE_ATTRIBUTES = 'messageAttributes', | |
96 | +} | |
97 | + | |
98 | +export enum GcpPubsubFieldsNameEnum { | |
99 | + PROJECT_ID = 'GCP project ID', | |
100 | + TOPIC_NAME = 'Topic name', | |
101 | + SERVICE_ACCOUNT_KEY = 'GCP service account key file', | |
102 | + SERVICE_ACCOUNT_KEY_FILE_NAME = 'serviceAccountKeyFileName', | |
103 | + MESSAGE_ATTRIBUTES = 'Message attributes', | |
104 | +} | |
105 | + | |
106 | +// Kafka | |
107 | +export enum KafkaFieldsEnum { | |
108 | + TOPIC_PATTERN = 'topicPattern', | |
109 | + BOOTSTRAP_SERVERS = 'bootstrapServers', | |
110 | + RETRIES = 'retries', | |
111 | + BATCH_SIZE = 'batchSize', | |
112 | + LINGER = 'linger', | |
113 | + BUFFER_MEMORY = 'bufferMemory', | |
114 | + ACKS = 'acks', | |
115 | + KEY_SERIALIZER = 'keySerializer', | |
116 | + VALUE_SERIALIZER = 'valueSerializer', | |
117 | + OTHER_PROPERTIES = 'otherProperties', | |
118 | + ADD_METADATA_KEY_VALUES_AS_KAFKA_HEADERS = 'addMetadataKeyValuesAsKafkaHeaders', | |
119 | + KAFKA_HEADERS_CHARSET = 'kafkaHeadersCharset', | |
120 | +} | |
121 | + | |
122 | +export enum KafkaFieldsNameEnum { | |
123 | + TOPIC_PATTERN = 'Topic pattern', | |
124 | + BOOTSTRAP_SERVERS = 'Bootstrap servers', | |
125 | + RETRIES = 'Automatically retry times if fails', | |
126 | + BATCH_SIZE = 'Produces batch size in bytes', | |
127 | + LINGER = 'Time to buffer locally(ms)', | |
128 | + BUFFER_MEMORY = 'Client buffer max size in bytes', | |
129 | + ACKS = 'Number of acknowledgments', | |
130 | + KEY_SERIALIZER = 'Key serializer', | |
131 | + VALUE_SERIALIZER = 'Value serializer', | |
132 | + OTHER_PROPERTIES = 'Other properties', | |
133 | + ADD_METADATA_KEY_VALUES_AS_KAFKA_HEADERS = 'Add Message metadata key-value pairs to Kafka record headers', | |
134 | + KAFKA_HEADERS_CHARSET = 'Charset encoding', | |
135 | +} | |
136 | + | |
137 | +// Mqtt | |
138 | +export enum MqttFieldsEnum { | |
139 | + TOPIC_PATTERN = 'topicPattern', | |
140 | + HOST = 'host', | |
141 | + PORT = 'port', | |
142 | + CONNECT_TIMEOUT_SEC = 'connectTimeoutSec', | |
143 | + CLIENT_ID = 'clientId', | |
144 | + APPEND_CLIENT_ID_SUFFIX = 'appendClientIdSuffix', | |
145 | + CLEAN_SESSION = 'cleanSession', | |
146 | + SSL = 'ssl', | |
147 | + CREDENTIALS = 'credentials', | |
148 | + | |
149 | + TYPE = 'type', | |
150 | + PASSWORD = 'password', | |
151 | + CA_CERT = 'caCert', | |
152 | + CA_CERT_FILE_NAME = 'caCertFileName', | |
153 | + PRIVATE_KEY = 'privateKey', | |
154 | + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName', | |
155 | + CERT = 'cert', | |
156 | + CERT_FILE_NAME = 'certFileName', | |
157 | + USERNAME = 'username', | |
158 | +} | |
159 | + | |
160 | +export enum MqttFieldsNameEnum { | |
161 | + TOPIC_PATTERN = 'Topic pattern', | |
162 | + HOST = 'Hose', | |
163 | + PORT = 'Port', | |
164 | + CONNECT_TIMEOUT_SEC = 'Connection timeout(sec)', | |
165 | + CLIENT_ID = 'Client ID', | |
166 | + APPEND_CLIENT_ID_SUFFIX = 'Add Service ID as suffix to Client ID', | |
167 | + CLEAN_SESSION = 'Clean session', | |
168 | + SSL = 'Enable SSL', | |
169 | + CREDENTIALS = 'credentials', | |
170 | + | |
171 | + TYPE = 'Credentials type', | |
172 | + PASSWORD = 'Password', | |
173 | + CA_CERT = 'Server CA certificate file', | |
174 | + CA_CERT_FILE_NAME = 'caCertFileName', | |
175 | + PRIVATE_KEY = 'Client private key file', | |
176 | + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName', | |
177 | + CERT = 'Client certificate file', | |
178 | + CERT_FILE_NAME = 'certFileName', | |
179 | + USERNAME = 'Username', | |
180 | +} | |
181 | + | |
182 | +// Rabbitmq | |
183 | +export enum RabbitmqFieldsEnum { | |
184 | + EXCHANGE_NAME_PATTERN = 'exchangeNamePattern', | |
185 | + ROUTING_KEY_PATTERN = 'routingKeyPattern', | |
186 | + MESSAGE_PROPERTIES = 'messageProperties', | |
187 | + HOST = 'host', | |
188 | + PORT = 'port', | |
189 | + VIRTUAL_HOST = 'virtualHost', | |
190 | + USERNAME = 'username', | |
191 | + PASSWORD = 'password', | |
192 | + AUTOMATIC_RECOVERY_ENABLED = 'automaticRecoveryEnabled', | |
193 | + CONNECTION_TIMEOUT = 'connectionTimeout', | |
194 | + HANDSHAKE_TIMEOUT = 'handshakeTimeout', | |
195 | + CLIENT_PROPERTIES = 'clientProperties', | |
196 | +} | |
197 | + | |
198 | +export enum RabbitmqFieldsNameEnum { | |
199 | + EXCHANGE_NAME_PATTERN = 'Exchange name pattern', | |
200 | + ROUTING_KEY_PATTERN = 'Routing key pattern', | |
201 | + MESSAGE_PROPERTIES = 'Message properties', | |
202 | + HOST = 'Host', | |
203 | + PORT = 'Port', | |
204 | + VIRTUAL_HOST = 'Virtual host', | |
205 | + USERNAME = 'Username', | |
206 | + PASSWORD = 'Password', | |
207 | + AUTOMATIC_RECOVERY_ENABLED = 'Automatic recovery', | |
208 | + CONNECTION_TIMEOUT = 'Connection timeout(ms)', | |
209 | + HANDSHAKE_TIMEOUT = 'Handshake timeout(ms)', | |
210 | + CLIENT_PROPERTIES = 'Client properties', | |
211 | +} | |
212 | + | |
213 | +// Rest api call | |
214 | +export enum RestApiCallFieldsEnum { | |
215 | + REST_ENDPOINT_URL_PATTERN = 'restEndpointUrlPattern', | |
216 | + REQUEST_METHOD = 'requestMethod', | |
217 | + USE_SIMPLE_CLIENT_HTTP_FACTORY = 'useSimpleClientHttpFactory', | |
218 | + IGNORE_REQUEST_BODY = 'ignoreRequestBody', | |
219 | + ENABLE_PROXY = 'enableProxy', | |
220 | + USE_SYSTEM_PROXY_PROPERTIES = 'useSystemProxyProperties', | |
221 | + PROXY_SCHEME = 'proxyScheme', | |
222 | + PROXY_HOST = 'proxyHost', | |
223 | + PROXY_PORT = 'proxyPort', | |
224 | + PROXY_USER = 'proxyUser', | |
225 | + PROXY_PASSWORD = 'proxyPassword', | |
226 | + READ_TIMEOUT_MS = 'readTimeoutMs', | |
227 | + MAX_PARALLEL_REQUESTS_COUNT = 'maxParallelRequestsCount', | |
228 | + HEADERS = 'headers', | |
229 | + USE_REDIS_QUEUE_FOR_MSG_PERSISTENCE = 'useRedisQueueForMsgPersistence', | |
230 | + TRIM_QUEUE = 'trimQueue', | |
231 | + MAX_QUEUE_SIZE = 'maxQueueSize', | |
232 | + CREDENTIALS = 'credentials', | |
233 | + | |
234 | + TYPE = 'type', | |
235 | + PASSWORD = 'password', | |
236 | + CA_CERT = 'caCert', | |
237 | + CA_CERT_FILE_NAME = 'caCertFileName', | |
238 | + PRIVATE_KEY = 'privateKey', | |
239 | + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName', | |
240 | + CERT = 'cert', | |
241 | + CERT_FILE_NAME = 'certFileName', | |
242 | + USERNAME = 'username', | |
243 | +} | |
244 | + | |
245 | +export enum RestApiCallFieldsNameEnum { | |
246 | + REST_ENDPOINT_URL_PATTERN = 'Endpoint URL pattern', | |
247 | + REQUEST_METHOD = 'Request method', | |
248 | + USE_SIMPLE_CLIENT_HTTP_FACTORY = 'Use simple client HTTP factory', | |
249 | + IGNORE_REQUEST_BODY = 'Without request body', | |
250 | + ENABLE_PROXY = 'Enable proxy', | |
251 | + USE_SYSTEM_PROXY_PROPERTIES = 'Use system proxy properties', | |
252 | + PROXY_SCHEME = 'Proxy scheme', | |
253 | + PROXY_HOST = 'Proxy host', | |
254 | + PROXY_PORT = 'Proxy port', | |
255 | + PROXY_USER = 'Proxy user', | |
256 | + PROXY_PASSWORD = 'Proxy password', | |
257 | + READ_TIMEOUT_MS = 'Read timeout in millis', | |
258 | + MAX_PARALLEL_REQUESTS_COUNT = 'Max number of parallel request', | |
259 | + HEADERS = 'Header', | |
260 | + USE_REDIS_QUEUE_FOR_MSG_PERSISTENCE = 'Use redis queue for message persistence', | |
261 | + TRIM_QUEUE = 'Trim redis queue', | |
262 | + MAX_QUEUE_SIZE = 'Redis queue max size', | |
263 | + CREDENTIALS = 'Credentials', | |
264 | + | |
265 | + TYPE = 'Credentials type', | |
266 | + PASSWORD = 'Password', | |
267 | + CA_CERT = 'Server CA certificate file', | |
268 | + CA_CERT_FILE_NAME = 'caCertFileName', | |
269 | + PRIVATE_KEY = 'Client private key file', | |
270 | + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName', | |
271 | + CERT = 'Client certificate file', | |
272 | + CERT_FILE_NAME = 'certFileName', | |
273 | + USERNAME = 'Username', | |
274 | +} | |
275 | + | |
276 | +// send email | |
277 | +export enum SendEmailFieldsEnum { | |
278 | + USE_SYSTEM_SMTP_SETTINGS = 'useSystemSmtpSettings', | |
279 | + SMTP_PROTOCOL = 'smtpProtocol', | |
280 | + SMTP_HOST = 'smtpHost', | |
281 | + SMTP_PORT = 'smtpPort', | |
282 | + TIMEOUT = 'timeout', | |
283 | + ENABLE_TLS = 'enableTls', | |
284 | + TLS_VERSION = 'tlsVersion', | |
285 | + ENABLE_PROXY = 'enableProxy', | |
286 | + PROXY_HOST = 'proxyHost', | |
287 | + PROXY_PORT = 'proxyPort', | |
288 | + PROXY_USER = 'proxyUser', | |
289 | + PROXY_PASSWORD = 'proxyPassword', | |
290 | + USERNAME = 'username', | |
291 | + PASSWORD = 'password', | |
292 | +} | |
293 | + | |
294 | +export enum SendEmailFieldsNameEnum { | |
295 | + USE_SYSTEM_SMTP_SETTINGS = 'Use system SMTP settings', | |
296 | + SMTP_PROTOCOL = 'Protocol', | |
297 | + SMTP_HOST = 'SMTP host', | |
298 | + SMTP_PORT = 'SMTP port', | |
299 | + TIMEOUT = 'Timeout ms', | |
300 | + ENABLE_TLS = 'Enable TLS', | |
301 | + TLS_VERSION = 'TLS version', | |
302 | + ENABLE_PROXY = 'Enable proxy', | |
303 | + PROXY_HOST = 'Proxy host', | |
304 | + PROXY_PORT = 'Proxy port', | |
305 | + PROXY_USER = 'Proxy user', | |
306 | + PROXY_PASSWORD = 'Proxy password', | |
307 | + USERNAME = 'Username', | |
308 | + PASSWORD = 'Password', | |
309 | +} | |
310 | + | |
311 | +export enum SendSMSFieldsEnum { | |
312 | + NUMBERS_TO_TEMPLATE = 'numbersToTemplate', | |
313 | + SMS_MESSAGE_TEMPLATE = 'smsMessageTemplate', | |
314 | + USE_SYSTEM_SMS_SETTINGS = 'useSystemSmsSettings', | |
315 | + SMS_PROVIDER_CONFIGURATION = 'smsProviderConfiguration', | |
316 | + | |
317 | + ACCESS_KEY_ID = 'accessKeyId', | |
318 | + SECRET_ACCESS_KEY = 'secretAccessKey', | |
319 | + REGION = 'region', | |
320 | + TYPE = 'type', | |
321 | + NUMBER_FROM = 'numberFrom', | |
322 | + ACCOUNT_SID = 'accountSid', | |
323 | + ACCOUNT_TOKEN = 'accountToken', | |
324 | +} | |
325 | + | |
326 | +export enum SendSMSFieldsNameEnum { | |
327 | + NUMBERS_TO_TEMPLATE = 'Phone Numbers To Template', | |
328 | + SMS_MESSAGE_TEMPLATE = 'SMS message Template', | |
329 | + USE_SYSTEM_SMS_SETTINGS = 'User system SMS provider settings', | |
330 | + SMS_PROVIDER_CONFIGURATION = 'smsProviderConfiguration', | |
331 | + | |
332 | + ACCESS_KEY_ID = 'AWS访问密钥ID', | |
333 | + SECRET_ACCESS_KEY = 'AWS访问密钥', | |
334 | + REGION = 'AWS地区', | |
335 | + TYPE = 'SMS服务商类型', | |
336 | + NUMBER_FROM = '发送方电话号码', | |
337 | + ACCOUNT_SID = 'Twilio账户SID', | |
338 | + ACCOUNT_TOKEN = 'Twilio账户令牌', | |
339 | +} | ... | ... |
1 | +// Filter Check Alarm Status Fields | |
2 | +export enum CheckAlarmStatusFieldEnum { | |
3 | + ALARM_STATUS_LIST = 'alarmStatusList', | |
4 | +} | |
5 | + | |
6 | +export enum CheckAlarmStatusFieldNameEnum { | |
7 | + ALARM_STATUS_LIST = 'Alarm status filter', | |
8 | +} | |
9 | + | |
10 | +// Filter CHeck Existence Fields | |
11 | +export enum CheckExistenceFieldsEnum { | |
12 | + MESSAGE_NAMES = 'messageNames', | |
13 | + METADATA_NAMES = 'metadataNames', | |
14 | + CHECK_ALL_KEYS = 'checkAllKeys', | |
15 | +} | |
16 | + | |
17 | +export enum CheckExistenceFieldsNameEnum { | |
18 | + MESSAGE_NAMES = '消息数据', | |
19 | + METADATA_NAMES = '消息元数据', | |
20 | + CHECK_ALL_KEYS = '检查所有选择的键是否都存在', | |
21 | +} | |
22 | + | |
23 | +// Filter Check Relation Fields | |
24 | +export enum CheckRelationFieldsEnum { | |
25 | + DIRECTION = 'direction', | |
26 | + CHECK_FOR_SINGLE_ENTITY = 'checkForSingleEntity', | |
27 | + ENTITY_TYPE = 'entityType', | |
28 | + RELEATION_TYPE = 'relationType', | |
29 | + ENTITY_ID = 'entityId', | |
30 | +} | |
31 | + | |
32 | +export enum CheckRelationFieldsNameEnum { | |
33 | + DIRECTION = '方向', | |
34 | + CHECK_FOR_SINGLE_ENTITY = 'Check relation to specific entity', | |
35 | + ENTITY_TYPE = '类型', | |
36 | + RELEATION_TYPE = '关联类型', | |
37 | +} | |
38 | + | |
39 | +// Filter Gps geofencing filter | |
40 | +export enum GpsGeofencingFilterFieldsEnum { | |
41 | + LATITUDE_KEY_NAME = 'latitudeKeyName', | |
42 | + LONGITUDE_KEY_NAME = 'longitudeKeyName', | |
43 | + PERIMETER_TYPE = 'perimeterType', | |
44 | + FETCH_PERIMETER_INFO_FROM_MESSAGE_METADATA = 'fetchPerimeterInfoFromMessageMetadata', | |
45 | + PERIMETER_KEY_NAME = 'perimeterKeyName', | |
46 | + CENTER_LATITUDE = 'centerLatitude', | |
47 | + CENTER_LONGITUDE = 'centerLongitude', | |
48 | + RANGE = 'range', | |
49 | + RANGE_UNIT = 'rangeUnit', | |
50 | + POLYGONS_DEFINITION = 'polygonsDefinition', | |
51 | +} | |
52 | + | |
53 | +export enum GpsGeofencingFilterFieldsNameEnum { | |
54 | + LATITUDE_KEY_NAME = 'Latitude Key Name', | |
55 | + LONGITUDE_KEY_NAME = 'Longitude Key Name', | |
56 | + PERIMETER_TYPE = 'Perimeter Type', | |
57 | + FETCH_PERIMETER_INFO_FROM_MESSAGE_METADATA = 'Fetch perimeter information from message metadata', | |
58 | + CENTER_LATITUDE = 'Center latitude', | |
59 | + CENTER_LONGITUDE = 'Center longitude', | |
60 | + RANGE = 'Range', | |
61 | + RANGE_UNIT = 'Range unit', | |
62 | + PERIMETER_KEY_NAME = 'Perimeter key name', | |
63 | + POLYGONS_DEFINITION = 'Polygons definition', | |
64 | +} | |
65 | + | |
66 | +// Filter Message Type | |
67 | +export enum MessageTypeFieldsEnum { | |
68 | + MESSAGE_TYPES = 'messageTypes', | |
69 | +} | |
70 | + | |
71 | +export enum MessageTypeFieldsNameEnum { | |
72 | + MESSAGE_TYPES = 'Message Types Filter', | |
73 | +} | |
74 | + | |
75 | +// Filter Originator Type | |
76 | +export enum OriginatorTypeFieldsEnum { | |
77 | + ORIGINATOR_TYPES = 'originatorTypes', | |
78 | +} | |
79 | + | |
80 | +export enum OriginatorTypeFieldsNameEnum { | |
81 | + ORIGINATOR_TYPES = 'Originator types filter', | |
82 | +} | |
83 | + | |
84 | +// Filter Script | |
85 | +export enum ScriptFieldsEnum { | |
86 | + JS_SCRIPT = 'jsScript', | |
87 | +} | |
88 | + | |
89 | +export enum ScriptFieldsNameEnum { | |
90 | + JS_SCRIPT = 'Filter', | |
91 | +} | |
92 | + | |
93 | +// Filter Switch | |
94 | +export enum SwitchFieldsEnum { | |
95 | + JS_SCRIPT = 'jsScript', | |
96 | +} | |
97 | + | |
98 | +export enum SwitchFieldsNameEnum { | |
99 | + JS_SCRIPT = 'Filter', | |
100 | +} | ... | ... |
1 | +export enum CheckPointFieldsEnum { | |
2 | + QUEUE_NAME = 'queueName', | |
3 | +} | |
4 | + | |
5 | +export enum CheckPointFieldsNameEnum { | |
6 | + QUEUE_NAME = '队列名称', | |
7 | +} | |
8 | + | |
9 | +export enum RuleChainFieldsEnum { | |
10 | + RULE_CHAIN_ID = 'ruleChainId', | |
11 | +} | |
12 | + | |
13 | +export enum RuleChainFieldsNameEnum { | |
14 | + RULE_CHAIN_ID = '规则链', | |
15 | +} | ... | ... |
1 | +// Change originator | |
2 | +export enum ChangeOriginatorFieldsEnum { | |
3 | + ORIGINATOR_SOURCE = 'originatorSource', | |
4 | + RELATIONS_QUERY = 'relationsQuery', | |
5 | +} | |
6 | + | |
7 | +export enum ChangeOriginatorFieldsNameEnum { | |
8 | + ORIGINATOR_SOURCE = 'Originator source', | |
9 | + RELATIONS_QUERY = 'Relations Query', | |
10 | +} | |
11 | + | |
12 | +export enum ScriptFieldsEnum { | |
13 | + JS_SCRIPT = 'jsScript', | |
14 | +} | |
15 | + | |
16 | +export enum ScriptFieldsNameEnum { | |
17 | + JS_SCRIPT = 'Transform', | |
18 | +} | |
19 | + | |
20 | +export enum ToEmailFieldsEnum { | |
21 | + FROM_TEMPLATE = 'fromTemplate', | |
22 | + TO_TEMPLATE = 'toTemplate', | |
23 | + CC_TEMPLATE = 'ccTemplate', | |
24 | + BCC_TEMPLATE = 'bccTemplate', | |
25 | + SUBJECT_TEMPLATE = 'subjectTemplate', | |
26 | + MAIL_BODY_TYPE = 'mailBodyType', | |
27 | + IS_HTML_TEMPLATE = 'isHtmlTemplate', | |
28 | + BODY_TEMPLATE = 'bodyTemplate', | |
29 | +} | |
30 | + | |
31 | +export enum ToEmailFieldsNameEnum { | |
32 | + FROM_TEMPLATE = 'From Template', | |
33 | + TO_TEMPLATE = 'To Template', | |
34 | + CC_TEMPLATE = 'Cc Template', | |
35 | + BCC_TEMPLATE = 'Bcc Template', | |
36 | + SUBJECT_TEMPLATE = 'Subject Template', | |
37 | + MAIL_BODY_TYPE = 'Mail body type', | |
38 | + IS_HTML_TEMPLATE = 'Dynamic mail body type', | |
39 | + BODY_TEMPLATE = 'Body Template', | |
40 | +} | ... | ... |
src/views/rule/designer/enum/index.ts
0 → 100644
1 | +export enum HandleTypeEnum { | |
2 | + SOURCE = 'source', | |
3 | + TARGET = 'target', | |
4 | +} | |
5 | + | |
6 | +export enum NodeTypeEnum { | |
7 | + CUSTOM = 'custom', | |
8 | +} | |
9 | + | |
10 | +export enum EdgeTypeEnum { | |
11 | + CUSTOM = 'custom', | |
12 | +} | |
13 | + | |
14 | +export enum BasicConnectionModalEnum { | |
15 | + BASIC = 'BASIC', | |
16 | + CUSTOM = 'CUSTOM', | |
17 | +} | |
18 | + | |
19 | +export enum MarkerArrowEnum { | |
20 | + BASIC_ARROW = 'basicArrow', | |
21 | + BASIC_ARROW_SELECTED = 'basicArrowSelected', | |
22 | +} | |
23 | + | |
24 | +export enum ElementsTypeEnum { | |
25 | + NODE = 'NODE', | |
26 | + EDGE = 'EDGE', | |
27 | +} | ... | ... |
src/views/rule/designer/enum/node.ts
0 → 100644
1 | +import { CommonFields, CommonFieldsName } from './formField/common'; | |
2 | + | |
3 | +export enum FetchNodeComFlagTypeENum { | |
4 | + CONNECTION_MODAL = 'CONNECTION_MODAL', | |
5 | + CREATE_MODAL = 'CREATE_MODAL', | |
6 | +} | |
7 | + | |
8 | +export enum EdgeBindDataFieldEnum { | |
9 | + TYPE = 'type', | |
10 | +} | |
11 | + | |
12 | +export enum EdgeBindDataFieldNameEnum { | |
13 | + TYPE = '链接标签', | |
14 | +} | |
15 | + | |
16 | +export const NodeBindDataFieldEnum = { | |
17 | + ...CommonFields, | |
18 | +}; | |
19 | + | |
20 | +export const NodeBindDataFieldNameEnum = { | |
21 | + ...CommonFieldsName, | |
22 | +}; | ... | ... |
src/views/rule/designer/hook/useAddEdges.ts
0 → 100644
1 | +import type { Connection } from '@vue-flow/core'; | |
2 | +import { EdgeTypeEnum } from '../enum'; | |
3 | +import type { EdgeData } from '../types/node'; | |
4 | +import { buildUUID } from '/@/utils/uuid'; | |
5 | + | |
6 | +export function useAddEdges() { | |
7 | + const getAddedgesParams = (params: Connection, data: string | string[] | any) => { | |
8 | + return { type: EdgeTypeEnum.CUSTOM, data: { data } as EdgeData, id: buildUUID(), ...params }; | |
9 | + }; | |
10 | + | |
11 | + return { getAddedgesParams }; | |
12 | +} | ... | ... |
src/views/rule/designer/hook/useAddNodes.ts
0 → 100644
1 | +import { Node } from '@vue-flow/core'; | |
2 | +import { NodeTypeEnum } from '../enum'; | |
3 | +import { buildUUID } from '/@/utils/uuid'; | |
4 | +import { NodeData } from '../types/node'; | |
5 | + | |
6 | +export const useAddNodes = () => { | |
7 | + const getAddNodesParams = ( | |
8 | + position: Node['position'], | |
9 | + data: NodeData, | |
10 | + options?: Partial<Node> | |
11 | + ): Node => { | |
12 | + return { | |
13 | + id: buildUUID(), | |
14 | + type: NodeTypeEnum.CUSTOM, | |
15 | + position, | |
16 | + data, | |
17 | + ...options, | |
18 | + }; | |
19 | + }; | |
20 | + | |
21 | + return { getAddNodesParams }; | |
22 | +}; | ... | ... |
1 | +import { Component, computed, ref, shallowRef, toRaw, unref } from 'vue'; | |
2 | +import { fetchConnectionComponent, fetchCreateComponent } from '../packages'; | |
3 | +import { CreateModalDefineExposeType, AwaitPopupWindowReturnDataType } from '../types'; | |
4 | +import { EdgeData, NodeData } from '../types/node'; | |
5 | +import { DataActionModeEnum } from '/@/enums/toolEnum'; | |
6 | +import { ElementsTypeEnum } from '../enum'; | |
7 | + | |
8 | +interface OptionsType { | |
9 | + mode: DataActionModeEnum; | |
10 | + type: ElementsTypeEnum; | |
11 | +} | |
12 | + | |
13 | +export interface ElementInfo { | |
14 | + id: string; | |
15 | + type: ElementsTypeEnum; | |
16 | +} | |
17 | + | |
18 | +export function useAwaitPopupWindowBindData( | |
19 | + options: OptionsType = { mode: DataActionModeEnum.CREATE, type: ElementsTypeEnum.NODE } | |
20 | +) { | |
21 | + const { type, mode } = options; | |
22 | + | |
23 | + const visible = ref(false); | |
24 | + | |
25 | + const nodeData = ref<NodeData>(); | |
26 | + | |
27 | + const edgeData = ref<EdgeData>(); | |
28 | + | |
29 | + const spinning = ref(false); | |
30 | + | |
31 | + const resolveFn = ref<(options: AwaitPopupWindowReturnDataType) => void>(); | |
32 | + | |
33 | + const createComponentEl = ref<Nullable<CreateModalDefineExposeType>>(); | |
34 | + | |
35 | + const shadowComponent = shallowRef<Nullable<Component>>(); | |
36 | + | |
37 | + const elementInfo = ref<ElementInfo>(); | |
38 | + | |
39 | + const getNodeSetValue = computed(() => { | |
40 | + return unref(mode) === DataActionModeEnum.CREATE | |
41 | + ? unref(nodeData)?.config?.configurationDescriptor.nodeDefinition.defaultConfiguration | |
42 | + : unref(nodeData)?.data?.configuration; | |
43 | + }); | |
44 | + | |
45 | + const getEdgeSetValue = computed(() => { | |
46 | + return { | |
47 | + type: | |
48 | + unref(mode) === DataActionModeEnum.CREATE | |
49 | + ? unref(nodeData)?.config?.configurationDescriptor?.nodeDefinition.relationTypes | |
50 | + : unref(edgeData)?.data, | |
51 | + }; | |
52 | + }); | |
53 | + | |
54 | + const getSetValue = computed(() => | |
55 | + unref(type) === ElementsTypeEnum.EDGE ? unref(getEdgeSetValue) : unref(getNodeSetValue) | |
56 | + ); | |
57 | + | |
58 | + const getComponentKey = computed(() => unref(nodeData)?.config?.key); | |
59 | + | |
60 | + const handleFetchComponent = async (nodeOptions: NodeData, edgeOptions?: EdgeData) => { | |
61 | + nodeData.value = nodeOptions; | |
62 | + edgeData.value = edgeOptions; | |
63 | + | |
64 | + spinning.value = true; | |
65 | + shadowComponent.value = null; | |
66 | + const modules = | |
67 | + ElementsTypeEnum.NODE === type | |
68 | + ? await fetchCreateComponent(nodeOptions.config!) | |
69 | + : await fetchConnectionComponent(nodeOptions.config!); | |
70 | + | |
71 | + const component = (await modules?.()) as Record<'default', Component>; | |
72 | + shadowComponent.value = component?.default; | |
73 | + spinning.value = false; | |
74 | + }; | |
75 | + | |
76 | + const open = async ( | |
77 | + nodeData: NodeData, | |
78 | + edgeData?: EdgeData, | |
79 | + _elementInfo?: ElementInfo | |
80 | + ): Promise<AwaitPopupWindowReturnDataType> => { | |
81 | + elementInfo.value = _elementInfo; | |
82 | + await handleFetchComponent(nodeData, edgeData); | |
83 | + return new Promise((_resolve) => { | |
84 | + visible.value = true; | |
85 | + resolveFn.value = _resolve; | |
86 | + }); | |
87 | + }; | |
88 | + | |
89 | + const handleOnMounted = () => { | |
90 | + unref(createComponentEl)?.setFieldsValue?.(toRaw(unref(getSetValue)), toRaw(unref(nodeData))); | |
91 | + }; | |
92 | + | |
93 | + const validate = async () => { | |
94 | + return (await unref(createComponentEl)?.validate?.()) || { flag: true }; | |
95 | + }; | |
96 | + | |
97 | + const handleSubmitData = (extraData: Recordable = {}, value: Recordable = {}) => { | |
98 | + return Object.assign( | |
99 | + {}, | |
100 | + extraData, | |
101 | + unref(type) === ElementsTypeEnum.NODE ? { configuration: toRaw(unref(value)) } : value | |
102 | + ); | |
103 | + }; | |
104 | + | |
105 | + const handleSubmit = async (extraData: Recordable = {}) => { | |
106 | + const { flag } = await validate(); | |
107 | + if (!flag) return; | |
108 | + const value = await unref(createComponentEl)?.getFieldsValue?.(); | |
109 | + unref(resolveFn)?.({ | |
110 | + flag: true, | |
111 | + data: handleSubmitData(extraData, value), | |
112 | + } as AwaitPopupWindowReturnDataType); | |
113 | + visible.value = false; | |
114 | + }; | |
115 | + | |
116 | + const handleCancel = () => { | |
117 | + unref(resolveFn)?.({ flag: false, data: null } as AwaitPopupWindowReturnDataType); | |
118 | + visible.value = false; | |
119 | + }; | |
120 | + | |
121 | + return { | |
122 | + visible, | |
123 | + nodeData, | |
124 | + spinning, | |
125 | + elementInfo, | |
126 | + shadowComponent, | |
127 | + createComponentEl, | |
128 | + getComponentKey, | |
129 | + open, | |
130 | + handleOnMounted, | |
131 | + handleSubmit, | |
132 | + handleCancel, | |
133 | + }; | |
134 | +} | ... | ... |
1 | +import { Ref, toRaw, unref } from 'vue'; | |
2 | +import { BasicNodeBindData, NodeData } from '../types/node'; | |
3 | +import { Elements, GraphNode } from '@vue-flow/core'; | |
4 | +import { RuleChainType } from '../types/ruleNode'; | |
5 | +import { allComponents } from '../packages'; | |
6 | +import { RuleNodeTypeEnum } from '../packages/index.type'; | |
7 | +import { buildUUID } from '/@/utils/uuid'; | |
8 | +import { isNullOrUnDef } from '/@/utils/is'; | |
9 | +import { useAddNodes } from './useAddNodes'; | |
10 | +import { useAddEdges } from './useAddEdges'; | |
11 | + | |
12 | +export function useBasicDataTransform() { | |
13 | + const nodeConfigMap = new Map<string, NodeData>(); | |
14 | + | |
15 | + function initNodeConfigMap() { | |
16 | + for (const key of Object.keys(allComponents)) { | |
17 | + const category = allComponents[key as RuleNodeTypeEnum]; | |
18 | + for (const nodeConfig of category.components) { | |
19 | + const { clazz } = nodeConfig; | |
20 | + nodeConfigMap.set(clazz, { config: nodeConfig, category: category.category }); | |
21 | + } | |
22 | + } | |
23 | + } | |
24 | + | |
25 | + function mergeData(data: NodeData['data'], nodeData: NodeData, node: GraphNode) { | |
26 | + const { x: layoutX, y: layoutY } = node.computedPosition; | |
27 | + | |
28 | + return { | |
29 | + debugMode: !!data?.debugMode, | |
30 | + name: data?.name, | |
31 | + type: nodeData.config?.clazz, | |
32 | + configuration: toRaw(unref(data?.configuration)), | |
33 | + additionalInfo: { | |
34 | + description: data?.description, | |
35 | + layoutX, | |
36 | + layoutY, | |
37 | + }, | |
38 | + }; | |
39 | + } | |
40 | + | |
41 | + function deconstructionConnection( | |
42 | + ruleChain: Ref<RuleChainType> | RuleChainType, | |
43 | + inputNodeId: string | |
44 | + ) { | |
45 | + const { connections, nodes, firstNodeIndex } = unref(ruleChain); | |
46 | + const indexMap = new Map<number, BasicNodeBindData>(); | |
47 | + const groupByConnections = new Map<string, string[]>(); | |
48 | + const SOURCE_HANDLE = '__handle-right'; | |
49 | + const TARGET_HANDLE = '__handle-left'; | |
50 | + const SEPARATOR = ','; | |
51 | + const edges: Elements = []; | |
52 | + const { getAddedgesParams } = useAddEdges(); | |
53 | + | |
54 | + nodes.forEach((item, index) => indexMap.set(index, item)); | |
55 | + | |
56 | + (connections || []).forEach((item) => { | |
57 | + const { fromIndex, toIndex, type } = item; | |
58 | + const key = `${fromIndex}${SEPARATOR}${toIndex}`; | |
59 | + if (!groupByConnections.has(key)) groupByConnections.set(key, []); | |
60 | + | |
61 | + const types = groupByConnections.get(key)!; | |
62 | + types.push(type); | |
63 | + }); | |
64 | + | |
65 | + for (const [key, types] of Array.from(groupByConnections.entries())) { | |
66 | + const [fromIndex, toIndex] = key.split(SEPARATOR); | |
67 | + | |
68 | + const sourceNode = indexMap.get(Number(fromIndex)); | |
69 | + const targetNode = indexMap.get(Number(toIndex)); | |
70 | + const source = sourceNode!.id!.id; | |
71 | + const target = targetNode!.id!.id; | |
72 | + const sourceHandle = `${source}${SOURCE_HANDLE}`; | |
73 | + const targetHandle = `${target}${TARGET_HANDLE}`; | |
74 | + | |
75 | + edges.push( | |
76 | + getAddedgesParams( | |
77 | + { | |
78 | + source, | |
79 | + target, | |
80 | + sourceHandle, | |
81 | + targetHandle, | |
82 | + }, | |
83 | + { type: types } | |
84 | + ) | |
85 | + ); | |
86 | + } | |
87 | + | |
88 | + if (!isNullOrUnDef(firstNodeIndex)) { | |
89 | + const targetNode = indexMap.get(firstNodeIndex); | |
90 | + const source = inputNodeId; | |
91 | + const target = targetNode!.id!.id; | |
92 | + const sourceHandle = `${source}$${SOURCE_HANDLE}`; | |
93 | + const targetHandle = `${target}${TARGET_HANDLE}`; | |
94 | + edges.push( | |
95 | + getAddedgesParams( | |
96 | + { | |
97 | + source, | |
98 | + target, | |
99 | + sourceHandle, | |
100 | + targetHandle, | |
101 | + }, | |
102 | + {} | |
103 | + ) | |
104 | + ); | |
105 | + } | |
106 | + | |
107 | + return edges; | |
108 | + } | |
109 | + | |
110 | + function genNewNodeByData(node: BasicNodeBindData, config: NodeData) { | |
111 | + const { additionalInfo, configuration, debugMode, name, id } = node; | |
112 | + const { layoutX, layoutY, description } = additionalInfo || {}; | |
113 | + const { getAddNodesParams } = useAddNodes(); | |
114 | + | |
115 | + return getAddNodesParams( | |
116 | + { x: layoutX!, y: layoutY! }, | |
117 | + { | |
118 | + ...config, | |
119 | + data: { | |
120 | + configuration, | |
121 | + debugMode, | |
122 | + description, | |
123 | + name, | |
124 | + }, | |
125 | + created: !!id?.id, | |
126 | + }, | |
127 | + { | |
128 | + id: id?.id || buildUUID(), | |
129 | + } | |
130 | + ); | |
131 | + } | |
132 | + | |
133 | + function deconstructionNode(nodes: RuleChainType['nodes']) { | |
134 | + const addNodes: Elements = []; | |
135 | + for (const node of unref(nodes)) { | |
136 | + const { type } = node; | |
137 | + if (!type) continue; | |
138 | + const nodeConfig = nodeConfigMap.get(type); | |
139 | + | |
140 | + if (!nodeConfig) { | |
141 | + throw `No component configuration of type '${type}' was found`; | |
142 | + } | |
143 | + | |
144 | + const newNode = genNewNodeByData(node, nodeConfig); | |
145 | + | |
146 | + addNodes.push(newNode); | |
147 | + } | |
148 | + return addNodes; | |
149 | + } | |
150 | + | |
151 | + function deconstructionData( | |
152 | + ruleChain: RuleChainType | Ref<RuleChainType | undefined>, | |
153 | + inputNodeId: string | |
154 | + ) { | |
155 | + if (!ruleChain || !unref(ruleChain)) return; | |
156 | + ruleChain = toRaw(unref(ruleChain))!; | |
157 | + | |
158 | + const nodes = deconstructionNode(ruleChain?.nodes || []); | |
159 | + | |
160 | + const edges = deconstructionConnection(ruleChain!, inputNodeId); | |
161 | + | |
162 | + return { | |
163 | + nodes, | |
164 | + edges, | |
165 | + }; | |
166 | + } | |
167 | + | |
168 | + initNodeConfigMap(); | |
169 | + | |
170 | + return { | |
171 | + mergeData, | |
172 | + deconstructionData, | |
173 | + }; | |
174 | +} | ... | ... |
1 | +import { EdgeProps, useEdge } from '@vue-flow/core'; | |
2 | +import { computed, unref } from 'vue'; | |
3 | +import { MarkerArrowEnum } from '../enum'; | |
4 | + | |
5 | +export const useConnectionFocus = (props: EdgeProps) => { | |
6 | + const { edge } = useEdge(props.id); | |
7 | + | |
8 | + const getSelected = computed(() => unref(edge)?.selected); | |
9 | + | |
10 | + const getMarkerEnd = computed( | |
11 | + () => | |
12 | + `url(#${ | |
13 | + unref(getSelected) ? MarkerArrowEnum.BASIC_ARROW_SELECTED : MarkerArrowEnum.BASIC_ARROW | |
14 | + })` | |
15 | + ); | |
16 | + | |
17 | + return { | |
18 | + getMarkerEnd, | |
19 | + getSelected, | |
20 | + }; | |
21 | +}; | ... | ... |
1 | +import { GraphEdge, GraphNode, VueFlowStore } from '@vue-flow/core'; | |
2 | +import { getRuleNodeCache, setRuleNodeCache } from './useRuleCopyPaste'; | |
3 | +import { RuleContextMenuEnum } from './useRuleChainContextMenu'; | |
4 | +import { useAddNodes } from './useAddNodes'; | |
5 | +import { buildUUID } from '/@/utils/uuid'; | |
6 | +import { toRaw, unref } from 'vue'; | |
7 | +import { useSaveAndRedo } from './useSaveAndRedo'; | |
8 | +import { isUnDef } from '/@/utils/is'; | |
9 | +import { useAddEdges } from './useAddEdges'; | |
10 | +import { EdgeData } from '../types/node'; | |
11 | + | |
12 | +interface HandleContextMenuActionParamsType { | |
13 | + menuType: RuleContextMenuEnum; | |
14 | + event?: Event; | |
15 | + flowActionType?: VueFlowStore; | |
16 | + node?: GraphNode; | |
17 | + edge?: GraphEdge; | |
18 | + useSaveAndRedoActionType?: ReturnType<typeof useSaveAndRedo>; | |
19 | +} | |
20 | + | |
21 | +export const NODE_WIDTH = 176; | |
22 | +export const NODE_HEIGHT = 48; | |
23 | + | |
24 | +function getElementsCenter(nodes: GraphNode[]) { | |
25 | + let leftTopX: number | undefined; | |
26 | + let leftTopY: number | undefined; | |
27 | + let rightBottomX: number | undefined; | |
28 | + let rightBottomY: number | undefined; | |
29 | + | |
30 | + for (const node of nodes) { | |
31 | + const { position } = node; | |
32 | + const { x, y } = position; | |
33 | + if (isUnDef(leftTopX)) { | |
34 | + leftTopX = x; | |
35 | + leftTopY = y; | |
36 | + rightBottomX = x + NODE_WIDTH; | |
37 | + rightBottomY = y + NODE_HEIGHT; | |
38 | + | |
39 | + continue; | |
40 | + } | |
41 | + | |
42 | + if (x < leftTopX!) { | |
43 | + leftTopX = x; | |
44 | + if (y < leftTopY!) { | |
45 | + leftTopY = y; | |
46 | + } | |
47 | + continue; | |
48 | + } | |
49 | + | |
50 | + if (x + NODE_WIDTH > rightBottomX!) { | |
51 | + rightBottomX = x + NODE_WIDTH; | |
52 | + if (y + NODE_HEIGHT > rightBottomY!) { | |
53 | + rightBottomY = y + NODE_HEIGHT; | |
54 | + } | |
55 | + } | |
56 | + } | |
57 | + | |
58 | + return { | |
59 | + originX: (rightBottomX! - leftTopX!) / 2 + leftTopX!, | |
60 | + originY: (rightBottomY! - leftTopY!) / 2 + leftTopY!, | |
61 | + }; | |
62 | +} | |
63 | + | |
64 | +export function useContextMenuAction() { | |
65 | + const copy = (params: HandleContextMenuActionParamsType) => { | |
66 | + const { node } = params; | |
67 | + if (!node) return; | |
68 | + const { position, data } = node; | |
69 | + const { getAddNodesParams } = useAddNodes(); | |
70 | + const { x, y } = position; | |
71 | + | |
72 | + const value = getAddNodesParams(position, data, { id: buildUUID() }); | |
73 | + | |
74 | + setRuleNodeCache({ | |
75 | + nodes: [value], | |
76 | + originX: x + NODE_WIDTH / 2 + x, | |
77 | + originY: y + NODE_HEIGHT / 2, | |
78 | + }); | |
79 | + }; | |
80 | + | |
81 | + const paste = (params: HandleContextMenuActionParamsType) => { | |
82 | + const { event, flowActionType, useSaveAndRedoActionType } = params; | |
83 | + const { triggerChange } = useSaveAndRedoActionType || {}; | |
84 | + const { getAddNodesParams } = useAddNodes(); | |
85 | + const { getAddedgesParams } = useAddEdges(); | |
86 | + const clientX = (event as MouseEvent).offsetX; | |
87 | + const clientY = (event as MouseEvent).offsetY; | |
88 | + | |
89 | + const { edges = [], nodes = [], originX, originY } = getRuleNodeCache(); | |
90 | + | |
91 | + const newNode = nodes.map((node) => { | |
92 | + const { position, data, id } = node; | |
93 | + const { x, y } = position; | |
94 | + | |
95 | + const newX = clientX - originX! + x + NODE_WIDTH / 2; | |
96 | + const newY = clientY - originY! + y + NODE_HEIGHT / 2; | |
97 | + | |
98 | + return getAddNodesParams({ x: newX, y: newY }, { ...data, created: false }, { id }); | |
99 | + }); | |
100 | + | |
101 | + const newEdges = edges.map((edge) => getAddedgesParams(edge, edge.data)); | |
102 | + | |
103 | + flowActionType?.addNodes(newNode); | |
104 | + flowActionType?.addEdges(newEdges); | |
105 | + | |
106 | + triggerChange?.(); | |
107 | + | |
108 | + flowActionType?.removeSelectedElements(); | |
109 | + }; | |
110 | + | |
111 | + const selectAll = (params: HandleContextMenuActionParamsType) => { | |
112 | + const { flowActionType } = params; | |
113 | + flowActionType?.addSelectedElements(unref(flowActionType.getElements)); | |
114 | + }; | |
115 | + | |
116 | + const unselect = (params: HandleContextMenuActionParamsType) => { | |
117 | + const { flowActionType } = params; | |
118 | + flowActionType?.removeSelectedElements(); | |
119 | + }; | |
120 | + | |
121 | + const deleteElement = (parmas: HandleContextMenuActionParamsType) => { | |
122 | + const { useSaveAndRedoActionType, flowActionType, node, edge } = parmas; | |
123 | + const { triggerChange } = useSaveAndRedoActionType || {}; | |
124 | + | |
125 | + node && flowActionType?.removeNodes(node); | |
126 | + edge && flowActionType?.removeEdges(edge); | |
127 | + | |
128 | + triggerChange?.(); | |
129 | + }; | |
130 | + | |
131 | + const deleteElements = (params: HandleContextMenuActionParamsType) => { | |
132 | + const { flowActionType, useSaveAndRedoActionType } = params; | |
133 | + flowActionType?.removeNodes(unref(flowActionType.getSelectedNodes)); | |
134 | + | |
135 | + useSaveAndRedoActionType?.triggerChange?.(); | |
136 | + }; | |
137 | + | |
138 | + const selectCopy = (params: HandleContextMenuActionParamsType) => { | |
139 | + const { flowActionType } = params; | |
140 | + const { getAddNodesParams } = useAddNodes(); | |
141 | + const { getAddedgesParams } = useAddEdges(); | |
142 | + | |
143 | + const edges = unref(flowActionType?.getSelectedEdges)?.map((edge) => | |
144 | + getAddedgesParams( | |
145 | + { | |
146 | + source: edge.source, | |
147 | + target: edge.target, | |
148 | + sourceHandle: edge.sourceHandle, | |
149 | + targetHandle: edge.targetHandle, | |
150 | + }, | |
151 | + toRaw(unref(edge.data as EdgeData)?.data) | |
152 | + ) | |
153 | + ); | |
154 | + | |
155 | + const nodes = unref(flowActionType?.getSelectedNodes)?.map((node) => { | |
156 | + const { id: oldId } = node; | |
157 | + const newId = buildUUID(); | |
158 | + | |
159 | + for (const connection of edges || []) { | |
160 | + if (connection.source.includes(oldId)) { | |
161 | + connection.source = newId; | |
162 | + connection.sourceHandle = connection.sourceHandle?.replaceAll(oldId, newId); | |
163 | + continue; | |
164 | + } | |
165 | + | |
166 | + if (connection.target.includes(oldId)) { | |
167 | + connection.target = newId; | |
168 | + connection.targetHandle = connection.targetHandle?.replaceAll(oldId, newId); | |
169 | + } | |
170 | + } | |
171 | + | |
172 | + return getAddNodesParams(node.position, toRaw(unref(node.data)), { id: newId }); | |
173 | + }); | |
174 | + | |
175 | + const originRect = getElementsCenter(unref(flowActionType?.getSelectedNodes) || []); | |
176 | + | |
177 | + setRuleNodeCache({ nodes, edges, ...originRect }); | |
178 | + }; | |
179 | + | |
180 | + const applyChange = (params: HandleContextMenuActionParamsType) => { | |
181 | + const { useSaveAndRedoActionType, flowActionType } = params; | |
182 | + | |
183 | + useSaveAndRedoActionType?.handleApplyChange(flowActionType!); | |
184 | + }; | |
185 | + | |
186 | + const undoChange = (params: HandleContextMenuActionParamsType) => { | |
187 | + const { useSaveAndRedoActionType, flowActionType } = params; | |
188 | + | |
189 | + useSaveAndRedoActionType?.handleRedoChange(flowActionType!); | |
190 | + }; | |
191 | + | |
192 | + const handleContextMenuAction = (params: HandleContextMenuActionParamsType) => { | |
193 | + const { menuType } = params; | |
194 | + | |
195 | + const handlerMapping = { | |
196 | + [RuleContextMenuEnum.COPY]: copy, | |
197 | + [RuleContextMenuEnum.PASTE]: paste, | |
198 | + [RuleContextMenuEnum.SELECT_ALL]: selectAll, | |
199 | + [RuleContextMenuEnum.UNSELECTED]: unselect, | |
200 | + [RuleContextMenuEnum.DELETE]: deleteElement, | |
201 | + [RuleContextMenuEnum.DELETE_SELECT]: deleteElements, | |
202 | + [RuleContextMenuEnum.SELECT_COPY]: selectCopy, | |
203 | + [RuleContextMenuEnum.APPLY_CHANGE]: applyChange, | |
204 | + [RuleContextMenuEnum.UNDO_CHANGE]: undoChange, | |
205 | + }; | |
206 | + | |
207 | + if (handlerMapping[menuType]) { | |
208 | + handlerMapping[menuType]?.(params); | |
209 | + } | |
210 | + }; | |
211 | + | |
212 | + return { | |
213 | + handleContextMenuAction, | |
214 | + }; | |
215 | +} | ... | ... |
src/views/rule/designer/hook/useDataTool.ts
0 → 100644
1 | +import { Ref, toRaw, unref } from 'vue'; | |
2 | +import { NodeData } from '../types/node'; | |
3 | + | |
4 | +export function useDataTool() { | |
5 | + /** | |
6 | + * @description 通过NodeData获取默认配置信息 | |
7 | + * @param nodeData | |
8 | + * @returns | |
9 | + */ | |
10 | + function getDefaultConfigurationByNodeData<T = any>(nodeData: Ref<NodeData> | NodeData) { | |
11 | + nodeData = toRaw(unref(nodeData)); | |
12 | + | |
13 | + const { nodeDefinition } = nodeData.config?.configurationDescriptor || {}; | |
14 | + const { defaultConfiguration } = nodeDefinition || {}; | |
15 | + | |
16 | + return { defaultConfiguration: defaultConfiguration as T }; | |
17 | + } | |
18 | + | |
19 | + /** | |
20 | + * @description 通过NodeData获取节点绑定信息 | |
21 | + * @param nodeData | |
22 | + * @returns | |
23 | + */ | |
24 | + function getBindDataByNodeData<T = any>(nodeData: Ref<NodeData> | NodeData) { | |
25 | + nodeData = toRaw(unref(nodeData)); | |
26 | + | |
27 | + const data = nodeData.data as T; | |
28 | + | |
29 | + return { data }; | |
30 | + } | |
31 | + | |
32 | + return { getDefaultConfigurationByNodeData, getBindDataByNodeData }; | |
33 | +} | ... | ... |
1 | +import { Ref, toRaw, unref } from 'vue'; | |
2 | +import type { VueFlowStore } from '@vue-flow/core'; | |
3 | +import type { FlowElRef } from '../types/flow'; | |
4 | +import type { CreateNodeModal } from '../src/components/CreateNodeModal'; | |
5 | +import type { DragTransferData } from '../types/node'; | |
6 | +import { useAddNodes } from './useAddNodes'; | |
7 | + | |
8 | +type EffectSymbol = DataTransfer['dropEffect']; | |
9 | + | |
10 | +export const TRANSFER_DATA_KEY = 'NODE_INFO'; | |
11 | +export const EFFECT_SYMBOL: EffectSymbol = 'move'; | |
12 | + | |
13 | +interface UseDragCreateOptionsType { | |
14 | + el: Ref<Nullable<FlowElRef>>; | |
15 | + createNodeModalActionType: Ref<Nullable<InstanceType<typeof CreateNodeModal>>>; | |
16 | + flowActionType: VueFlowStore; | |
17 | + triggerChange: () => void; | |
18 | +} | |
19 | + | |
20 | +export function useDragCreate(options: UseDragCreateOptionsType) { | |
21 | + const { el, createNodeModalActionType, flowActionType, triggerChange } = options; | |
22 | + const { project, addNodes } = flowActionType; | |
23 | + const { getAddNodesParams } = useAddNodes(); | |
24 | + | |
25 | + const handleOnDrop = async (event: DragEvent) => { | |
26 | + const value = event.dataTransfer?.getData(TRANSFER_DATA_KEY); | |
27 | + const transferData: DragTransferData = JSON.parse(value || ''); | |
28 | + const { options: nodeData, offsetX, offsetY } = transferData; | |
29 | + const { flag, data } = (await unref(createNodeModalActionType)?.open(nodeData)) || {}; | |
30 | + if (!flag) return; | |
31 | + | |
32 | + const flowBounds = unref(el)?.$el.getBoundingClientRect() as DOMRect; | |
33 | + | |
34 | + const position = project({ | |
35 | + x: event.clientX - flowBounds.left - offsetX, | |
36 | + y: event.clientY - flowBounds.top - offsetY, | |
37 | + }); | |
38 | + | |
39 | + const newNode = getAddNodesParams(position, { ...toRaw(unref(nodeData)), data }); | |
40 | + addNodes(newNode); | |
41 | + | |
42 | + triggerChange(); | |
43 | + }; | |
44 | + | |
45 | + const handleOnDragOver = (event: DragEvent) => { | |
46 | + event.preventDefault(); | |
47 | + | |
48 | + if (event.dataTransfer) event.dataTransfer.dropEffect = EFFECT_SYMBOL; | |
49 | + }; | |
50 | + | |
51 | + const handleOnDragStart = (event: DragEvent, options: object) => { | |
52 | + if (event.dataTransfer) { | |
53 | + event.dataTransfer.setData(TRANSFER_DATA_KEY, JSON.stringify(options)); | |
54 | + event.dataTransfer.effectAllowed = EFFECT_SYMBOL; | |
55 | + } | |
56 | + }; | |
57 | + | |
58 | + return { | |
59 | + handleOnDrop, | |
60 | + handleOnDragOver, | |
61 | + handleOnDragStart, | |
62 | + }; | |
63 | +} | ... | ... |
1 | +import type { Ref } from 'vue'; | |
2 | +import { inject, provide } from 'vue'; | |
3 | +import type { VueFlowStore } from '@vue-flow/core'; | |
4 | +import type { CreateNodeModal } from '../src/components/CreateNodeModal'; | |
5 | +import type { CreateEdgeModal } from '../src/components/CreateEdgeModal'; | |
6 | +import { UpdateNodeDrawer } from '../src/components/UpdateNodeDrawer'; | |
7 | +import { UpdateEdgeDrawer } from '../src/components/UpdateEdgeDrawer'; | |
8 | + | |
9 | +const SYMBOL = Symbol('flow-context'); | |
10 | + | |
11 | +interface FlowContextOptionsType { | |
12 | + /** | |
13 | + * @description 节点 actions | |
14 | + */ | |
15 | + createNodeModalActionType: Ref<Nullable<InstanceType<typeof CreateNodeModal>>>; | |
16 | + | |
17 | + /** | |
18 | + * @description 连接线 actions | |
19 | + */ | |
20 | + createEdgeModalActionType: Ref<Nullable<InstanceType<typeof CreateEdgeModal>>>; | |
21 | + | |
22 | + /** | |
23 | + * @description 节点更新 actions | |
24 | + */ | |
25 | + updateNodeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateNodeDrawer>>>; | |
26 | + | |
27 | + /** | |
28 | + * @description 连接线更新 actions | |
29 | + */ | |
30 | + updateEdgeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>; | |
31 | + | |
32 | + /** | |
33 | + * @description vue flow store | |
34 | + */ | |
35 | + flowActionType: VueFlowStore; | |
36 | + | |
37 | + /** | |
38 | + * @description 更新变化 | |
39 | + */ | |
40 | + triggerChange: () => void; | |
41 | +} | |
42 | + | |
43 | +export const createFlowContext = (options: FlowContextOptionsType) => { | |
44 | + provide(SYMBOL, options); | |
45 | +}; | |
46 | + | |
47 | +export const useFlowContext = () => { | |
48 | + return inject(SYMBOL) as FlowContextOptionsType; | |
49 | +}; | ... | ... |
1 | +import { useFullscreen } from '@vueuse/core'; | |
2 | +import type { Ref } from 'vue'; | |
3 | +import { computed, unref } from 'vue'; | |
4 | + | |
5 | +export function useFullScreen(el: Ref<Nullable<HTMLDivElement>>) { | |
6 | + const { toggle, isFullscreen } = useFullscreen(el); | |
7 | + | |
8 | + const getFullScreenIcon = computed(() => | |
9 | + unref(isFullscreen) ? 'bx:exit-fullscreen' : 'mdi:fullscreen' | |
10 | + ); | |
11 | + | |
12 | + return { | |
13 | + getFullScreenIcon, | |
14 | + handleFullScreen: toggle, | |
15 | + }; | |
16 | +} | ... | ... |
src/views/rule/designer/hook/useInputNode.ts
0 → 100644
1 | +import { Config as InputConfig } from '../packages/Entry/Input/config'; | |
2 | +import { useAddNodes } from './useAddNodes'; | |
3 | + | |
4 | +export function useInputNode() { | |
5 | + const getInputNodeConfig = (id?: string) => { | |
6 | + const { getAddNodesParams } = useAddNodes(); | |
7 | + | |
8 | + const newNode = getAddNodesParams( | |
9 | + { x: 80, y: 50 }, | |
10 | + { | |
11 | + ...new InputConfig(), | |
12 | + data: { | |
13 | + name: '输入', | |
14 | + description: '规则链的逻辑输入,将传入消息转发到下一个相关规则节点。', | |
15 | + }, | |
16 | + }, | |
17 | + { id, draggable: false, selectable: false } | |
18 | + ); | |
19 | + | |
20 | + return newNode; | |
21 | + }; | |
22 | + | |
23 | + return { getInputNodeConfig }; | |
24 | +} | ... | ... |
1 | +import { NodeMouseEvent } from '@vue-flow/core'; | |
2 | +import { useContextMenu } from '../src/components/RuleChainContextMenu'; | |
3 | +import { RuleChainContextMenuItemType } from '../src/components/RuleChainContextMenu/index.type'; | |
4 | +import { ElementsTypeEnum } from '../enum'; | |
5 | +import { checkHasCacheRuleNode } from './useRuleCopyPaste'; | |
6 | + | |
7 | +export enum RuleContextMenuEnum { | |
8 | + DETAIL = 'DETAIL', | |
9 | + COPY = 'COPY', | |
10 | + DELETE = 'DELETE', | |
11 | + | |
12 | + SELECT_COPY = 'SELECT_COPY', | |
13 | + PASTE = 'PASTE', | |
14 | + UNSELECTED = 'UNSELECTED', | |
15 | + DELETE_SELECT = 'DELETE_SELECT', | |
16 | + APPLY_CHANGE = 'APPLY_CHANGE', | |
17 | + UNDO_CHANGE = 'UNDO_CHANGE', | |
18 | + | |
19 | + SELECT_ALL = 'SELECT_ALL', | |
20 | +} | |
21 | + | |
22 | +export enum RuleContextMenuNameEnum { | |
23 | + DETAIL = '详情', | |
24 | + COPY = '复制', | |
25 | + DELETE = '删除', | |
26 | + | |
27 | + SELECT_COPY = '选择副本', | |
28 | + PASTE = '粘贴', | |
29 | + UNSELECTED = '取消选择', | |
30 | + DELETE_SELECT = '删除选定', | |
31 | + APPLY_CHANGE = '应用更改', | |
32 | + UNDO_CHANGE = '撤销更改', | |
33 | + | |
34 | + SELECT_ALL = '选择全部', | |
35 | +} | |
36 | + | |
37 | +export enum RuleChainContextMenuIconEnum { | |
38 | + DETAIL = 'material-symbols:menu', | |
39 | + COPY = 'material-symbols:content-copy', | |
40 | + DELETE = 'material-symbols:delete', | |
41 | + | |
42 | + SELECT_COPY = 'material-symbols:content-copy', | |
43 | + PASTE = 'material-symbols:content-paste', | |
44 | + UNSELECTED = 'material-symbols:tab-unselected', | |
45 | + DELETE_SELECT = 'material-symbols:close', | |
46 | + APPLY_CHANGE = 'material-symbols:done', | |
47 | + UNDO_CHANGE = 'material-symbols:close', | |
48 | + | |
49 | + SELECT_ALL = 'material-symbols:select-all', | |
50 | + | |
51 | + // LINK = 'material-symbols:trending-flat', | |
52 | +} | |
53 | + | |
54 | +export enum RuleChainContextMenuShortcutKeyEnum { | |
55 | + DELETE = 'Ctrl(⌘) X', | |
56 | + | |
57 | + SELECT_COPY = 'Ctrl(⌘) C', | |
58 | + PASTE = 'Ctrl(⌘) V', | |
59 | + UNSELECTED = 'Esc', | |
60 | + DELETE_SELECT = 'Del', | |
61 | + APPLY_CHANGE = 'Ctrl(⌘) S', | |
62 | + UNDO_CHANGE = 'Ctrl(⌘) Z', | |
63 | + | |
64 | + SELECT_ALL = 'Ctrl(⌘) A', | |
65 | +} | |
66 | + | |
67 | +const getMenuItem = (key: RuleContextMenuEnum, handler: Fn, disabled = false) => { | |
68 | + return { | |
69 | + key, | |
70 | + label: RuleContextMenuNameEnum[key], | |
71 | + icon: RuleChainContextMenuIconEnum[key], | |
72 | + shortcutKey: RuleChainContextMenuShortcutKeyEnum[key], | |
73 | + handler: () => handler?.(key), | |
74 | + disabled, | |
75 | + } as RuleChainContextMenuItemType; | |
76 | +}; | |
77 | + | |
78 | +const getDivider = (): RuleChainContextMenuItemType => ({ divider: true }); | |
79 | + | |
80 | +export function useCreateRuleChainContextMenu() { | |
81 | + const [createContextMenu] = useContextMenu(); | |
82 | + | |
83 | + const createNodeContextMenu = (params: NodeMouseEvent): Promise<RuleContextMenuEnum | ''> => { | |
84 | + return new Promise(async (resolve) => { | |
85 | + await createContextMenu(params, { | |
86 | + items: [ | |
87 | + getMenuItem(RuleContextMenuEnum.DETAIL, resolve), | |
88 | + getMenuItem(RuleContextMenuEnum.COPY, resolve), | |
89 | + getMenuItem(RuleContextMenuEnum.DELETE, resolve), | |
90 | + ], | |
91 | + }); | |
92 | + resolve(''); | |
93 | + }); | |
94 | + }; | |
95 | + | |
96 | + const createElementsSelectedContextMenu = ( | |
97 | + params: NodeMouseEvent, | |
98 | + changeMarker: boolean, | |
99 | + elementsType: ElementsTypeEnum.NODE = ElementsTypeEnum.NODE | |
100 | + ): Promise<RuleContextMenuEnum | ''> => { | |
101 | + return new Promise(async (resolve) => { | |
102 | + await createContextMenu(params, { | |
103 | + items: [ | |
104 | + ...(elementsType === ElementsTypeEnum.NODE | |
105 | + ? [getMenuItem(RuleContextMenuEnum.SELECT_COPY, resolve)] | |
106 | + : []), | |
107 | + getMenuItem(RuleContextMenuEnum.PASTE, resolve, !checkHasCacheRuleNode()), | |
108 | + getDivider(), | |
109 | + getMenuItem(RuleContextMenuEnum.UNSELECTED, resolve), | |
110 | + getMenuItem(RuleContextMenuEnum.DELETE_SELECT, resolve), | |
111 | + getDivider(), | |
112 | + getMenuItem(RuleContextMenuEnum.APPLY_CHANGE, resolve, !changeMarker), | |
113 | + getMenuItem(RuleContextMenuEnum.UNDO_CHANGE, resolve, !changeMarker), | |
114 | + ], | |
115 | + }); | |
116 | + resolve(''); | |
117 | + }); | |
118 | + }; | |
119 | + | |
120 | + const createPanelContextMenu = ( | |
121 | + params: NodeMouseEvent, | |
122 | + changeMarker: boolean | |
123 | + ): Promise<RuleContextMenuEnum | ''> => { | |
124 | + return new Promise(async (resolve) => { | |
125 | + await createContextMenu(params, { | |
126 | + items: [ | |
127 | + getMenuItem(RuleContextMenuEnum.PASTE, resolve, !checkHasCacheRuleNode()), | |
128 | + getMenuItem(RuleContextMenuEnum.SELECT_ALL, resolve), | |
129 | + getMenuItem(RuleContextMenuEnum.APPLY_CHANGE, resolve, !changeMarker), | |
130 | + getMenuItem(RuleContextMenuEnum.UNDO_CHANGE, resolve, !changeMarker), | |
131 | + ], | |
132 | + }); | |
133 | + resolve(''); | |
134 | + }); | |
135 | + }; | |
136 | + | |
137 | + const createEdgeContextMenu = ( | |
138 | + params: NodeMouseEvent, | |
139 | + isInput = false | |
140 | + ): Promise<RuleContextMenuEnum | ''> => { | |
141 | + return new Promise(async (resolve) => { | |
142 | + await createContextMenu(params, { | |
143 | + items: [ | |
144 | + ...(isInput ? [] : [getMenuItem(RuleContextMenuEnum.DETAIL, resolve)]), | |
145 | + getMenuItem(RuleContextMenuEnum.DELETE, resolve), | |
146 | + ], | |
147 | + }); | |
148 | + resolve(''); | |
149 | + }); | |
150 | + }; | |
151 | + return { | |
152 | + createNodeContextMenu, | |
153 | + createElementsSelectedContextMenu, | |
154 | + createPanelContextMenu, | |
155 | + createEdgeContextMenu, | |
156 | + }; | |
157 | +} | ... | ... |
1 | +import { Edge, Node } from '@vue-flow/core'; | |
2 | +import { RULE_NODE_KEY, RULE_NODE_LOCAL_CACHE_KEY } from '/@/enums/cacheEnum'; | |
3 | +import { createLocalStorage } from '/@/utils/cache'; | |
4 | + | |
5 | +const ruleNodeStorage = createLocalStorage({ prefixKey: RULE_NODE_LOCAL_CACHE_KEY }); | |
6 | + | |
7 | +interface RuleNodeCacheType { | |
8 | + nodes?: Node[]; | |
9 | + edges?: Edge[]; | |
10 | + originX?: number; | |
11 | + originY?: number; | |
12 | +} | |
13 | + | |
14 | +export const setRuleNodeCache = ({ | |
15 | + nodes = [], | |
16 | + edges = [], | |
17 | + originX, | |
18 | + originY, | |
19 | +}: RuleNodeCacheType) => { | |
20 | + ruleNodeStorage.set(RULE_NODE_KEY, { | |
21 | + nodes, | |
22 | + edges, | |
23 | + originX, | |
24 | + originY, | |
25 | + }); | |
26 | +}; | |
27 | + | |
28 | +export const getRuleNodeCache = (): RuleNodeCacheType => ruleNodeStorage.get(RULE_NODE_KEY); | |
29 | + | |
30 | +export const checkHasCacheRuleNode = () => !!getRuleNodeCache(); | |
31 | + | |
32 | +function initRuleNodeStorage() { | |
33 | + const value = ruleNodeStorage.get(RULE_NODE_KEY); | |
34 | + value && ruleNodeStorage.set(RULE_NODE_KEY, value); | |
35 | +} | |
36 | + | |
37 | +initRuleNodeStorage(); | ... | ... |
src/views/rule/designer/hook/useRuleFlow.ts
0 → 100644
1 | +import type { | |
2 | + Connection, | |
3 | + EdgeComponent, | |
4 | + NodeComponent, | |
5 | + ValidConnectionFunc, | |
6 | + GraphNode, | |
7 | + NodeMouseEvent, | |
8 | + GraphEdge, | |
9 | + EdgeMouseEvent, | |
10 | +} from '@vue-flow/core'; | |
11 | +import type { Ref } from 'vue'; | |
12 | +import type { CreateNodeModal } from '../src/components/CreateNodeModal'; | |
13 | +import type { EdgeData, NodeData } from '../types/node'; | |
14 | +import type { CreateEdgeModal } from '../src/components/CreateEdgeModal'; | |
15 | +import { BasicEdge, BasicNode } from '../src/components'; | |
16 | +import { EdgeTypeEnum, ElementsTypeEnum, NodeTypeEnum } from '../enum'; | |
17 | +import { markRaw, toRaw, unref } from 'vue'; | |
18 | +import { isFunction } from 'lodash-es'; | |
19 | +import { ConnectionLineType, SelectionMode, useVueFlow } from '@vue-flow/core'; | |
20 | +import { isInputHandle, isOutputHandle } from '../utils'; | |
21 | +import { useAddEdges } from './useAddEdges'; | |
22 | +import { UpdateNodeDrawer } from '../src/components/UpdateNodeDrawer'; | |
23 | +import { UpdateEdgeDrawer } from '../src/components/UpdateEdgeDrawer'; | |
24 | +import { isNumber } from '/@/utils/is'; | |
25 | +import { RuleContextMenuEnum, useCreateRuleChainContextMenu } from './useRuleChainContextMenu'; | |
26 | +import { RuleChainDetail } from '../types/ruleNode'; | |
27 | +import { useContextMenuAction } from './useContextMenuAction'; | |
28 | +import { useSaveAndRedo } from './useSaveAndRedo'; | |
29 | +import { EntryCategoryComponentEnum } from '../enum/category'; | |
30 | + | |
31 | +interface UseRuleFlowOptionsType { | |
32 | + id: string; | |
33 | + ruleChainDetail: Ref<RuleChainDetail | undefined>; | |
34 | + createNodeModalActionType: Ref<Nullable<InstanceType<typeof CreateNodeModal>>>; | |
35 | + createEdgeModalActionType: Ref<Nullable<InstanceType<typeof CreateEdgeModal>>>; | |
36 | + updateNodeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateNodeDrawer>>>; | |
37 | + updateEdgeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>; | |
38 | + useSaveAndRedoActionType: ReturnType<typeof useSaveAndRedo>; | |
39 | +} | |
40 | + | |
41 | +const validateInputAndOutput: ValidConnectionFunc = (connection: Connection) => { | |
42 | + const { sourceHandle, targetHandle, source, target } = connection; | |
43 | + | |
44 | + return ( | |
45 | + isOutputHandle(sourceHandle || '') && isInputHandle(targetHandle || '') && source !== target | |
46 | + ); | |
47 | +}; | |
48 | + | |
49 | +export function useRuleFlow(options: UseRuleFlowOptionsType) { | |
50 | + const { | |
51 | + id, | |
52 | + ruleChainDetail, | |
53 | + createEdgeModalActionType, | |
54 | + updateEdgeDrawerActionType, | |
55 | + updateNodeDrawerActionType, | |
56 | + useSaveAndRedoActionType, | |
57 | + } = options; | |
58 | + | |
59 | + const { triggerChange } = useSaveAndRedoActionType; | |
60 | + | |
61 | + const flowActionType = useVueFlow({ | |
62 | + id, | |
63 | + maxZoom: 1, | |
64 | + minZoom: 1, | |
65 | + panOnScroll: true, | |
66 | + selectionMode: SelectionMode.Partial, | |
67 | + nodeTypes: { | |
68 | + [NodeTypeEnum.CUSTOM]: markRaw(BasicNode) as NodeComponent, | |
69 | + }, | |
70 | + edgeTypes: { | |
71 | + [EdgeTypeEnum.CUSTOM]: markRaw(BasicEdge) as EdgeComponent, | |
72 | + }, | |
73 | + connectionLineOptions: { | |
74 | + type: ConnectionLineType.Bezier, | |
75 | + }, | |
76 | + defaultViewport: { | |
77 | + x: 0, | |
78 | + y: 0, | |
79 | + }, | |
80 | + isValidConnection(connection, elements) { | |
81 | + const validateList = [validateInputAndOutput]; | |
82 | + const targetData = elements.targetNode.data as NodeData; | |
83 | + | |
84 | + if ( | |
85 | + targetData.category?.validateConnection && | |
86 | + isFunction(targetData.category.validateConnection) | |
87 | + ) | |
88 | + validateList.push(targetData.category?.validateConnection); | |
89 | + | |
90 | + if (targetData.config?.validateConnection && isFunction(targetData.config.validateConnection)) | |
91 | + validateList.push(targetData.config.validateConnection); | |
92 | + | |
93 | + if (!validateList.every((item) => item(connection, elements))) return false; | |
94 | + | |
95 | + return true; | |
96 | + }, | |
97 | + }); | |
98 | + | |
99 | + const { | |
100 | + getEdges, | |
101 | + addEdges, | |
102 | + findEdge, | |
103 | + findNode, | |
104 | + setViewport, | |
105 | + removeEdges, | |
106 | + onConnect, | |
107 | + onPaneReady, | |
108 | + onNodeDoubleClick, | |
109 | + onEdgeDoubleClick, | |
110 | + onNodeDragStop, | |
111 | + onNodeContextMenu, | |
112 | + onEdgeContextMenu, | |
113 | + onPaneContextMenu, | |
114 | + } = flowActionType; | |
115 | + | |
116 | + const { getAddedgesParams } = useAddEdges(); | |
117 | + | |
118 | + onConnect(async (params) => { | |
119 | + const { source } = params; | |
120 | + const sourceNode = findNode(source); | |
121 | + const sourceData = sourceNode?.data as NodeData; | |
122 | + | |
123 | + let types: string[] = []; | |
124 | + | |
125 | + if (sourceData && validateHasLabelConnection(sourceData)) { | |
126 | + const { flag, data } = (await unref(createEdgeModalActionType)?.open(sourceData)) || {}; | |
127 | + if (!flag) return; | |
128 | + types = toRaw(unref(data)); | |
129 | + } | |
130 | + | |
131 | + handleMaxConnectionPoint(sourceNode); | |
132 | + | |
133 | + addEdges(getAddedgesParams(params, types)); | |
134 | + | |
135 | + triggerChange(); | |
136 | + }); | |
137 | + | |
138 | + onPaneReady(async () => { | |
139 | + setViewport({ x: 0, y: 0, zoom: 1 }); | |
140 | + }); | |
141 | + | |
142 | + onNodeDoubleClick(async ({ node }) => { | |
143 | + handleUpdateNode(node); | |
144 | + }); | |
145 | + | |
146 | + onEdgeDoubleClick(async ({ edge }) => { | |
147 | + handleUpdateEdge(edge); | |
148 | + }); | |
149 | + | |
150 | + onNodeDragStop(() => { | |
151 | + triggerChange(); | |
152 | + }); | |
153 | + | |
154 | + const { | |
155 | + createNodeContextMenu, | |
156 | + createElementsSelectedContextMenu, | |
157 | + createEdgeContextMenu, | |
158 | + createPanelContextMenu, | |
159 | + } = useCreateRuleChainContextMenu(); | |
160 | + | |
161 | + const { handleContextMenuAction } = useContextMenuAction(); | |
162 | + | |
163 | + onNodeContextMenu(async (params) => { | |
164 | + const menuType = params.node.selected | |
165 | + ? await createElementsSelectedContextMenu( | |
166 | + params, | |
167 | + unref(useSaveAndRedoActionType.changeMarker) | |
168 | + ) | |
169 | + : await createNodeContextMenu(params); | |
170 | + | |
171 | + if (menuType) { | |
172 | + if (menuType === RuleContextMenuEnum.DETAIL) { | |
173 | + handleUpdateNode(params.node); | |
174 | + return; | |
175 | + } | |
176 | + | |
177 | + handleContextMenuAction({ | |
178 | + menuType, | |
179 | + flowActionType, | |
180 | + event: params.event, | |
181 | + node: params.node, | |
182 | + useSaveAndRedoActionType, | |
183 | + }); | |
184 | + } | |
185 | + }); | |
186 | + | |
187 | + onEdgeContextMenu(async (params) => { | |
188 | + const isInputNode = | |
189 | + (params.edge.sourceNode.data as NodeData).config?.key === EntryCategoryComponentEnum.INPUT; | |
190 | + const menuType = await createEdgeContextMenu( | |
191 | + getCreateEdgeContextMenuParams(params), | |
192 | + isInputNode | |
193 | + ); | |
194 | + | |
195 | + if (menuType) { | |
196 | + if (menuType === RuleContextMenuEnum.DETAIL) { | |
197 | + handleUpdateEdge(params.edge); | |
198 | + return; | |
199 | + } | |
200 | + | |
201 | + handleContextMenuAction({ | |
202 | + menuType, | |
203 | + flowActionType, | |
204 | + event: params.event, | |
205 | + useSaveAndRedoActionType, | |
206 | + edge: params.edge, | |
207 | + }); | |
208 | + } | |
209 | + }); | |
210 | + | |
211 | + onPaneContextMenu(async (params) => { | |
212 | + const menuType = unref(flowActionType.getSelectedElements).length | |
213 | + ? await createElementsSelectedContextMenu( | |
214 | + getCreatePanelContextMenuParams(params), | |
215 | + unref(useSaveAndRedoActionType.changeMarker) | |
216 | + ) | |
217 | + : await createPanelContextMenu( | |
218 | + getCreatePanelContextMenuParams(params), | |
219 | + unref(useSaveAndRedoActionType.changeMarker) | |
220 | + ); | |
221 | + | |
222 | + if (menuType) { | |
223 | + handleContextMenuAction({ | |
224 | + menuType, | |
225 | + flowActionType, | |
226 | + event: params, | |
227 | + useSaveAndRedoActionType, | |
228 | + }); | |
229 | + } | |
230 | + }); | |
231 | + | |
232 | + /** | |
233 | + * @description 验证是否有连接label | |
234 | + * @param sourceData | |
235 | + * @returns | |
236 | + */ | |
237 | + function validateHasLabelConnection(sourceData: NodeData) { | |
238 | + return !!sourceData?.config?.configurationDescriptor.nodeDefinition?.relationTypes?.length; | |
239 | + } | |
240 | + | |
241 | + function handleMaxConnectionPoint(sourceNode?: GraphNode) { | |
242 | + if (!sourceNode) return; | |
243 | + | |
244 | + const maxConnectionPoint = unref(sourceNode).data?.config?.maxConnectionPoint; | |
245 | + | |
246 | + if (!maxConnectionPoint || !isNumber(maxConnectionPoint)) return; | |
247 | + | |
248 | + const sourceId = sourceNode.id; | |
249 | + const connectionPool = unref(getEdges).filter((item) => item.source === sourceId); | |
250 | + if (connectionPool.length >= maxConnectionPoint && connectionPool[0]) { | |
251 | + removeEdges(connectionPool[0].id); | |
252 | + } | |
253 | + } | |
254 | + | |
255 | + async function handleUpdateNode(node: GraphNode) { | |
256 | + if ((node.data as NodeData).config?.disableAction) return; | |
257 | + const { flag, data } = | |
258 | + (await unref(updateNodeDrawerActionType)?.open( | |
259 | + toRaw((node as NodeData)?.data as unknown as NodeData), | |
260 | + void 0, | |
261 | + { id: node.id, type: ElementsTypeEnum.NODE } | |
262 | + )) || {}; | |
263 | + | |
264 | + if (!flag) return; | |
265 | + | |
266 | + const currentNode = findNode(node.id); | |
267 | + (currentNode!.data as NodeData).data = data; | |
268 | + triggerChange(); | |
269 | + } | |
270 | + | |
271 | + async function handleUpdateEdge(edge: GraphEdge) { | |
272 | + if (!validateHasLabelConnection(edge.sourceNode.data)) return; | |
273 | + | |
274 | + if ((edge.sourceNode.data as NodeData).config?.disableAction) return; | |
275 | + | |
276 | + const { flag, data } = | |
277 | + (await unref(updateEdgeDrawerActionType)?.open( | |
278 | + toRaw(unref(edge.sourceNode?.data as unknown as NodeData)), | |
279 | + toRaw(unref(edge.data as EdgeData)), | |
280 | + { id: edge.id, type: ElementsTypeEnum.EDGE } | |
281 | + )) || {}; | |
282 | + | |
283 | + if (!flag) return; | |
284 | + | |
285 | + const currentEdge = findEdge(edge.id); | |
286 | + | |
287 | + (currentEdge!.data as EdgeData).data = toRaw(unref(data)); | |
288 | + | |
289 | + triggerChange?.(); | |
290 | + } | |
291 | + | |
292 | + function getCreatePanelContextMenuParams(params: Event) { | |
293 | + return { | |
294 | + event: params as MouseEvent, | |
295 | + node: { | |
296 | + data: { | |
297 | + data: { name: '规则链' }, | |
298 | + config: { | |
299 | + name: unref(ruleChainDetail)?.name, | |
300 | + backgroundColor: '#aac7e4', | |
301 | + configurationDescriptor: { | |
302 | + nodeDefinition: { | |
303 | + icon: 'material-symbols:settings-ethernet', | |
304 | + }, | |
305 | + }, | |
306 | + }, | |
307 | + }, | |
308 | + }, | |
309 | + } as NodeMouseEvent; | |
310 | + } | |
311 | + | |
312 | + function getCreateEdgeContextMenuParams(params: EdgeMouseEvent) { | |
313 | + return { | |
314 | + event: params.event as MouseEvent, | |
315 | + node: { | |
316 | + data: { | |
317 | + data: { name: '链接' }, | |
318 | + config: { | |
319 | + name: unref(params.edge.data as EdgeData)?.data?.type?.join(' / '), | |
320 | + backgroundColor: '#aac7e4', | |
321 | + configurationDescriptor: { | |
322 | + nodeDefinition: { | |
323 | + icon: 'material-symbols:trending-flat', | |
324 | + }, | |
325 | + }, | |
326 | + }, | |
327 | + }, | |
328 | + }, | |
329 | + } as NodeMouseEvent; | |
330 | + } | |
331 | + | |
332 | + return { flowActionType }; | |
333 | +} | ... | ... |