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,22 +5,28 @@ | ||
5 | "public/resource/tinymce/langs" | 5 | "public/resource/tinymce/langs" |
6 | ], | 6 | ], |
7 | "cSpell.words": [ | 7 | "cSpell.words": [ |
8 | + "ACKS", | ||
9 | + "clazz", | ||
8 | "Cmds", | 10 | "Cmds", |
9 | "COAP", | 11 | "COAP", |
10 | "echarts", | 12 | "echarts", |
11 | "edrx", | 13 | "edrx", |
12 | - "EFENTO", | 14 | + "EFENTO", |
13 | "fingerprintjs", | 15 | "fingerprintjs", |
14 | "flvjs", | 16 | "flvjs", |
15 | - "flvjs", | ||
16 | "inited", | 17 | "inited", |
17 | "liveui", | 18 | "liveui", |
18 | "MQTT", | 19 | "MQTT", |
20 | + "noconflict", | ||
19 | "notif", | 21 | "notif", |
20 | "PROTOBUF", | 22 | "PROTOBUF", |
23 | + "Rabbitmq", | ||
21 | "rtsp", | 24 | "rtsp", |
22 | "SCADA", | 25 | "SCADA", |
26 | + "SMTPS", | ||
23 | "SNMP", | 27 | "SNMP", |
28 | + "TSLV", | ||
29 | + "UNACK", | ||
24 | "unref", | 30 | "unref", |
25 | "vben", | 31 | "vben", |
26 | "videojs", | 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,13 +32,18 @@ | ||
32 | "reinstall": "rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run bootstrap", | 32 | "reinstall": "rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run bootstrap", |
33 | "prepare": "husky install", | 33 | "prepare": "husky install", |
34 | "gen:icon": "esno ./build/generate/icon/index.ts", | 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 | "dependencies": { | 38 | "dependencies": { |
38 | "@fingerprintjs/fingerprintjs": "^3.4.1", | 39 | "@fingerprintjs/fingerprintjs": "^3.4.1", |
39 | "@iconify/iconify": "^2.0.3", | 40 | "@iconify/iconify": "^2.0.3", |
40 | "@logicflow/core": "^0.6.9", | 41 | "@logicflow/core": "^0.6.9", |
41 | "@logicflow/extension": "^0.6.9", | 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 | "@vueuse/core": "^10.1.0", | 47 | "@vueuse/core": "^10.1.0", |
43 | "@zxcvbn-ts/core": "^1.0.0-beta.0", | 48 | "@zxcvbn-ts/core": "^1.0.0-beta.0", |
44 | "ace-builds": "^1.4.14", | 49 | "ace-builds": "^1.4.14", |
@@ -53,6 +58,7 @@ | @@ -53,6 +58,7 @@ | ||
53 | "flv.js": "^1.6.2", | 58 | "flv.js": "^1.6.2", |
54 | "hls.js": "^1.0.10", | 59 | "hls.js": "^1.0.10", |
55 | "intro.js": "^4.1.0", | 60 | "intro.js": "^4.1.0", |
61 | + "js-beautify": "^1.14.9", | ||
56 | "jsoneditor": "^9.7.2", | 62 | "jsoneditor": "^9.7.2", |
57 | "jwt-decode": "^3.1.2", | 63 | "jwt-decode": "^3.1.2", |
58 | "lodash-es": "^4.17.21", | 64 | "lodash-es": "^4.17.21", |
@@ -68,7 +74,7 @@ | @@ -68,7 +74,7 @@ | ||
68 | "vditor": "^3.8.6", | 74 | "vditor": "^3.8.6", |
69 | "video.js": "^7.20.3", | 75 | "video.js": "^7.20.3", |
70 | "videojs-flvjs-es6": "^1.0.1", | 76 | "videojs-flvjs-es6": "^1.0.1", |
71 | - "vue": "3.2.31", | 77 | + "vue": "3.3.4", |
72 | "vue-i18n": "9.1.7", | 78 | "vue-i18n": "9.1.7", |
73 | "vue-json-pretty": "^2.0.4", | 79 | "vue-json-pretty": "^2.0.4", |
74 | "vue-router": "^4.0.11", | 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,6 +22,8 @@ enum ScreenManagerApi { | ||
22 | GET_ATTRBUTELIST = '/device/attributes/', | 22 | GET_ATTRBUTELIST = '/device/attributes/', |
23 | ALARM_PROFILE = '/alarm/profile/', | 23 | ALARM_PROFILE = '/alarm/profile/', |
24 | MASTER_GET_DEVICE = '/device/list', | 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,3 +132,45 @@ export const byOrganizationIdGetMasterDevice = (params: { | ||
130 | }); | 132 | }); |
131 | }; | 133 | }; |
132 | //TODO-fengtao | 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 | <script lang="ts" setup> | 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 | enum EventEnum { | 12 | enum EventEnum { |
11 | UPDATE_VALUE = 'update:value', | 13 | UPDATE_VALUE = 'update:value', |
@@ -16,89 +18,134 @@ | @@ -16,89 +18,134 @@ | ||
16 | 18 | ||
17 | const props = withDefaults( | 19 | const props = withDefaults( |
18 | defineProps<{ | 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 | height: 150, | 27 | height: 150, |
31 | } | 28 | } |
32 | ); | 29 | ); |
33 | 30 | ||
34 | const emit = defineEmits<{ | 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 | const jsonEditorElRef = ref<Nullable<any>>(); | 38 | const jsonEditorElRef = ref<Nullable<any>>(); |
42 | 39 | ||
43 | - const editoreRef = ref<JSONEditor>(); | 40 | + const editoreRef = ref<Ace.Editor>(); |
44 | 41 | ||
45 | const isFocus = ref(false); | 42 | const isFocus = ref(false); |
46 | 43 | ||
47 | - const handleChange = (value: any) => { | 44 | + const handleOnChange = () => { |
45 | + const value = get(); | ||
48 | emit(EventEnum.UPDATE_VALUE, value, unref(editoreRef)); | 46 | emit(EventEnum.UPDATE_VALUE, value, unref(editoreRef)); |
49 | emit(EventEnum.CHANGE, value, unref(editoreRef)); | 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 | const initialize = () => { | 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 | watch( | 84 | watch( |
77 | () => props.value, | 85 | () => props.value, |
78 | (target) => { | 86 | (target) => { |
87 | + // const position = unref(editoreRef)?.getCursorPosition(); | ||
79 | if (unref(isFocus)) return; | 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 | immediate: true, | 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 | const get = (): string => { | 105 | const get = (): string => { |
88 | - return unref(editoreRef)?.getText() || ''; | 106 | + return unref(editoreRef)?.getValue() || ''; |
89 | }; | 107 | }; |
90 | 108 | ||
91 | const set = (data: any) => { | 109 | const set = (data: any) => { |
92 | - return unref(editoreRef)?.set(data); | 110 | + return unref(editoreRef)?.setValue(getFormatValue(data)); |
93 | }; | 111 | }; |
94 | 112 | ||
95 | onMounted(() => { | 113 | onMounted(() => { |
96 | initialize(); | 114 | initialize(); |
97 | - unref(editoreRef)?.setText(props.value || ''); | 115 | + unref(editoreRef)?.setValue(getFormatValue(props.value)); |
98 | }); | 116 | }); |
99 | 117 | ||
100 | onUnmounted(() => { | 118 | onUnmounted(() => { |
119 | + unref(editoreRef)?.off('change', handleOnChange); | ||
120 | + unref(editoreRef)?.off('blur', handleOnBlur); | ||
121 | + unref(editoreRef)?.off('focus', handleOnFocus); | ||
101 | unref(editoreRef)?.destroy(); | 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 | defineExpose({ | 151 | defineExpose({ |
@@ -108,22 +155,41 @@ | @@ -108,22 +155,41 @@ | ||
108 | </script> | 155 | </script> |
109 | 156 | ||
110 | <template> | 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 | </div> | 194 | </div> |
114 | </template> | 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,6 +13,7 @@ export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue'; | ||
13 | export { default as ApiUpload } from './src/components/ApiUpload.vue'; | 13 | export { default as ApiUpload } from './src/components/ApiUpload.vue'; |
14 | 14 | ||
15 | export { default as StructForm } from './src/externalCompns/components/StructForm/StructForm.vue'; | 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 | export { | 19 | export { |
@@ -14,6 +14,7 @@ | @@ -14,6 +14,7 @@ | ||
14 | import { get, omit } from 'lodash-es'; | 14 | import { get, omit } from 'lodash-es'; |
15 | import { LoadingOutlined } from '@ant-design/icons-vue'; | 15 | import { LoadingOutlined } from '@ant-design/icons-vue'; |
16 | import { useI18n } from '/@/hooks/web/useI18n'; | 16 | import { useI18n } from '/@/hooks/web/useI18n'; |
17 | + import { useDebounceFn } from '@vueuse/shared'; | ||
17 | 18 | ||
18 | const emit = defineEmits(['options-change', 'change']); | 19 | const emit = defineEmits(['options-change', 'change']); |
19 | const props = withDefaults( | 20 | const props = withDefaults( |
@@ -27,6 +28,7 @@ | @@ -27,6 +28,7 @@ | ||
27 | labelField?: string; | 28 | labelField?: string; |
28 | valueField?: string; | 29 | valueField?: string; |
29 | immediate?: boolean; | 30 | immediate?: boolean; |
31 | + searchField?: string; | ||
30 | queryEmptyDataAgin?: boolean; | 32 | queryEmptyDataAgin?: boolean; |
31 | onChangeHook?: ({ options }: OnChangeHookParams) => void; | 33 | onChangeHook?: ({ options }: OnChangeHookParams) => void; |
32 | dropdownVisibleChangeHook?: ({ options }: OnChangeHookParams) => void; | 34 | dropdownVisibleChangeHook?: ({ options }: OnChangeHookParams) => void; |
@@ -35,6 +37,7 @@ | @@ -35,6 +37,7 @@ | ||
35 | resultField: '', | 37 | resultField: '', |
36 | labelField: 'label', | 38 | labelField: 'label', |
37 | valueField: 'value', | 39 | valueField: 'value', |
40 | + searchField: 'text', | ||
38 | immediate: true, | 41 | immediate: true, |
39 | queryEmptyDataAgin: true, | 42 | queryEmptyDataAgin: true, |
40 | } | 43 | } |
@@ -53,17 +56,27 @@ | @@ -53,17 +56,27 @@ | ||
53 | const { labelField, valueField = 'value', numberToString } = props; | 56 | const { labelField, valueField = 'value', numberToString } = props; |
54 | return unref(options).reduce((prev, next: Recordable) => { | 57 | return unref(options).reduce((prev, next: Recordable) => { |
55 | if (next) { | 58 | if (next) { |
56 | - const value = next[valueField]; | 59 | + const value = get(next, valueField); |
60 | + const label = get(next, labelField); | ||
57 | prev.push({ | 61 | prev.push({ |
58 | - label: next[labelField], | ||
59 | - value: numberToString ? `${value}` : value, | ||
60 | ...omit(next, [labelField, valueField]), | 62 | ...omit(next, [labelField, valueField]), |
63 | + label, | ||
64 | + value: numberToString ? `${value}` : value, | ||
61 | }); | 65 | }); |
62 | } | 66 | } |
63 | return prev; | 67 | return prev; |
64 | }, [] as OptionsItem[]); | 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 | watchEffect(() => { | 80 | watchEffect(() => { |
68 | props.immediate && fetch(); | 81 | props.immediate && fetch(); |
69 | }); | 82 | }); |
@@ -122,8 +135,9 @@ | @@ -122,8 +135,9 @@ | ||
122 | onChangeHook({ options }); | 135 | onChangeHook({ options }); |
123 | } | 136 | } |
124 | 137 | ||
138 | + const debounceSearchFunction = useDebounceFn(handleSearch, 300); | ||
125 | async function handleSearch(params?: string) { | 139 | async function handleSearch(params?: string) { |
126 | - let { searchApi, api } = props; | 140 | + let { searchApi, api, searchField } = props; |
127 | if (!searchApi || !isFunction(searchApi)) { | 141 | if (!searchApi || !isFunction(searchApi)) { |
128 | if (!api || !isFunction(api)) return; | 142 | if (!api || !isFunction(api)) return; |
129 | searchApi = api; | 143 | searchApi = api; |
@@ -131,7 +145,7 @@ | @@ -131,7 +145,7 @@ | ||
131 | options.value = []; | 145 | options.value = []; |
132 | try { | 146 | try { |
133 | loading.value = true; | 147 | loading.value = true; |
134 | - const res = await searchApi({ ...props.params, text: params }); | 148 | + const res = await searchApi({ ...props.params, [searchField]: params }); |
135 | if (Array.isArray(res)) { | 149 | if (Array.isArray(res)) { |
136 | options.value = res; | 150 | options.value = res; |
137 | emitChange(); | 151 | emitChange(); |
@@ -152,11 +166,10 @@ | @@ -152,11 +166,10 @@ | ||
152 | <template> | 166 | <template> |
153 | <Select | 167 | <Select |
154 | @dropdownVisibleChange="handleFetch" | 168 | @dropdownVisibleChange="handleFetch" |
155 | - v-bind="attrs" | ||
156 | - show-search | 169 | + v-bind="getBindProps" |
157 | @change="handleChange" | 170 | @change="handleChange" |
158 | :options="getOptions" | 171 | :options="getOptions" |
159 | - @search="handleSearch" | 172 | + @search="debounceSearchFunction" |
160 | v-model:value="state" | 173 | v-model:value="state" |
161 | > | 174 | > |
162 | <template #[item]="data" v-for="item in Object.keys($slots)"> | 175 | <template #[item]="data" v-for="item in Object.keys($slots)"> |
@@ -6,7 +6,7 @@ | @@ -6,7 +6,7 @@ | ||
6 | <script lang="ts" setup> | 6 | <script lang="ts" setup> |
7 | import { ref, watchEffect, computed, unref, watch, reactive } from 'vue'; | 7 | import { ref, watchEffect, computed, unref, watch, reactive } from 'vue'; |
8 | import { Select, Spin } from 'ant-design-vue'; | 8 | import { Select, Spin } from 'ant-design-vue'; |
9 | - import { isFunction } from '/@/utils/is'; | 9 | + import { isFunction, isNullAndUnDef } from '/@/utils/is'; |
10 | import { useRuleFormItem } from '/@/hooks/component/useFormItem'; | 10 | import { useRuleFormItem } from '/@/hooks/component/useFormItem'; |
11 | import { useAttrs } from '/@/hooks/core/useAttrs'; | 11 | import { useAttrs } from '/@/hooks/core/useAttrs'; |
12 | import { get, omit } from 'lodash-es'; | 12 | import { get, omit } from 'lodash-es'; |
@@ -30,8 +30,11 @@ | @@ -30,8 +30,11 @@ | ||
30 | labelField?: string; | 30 | labelField?: string; |
31 | valueField?: string; | 31 | valueField?: string; |
32 | immediate?: boolean; | 32 | immediate?: boolean; |
33 | - pagenation?: Pagination; | 33 | + searchField?: string; |
34 | + pagination?: Pagination; | ||
34 | queryEmptyDataAgin?: boolean; | 35 | queryEmptyDataAgin?: boolean; |
36 | + fetchSearch?: boolean; | ||
37 | + filterOption?: (inputValue: string, options: Recordable) => boolean; | ||
35 | }>(), | 38 | }>(), |
36 | { | 39 | { |
37 | resultField: '', | 40 | resultField: '', |
@@ -39,14 +42,15 @@ | @@ -39,14 +42,15 @@ | ||
39 | valueField: 'value', | 42 | valueField: 'value', |
40 | immediate: true, | 43 | immediate: true, |
41 | queryEmptyDataAgin: true, | 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 | const OptionsItem = (_, { attrs }: { attrs: { vNode: any } }) => attrs.vNode; | 50 | const OptionsItem = (_, { attrs }: { attrs: { vNode: any } }) => attrs.vNode; |
47 | 51 | ||
48 | const options = ref<OptionsItem[]>([]); | 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 | const scrollLoading = ref(false); | 54 | const scrollLoading = ref(false); |
51 | const lock = ref(false); | 55 | const lock = ref(false); |
52 | const loading = ref(false); | 56 | const loading = ref(false); |
@@ -55,6 +59,13 @@ | @@ -55,6 +59,13 @@ | ||
55 | const attrs = useAttrs(); | 59 | const attrs = useAttrs(); |
56 | const { t } = useI18n(); | 60 | const { t } = useI18n(); |
57 | 61 | ||
62 | + const getPagination = computed(() => { | ||
63 | + return { | ||
64 | + ...props.pagination, | ||
65 | + ...unref(pagination), | ||
66 | + }; | ||
67 | + }); | ||
68 | + | ||
58 | // Embedded in the form, just use the hook binding to perform form verification | 69 | // Embedded in the form, just use the hook binding to perform form verification |
59 | const [state] = useRuleFormItem(props, 'value', 'change', emitData); | 70 | const [state] = useRuleFormItem(props, 'value', 'change', emitData); |
60 | 71 | ||
@@ -86,16 +97,18 @@ | @@ -86,16 +97,18 @@ | ||
86 | { deep: true } | 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 | if (!api || !isFunction(api)) return; | 102 | if (!api || !isFunction(api)) return; |
103 | + const isFetchSearchFlag = fetchSearch && !isNullAndUnDef(searchText) && searchField; | ||
92 | try { | 104 | try { |
93 | !unref(getOptions).length ? (loading.value = true) : (scrollLoading.value = true); | 105 | !unref(getOptions).length ? (loading.value = true) : (scrollLoading.value = true); |
94 | lock.value = true; | 106 | lock.value = true; |
95 | const { total, items } = await api({ | 107 | const { total, items } = await api({ |
96 | ...props.params, | 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 | pagination.total = total; | 114 | pagination.total = total; |
@@ -105,11 +118,13 @@ | @@ -105,11 +118,13 @@ | ||
105 | return; | 118 | return; |
106 | } | 119 | } |
107 | if (props.resultField) { | 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 | emitChange(); | 125 | emitChange(); |
111 | } catch (error) { | 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 | console.warn(error); | 128 | console.warn(error); |
114 | } finally { | 129 | } finally { |
115 | isFirstLoad.value = false; | 130 | isFirstLoad.value = false; |
@@ -134,17 +149,39 @@ | @@ -134,17 +149,39 @@ | ||
134 | emitData.value = args; | 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 | async function handlePopupScroll(event: MouseEvent) { | 160 | async function handlePopupScroll(event: MouseEvent) { |
138 | const { scrollHeight, scrollTop, clientHeight } = event.target as HTMLDivElement; | 161 | const { scrollHeight, scrollTop, clientHeight } = event.target as HTMLDivElement; |
139 | if (scrollTop + clientHeight >= scrollHeight) { | 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 | await fetch(); | 167 | await fetch(); |
143 | } | 168 | } |
144 | } | 169 | } |
145 | } | 170 | } |
146 | 171 | ||
147 | const debounceHandlePopupScroll = useDebounceFn(handlePopupScroll, 100); | 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 | </script> | 185 | </script> |
149 | 186 | ||
150 | <template> | 187 | <template> |
@@ -153,6 +190,8 @@ | @@ -153,6 +190,8 @@ | ||
153 | v-bind="attrs" | 190 | v-bind="attrs" |
154 | @change="handleChange" | 191 | @change="handleChange" |
155 | :options="getOptions" | 192 | :options="getOptions" |
193 | + :filterOption="handleFilterOption" | ||
194 | + :showSearch="true" | ||
156 | v-model:value="state" | 195 | v-model:value="state" |
157 | @popup-scroll="debounceHandlePopupScroll" | 196 | @popup-scroll="debounceHandlePopupScroll" |
158 | > | 197 | > |
@@ -40,16 +40,19 @@ | @@ -40,16 +40,19 @@ | ||
40 | accept?: string; | 40 | accept?: string; |
41 | maxSize?: number; | 41 | maxSize?: number; |
42 | disabled?: boolean; | 42 | disabled?: boolean; |
43 | - listType?: string; | 43 | + listType?: 'text' | 'picture-card' | 'picture'; |
44 | multiple?: boolean; | 44 | multiple?: boolean; |
45 | maxFileLimit?: number; | 45 | maxFileLimit?: number; |
46 | - showUploadList?: boolean | { showPreviewIcon?: boolean; showRemoveIcon?: boolean }; | 46 | + showUploadList?: InstanceType<typeof Upload>['$props']['showUploadList']; |
47 | transformFile?: (file: File) => string | Blob | Promise<string | Blob | File>; | 47 | transformFile?: (file: File) => string | Blob | Promise<string | Blob | File>; |
48 | api: (file: string | Blob | Promise<string | Blob | File>) => Promise<FileItem>; | 48 | api: (file: string | Blob | Promise<string | Blob | File>) => Promise<FileItem>; |
49 | + overFileLimitHiddenUploadEntry?: boolean; | ||
49 | }>(), | 50 | }>(), |
50 | { | 51 | { |
51 | fileList: () => [], | 52 | fileList: () => [], |
52 | maxSize: 5 * 1024 * 1024, | 53 | maxSize: 5 * 1024 * 1024, |
54 | + overFileLimitHiddenUploadEntry: true, | ||
55 | + listType: 'text', | ||
53 | showUploadList: () => ({ showPreviewIcon: true, showRemoveIcon: true }), | 56 | showUploadList: () => ({ showPreviewIcon: true, showRemoveIcon: true }), |
54 | } | 57 | } |
55 | ); | 58 | ); |
@@ -75,7 +78,7 @@ | @@ -75,7 +78,7 @@ | ||
75 | 78 | ||
76 | const getMaxFileLimit = computed(() => { | 79 | const getMaxFileLimit = computed(() => { |
77 | const { maxFileLimit } = props; | 80 | const { maxFileLimit } = props; |
78 | - return isPictureCard.value ? 1 : maxFileLimit; | 81 | + return isPictureCard.value ? 1 : maxFileLimit || 1; |
79 | }); | 82 | }); |
80 | 83 | ||
81 | const handleUpload = async (file: File | string | Blob | Promise<string | Blob | File>) => { | 84 | const handleUpload = async (file: File | string | Blob | Promise<string | Blob | File>) => { |
@@ -131,11 +134,15 @@ | @@ -131,11 +134,15 @@ | ||
131 | :list-type="props.listType" | 134 | :list-type="props.listType" |
132 | :disabled="getDisabled" | 135 | :disabled="getDisabled" |
133 | :before-upload="handleBeforeUpload" | 136 | :before-upload="handleBeforeUpload" |
137 | + :show-upload-list="showUploadList" | ||
134 | @preview="handlePreview" | 138 | @preview="handlePreview" |
135 | @download="handleDownload" | 139 | @download="handleDownload" |
136 | :remove="handleRemove" | 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 | <div class="w-full h-full flex flex-col justify-center content-center"> | 146 | <div class="w-full h-full flex flex-col justify-center content-center"> |
140 | <Tooltip title="点击上传或拖拽上传"> | 147 | <Tooltip title="点击上传或拖拽上传"> |
141 | <InboxOutlined class="text-[3rem] !text-blue-500" /> | 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,4 +130,11 @@ export type ComponentType = | ||
130 | | 'ControlGroup' | 130 | | 'ControlGroup' |
131 | | 'JSONEditor' | 131 | | 'JSONEditor' |
132 | | 'OrgTreeSelect' | 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,6 +38,11 @@ export const PLATFORM = 'PLATFORM'; | ||
38 | export const PLATFORM_INFO_CACHE_KEY = 'PLATFORM_INFO'; | 38 | export const PLATFORM_INFO_CACHE_KEY = 'PLATFORM_INFO'; |
39 | 39 | ||
40 | export const MENU_LIST = 'MENU_LIST'; | 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 | export enum CacheTypeEnum { | 46 | export enum CacheTypeEnum { |
42 | SESSION, | 47 | SESSION, |
43 | LOCAL, | 48 | LOCAL, |
@@ -19,4 +19,8 @@ export enum DictEnum { | @@ -19,4 +19,8 @@ export enum DictEnum { | ||
19 | DISABLE_CUSTOMER_AUTH = 'disabled_customer_auth', | 19 | DISABLE_CUSTOMER_AUTH = 'disabled_customer_auth', |
20 | // 寄存器数据格式 | 20 | // 寄存器数据格式 |
21 | REGISTER_DATA_FORMAT = 'register_data_format', | 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 | } |
@@ -16,4 +16,6 @@ export const PageEnum = { | @@ -16,4 +16,6 @@ export const PageEnum = { | ||
16 | DEVICE_LIST: '/device/list', | 16 | DEVICE_LIST: '/device/list', |
17 | 17 | ||
18 | SHARE_PAGE: '/share/:viewType/:id/:publicId', | 18 | SHARE_PAGE: '/share/:viewType/:id/:publicId', |
19 | + | ||
20 | + RULE_CHAIN_DETAIL: '/rule/chain/:id', | ||
19 | }; | 21 | }; |
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,6 +3,7 @@ import { RouteLocationNormalizedLoaded } from 'vue-router'; | ||
3 | const menuMap = new Map(); | 3 | const menuMap = new Map(); |
4 | 4 | ||
5 | menuMap.set('/visual/board/detail/:boardId/:boardName?', '/visual/board'); | 5 | menuMap.set('/visual/board/detail/:boardId/:boardName?', '/visual/board'); |
6 | +menuMap.set('/rule/chain/:id', '/rule/chain'); | ||
6 | 7 | ||
7 | export const useMenuActiveFix = (route: RouteLocationNormalizedLoaded) => { | 8 | export const useMenuActiveFix = (route: RouteLocationNormalizedLoaded) => { |
8 | let flag = false; | 9 | let flag = false; |
@@ -3,20 +3,7 @@ import { FormSchema } from '/@/components/Form'; | @@ -3,20 +3,7 @@ import { FormSchema } from '/@/components/Form'; | ||
3 | import { BasicColumn } from '/@/components/Table'; | 3 | import { BasicColumn } from '/@/components/Table'; |
4 | import moment from 'moment'; | 4 | import moment from 'moment'; |
5 | import { findDictItemByCode } from '/@/api/system/dict'; | 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 | export const alarmSearchSchemas: FormSchema[] = [ | 8 | export const alarmSearchSchemas: FormSchema[] = [ |
22 | { | 9 | { |
1 | -import { AlarmStatus, AlarmStatusMean } from '../config/detail.config'; | ||
2 | import { clearOrAckAlarm, getDeviceAlarm } from '/@/api/device/deviceManager'; | 1 | import { clearOrAckAlarm, getDeviceAlarm } from '/@/api/device/deviceManager'; |
3 | import { notification, Button, Tag } from 'ant-design-vue'; | 2 | import { notification, Button, Tag } from 'ant-design-vue'; |
4 | import { h, onMounted, onUnmounted } from 'vue'; | 3 | import { h, onMounted, onUnmounted } from 'vue'; |
@@ -8,6 +7,7 @@ import { RoleEnum } from '/@/enums/roleEnum'; | @@ -8,6 +7,7 @@ import { RoleEnum } from '/@/enums/roleEnum'; | ||
8 | import { usePermission } from '/@/hooks/web/usePermission'; | 7 | import { usePermission } from '/@/hooks/web/usePermission'; |
9 | import { useUserStore } from '/@/store/modules/user'; | 8 | import { useUserStore } from '/@/store/modules/user'; |
10 | import { useGlobSetting } from '/@/hooks/setting'; | 9 | import { useGlobSetting } from '/@/hooks/setting'; |
10 | +import { AlarmStatus, AlarmStatusMean } from '/@/enums/alarmEnum'; | ||
11 | 11 | ||
12 | interface UseAlarmNotifyParams { | 12 | interface UseAlarmNotifyParams { |
13 | alarmNotifyStatus?: AlarmStatus; | 13 | alarmNotifyStatus?: AlarmStatus; |
@@ -91,7 +91,7 @@ export const formSchema: FormSchema[] = [ | @@ -91,7 +91,7 @@ export const formSchema: FormSchema[] = [ | ||
91 | valueField: 'fileList', | 91 | valueField: 'fileList', |
92 | componentProps: () => { | 92 | componentProps: () => { |
93 | return { | 93 | return { |
94 | - listType: 'picture-card', | 94 | + // listType: 'picture-card', |
95 | maxFileLimit: 1, | 95 | maxFileLimit: 1, |
96 | api: async (file: File) => { | 96 | api: async (file: File) => { |
97 | try { | 97 | try { |
@@ -110,6 +110,10 @@ export const formSchema: FormSchema[] = [ | @@ -110,6 +110,10 @@ export const formSchema: FormSchema[] = [ | ||
110 | onPreview: (fileList: FileItem) => { | 110 | onPreview: (fileList: FileItem) => { |
111 | createImgPreview({ imageList: [fileList.url!] }); | 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,7 +57,7 @@ export const formSchema: FormSchema[] = [ | ||
57 | valueField: 'fileList', | 57 | valueField: 'fileList', |
58 | componentProps: () => { | 58 | componentProps: () => { |
59 | return { | 59 | return { |
60 | - listType: 'picture-card', | 60 | + // listType: 'picture-card', |
61 | maxFileLimit: 1, | 61 | maxFileLimit: 1, |
62 | api: async (file: File) => { | 62 | api: async (file: File) => { |
63 | try { | 63 | try { |
@@ -73,6 +73,10 @@ export const formSchema: FormSchema[] = [ | @@ -73,6 +73,10 @@ export const formSchema: FormSchema[] = [ | ||
73 | return {}; | 73 | return {}; |
74 | } | 74 | } |
75 | }, | 75 | }, |
76 | + showUploadList: true, | ||
77 | + onDownload(file) { | ||
78 | + console.log(file); | ||
79 | + }, | ||
76 | onPreview: (fileList: FileItem) => { | 80 | onPreview: (fileList: FileItem) => { |
77 | createImgPreview({ imageList: [fileList.url!] }); | 81 | createImgPreview({ imageList: [fileList.url!] }); |
78 | }, | 82 | }, |
@@ -23,7 +23,7 @@ | @@ -23,7 +23,7 @@ | ||
23 | layout: 'vertical', | 23 | layout: 'vertical', |
24 | }); | 24 | }); |
25 | 25 | ||
26 | - const { genForm } = useGenDynamicForm(); | 26 | + const { genForm, transformValue } = useGenDynamicForm(); |
27 | 27 | ||
28 | const keys = ref<string[]>([]); | 28 | const keys = ref<string[]>([]); |
29 | 29 | ||
@@ -159,8 +159,8 @@ | @@ -159,8 +159,8 @@ | ||
159 | 159 | ||
160 | sendValue.value = await genModbusCommand(unref(modBUSForm)); | 160 | sendValue.value = await genModbusCommand(unref(modBUSForm)); |
161 | } else { | 161 | } else { |
162 | - const _value = getFieldsValue(); | ||
163 | - | 162 | + await validate(); |
163 | + const _value = transformValue(getFieldsValue()); | ||
164 | sendValue.value = unref(keys).reduce((prev, next) => { | 164 | sendValue.value = unref(keys).reduce((prev, next) => { |
165 | return { ...prev, [next]: _value[next] }; | 165 | return { ...prev, [next]: _value[next] }; |
166 | }, {}); | 166 | }, {}); |
1 | import { DataType, Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel'; | 1 | import { DataType, Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel'; |
2 | import { JSONEditor } from '/@/components/CodeEditor'; | 2 | import { JSONEditor } from '/@/components/CodeEditor'; |
3 | import { FormSchema, useComponentRegister } from '/@/components/Form'; | 3 | import { FormSchema, useComponentRegister } from '/@/components/Form'; |
4 | +import { useJsonParse } from '/@/hooks/business/useJsonParse'; | ||
4 | import { DataTypeEnum } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; | 5 | import { DataTypeEnum } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; |
5 | 6 | ||
6 | export interface BasicCreateFormParams { | 7 | export interface BasicCreateFormParams { |
@@ -106,6 +107,19 @@ export const useGenDynamicForm = () => { | @@ -106,6 +107,19 @@ export const useGenDynamicForm = () => { | ||
106 | field: identifier, | 107 | field: identifier, |
107 | label: functionName, | 108 | label: functionName, |
108 | component: 'JSONEditor', | 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,11 +131,14 @@ export const useGenDynamicForm = () => { | ||
117 | [DataTypeEnum.IS_STRUCT]: createInputJson, | 131 | [DataTypeEnum.IS_STRUCT]: createInputJson, |
118 | }; | 132 | }; |
119 | 133 | ||
134 | + const fieldTypeMap = new Map<string, DataTypeEnum>(); | ||
120 | const genForm = (schemas: StructJSON[]) => { | 135 | const genForm = (schemas: StructJSON[]) => { |
136 | + fieldTypeMap.clear(); | ||
121 | const formSchema = schemas.map((item) => { | 137 | const formSchema = schemas.map((item) => { |
122 | const { functionName, identifier, dataType } = item; | 138 | const { functionName, identifier, dataType } = item; |
123 | const { type } = dataType || {}; | 139 | const { type } = dataType || {}; |
124 | 140 | ||
141 | + fieldTypeMap.set(identifier!, dataType!.type); | ||
125 | const method = schemaMethod[type!]; | 142 | const method = schemaMethod[type!]; |
126 | 143 | ||
127 | const formSchema = method?.({ | 144 | const formSchema = method?.({ |
@@ -136,5 +153,21 @@ export const useGenDynamicForm = () => { | @@ -136,5 +153,21 @@ export const useGenDynamicForm = () => { | ||
136 | return formSchema.filter(Boolean); | 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 | +} |