Showing
40 changed files
with
1214 additions
and
724 deletions
@@ -12,11 +12,11 @@ export const getDeviceProfile = (deviceType?: string) => { | @@ -12,11 +12,11 @@ export const getDeviceProfile = (deviceType?: string) => { | ||
12 | }; | 12 | }; |
13 | 13 | ||
14 | // 获取历史数据 | 14 | // 获取历史数据 |
15 | -export const getDeviceHistoryInfo = (params: Recordable, orderBy) => { | 15 | +export const getDeviceHistoryInfo = (params: Recordable, orderBy?: string) => { |
16 | return defHttp.get<HistoryData>( | 16 | return defHttp.get<HistoryData>( |
17 | { | 17 | { |
18 | url: `/plugins/telemetry/DEVICE/${params.entityId}/values/timeseries`, | 18 | url: `/plugins/telemetry/DEVICE/${params.entityId}/values/timeseries`, |
19 | - params: { ...params, entityId: null, orderBy }, | 19 | + params: { ...params, entityId: null, orderBy: orderBy || 'DESC' }, |
20 | }, | 20 | }, |
21 | { | 21 | { |
22 | joinPrefix: false, | 22 | joinPrefix: false, |
1 | -import { defHttp } from '/@/utils/http/axios'; | ||
2 | -import { | ||
3 | - TDeviceConfigParams, | ||
4 | - IDeviceConfigAddOrEditModel, | ||
5 | - ProfileRecord, | ||
6 | - RuleChainRecord, | ||
7 | -} from '/@/api/device/model/deviceConfigModel'; | ||
8 | -import { PaginationResult } from '/#/axios'; | ||
9 | - | ||
10 | -enum EDeviceConfigApi { | ||
11 | - /** | ||
12 | - * 设备配置URL | ||
13 | - */ | ||
14 | - DEVICE_CONFIG_GET_PAGE = '/device_profile', | ||
15 | - DEVICE_CONFIG_POST_ADD_OR_EDIT = '/device_profile', | ||
16 | - DEVICE_CONFIG_GET_DETAIL = '/device_profile/', | ||
17 | - DEVICE_CONFIG_DELETE = '/device_profile', | ||
18 | - DEVICE_CONFIG_GET_RULECHAIN = '/rule_chain/me/list', | ||
19 | - ALARM_CONTACT_GET_PAGE = '/alarm_contact', | ||
20 | - DEVICE_CONFIG_EXPORT = '/device_profile/export', | ||
21 | - DEVICE_CONFIG_IMPORT = '/device_profile/import', | ||
22 | - SET_DEVICE_ISDEFAULT = '/deviceProfile', | ||
23 | - FRP_API = '/frp/', | ||
24 | - GET_TB_DEVICE_ID = '/device/get_subset', | ||
25 | - COMMODRECORD = '/rpc', | ||
26 | -} | ||
27 | - | ||
28 | -/** | ||
29 | - * 设备配置详情 | ||
30 | - */ | ||
31 | -export const deviceConfigGetDetail = (id: string) => { | ||
32 | - return defHttp.get({ | ||
33 | - url: `${EDeviceConfigApi.DEVICE_CONFIG_GET_DETAIL}${id}`, | ||
34 | - }); | ||
35 | -}; | ||
36 | - | ||
37 | -/** | ||
38 | - * 获取规则链 | ||
39 | - */ | ||
40 | -export const deviceConfigGetRuleChain = () => { | ||
41 | - return defHttp.get<RuleChainRecord[]>({ | ||
42 | - url: EDeviceConfigApi.DEVICE_CONFIG_GET_RULECHAIN, | ||
43 | - }); | ||
44 | -}; | ||
45 | - | ||
46 | -/** | ||
47 | - * 获取告警联系人 | ||
48 | - */ | ||
49 | -export const alarmContactGetPage = () => { | ||
50 | - return defHttp.get({ | ||
51 | - url: `${EDeviceConfigApi.ALARM_CONTACT_GET_PAGE}?page=1&pageSize=10`, | ||
52 | - }); | ||
53 | -}; | ||
54 | - | ||
55 | -/** | ||
56 | - * 分页查询设备配置页面 | ||
57 | - */ | ||
58 | -export const deviceConfigGetQuery = (params?: TDeviceConfigParams) => { | ||
59 | - return defHttp.get<PaginationResult<ProfileRecord>>({ | ||
60 | - url: EDeviceConfigApi.DEVICE_CONFIG_GET_PAGE, | ||
61 | - params, | ||
62 | - }); | ||
63 | -}; | ||
64 | - | ||
65 | -/** | ||
66 | - * 新增或者编辑设备配置 | ||
67 | - | ||
68 | - */ | ||
69 | -export const deviceConfigAddOrEdit = (params: IDeviceConfigAddOrEditModel) => { | ||
70 | - return defHttp.post<IDeviceConfigAddOrEditModel>({ | ||
71 | - url: EDeviceConfigApi.DEVICE_CONFIG_POST_ADD_OR_EDIT, | ||
72 | - params, | ||
73 | - }); | ||
74 | -}; | ||
75 | - | ||
76 | -/** | ||
77 | - * 删除设备配置 | ||
78 | - */ | ||
79 | -export const deviceConfigDelete = (ids: string[]) => { | ||
80 | - return defHttp.delete({ | ||
81 | - url: EDeviceConfigApi.DEVICE_CONFIG_DELETE, | ||
82 | - data: { | ||
83 | - ids, | ||
84 | - }, | ||
85 | - }); | ||
86 | -}; | ||
87 | - | ||
88 | -/** | ||
89 | - * 导出设备配置 | ||
90 | - */ | ||
91 | -export const deviceConfigExport = (params: IDeviceConfigAddOrEditModel) => { | ||
92 | - return defHttp.post<IDeviceConfigAddOrEditModel>({ | ||
93 | - url: EDeviceConfigApi.DEVICE_CONFIG_EXPORT, | ||
94 | - params, | ||
95 | - }); | ||
96 | -}; | ||
97 | - | ||
98 | -/** | ||
99 | - * 导入设备配置 | ||
100 | - */ | ||
101 | -export const deviceConfigImport = (params: IDeviceConfigAddOrEditModel) => { | ||
102 | - return defHttp.post<IDeviceConfigAddOrEditModel>({ | ||
103 | - url: EDeviceConfigApi.DEVICE_CONFIG_IMPORT, | ||
104 | - params, | ||
105 | - }); | ||
106 | -}; | ||
107 | - | ||
108 | -/** | ||
109 | - * | ||
110 | - * 设置该设备配置为默认 | ||
111 | - */ | ||
112 | -export const setDeviceProfileIsDefaultApi = (id: string, v, params?: {}) => { | ||
113 | - return defHttp.post( | ||
114 | - { | ||
115 | - url: EDeviceConfigApi.SET_DEVICE_ISDEFAULT + '/' + id + '/' + v, | ||
116 | - params, | ||
117 | - }, | ||
118 | - { | ||
119 | - joinPrefix: false, | ||
120 | - } | ||
121 | - ); | ||
122 | -}; | ||
123 | - | ||
124 | -/** | ||
125 | - * Frp内网穿透信息API | ||
126 | - */ | ||
127 | -export const frpGetInfoApi = (proxyName: string) => { | ||
128 | - return defHttp.get({ | ||
129 | - url: `${EDeviceConfigApi.FRP_API}${proxyName}`, | ||
130 | - }); | ||
131 | -}; | ||
132 | - | ||
133 | -export const frpPutInfoApi = (proxyName: string, enableRemote: number) => { | ||
134 | - return defHttp.put({ | ||
135 | - url: `${EDeviceConfigApi.FRP_API}${proxyName}/${enableRemote}`, | ||
136 | - }); | ||
137 | -}; | ||
138 | - | ||
139 | -export const getTbDeviceId = (params: string) => { | ||
140 | - return defHttp.get({ | ||
141 | - url: `${EDeviceConfigApi.GET_TB_DEVICE_ID}/${params}`, | ||
142 | - }); | ||
143 | -}; | ||
144 | - | ||
145 | -/** | ||
146 | - * 命令下发记录 | ||
147 | - */ | ||
148 | -export const deviceCommandRecordGetQuery = (params?: TDeviceConfigParams) => { | ||
149 | - return defHttp.get({ | ||
150 | - url: EDeviceConfigApi.COMMODRECORD, | ||
151 | - params, | ||
152 | - }); | ||
153 | -}; | 1 | +import { defHttp } from '/@/utils/http/axios'; |
2 | +import { | ||
3 | + TDeviceConfigParams, | ||
4 | + IDeviceConfigAddOrEditModel, | ||
5 | + ProfileRecord, | ||
6 | + RuleChainRecord, | ||
7 | + DeviceProfileDetail, | ||
8 | +} from '/@/api/device/model/deviceConfigModel'; | ||
9 | +import { PaginationResult } from '/#/axios'; | ||
10 | + | ||
11 | +enum EDeviceConfigApi { | ||
12 | + /** | ||
13 | + * 设备配置URL | ||
14 | + */ | ||
15 | + DEVICE_CONFIG_GET_PAGE = '/device_profile', | ||
16 | + DEVICE_CONFIG_POST_ADD_OR_EDIT = '/device_profile', | ||
17 | + DEVICE_CONFIG_GET_DETAIL = '/device_profile/', | ||
18 | + DEVICE_CONFIG_DELETE = '/device_profile', | ||
19 | + DEVICE_CONFIG_GET_RULECHAIN = '/rule_chain/me/list', | ||
20 | + ALARM_CONTACT_GET_PAGE = '/alarm_contact', | ||
21 | + DEVICE_CONFIG_EXPORT = '/device_profile/export', | ||
22 | + DEVICE_CONFIG_IMPORT = '/device_profile/import', | ||
23 | + SET_DEVICE_ISDEFAULT = '/deviceProfile', | ||
24 | + FRP_API = '/frp/', | ||
25 | + GET_TB_DEVICE_ID = '/device/get_subset', | ||
26 | + COMMODRECORD = '/rpc', | ||
27 | +} | ||
28 | + | ||
29 | +/** | ||
30 | + * 设备配置详情 | ||
31 | + */ | ||
32 | +export const deviceConfigGetDetail = (id: string) => { | ||
33 | + return defHttp.get<DeviceProfileDetail>({ | ||
34 | + url: `${EDeviceConfigApi.DEVICE_CONFIG_GET_DETAIL}${id}`, | ||
35 | + }); | ||
36 | +}; | ||
37 | + | ||
38 | +/** | ||
39 | + * 获取规则链 | ||
40 | + */ | ||
41 | +export const deviceConfigGetRuleChain = () => { | ||
42 | + return defHttp.get<RuleChainRecord[]>({ | ||
43 | + url: EDeviceConfigApi.DEVICE_CONFIG_GET_RULECHAIN, | ||
44 | + }); | ||
45 | +}; | ||
46 | + | ||
47 | +/** | ||
48 | + * 获取告警联系人 | ||
49 | + */ | ||
50 | +export const alarmContactGetPage = () => { | ||
51 | + return defHttp.get({ | ||
52 | + url: `${EDeviceConfigApi.ALARM_CONTACT_GET_PAGE}?page=1&pageSize=10`, | ||
53 | + }); | ||
54 | +}; | ||
55 | + | ||
56 | +/** | ||
57 | + * 分页查询设备配置页面 | ||
58 | + */ | ||
59 | +export const deviceConfigGetQuery = (params?: TDeviceConfigParams) => { | ||
60 | + return defHttp.get<PaginationResult<ProfileRecord>>({ | ||
61 | + url: EDeviceConfigApi.DEVICE_CONFIG_GET_PAGE, | ||
62 | + params, | ||
63 | + }); | ||
64 | +}; | ||
65 | + | ||
66 | +/** | ||
67 | + * 新增或者编辑设备配置 | ||
68 | + | ||
69 | + */ | ||
70 | +export const deviceConfigAddOrEdit = (params: IDeviceConfigAddOrEditModel) => { | ||
71 | + return defHttp.post<IDeviceConfigAddOrEditModel>({ | ||
72 | + url: EDeviceConfigApi.DEVICE_CONFIG_POST_ADD_OR_EDIT, | ||
73 | + params, | ||
74 | + }); | ||
75 | +}; | ||
76 | + | ||
77 | +/** | ||
78 | + * 删除设备配置 | ||
79 | + */ | ||
80 | +export const deviceConfigDelete = (ids: string[]) => { | ||
81 | + return defHttp.delete({ | ||
82 | + url: EDeviceConfigApi.DEVICE_CONFIG_DELETE, | ||
83 | + data: { | ||
84 | + ids, | ||
85 | + }, | ||
86 | + }); | ||
87 | +}; | ||
88 | + | ||
89 | +/** | ||
90 | + * 导出设备配置 | ||
91 | + */ | ||
92 | +export const deviceConfigExport = (params: IDeviceConfigAddOrEditModel) => { | ||
93 | + return defHttp.post<IDeviceConfigAddOrEditModel>({ | ||
94 | + url: EDeviceConfigApi.DEVICE_CONFIG_EXPORT, | ||
95 | + params, | ||
96 | + }); | ||
97 | +}; | ||
98 | + | ||
99 | +/** | ||
100 | + * 导入设备配置 | ||
101 | + */ | ||
102 | +export const deviceConfigImport = (params: IDeviceConfigAddOrEditModel) => { | ||
103 | + return defHttp.post<IDeviceConfigAddOrEditModel>({ | ||
104 | + url: EDeviceConfigApi.DEVICE_CONFIG_IMPORT, | ||
105 | + params, | ||
106 | + }); | ||
107 | +}; | ||
108 | + | ||
109 | +/** | ||
110 | + * | ||
111 | + * 设置该设备配置为默认 | ||
112 | + */ | ||
113 | +export const setDeviceProfileIsDefaultApi = (id: string, v, params?: {}) => { | ||
114 | + return defHttp.post( | ||
115 | + { | ||
116 | + url: EDeviceConfigApi.SET_DEVICE_ISDEFAULT + '/' + id + '/' + v, | ||
117 | + params, | ||
118 | + }, | ||
119 | + { | ||
120 | + joinPrefix: false, | ||
121 | + } | ||
122 | + ); | ||
123 | +}; | ||
124 | + | ||
125 | +/** | ||
126 | + * Frp内网穿透信息API | ||
127 | + */ | ||
128 | +export const frpGetInfoApi = (proxyName: string) => { | ||
129 | + return defHttp.get({ | ||
130 | + url: `${EDeviceConfigApi.FRP_API}${proxyName}`, | ||
131 | + }); | ||
132 | +}; | ||
133 | + | ||
134 | +export const frpPutInfoApi = (proxyName: string, enableRemote: number) => { | ||
135 | + return defHttp.put({ | ||
136 | + url: `${EDeviceConfigApi.FRP_API}${proxyName}/${enableRemote}`, | ||
137 | + }); | ||
138 | +}; | ||
139 | + | ||
140 | +export const getTbDeviceId = (params: string) => { | ||
141 | + return defHttp.get({ | ||
142 | + url: `${EDeviceConfigApi.GET_TB_DEVICE_ID}/${params}`, | ||
143 | + }); | ||
144 | +}; | ||
145 | + | ||
146 | +/** | ||
147 | + * 命令下发记录 | ||
148 | + */ | ||
149 | +export const deviceCommandRecordGetQuery = (params?: TDeviceConfigParams) => { | ||
150 | + return defHttp.get({ | ||
151 | + url: EDeviceConfigApi.COMMODRECORD, | ||
152 | + params, | ||
153 | + }); | ||
154 | +}; |
1 | -import { BasicPageParams } from '/@/api/model/baseModel'; | ||
2 | - | ||
3 | -export type TDeviceConfigPageQueryParam = BasicPageParams & TDeviceConfigParams; | ||
4 | - | ||
5 | -export type TDeviceConfigParams = { | ||
6 | - page?: any; | ||
7 | - pageSize?: any; | ||
8 | - name?: string; | ||
9 | - transportType?: string; | ||
10 | - orderFiled?: string; | ||
11 | - orderType?: string; | ||
12 | - tbDeviceId?: string; | ||
13 | -}; | ||
14 | - | ||
15 | -export interface IDeviceConfigAddOrEditModel { | ||
16 | - defaultQueueName?: string; //处理队列 | ||
17 | - alarmProfile?: { | ||
18 | - alarmContactId: string; | ||
19 | - createTime: '2021-12-15T02:17:26.644Z'; | ||
20 | - creator: string; | ||
21 | - defaultConfig: string; | ||
22 | - description: string; | ||
23 | - deviceProfileId: string; | ||
24 | - enabled: true; | ||
25 | - icon: string; | ||
26 | - id: string; | ||
27 | - messageMode: string; | ||
28 | - name: string; | ||
29 | - roleIds: [string]; | ||
30 | - tenantExpireTime: '2021-12-15T02:17:26.644Z'; | ||
31 | - tenantId: string; | ||
32 | - tenantStatus: 'DISABLED'; | ||
33 | - updateTime: '2021-12-15T02:17:26.644Z'; | ||
34 | - updater: string; | ||
35 | - }; | ||
36 | - convertJs?: string; | ||
37 | - createTime?: '2021-12-15T02:17:26.644Z'; | ||
38 | - creator?: string; | ||
39 | - defaultConfig?: string; | ||
40 | - defaultRuleChainId?: string; | ||
41 | - description?: string; | ||
42 | - enabled?: true; | ||
43 | - icon?: string; | ||
44 | - id?: string; | ||
45 | - name?: string; | ||
46 | - profileData?: { | ||
47 | - configuration: {}; | ||
48 | - transportConfiguration: {}; | ||
49 | - provisionConfiguration: { | ||
50 | - provisionDeviceSecret: string; | ||
51 | - }; | ||
52 | - //报警类型字段 | ||
53 | - alarms: [ | ||
54 | - { | ||
55 | - id: 'highTemperatureAlarmID'; | ||
56 | - alarmType: 'High Temperature Alarm'; | ||
57 | - createRules: { | ||
58 | - additionalProp1: { | ||
59 | - condition: { | ||
60 | - condition: [ | ||
61 | - { | ||
62 | - key: { | ||
63 | - type: 'TIME_SERIES'; | ||
64 | - key: 'temp'; | ||
65 | - }; | ||
66 | - valueType: 'NUMERIC'; | ||
67 | - value: {}; | ||
68 | - predicate: {}; | ||
69 | - } | ||
70 | - ]; | ||
71 | - spec: {}; | ||
72 | - }; | ||
73 | - schedule: { | ||
74 | - type: 'ANY_TIME'; | ||
75 | - }; | ||
76 | - alarmDetails: string; | ||
77 | - dashboardId: { | ||
78 | - id: '784f394c-42b6-435a-983c-b7beff2784f9'; | ||
79 | - entityType: 'DASHBOARD'; | ||
80 | - }; | ||
81 | - }; | ||
82 | - additionalProp2: { | ||
83 | - condition: { | ||
84 | - condition: [ | ||
85 | - { | ||
86 | - key: { | ||
87 | - type: 'TIME_SERIES'; | ||
88 | - key: 'temp'; | ||
89 | - }; | ||
90 | - valueType: 'NUMERIC'; | ||
91 | - value: {}; | ||
92 | - predicate: {}; | ||
93 | - } | ||
94 | - ]; | ||
95 | - spec: {}; | ||
96 | - }; | ||
97 | - schedule: { | ||
98 | - type: 'ANY_TIME'; | ||
99 | - }; | ||
100 | - alarmDetails: string; | ||
101 | - dashboardId: { | ||
102 | - id: '784f394c-42b6-435a-983c-b7beff2784f9'; | ||
103 | - entityType: 'DASHBOARD'; | ||
104 | - }; | ||
105 | - }; | ||
106 | - additionalProp3: { | ||
107 | - condition: { | ||
108 | - condition: [ | ||
109 | - { | ||
110 | - key: { | ||
111 | - type: 'TIME_SERIES'; | ||
112 | - key: 'temp'; | ||
113 | - }; | ||
114 | - valueType: 'NUMERIC'; | ||
115 | - value: {}; | ||
116 | - predicate: {}; | ||
117 | - } | ||
118 | - ]; | ||
119 | - spec: {}; | ||
120 | - }; | ||
121 | - schedule: { | ||
122 | - type: 'ANY_TIME'; | ||
123 | - }; | ||
124 | - alarmDetails: string; | ||
125 | - dashboardId: { | ||
126 | - id: '784f394c-42b6-435a-983c-b7beff2784f9'; | ||
127 | - entityType: 'DASHBOARD'; | ||
128 | - }; | ||
129 | - }; | ||
130 | - }; | ||
131 | - clearRule: { | ||
132 | - condition: { | ||
133 | - condition: [ | ||
134 | - { | ||
135 | - key: { | ||
136 | - type: 'TIME_SERIES'; | ||
137 | - key: 'temp'; | ||
138 | - }; | ||
139 | - valueType: 'NUMERIC'; | ||
140 | - value: {}; | ||
141 | - predicate: {}; | ||
142 | - } | ||
143 | - ]; | ||
144 | - spec: {}; | ||
145 | - }; | ||
146 | - schedule: { | ||
147 | - type: 'ANY_TIME'; | ||
148 | - }; | ||
149 | - alarmDetails: string; | ||
150 | - dashboardId: { | ||
151 | - id: '784f394c-42b6-435a-983c-b7beff2784f9'; | ||
152 | - entityType: 'DASHBOARD'; | ||
153 | - }; | ||
154 | - }; | ||
155 | - propagate: true; | ||
156 | - propagateRelationTypes: [string]; | ||
157 | - } | ||
158 | - ]; | ||
159 | - }; | ||
160 | - roleIds?: [string]; | ||
161 | - tbProfileId?: string; | ||
162 | - tenantExpireTime?: '2021-12-15T02:17:26.645Z'; | ||
163 | - tenantId?: string; | ||
164 | - tenantStatus?: 'DISABLED'; | ||
165 | - transportType?: string; | ||
166 | - updateTime?: '2021-12-15T02:17:26.645Z'; | ||
167 | - updater?: string; | ||
168 | -} | ||
169 | - | ||
170 | -export interface Data { | ||
171 | - CO: number; | ||
172 | -} | ||
173 | - | ||
174 | -export interface Details { | ||
175 | - data: Data; | ||
176 | -} | ||
177 | - | ||
178 | -export interface AlarmLogItem { | ||
179 | - id: string; | ||
180 | - tenantId: string; | ||
181 | - creator?: any; | ||
182 | - updater?: any; | ||
183 | - createdTime: string; | ||
184 | - updatedTime: string; | ||
185 | - customerId: string; | ||
186 | - tbDeviceId: string; | ||
187 | - originatorType: number; | ||
188 | - deviceId: string; | ||
189 | - deviceName: string; | ||
190 | - type: string; | ||
191 | - severity: string; | ||
192 | - status: string; | ||
193 | - startTs: string; | ||
194 | - endTs: string; | ||
195 | - ackTs: string; | ||
196 | - clearTs: string; | ||
197 | - details: Details; | ||
198 | - propagate: boolean; | ||
199 | - propagateRelationTypes?: any; | ||
200 | - organizationId: string; | ||
201 | - organizationName: string; | ||
202 | -} | ||
203 | - | ||
204 | -export interface Configuration { | ||
205 | - type: string; | ||
206 | -} | ||
207 | - | ||
208 | -export interface TransportConfiguration { | ||
209 | - type: string; | ||
210 | -} | ||
211 | - | ||
212 | -export interface ProvisionConfiguration { | ||
213 | - type: string; | ||
214 | - provisionDeviceSecret?: any; | ||
215 | -} | ||
216 | - | ||
217 | -export interface ProfileData { | ||
218 | - configuration: Configuration; | ||
219 | - transportConfiguration: TransportConfiguration; | ||
220 | - provisionConfiguration: ProvisionConfiguration; | ||
221 | - alarms?: any; | ||
222 | -} | ||
223 | - | ||
224 | -export interface ProfileRecord { | ||
225 | - id: string; | ||
226 | - creator: string; | ||
227 | - createTime: string; | ||
228 | - updater: string; | ||
229 | - updateTime: string; | ||
230 | - name: string; | ||
231 | - tenantId: string; | ||
232 | - transportType: string; | ||
233 | - provisionType: string; | ||
234 | - deviceType: string; | ||
235 | - tbProfileId: string; | ||
236 | - profileData: ProfileData; | ||
237 | - defaultRuleChainId: string; | ||
238 | - defaultQueueName: string; | ||
239 | - image: string; | ||
240 | - type: string; | ||
241 | - default: boolean; | ||
242 | - | ||
243 | - checked?: boolean; | ||
244 | -} | ||
245 | - | ||
246 | -export interface IDRecord { | ||
247 | - entityType: string; | ||
248 | - id: string; | ||
249 | -} | ||
250 | - | ||
251 | -export interface RuleChainRecord { | ||
252 | - id: IDRecord; | ||
253 | - createdTime: number; | ||
254 | - additionalInfo?: any; | ||
255 | - tenantId: IDRecord; | ||
256 | - name: string; | ||
257 | - type: string; | ||
258 | - firstRuleNodeId: IDRecord; | ||
259 | - root: boolean; | ||
260 | - debugMode: boolean; | ||
261 | - configuration?: any; | ||
262 | -} | 1 | +import { BasicPageParams } from '/@/api/model/baseModel'; |
2 | + | ||
3 | +export type TDeviceConfigPageQueryParam = BasicPageParams & TDeviceConfigParams; | ||
4 | + | ||
5 | +export type TDeviceConfigParams = { | ||
6 | + page?: any; | ||
7 | + pageSize?: any; | ||
8 | + name?: string; | ||
9 | + transportType?: string; | ||
10 | + orderFiled?: string; | ||
11 | + orderType?: string; | ||
12 | + tbDeviceId?: string; | ||
13 | +}; | ||
14 | + | ||
15 | +export interface IDeviceConfigAddOrEditModel { | ||
16 | + defaultQueueName?: string; //处理队列 | ||
17 | + alarmProfile?: { | ||
18 | + alarmContactId: string; | ||
19 | + createTime: '2021-12-15T02:17:26.644Z'; | ||
20 | + creator: string; | ||
21 | + defaultConfig: string; | ||
22 | + description: string; | ||
23 | + deviceProfileId: string; | ||
24 | + enabled: true; | ||
25 | + icon: string; | ||
26 | + id: string; | ||
27 | + messageMode: string; | ||
28 | + name: string; | ||
29 | + roleIds: [string]; | ||
30 | + tenantExpireTime: '2021-12-15T02:17:26.644Z'; | ||
31 | + tenantId: string; | ||
32 | + tenantStatus: 'DISABLED'; | ||
33 | + updateTime: '2021-12-15T02:17:26.644Z'; | ||
34 | + updater: string; | ||
35 | + }; | ||
36 | + convertJs?: string; | ||
37 | + createTime?: '2021-12-15T02:17:26.644Z'; | ||
38 | + creator?: string; | ||
39 | + defaultConfig?: string; | ||
40 | + defaultRuleChainId?: string; | ||
41 | + description?: string; | ||
42 | + enabled?: true; | ||
43 | + icon?: string; | ||
44 | + id?: string; | ||
45 | + name?: string; | ||
46 | + profileData?: { | ||
47 | + configuration: {}; | ||
48 | + transportConfiguration: {}; | ||
49 | + provisionConfiguration: { | ||
50 | + provisionDeviceSecret: string; | ||
51 | + }; | ||
52 | + //报警类型字段 | ||
53 | + alarms: [ | ||
54 | + { | ||
55 | + id: 'highTemperatureAlarmID'; | ||
56 | + alarmType: 'High Temperature Alarm'; | ||
57 | + createRules: { | ||
58 | + additionalProp1: { | ||
59 | + condition: { | ||
60 | + condition: [ | ||
61 | + { | ||
62 | + key: { | ||
63 | + type: 'TIME_SERIES'; | ||
64 | + key: 'temp'; | ||
65 | + }; | ||
66 | + valueType: 'NUMERIC'; | ||
67 | + value: {}; | ||
68 | + predicate: {}; | ||
69 | + } | ||
70 | + ]; | ||
71 | + spec: {}; | ||
72 | + }; | ||
73 | + schedule: { | ||
74 | + type: 'ANY_TIME'; | ||
75 | + }; | ||
76 | + alarmDetails: string; | ||
77 | + dashboardId: { | ||
78 | + id: '784f394c-42b6-435a-983c-b7beff2784f9'; | ||
79 | + entityType: 'DASHBOARD'; | ||
80 | + }; | ||
81 | + }; | ||
82 | + additionalProp2: { | ||
83 | + condition: { | ||
84 | + condition: [ | ||
85 | + { | ||
86 | + key: { | ||
87 | + type: 'TIME_SERIES'; | ||
88 | + key: 'temp'; | ||
89 | + }; | ||
90 | + valueType: 'NUMERIC'; | ||
91 | + value: {}; | ||
92 | + predicate: {}; | ||
93 | + } | ||
94 | + ]; | ||
95 | + spec: {}; | ||
96 | + }; | ||
97 | + schedule: { | ||
98 | + type: 'ANY_TIME'; | ||
99 | + }; | ||
100 | + alarmDetails: string; | ||
101 | + dashboardId: { | ||
102 | + id: '784f394c-42b6-435a-983c-b7beff2784f9'; | ||
103 | + entityType: 'DASHBOARD'; | ||
104 | + }; | ||
105 | + }; | ||
106 | + additionalProp3: { | ||
107 | + condition: { | ||
108 | + condition: [ | ||
109 | + { | ||
110 | + key: { | ||
111 | + type: 'TIME_SERIES'; | ||
112 | + key: 'temp'; | ||
113 | + }; | ||
114 | + valueType: 'NUMERIC'; | ||
115 | + value: {}; | ||
116 | + predicate: {}; | ||
117 | + } | ||
118 | + ]; | ||
119 | + spec: {}; | ||
120 | + }; | ||
121 | + schedule: { | ||
122 | + type: 'ANY_TIME'; | ||
123 | + }; | ||
124 | + alarmDetails: string; | ||
125 | + dashboardId: { | ||
126 | + id: '784f394c-42b6-435a-983c-b7beff2784f9'; | ||
127 | + entityType: 'DASHBOARD'; | ||
128 | + }; | ||
129 | + }; | ||
130 | + }; | ||
131 | + clearRule: { | ||
132 | + condition: { | ||
133 | + condition: [ | ||
134 | + { | ||
135 | + key: { | ||
136 | + type: 'TIME_SERIES'; | ||
137 | + key: 'temp'; | ||
138 | + }; | ||
139 | + valueType: 'NUMERIC'; | ||
140 | + value: {}; | ||
141 | + predicate: {}; | ||
142 | + } | ||
143 | + ]; | ||
144 | + spec: {}; | ||
145 | + }; | ||
146 | + schedule: { | ||
147 | + type: 'ANY_TIME'; | ||
148 | + }; | ||
149 | + alarmDetails: string; | ||
150 | + dashboardId: { | ||
151 | + id: '784f394c-42b6-435a-983c-b7beff2784f9'; | ||
152 | + entityType: 'DASHBOARD'; | ||
153 | + }; | ||
154 | + }; | ||
155 | + propagate: true; | ||
156 | + propagateRelationTypes: [string]; | ||
157 | + } | ||
158 | + ]; | ||
159 | + }; | ||
160 | + roleIds?: [string]; | ||
161 | + tbProfileId?: string; | ||
162 | + tenantExpireTime?: '2021-12-15T02:17:26.645Z'; | ||
163 | + tenantId?: string; | ||
164 | + tenantStatus?: 'DISABLED'; | ||
165 | + transportType?: string; | ||
166 | + updateTime?: '2021-12-15T02:17:26.645Z'; | ||
167 | + updater?: string; | ||
168 | +} | ||
169 | + | ||
170 | +export interface Data { | ||
171 | + CO: number; | ||
172 | +} | ||
173 | + | ||
174 | +export interface Details { | ||
175 | + data: Data; | ||
176 | +} | ||
177 | + | ||
178 | +export interface AlarmLogItem { | ||
179 | + id: string; | ||
180 | + tenantId: string; | ||
181 | + creator?: any; | ||
182 | + updater?: any; | ||
183 | + createdTime: string; | ||
184 | + updatedTime: string; | ||
185 | + customerId: string; | ||
186 | + tbDeviceId: string; | ||
187 | + originatorType: number; | ||
188 | + deviceId: string; | ||
189 | + deviceName: string; | ||
190 | + type: string; | ||
191 | + severity: string; | ||
192 | + status: string; | ||
193 | + startTs: string; | ||
194 | + endTs: string; | ||
195 | + ackTs: string; | ||
196 | + clearTs: string; | ||
197 | + details: Details; | ||
198 | + propagate: boolean; | ||
199 | + propagateRelationTypes?: any; | ||
200 | + organizationId: string; | ||
201 | + organizationName: string; | ||
202 | +} | ||
203 | + | ||
204 | +export interface Configuration { | ||
205 | + type: string; | ||
206 | +} | ||
207 | + | ||
208 | +export interface TransportConfiguration { | ||
209 | + type: string; | ||
210 | +} | ||
211 | + | ||
212 | +export interface ProvisionConfiguration { | ||
213 | + type: string; | ||
214 | + provisionDeviceSecret?: any; | ||
215 | +} | ||
216 | + | ||
217 | +export interface ProfileData { | ||
218 | + configuration: Configuration; | ||
219 | + transportConfiguration: TransportConfiguration; | ||
220 | + provisionConfiguration: ProvisionConfiguration; | ||
221 | + alarms?: any; | ||
222 | +} | ||
223 | + | ||
224 | +export interface ProfileRecord { | ||
225 | + id: string; | ||
226 | + creator: string; | ||
227 | + createTime: string; | ||
228 | + updater: string; | ||
229 | + updateTime: string; | ||
230 | + name: string; | ||
231 | + tenantId: string; | ||
232 | + transportType: string; | ||
233 | + provisionType: string; | ||
234 | + deviceType: string; | ||
235 | + tbProfileId: string; | ||
236 | + profileData: ProfileData; | ||
237 | + defaultRuleChainId: string; | ||
238 | + defaultQueueName: string; | ||
239 | + image: string; | ||
240 | + type: string; | ||
241 | + default: boolean; | ||
242 | + | ||
243 | + checked?: boolean; | ||
244 | +} | ||
245 | + | ||
246 | +export interface IDRecord { | ||
247 | + entityType: string; | ||
248 | + id: string; | ||
249 | +} | ||
250 | + | ||
251 | +export interface RuleChainRecord { | ||
252 | + id: IDRecord; | ||
253 | + createdTime: number; | ||
254 | + additionalInfo?: any; | ||
255 | + tenantId: IDRecord; | ||
256 | + name: string; | ||
257 | + type: string; | ||
258 | + firstRuleNodeId: IDRecord; | ||
259 | + root: boolean; | ||
260 | + debugMode: boolean; | ||
261 | + configuration?: any; | ||
262 | +} | ||
263 | + | ||
264 | +export interface DeviceProfileDetail { | ||
265 | + id: string; | ||
266 | + creator: string; | ||
267 | + createTime: string; | ||
268 | + updater: string; | ||
269 | + updateTime: string; | ||
270 | + name: string; | ||
271 | + description: string; | ||
272 | + tenantId: string; | ||
273 | + transportType: string; | ||
274 | + provisionType: string; | ||
275 | + deviceType: string; | ||
276 | + tbProfileId: string; | ||
277 | + profileData: ProfileData; | ||
278 | + defaultQueueName: string; | ||
279 | + type: string; | ||
280 | + deviceCount: number; | ||
281 | + default: boolean; | ||
282 | +} | ||
283 | + | ||
284 | +export interface ProfileData { | ||
285 | + configuration: Configuration; | ||
286 | + transportConfiguration: TransportConfiguration; | ||
287 | + provisionConfiguration: ProvisionConfiguration; | ||
288 | + alarms: any; | ||
289 | + thingsModel: any; | ||
290 | +} | ||
291 | + | ||
292 | +export interface Configuration { | ||
293 | + type: string; | ||
294 | +} | ||
295 | + | ||
296 | +export interface TransportConfiguration { | ||
297 | + type: string; | ||
298 | +} | ||
299 | + | ||
300 | +export interface ProvisionConfiguration { | ||
301 | + type: string; | ||
302 | + provisionDeviceSecret: any; | ||
303 | +} |
@@ -230,10 +230,10 @@ | @@ -230,10 +230,10 @@ | ||
230 | 230 | ||
231 | function setFormModel(key: string, value: any) { | 231 | function setFormModel(key: string, value: any) { |
232 | formModel[key] = value; | 232 | formModel[key] = value; |
233 | - // const { validateTrigger } = unref(getBindValue); | ||
234 | - // if (!validateTrigger || validateTrigger === 'change') { | ||
235 | - // validateFields([key]).catch((_) => {}); | ||
236 | - // } | 233 | + const { validateTrigger } = unref(getBindValue); |
234 | + if (!validateTrigger || validateTrigger === 'change') { | ||
235 | + validateFields([key]).catch((_) => {}); | ||
236 | + } | ||
237 | } | 237 | } |
238 | 238 | ||
239 | function handleEnterPress(e: KeyboardEvent) { | 239 | function handleEnterPress(e: KeyboardEvent) { |
@@ -242,7 +242,7 @@ | @@ -242,7 +242,7 @@ | ||
242 | const value = target ? (isCheck ? target.checked : target.value) : e; | 242 | const value = target ? (isCheck ? target.checked : target.value) : e; |
243 | props.setFormModel(field, value); | 243 | props.setFormModel(field, value); |
244 | }, | 244 | }, |
245 | - onBlur: (...args) => { | 245 | + onBlur: (...args: any[]) => { |
246 | unref(getComponentsProps)?.onBlur?.(...args); | 246 | unref(getComponentsProps)?.onBlur?.(...args); |
247 | props.validateFields([field], { triggerName: 'blur' }).catch((_) => {}); | 247 | props.validateFields([field], { triggerName: 'blur' }).catch((_) => {}); |
248 | }, | 248 | }, |
@@ -38,7 +38,7 @@ export const basicProps = { | @@ -38,7 +38,7 @@ export const basicProps = { | ||
38 | }, | 38 | }, |
39 | autoSetPlaceHolder: propTypes.bool.def(true), | 39 | autoSetPlaceHolder: propTypes.bool.def(true), |
40 | // 在INPUT组件上单击回车时,是否自动提交 | 40 | // 在INPUT组件上单击回车时,是否自动提交 |
41 | - autoSubmitOnEnter: propTypes.bool.def(false), | 41 | + autoSubmitOnEnter: propTypes.bool.def(true), |
42 | submitOnReset: propTypes.bool, | 42 | submitOnReset: propTypes.bool, |
43 | size: propTypes.oneOf(['default', 'small', 'large']).def('default'), | 43 | size: propTypes.oneOf(['default', 'small', 'large']).def('default'), |
44 | // 禁用表单 | 44 | // 禁用表单 |
@@ -52,6 +52,7 @@ export function useBatchDelete( | @@ -52,6 +52,7 @@ export function useBatchDelete( | ||
52 | if (record) { | 52 | if (record) { |
53 | await deleteFn([record.id]); | 53 | await deleteFn([record.id]); |
54 | createMessage.success('删除成功'); | 54 | createMessage.success('删除成功'); |
55 | + selectedRowIds.value = []; | ||
55 | } else { | 56 | } else { |
56 | await deleteFn(selectedRowIds.value); | 57 | await deleteFn(selectedRowIds.value); |
57 | createMessage.success('批量删除成功'); | 58 | createMessage.success('批量删除成功'); |
@@ -116,7 +116,7 @@ | @@ -116,7 +116,7 @@ | ||
116 | const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); | 116 | const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); |
117 | const [registerModal, { openModal }] = useModal(); | 117 | const [registerModal, { openModal }] = useModal(); |
118 | // 表格hooks | 118 | // 表格hooks |
119 | - const [registerTable, { reload, setProps }] = useTable({ | 119 | + const [registerTable, { reload, setProps, clearSelectedRowKeys }] = useTable({ |
120 | title: '视频列表', | 120 | title: '视频列表', |
121 | api: cameraPage, | 121 | api: cameraPage, |
122 | columns, | 122 | columns, |
@@ -145,6 +145,7 @@ | @@ -145,6 +145,7 @@ | ||
145 | // 刷新 | 145 | // 刷新 |
146 | const handleSuccess = () => { | 146 | const handleSuccess = () => { |
147 | reload(); | 147 | reload(); |
148 | + clearSelectedRowKeys(); | ||
148 | }; | 149 | }; |
149 | const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | 150 | const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( |
150 | deleteCameraManage, | 151 | deleteCameraManage, |
@@ -2,9 +2,10 @@ | @@ -2,9 +2,10 @@ | ||
2 | <div ref="chartRef" :style="{ height, width }"></div> | 2 | <div ref="chartRef" :style="{ height, width }"></div> |
3 | </template> | 3 | </template> |
4 | <script lang="ts" setup> | 4 | <script lang="ts" setup> |
5 | - import { ref, Ref, withDefaults, onMounted, watch } from 'vue'; | 5 | + import { ref, Ref, onMounted, watch } from 'vue'; |
6 | import { useECharts } from '/@/hooks/web/useECharts'; | 6 | import { useECharts } from '/@/hooks/web/useECharts'; |
7 | import { getTrendData } from '/@/api/dashboard'; | 7 | import { getTrendData } from '/@/api/dashboard'; |
8 | + import { getDateByShortcutQueryKey, ShortcutQueryKeyEnum } from '../hooks/useDate'; | ||
8 | 9 | ||
9 | interface Props { | 10 | interface Props { |
10 | width?: string; | 11 | width?: string; |
@@ -77,11 +78,8 @@ | @@ -77,11 +78,8 @@ | ||
77 | const chartRef = ref<HTMLDivElement | null>(null); | 78 | const chartRef = ref<HTMLDivElement | null>(null); |
78 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); | 79 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
79 | onMounted(async () => { | 80 | onMounted(async () => { |
80 | - const endTs = Date.now(); | ||
81 | const res = await getTrendData({ | 81 | const res = await getTrendData({ |
82 | - startTs: endTs - 2592000000, | ||
83 | - endTs, | ||
84 | - interval: 86400000, | 82 | + ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_30_DAY), |
85 | trend: 'CUSTOMER_TREND', | 83 | trend: 'CUSTOMER_TREND', |
86 | }); | 84 | }); |
87 | 85 |
@@ -95,6 +95,20 @@ | @@ -95,6 +95,20 @@ | ||
95 | > | 95 | > |
96 | <template #extra> | 96 | <template #extra> |
97 | <div class="extra-date"> | 97 | <div class="extra-date"> |
98 | + <Tooltip :overlayStyle="{ maxWidth: '340px' }"> | ||
99 | + <template #title> | ||
100 | + <section> | ||
101 | + <div>30天: 查询最近30天的数据,间隔时间为1天.</div> | ||
102 | + <div>最近三个月: 查询最近三个月的数据,间隔时间为1天.</div> | ||
103 | + <div>最近一年: 查询最近一年的数据,间隔时间为30天.</div> | ||
104 | + <div> | ||
105 | + 间隔时间: | ||
106 | + 以当前时间作为结束时间,往前推移对应天数或小时的时间作为开始时间,然后在此时间区间内进行分组聚合查询. | ||
107 | + </div> | ||
108 | + </section> | ||
109 | + </template> | ||
110 | + <QuestionCircleOutlined class="!mr-2 cursor-pointer" /> | ||
111 | + </Tooltip> | ||
98 | <template v-for="(item, index) in TenantOrCustomerDateList" :key="item.value"> | 112 | <template v-for="(item, index) in TenantOrCustomerDateList" :key="item.value"> |
99 | <span | 113 | <span |
100 | @click="quickQueryTenantOrCustomerTime(index, item.value)" | 114 | @click="quickQueryTenantOrCustomerTime(index, item.value)" |
@@ -80,6 +80,20 @@ | @@ -80,6 +80,20 @@ | ||
80 | > | 80 | > |
81 | <template #extra> | 81 | <template #extra> |
82 | <div class="extra-date"> | 82 | <div class="extra-date"> |
83 | + <Tooltip :overlayStyle="{ maxWidth: '340px' }"> | ||
84 | + <template #title> | ||
85 | + <section> | ||
86 | + <div>30天: 查询最近30天的数据,间隔时间为1天.</div> | ||
87 | + <div>最近三个月: 查询最近三个月的数据,间隔时间为1天.</div> | ||
88 | + <div>最近一年: 查询最近一年的数据,间隔时间为30天.</div> | ||
89 | + <div> | ||
90 | + 间隔时间: | ||
91 | + 以当前时间作为结束时间,往前推移对应天数或小时的时间作为开始时间,然后在此时间区间内进行分组聚合查询. | ||
92 | + </div> | ||
93 | + </section> | ||
94 | + </template> | ||
95 | + <QuestionCircleOutlined class="!mr-2 cursor-pointer" /> | ||
96 | + </Tooltip> | ||
83 | <template v-for="(item, index) in TenantOrCustomerDateList" :key="item.value"> | 97 | <template v-for="(item, index) in TenantOrCustomerDateList" :key="item.value"> |
84 | <span | 98 | <span |
85 | @click="quickQueryTenantOrCustomerTime(index, item.value, 'tenant')" | 99 | @click="quickQueryTenantOrCustomerTime(index, item.value, 'tenant')" |
@@ -445,7 +459,7 @@ | @@ -445,7 +459,7 @@ | ||
445 | if (activeIndex.value === index) return; | 459 | if (activeIndex.value === index) return; |
446 | activeIndex.value = index; | 460 | activeIndex.value = index; |
447 | dateValue.value = ''; | 461 | dateValue.value = ''; |
448 | - console.log(interval); | 462 | + |
449 | if (isCustomer) { | 463 | if (isCustomer) { |
450 | if (activeKey.value === '1') { | 464 | if (activeKey.value === '1') { |
451 | const data = await getTrendData({ | 465 | const data = await getTrendData({ |
@@ -2,9 +2,10 @@ | @@ -2,9 +2,10 @@ | ||
2 | <div ref="chartRef" :style="{ height, width }"></div> | 2 | <div ref="chartRef" :style="{ height, width }"></div> |
3 | </template> | 3 | </template> |
4 | <script lang="ts" setup> | 4 | <script lang="ts" setup> |
5 | - import { ref, Ref, withDefaults, onMounted, watch } from 'vue'; | 5 | + import { ref, Ref, onMounted, watch } from 'vue'; |
6 | import { useECharts } from '/@/hooks/web/useECharts'; | 6 | import { useECharts } from '/@/hooks/web/useECharts'; |
7 | import { getTrendData } from '/@/api/dashboard/index'; | 7 | import { getTrendData } from '/@/api/dashboard/index'; |
8 | + import { getDateByShortcutQueryKey, ShortcutQueryKeyEnum } from '../hooks/useDate'; | ||
8 | interface Props { | 9 | interface Props { |
9 | width?: string; | 10 | width?: string; |
10 | height?: string; | 11 | height?: string; |
@@ -77,11 +78,8 @@ | @@ -77,11 +78,8 @@ | ||
77 | const chartRef = ref<HTMLDivElement | null>(null); | 78 | const chartRef = ref<HTMLDivElement | null>(null); |
78 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); | 79 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
79 | onMounted(async () => { | 80 | onMounted(async () => { |
80 | - const endTs = Date.now(); | ||
81 | const res = await getTrendData({ | 81 | const res = await getTrendData({ |
82 | - startTs: endTs - 2592000000, | ||
83 | - endTs, | ||
84 | - interval: 86400000, | 82 | + ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_30_DAY), |
85 | trend: 'TENANT_TREND', | 83 | trend: 'TENANT_TREND', |
86 | }); | 84 | }); |
87 | const transferResult = res.map((item) => [item.ts, item.value]); | 85 | const transferResult = res.map((item) => [item.ts, item.value]); |
1 | -import { formatToDateTime } from '/@/utils/dateUtil'; | 1 | +import { dateUtil, formatToDateTime } from '/@/utils/dateUtil'; |
2 | import { ref } from 'vue'; | 2 | import { ref } from 'vue'; |
3 | import { getTrendData } from '/@/api/dashboard'; | 3 | import { getTrendData } from '/@/api/dashboard'; |
4 | 4 | ||
5 | +export enum ShortcutQueryKeyEnum { | ||
6 | + LATEST_30_DAY = 'LATEST_30_DAY', | ||
7 | + LATEST_3_MONTH = 'LATEST_3_MONTH', | ||
8 | + LATEST_1_YEAR = 'LATEST_1_YEAR', | ||
9 | +} | ||
10 | + | ||
11 | +export function getDateByShortcutQueryKey(value: ShortcutQueryKeyEnum) { | ||
12 | + const mapping = { | ||
13 | + [ShortcutQueryKeyEnum.LATEST_30_DAY]: () => { | ||
14 | + return { | ||
15 | + startTs: dateUtil().subtract(30, 'day').startOf('day').valueOf(), | ||
16 | + interval: 24 * 60 * 60 * 1000, | ||
17 | + }; | ||
18 | + }, | ||
19 | + [ShortcutQueryKeyEnum.LATEST_3_MONTH]: () => { | ||
20 | + return { | ||
21 | + startTs: dateUtil().subtract(3, 'month').startOf('day').valueOf(), | ||
22 | + interval: 24 * 60 * 60 * 1000, | ||
23 | + }; | ||
24 | + }, | ||
25 | + [ShortcutQueryKeyEnum.LATEST_1_YEAR]: () => { | ||
26 | + return { | ||
27 | + startTs: dateUtil().subtract(1, 'year').startOf('day').valueOf(), | ||
28 | + interval: 30 * 24 * 60 * 60 * 1000, | ||
29 | + }; | ||
30 | + }, | ||
31 | + }; | ||
32 | + | ||
33 | + const result = mapping?.[value]?.(); | ||
34 | + | ||
35 | + return { | ||
36 | + ...result, | ||
37 | + endTs: dateUtil().add(1, 'day').startOf('day').valueOf(), | ||
38 | + }; | ||
39 | +} | ||
40 | + | ||
5 | export function useDate() { | 41 | export function useDate() { |
6 | const tenantDateValue = ref([]); | 42 | const tenantDateValue = ref([]); |
7 | const customerDateValue = ref([]); | 43 | const customerDateValue = ref([]); |
@@ -10,26 +46,23 @@ export function useDate() { | @@ -10,26 +46,23 @@ export function useDate() { | ||
10 | const activeTenantIndex = ref(0); | 46 | const activeTenantIndex = ref(0); |
11 | const activeCustomerIndex = ref(0); | 47 | const activeCustomerIndex = ref(0); |
12 | const TenantOrCustomerDateList = ref([ | 48 | const TenantOrCustomerDateList = ref([ |
13 | - { label: '30天', value: 2592000000 }, | ||
14 | - { label: '最近三个月', value: 7776000000 }, | ||
15 | - { label: '最近一年', value: 31536000000 }, | 49 | + { label: '30天', value: ShortcutQueryKeyEnum.LATEST_30_DAY }, |
50 | + { label: '最近三个月', value: ShortcutQueryKeyEnum.LATEST_3_MONTH }, | ||
51 | + { label: '最近一年', value: ShortcutQueryKeyEnum.LATEST_1_YEAR }, | ||
16 | ]); | 52 | ]); |
17 | 53 | ||
18 | // 租户趋势和客户趋势快速选择时间 | 54 | // 租户趋势和客户趋势快速选择时间 |
19 | async function quickQueryTenantOrCustomerTime( | 55 | async function quickQueryTenantOrCustomerTime( |
20 | index: number, | 56 | index: number, |
21 | - value: number, | 57 | + value: ShortcutQueryKeyEnum, |
22 | flag: 'tenant' | 'customer' | 58 | flag: 'tenant' | 'customer' |
23 | ) { | 59 | ) { |
24 | - const endTs = Date.now(); | ||
25 | if (flag === 'tenant') { | 60 | if (flag === 'tenant') { |
26 | if (activeTenantIndex.value === index) return; | 61 | if (activeTenantIndex.value === index) return; |
27 | activeTenantIndex.value = index; | 62 | activeTenantIndex.value = index; |
28 | tenantDateValue.value = []; | 63 | tenantDateValue.value = []; |
29 | const res = await getTrendData({ | 64 | const res = await getTrendData({ |
30 | - startTs: endTs - value, | ||
31 | - endTs, | ||
32 | - interval: value === 2592000000 ? 86400000 : value === 7776000000 ? 172800000 : 2592000000, | 65 | + ...getDateByShortcutQueryKey(value), |
33 | trend: 'TENANT_TREND', | 66 | trend: 'TENANT_TREND', |
34 | }); | 67 | }); |
35 | tenantTrendList.value = res.map((item) => [item.ts, item.value]); | 68 | tenantTrendList.value = res.map((item) => [item.ts, item.value]); |
@@ -38,9 +71,7 @@ export function useDate() { | @@ -38,9 +71,7 @@ export function useDate() { | ||
38 | activeCustomerIndex.value = index; | 71 | activeCustomerIndex.value = index; |
39 | customerDateValue.value = []; | 72 | customerDateValue.value = []; |
40 | const res = await getTrendData({ | 73 | const res = await getTrendData({ |
41 | - startTs: endTs - value, | ||
42 | - endTs, | ||
43 | - interval: value === 2592000000 ? 86400000 : value === 7776000000 ? 172800000 : 2592000000, | 74 | + ...getDateByShortcutQueryKey(value), |
44 | trend: 'CUSTOMER_TREND', | 75 | trend: 'CUSTOMER_TREND', |
45 | }); | 76 | }); |
46 | customerTrendList.value = res.map((item) => [item.ts, item.value]); | 77 | customerTrendList.value = res.map((item) => [item.ts, item.value]); |
@@ -7,7 +7,7 @@ import { JSONEditor } from '/@/components/CodeEditor'; | @@ -7,7 +7,7 @@ import { JSONEditor } from '/@/components/CodeEditor'; | ||
7 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; | 7 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
8 | import { getModelServices } from '/@/api/device/modelOfMatter'; | 8 | import { getModelServices } from '/@/api/device/modelOfMatter'; |
9 | import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; | 9 | import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; |
10 | -import { toRaw, unref } from 'vue'; | 10 | +import { nextTick, toRaw, unref } from 'vue'; |
11 | import ObjectModelValidateForm from '/@/components/Form/src/externalCompns/components/ObjectModelValidateForm/ObjectModelValidateForm.vue'; | 11 | import ObjectModelValidateForm from '/@/components/Form/src/externalCompns/components/ObjectModelValidateForm/ObjectModelValidateForm.vue'; |
12 | import { CommandDeliveryWayEnum, ServiceCallTypeEnum } from '/@/enums/toolEnum'; | 12 | import { CommandDeliveryWayEnum, ServiceCallTypeEnum } from '/@/enums/toolEnum'; |
13 | import { TaskTypeEnum } from '/@/views/task/center/config'; | 13 | import { TaskTypeEnum } from '/@/views/task/center/config'; |
@@ -246,8 +246,9 @@ export const step1Schemas: FormSchema[] = [ | @@ -246,8 +246,9 @@ export const step1Schemas: FormSchema[] = [ | ||
246 | required: true, | 246 | required: true, |
247 | component: 'ApiSelect', | 247 | component: 'ApiSelect', |
248 | ifShow: ({ values }) => values.deviceType === 'SENSOR' && values.organizationId, | 248 | ifShow: ({ values }) => values.deviceType === 'SENSOR' && values.organizationId, |
249 | - componentProps: ({ formModel }) => { | 249 | + componentProps: ({ formModel, formActionType }) => { |
250 | const { organizationId, transportType } = formModel; | 250 | const { organizationId, transportType } = formModel; |
251 | + const { validateFields } = formActionType; | ||
251 | if (![organizationId, transportType].every(Boolean)) return {}; | 252 | if (![organizationId, transportType].every(Boolean)) return {}; |
252 | return { | 253 | return { |
253 | api: async (params: Recordable) => { | 254 | api: async (params: Recordable) => { |
@@ -266,6 +267,10 @@ export const step1Schemas: FormSchema[] = [ | @@ -266,6 +267,10 @@ export const step1Schemas: FormSchema[] = [ | ||
266 | }, | 267 | }, |
267 | valueField: 'tbDeviceId', | 268 | valueField: 'tbDeviceId', |
268 | labelField: 'alias', | 269 | labelField: 'alias', |
270 | + onChange: async () => { | ||
271 | + await nextTick(); | ||
272 | + validateFields(['gatewayId']); | ||
273 | + }, | ||
269 | }; | 274 | }; |
270 | }, | 275 | }, |
271 | }, | 276 | }, |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | import { Upload, Button } from 'ant-design-vue'; | 2 | import { Upload, Button } from 'ant-design-vue'; |
3 | import { InboxOutlined } from '@ant-design/icons-vue'; | 3 | import { InboxOutlined } from '@ant-design/icons-vue'; |
4 | - import { computed, ref } from 'vue'; | 4 | + import { computed } from 'vue'; |
5 | import StepContainer from './StepContainer.vue'; | 5 | import StepContainer from './StepContainer.vue'; |
6 | import XLSX, { CellObject } from 'xlsx'; | 6 | import XLSX, { CellObject } from 'xlsx'; |
7 | import { basicProps } from './props'; | 7 | import { basicProps } from './props'; |
8 | import { UploadFileParseValue } from './type'; | 8 | import { UploadFileParseValue } from './type'; |
9 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
9 | 10 | ||
10 | const props = defineProps({ | 11 | const props = defineProps({ |
11 | ...basicProps, | 12 | ...basicProps, |
13 | + fileList: { | ||
14 | + required: true, | ||
15 | + type: Array as PropType<(Record<'uid' | 'name', string> & File)[]>, | ||
16 | + }, | ||
12 | value: { | 17 | value: { |
13 | require: true, | 18 | require: true, |
14 | type: Object as PropType<UploadFileParseValue>, | 19 | type: Object as PropType<UploadFileParseValue>, |
15 | }, | 20 | }, |
16 | }); | 21 | }); |
17 | 22 | ||
18 | - const emit = defineEmits(['update:value']); | ||
19 | - | ||
20 | - const fileList = ref<Record<'uid' | 'name', string>[]>([]); | 23 | + const emit = defineEmits(['update:value', 'update:fileList']); |
21 | 24 | ||
22 | interface FileRequestParams { | 25 | interface FileRequestParams { |
23 | file: File & { uid: string }; | 26 | file: File & { uid: string }; |
@@ -48,23 +51,30 @@ | @@ -48,23 +51,30 @@ | ||
48 | return new Promise((resolve, reject) => { | 51 | return new Promise((resolve, reject) => { |
49 | const fileReader = new FileReader(); | 52 | const fileReader = new FileReader(); |
50 | fileReader.onload = (event: ProgressEvent) => { | 53 | fileReader.onload = (event: ProgressEvent) => { |
51 | - const data = (event.target as FileReader).result as string; | ||
52 | - | ||
53 | - const result = XLSX.read(data, { type: 'string' }); | ||
54 | - | ||
55 | - const sheetName = result.SheetNames.at(0); | ||
56 | - const workbook = result.Sheets; | ||
57 | - const sheet = workbook[sheetName as string]; | ||
58 | - const sheetRange = sheet['!ref']; | ||
59 | - | ||
60 | - const { | ||
61 | - s: { c: startColumn }, | ||
62 | - e: { c: endColumn }, | ||
63 | - } = XLSX.utils.decode_range(sheetRange!); | ||
64 | - | ||
65 | - const header = getTableHeader(sheet, [startColumn, endColumn]); | ||
66 | - const content = XLSX.utils.sheet_to_json(sheet, { range: sheetRange }) as Recordable[]; | ||
67 | - resolve({ header, content }); | 54 | + try { |
55 | + const data = (event.target as FileReader).result as string; | ||
56 | + | ||
57 | + const result = XLSX.read(data, { type: 'string' }); | ||
58 | + | ||
59 | + const sheetName = result.SheetNames.at(0); | ||
60 | + const workbook = result.Sheets; | ||
61 | + const sheet = workbook[sheetName as string]; | ||
62 | + const sheetRange = sheet['!ref']; | ||
63 | + | ||
64 | + const { | ||
65 | + s: { c: startColumn }, | ||
66 | + e: { c: endColumn }, | ||
67 | + } = XLSX.utils.decode_range(sheetRange!); | ||
68 | + | ||
69 | + const header = getTableHeader(sheet, [startColumn, endColumn]); | ||
70 | + const content = XLSX.utils.sheet_to_json(sheet, { range: sheetRange }) as Recordable[]; | ||
71 | + | ||
72 | + resolve({ header, content }); | ||
73 | + } catch (error) { | ||
74 | + const { createMessage } = useMessage(); | ||
75 | + createMessage.error('请检查csv文件是否正确'); | ||
76 | + throw error; | ||
77 | + } | ||
68 | }; | 78 | }; |
69 | 79 | ||
70 | fileReader.onerror = () => { | 80 | fileReader.onerror = () => { |
@@ -75,19 +85,19 @@ | @@ -75,19 +85,19 @@ | ||
75 | }; | 85 | }; |
76 | 86 | ||
77 | const handleParseFile = async ({ file, onSuccess, onError }: FileRequestParams) => { | 87 | const handleParseFile = async ({ file, onSuccess, onError }: FileRequestParams) => { |
78 | - fileList.value = []; | ||
79 | const value = await readFile(file); | 88 | const value = await readFile(file); |
80 | if (!value) { | 89 | if (!value) { |
81 | onError(); | 90 | onError(); |
82 | return; | 91 | return; |
83 | } | 92 | } |
84 | - fileList.value = [file]; | 93 | + |
94 | + emit('update:fileList', [file]); | ||
85 | emit('update:value', value); | 95 | emit('update:value', value); |
86 | onSuccess({}, file); | 96 | onSuccess({}, file); |
87 | }; | 97 | }; |
88 | 98 | ||
89 | const canGoNextStep = computed(() => { | 99 | const canGoNextStep = computed(() => { |
90 | - return !!fileList.value.length; | 100 | + return !!props.fileList.length; |
91 | }); | 101 | }); |
92 | 102 | ||
93 | const handlePreviousStep = () => { | 103 | const handlePreviousStep = () => { |
@@ -97,16 +107,22 @@ | @@ -97,16 +107,22 @@ | ||
97 | const handleNextStep = () => { | 107 | const handleNextStep = () => { |
98 | props.goNextStep?.(); | 108 | props.goNextStep?.(); |
99 | }; | 109 | }; |
110 | + | ||
111 | + const handleRemove = () => { | ||
112 | + emit('update:fileList', []); | ||
113 | + return true; | ||
114 | + }; | ||
100 | </script> | 115 | </script> |
101 | 116 | ||
102 | <template> | 117 | <template> |
103 | <StepContainer> | 118 | <StepContainer> |
104 | <div class="">设备文件</div> | 119 | <div class="">设备文件</div> |
105 | <Upload.Dragger | 120 | <Upload.Dragger |
106 | - v-model:fileList="fileList" | 121 | + :fileList="fileList" |
107 | :customRequest="handleParseFile" | 122 | :customRequest="handleParseFile" |
108 | accept=".csv" | 123 | accept=".csv" |
109 | name="file" | 124 | name="file" |
125 | + :remove="handleRemove" | ||
110 | > | 126 | > |
111 | <section class="cursor-pointer flex flex-col justify-center items-center"> | 127 | <section class="cursor-pointer flex flex-col justify-center items-center"> |
112 | <InboxOutlined class="text-[4rem] !text-blue-400" /> | 128 | <InboxOutlined class="text-[4rem] !text-blue-400" /> |
@@ -17,6 +17,8 @@ | @@ -17,6 +17,8 @@ | ||
17 | 17 | ||
18 | const basicInfo = ref({}); | 18 | const basicInfo = ref({}); |
19 | 19 | ||
20 | + const fileList = ref<(File & Record<'uid' | 'name', string>)[]>([]); | ||
21 | + | ||
20 | const fileParseValue = ref<UploadFileParseValue>({ header: [], content: [] }); | 22 | const fileParseValue = ref<UploadFileParseValue>({ header: [], content: [] }); |
21 | 23 | ||
22 | const columnConfiguration = ref<Record<'type', string>[]>([]); | 24 | const columnConfiguration = ref<Record<'type', string>[]>([]); |
@@ -61,6 +63,7 @@ | @@ -61,6 +63,7 @@ | ||
61 | 63 | ||
62 | const reset = () => { | 64 | const reset = () => { |
63 | basicInfo.value = {}; | 65 | basicInfo.value = {}; |
66 | + fileList.value = []; | ||
64 | fileParseValue.value = { header: [], content: [] }; | 67 | fileParseValue.value = { header: [], content: [] }; |
65 | columnConfiguration.value = []; | 68 | columnConfiguration.value = []; |
66 | importResult.value = {} as unknown as ImportDeviceResponse; | 69 | importResult.value = {} as unknown as ImportDeviceResponse; |
@@ -109,6 +112,7 @@ | @@ -109,6 +112,7 @@ | ||
109 | /> | 112 | /> |
110 | <ImportCsv | 113 | <ImportCsv |
111 | v-if="StepsEnum[item] === StepsEnum.IMPORT_FILE && StepsEnum[item] === currentStep" | 114 | v-if="StepsEnum[item] === StepsEnum.IMPORT_FILE && StepsEnum[item] === currentStep" |
115 | + v-model:fileList="fileList" | ||
112 | v-model:value="fileParseValue" | 116 | v-model:value="fileParseValue" |
113 | :go-next-step="goNextStep" | 117 | :go-next-step="goNextStep" |
114 | :go-previous-step="goPreviousStep" | 118 | :go-previous-step="goPreviousStep" |
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | import { ColEx } from '/@/components/Form/src/types'; | 11 | import { ColEx } from '/@/components/Form/src/types'; |
12 | import { useHistoryData } from '../../hook/useHistoryData'; | 12 | import { useHistoryData } from '../../hook/useHistoryData'; |
13 | import { formatToDateTime } from '/@/utils/dateUtil'; | 13 | import { formatToDateTime } from '/@/utils/dateUtil'; |
14 | - import { useTable, BasicTable } from '/@/components/Table'; | 14 | + import { useTable, BasicTable, BasicColumn } from '/@/components/Table'; |
15 | import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; | 15 | import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; |
16 | import { | 16 | import { |
17 | ModeSwitchButton, | 17 | ModeSwitchButton, |
@@ -60,13 +60,9 @@ | @@ -60,13 +60,9 @@ | ||
60 | } | 60 | } |
61 | } | 61 | } |
62 | 62 | ||
63 | - const [registerTable] = useTable({ | ||
64 | - showIndexColumn: false, | ||
65 | - showTableSetting: false, | ||
66 | - dataSource: historyData, | ||
67 | - maxHeight: 300, | ||
68 | - size: 'small', | ||
69 | - columns: [ | 63 | + const sortOrder = ref<any>('descend'); |
64 | + const columns: BasicColumn[] | any = computed(() => { | ||
65 | + return [ | ||
70 | { | 66 | { |
71 | title: '属性', | 67 | title: '属性', |
72 | dataIndex: 'name', | 68 | dataIndex: 'name', |
@@ -84,18 +80,50 @@ | @@ -84,18 +80,50 @@ | ||
84 | format: (val) => { | 80 | format: (val) => { |
85 | return formatToDateTime(val, 'YYYY-MM-DD HH:mm:ss'); | 81 | return formatToDateTime(val, 'YYYY-MM-DD HH:mm:ss'); |
86 | }, | 82 | }, |
87 | - sorter: 'descend', | 83 | + sorter: true, |
84 | + sortOrder: unref(sortOrder), | ||
85 | + sortDirections: ['descend', 'ascend', 'descend'], | ||
88 | }, | 86 | }, |
89 | - ], | 87 | + ]; |
88 | + }); | ||
89 | + | ||
90 | + const [registerTable, { setColumns }] = useTable({ | ||
91 | + showIndexColumn: false, | ||
92 | + showTableSetting: false, | ||
93 | + dataSource: historyData, | ||
94 | + maxHeight: 300, | ||
95 | + columns: unref(columns), | ||
96 | + size: 'small', | ||
90 | }); | 97 | }); |
91 | 98 | ||
92 | - const handleTableChange = async (pag, filters, sorter: any) => { | ||
93 | - console.log(pag, filters, sorter, 'pag, filters, sorter'); | 99 | + const getTableList = async (orderBy?: string) => { |
100 | + // 表单验证 | ||
101 | + await method.validate(); | ||
102 | + const value = method.getFieldsValue(); | ||
103 | + const searchParams = getSearchParams(value); | ||
104 | + | ||
105 | + if (!hasDeviceAttr()) return; | ||
106 | + // 发送请求 | ||
107 | + loading.value = true; | ||
108 | + const res = await getDeviceHistoryInfo( | ||
109 | + { | ||
110 | + ...searchParams, | ||
111 | + entityId: props.deviceDetail.tbDeviceId, | ||
112 | + }, | ||
113 | + orderBy | ||
114 | + ); | ||
115 | + historyData.value = getTableHistoryData(res); | ||
116 | + loading.value = false; | ||
117 | + }; | ||
118 | + | ||
119 | + const handleTableChange = async (_pag, _filters, sorter: any) => { | ||
120 | + sortOrder.value = sorter.order; | ||
121 | + await setColumns(unref(columns)); | ||
94 | if (sorter.field == 'ts') { | 122 | if (sorter.field == 'ts') { |
95 | if (sorter.order == 'descend') { | 123 | if (sorter.order == 'descend') { |
96 | - openHistoryPanel('ASC'); | 124 | + getTableList('DESC'); |
97 | } else { | 125 | } else { |
98 | - openHistoryPanel('DESC'); | 126 | + getTableList('ASC'); |
99 | } | 127 | } |
100 | } | 128 | } |
101 | }; | 129 | }; |
@@ -214,7 +242,7 @@ | @@ -214,7 +242,7 @@ | ||
214 | setOptions(setChartOptions(res, selectedKeys)); | 242 | setOptions(setChartOptions(res, selectedKeys)); |
215 | }; | 243 | }; |
216 | 244 | ||
217 | - const switchMode = (flag: EnumTableChartMode) => { | 245 | + const switchMode = async (flag: EnumTableChartMode) => { |
218 | mode.value = flag; | 246 | mode.value = flag; |
219 | }; | 247 | }; |
220 | 248 |
@@ -12,6 +12,23 @@ export interface BasicCreateFormParams { | @@ -12,6 +12,23 @@ export interface BasicCreateFormParams { | ||
12 | 12 | ||
13 | useComponentRegister('JSONEditor', JSONEditor); | 13 | useComponentRegister('JSONEditor', JSONEditor); |
14 | 14 | ||
15 | +const validateDouble = ( | ||
16 | + value: number, | ||
17 | + type: DataTypeEnum, | ||
18 | + min?: number | string, | ||
19 | + max?: number | string | ||
20 | +) => { | ||
21 | + min = | ||
22 | + Number(min) || type === DataTypeEnum.IS_NUMBER_INT ? Number.MIN_SAFE_INTEGER : Number.MIN_VALUE; | ||
23 | + max = | ||
24 | + Number(max) || type === DataTypeEnum.IS_NUMBER_INT ? Number.MAX_SAFE_INTEGER : Number.MAX_VALUE; | ||
25 | + | ||
26 | + return { | ||
27 | + flag: value < min || value > max, | ||
28 | + message: `取值范围在${min}~${max}之间`, | ||
29 | + }; | ||
30 | +}; | ||
31 | + | ||
15 | export const useGenDynamicForm = () => { | 32 | export const useGenDynamicForm = () => { |
16 | const createInputNumber = ({ | 33 | const createInputNumber = ({ |
17 | identifier, | 34 | identifier, |
@@ -30,19 +47,19 @@ export const useGenDynamicForm = () => { | @@ -30,19 +47,19 @@ export const useGenDynamicForm = () => { | ||
30 | type: 'number', | 47 | type: 'number', |
31 | trigger: 'change', | 48 | trigger: 'change', |
32 | validator: (_rule, value) => { | 49 | validator: (_rule, value) => { |
33 | - if ( | ||
34 | - value < (min ?? Number.MIN_SAFE_INTEGER) || | ||
35 | - value > (max || Number.MAX_SAFE_INTEGER) | ||
36 | - ) { | ||
37 | - return Promise.reject(`${functionName}取值范围在${min}~${max}之间`); | 50 | + const { flag, message } = validateDouble(value, type, min, max); |
51 | + if (flag) { | ||
52 | + return Promise.reject(`${functionName}${message}`); | ||
38 | } | 53 | } |
39 | return Promise.resolve(value); | 54 | return Promise.resolve(value); |
40 | }, | 55 | }, |
41 | }, | 56 | }, |
42 | ], | 57 | ], |
43 | componentProps: { | 58 | componentProps: { |
44 | - max: max ?? Number.MAX_SAFE_INTEGER, | ||
45 | - min: min ?? Number.MIN_SAFE_INTEGER, | 59 | + max: |
60 | + max ?? type === DataTypeEnum.IS_NUMBER_INT ? Number.MAX_SAFE_INTEGER : Number.MAX_VALUE, | ||
61 | + min: | ||
62 | + min ?? type === DataTypeEnum.IS_NUMBER_INT ? Number.MIN_SAFE_INTEGER : Number.MIN_VALUE, | ||
46 | step, | 63 | step, |
47 | placeholder: `请输入${functionName}`, | 64 | placeholder: `请输入${functionName}`, |
48 | precision: type === DataTypeEnum.IS_NUMBER_INT ? 0 : 2, | 65 | precision: type === DataTypeEnum.IS_NUMBER_INT ? 0 : 2, |
@@ -136,7 +153,7 @@ export const useGenDynamicForm = () => { | @@ -136,7 +153,7 @@ export const useGenDynamicForm = () => { | ||
136 | fieldTypeMap.clear(); | 153 | fieldTypeMap.clear(); |
137 | const formSchema = schemas.map((item) => { | 154 | const formSchema = schemas.map((item) => { |
138 | const { functionName, identifier, dataType } = item; | 155 | const { functionName, identifier, dataType } = item; |
139 | - console.log(item, 'item'); | 156 | + |
140 | const { type } = dataType || {}; | 157 | const { type } = dataType || {}; |
141 | 158 | ||
142 | fieldTypeMap.set(identifier!, dataType!.type); | 159 | fieldTypeMap.set(identifier!, dataType!.type); |
@@ -84,6 +84,7 @@ | @@ -84,6 +84,7 @@ | ||
84 | import DeviceConfigurationStep from './step/DeviceConfigurationStep.vue'; | 84 | import DeviceConfigurationStep from './step/DeviceConfigurationStep.vue'; |
85 | import TransportConfigurationStep from './step/TransportConfigurationStep.vue'; | 85 | import TransportConfigurationStep from './step/TransportConfigurationStep.vue'; |
86 | import PhysicalModelManagementStep from './step/PhysicalModelManagementStep.vue'; | 86 | import PhysicalModelManagementStep from './step/PhysicalModelManagementStep.vue'; |
87 | + import { DeviceProfileDetail } from '/@/api/device/model/deviceConfigModel'; | ||
87 | 88 | ||
88 | const emits = defineEmits(['success', 'register']); | 89 | const emits = defineEmits(['success', 'register']); |
89 | const activeKey = ref('1'); | 90 | const activeKey = ref('1'); |
@@ -105,15 +106,22 @@ | @@ -105,15 +106,22 @@ | ||
105 | }); | 106 | }); |
106 | const transportTypeStr = ref(''); | 107 | const transportTypeStr = ref(''); |
107 | const dynamicWidth = ref('55rem'); | 108 | const dynamicWidth = ref('55rem'); |
109 | + | ||
110 | + const isDefault = ref(false); | ||
108 | const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { | 111 | const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { |
109 | setModalProps({ confirmLoading: false }); | 112 | setModalProps({ confirmLoading: false }); |
110 | current.value = 0; | 113 | current.value = 0; |
111 | isUpdate.value = data.isUpdate; | 114 | isUpdate.value = data.isUpdate; |
112 | isViewDetail.value = data.isView; | 115 | isViewDetail.value = data.isView; |
113 | - const res = data.record !== undefined ? await deviceConfigGetDetail(data.record.id) : {}; | 116 | + const res = |
117 | + data.record !== undefined | ||
118 | + ? await deviceConfigGetDetail(data.record.id) | ||
119 | + : ({} as DeviceProfileDetail); | ||
114 | isEditId.value = data.record !== undefined ? data.record.id : null; | 120 | isEditId.value = data.record !== undefined ? data.record.id : null; |
115 | isEditCreatTime.value = data.record !== undefined ? data.record.createTime : null; | 121 | isEditCreatTime.value = data.record !== undefined ? data.record.createTime : null; |
116 | 122 | ||
123 | + isDefault.value = res.default; | ||
124 | + | ||
117 | const title = unref(isUpdate) ? '编辑产品' : '新增产品'; | 125 | const title = unref(isUpdate) ? '编辑产品' : '新增产品'; |
118 | setModalProps({ title, showOkBtn: true, showCancelBtn: true }); | 126 | setModalProps({ title, showOkBtn: true, showCancelBtn: true }); |
119 | if (unref(isUpdate)) { | 127 | if (unref(isUpdate)) { |
@@ -183,6 +191,7 @@ | @@ -183,6 +191,7 @@ | ||
183 | ...{ profileData: !isEmptyObj ? transportConfData.profileData : null }, | 191 | ...{ profileData: !isEmptyObj ? transportConfData.profileData : null }, |
184 | ...{ id: isUpdate.value ? isEditId.value : null }, | 192 | ...{ id: isUpdate.value ? isEditId.value : null }, |
185 | ...{ createTime: isUpdate.value ? isEditCreatTime.value : null }, | 193 | ...{ createTime: isUpdate.value ? isEditCreatTime.value : null }, |
194 | + default: !!unref(isDefault), | ||
186 | }); | 195 | }); |
187 | createMessage.success(isUpdate.value ? `编辑成功` : `新增成功`); | 196 | createMessage.success(isUpdate.value ? `编辑成功` : `新增成功`); |
188 | handleCancel(); | 197 | handleCancel(); |
@@ -70,7 +70,7 @@ | @@ -70,7 +70,7 @@ | ||
70 | formConfig: { | 70 | formConfig: { |
71 | labelWidth: 120, | 71 | labelWidth: 120, |
72 | schemas: searchFormSchema, | 72 | schemas: searchFormSchema, |
73 | - fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'YYYY-MM-DD HH:mm:ss']], | 73 | + fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']], |
74 | }, | 74 | }, |
75 | useSearchForm: true, | 75 | useSearchForm: true, |
76 | showTableSetting: true, | 76 | showTableSetting: true, |
@@ -67,7 +67,7 @@ | @@ -67,7 +67,7 @@ | ||
67 | formConfig: { | 67 | formConfig: { |
68 | labelWidth: 120, | 68 | labelWidth: 120, |
69 | schemas: searchFormSchema, | 69 | schemas: searchFormSchema, |
70 | - fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'YYYY-MM-DD HH:mm:ss']], | 70 | + fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']], |
71 | }, | 71 | }, |
72 | useSearchForm: true, | 72 | useSearchForm: true, |
73 | showTableSetting: true, | 73 | showTableSetting: true, |
1 | import { BasicColumn, FormSchema } from '/@/components/Table'; | 1 | import { BasicColumn, FormSchema } from '/@/components/Table'; |
2 | import { transformTime } from '/@/hooks/web/useDateToLocaleString'; | 2 | import { transformTime } from '/@/hooks/web/useDateToLocaleString'; |
3 | +import { isObject, isString } from '/@/utils/is'; | ||
3 | 4 | ||
4 | export const columns: BasicColumn[] = [ | 5 | export const columns: BasicColumn[] = [ |
5 | { | 6 | { |
@@ -55,6 +56,18 @@ export const exportJSONFile = (value: Recordable, name: string) => { | @@ -55,6 +56,18 @@ export const exportJSONFile = (value: Recordable, name: string) => { | ||
55 | URL.revokeObjectURL(objectURL); | 56 | URL.revokeObjectURL(objectURL); |
56 | }; | 57 | }; |
57 | 58 | ||
59 | +export const paseJSON = (string: string) => { | ||
60 | + let data = null; | ||
61 | + let flag = false; | ||
62 | + try { | ||
63 | + if (!isString(string)) return { flag: false, data }; | ||
64 | + data = JSON.parse(string); | ||
65 | + flag = true; | ||
66 | + if (!isObject(data)) flag = false; | ||
67 | + } catch (error) {} | ||
68 | + return { flag, data }; | ||
69 | +}; | ||
70 | + | ||
58 | export enum RuleChainPermisssion { | 71 | export enum RuleChainPermisssion { |
59 | DETAIL = 'rule:chain:detail', | 72 | DETAIL = 'rule:chain:detail', |
60 | } | 73 | } |
@@ -8,7 +8,7 @@ | @@ -8,7 +8,7 @@ | ||
8 | <Upload :show-upload-list="false" :customRequest="handleImport"> | 8 | <Upload :show-upload-list="false" :customRequest="handleImport"> |
9 | <Button type="primary" :loading="importLoading"> 导入规则链 </Button> | 9 | <Button type="primary" :loading="importLoading"> 导入规则链 </Button> |
10 | </Upload> | 10 | </Upload> |
11 | - <!-- <Authority> | 11 | + <Authority> |
12 | <Popconfirm | 12 | <Popconfirm |
13 | title="您确定要批量删除数据" | 13 | title="您确定要批量删除数据" |
14 | ok-text="确定" | 14 | ok-text="确定" |
@@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
17 | > | 17 | > |
18 | <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> | 18 | <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> |
19 | </Popconfirm> | 19 | </Popconfirm> |
20 | - </Authority> --> | 20 | + </Authority> |
21 | </template> | 21 | </template> |
22 | <template #root="{ record }"> | 22 | <template #root="{ record }"> |
23 | <Tag :color="record.root ? 'green' : 'red'"> {{ record.root ? '是' : '否' }}</Tag> | 23 | <Tag :color="record.root ? 'green' : 'red'"> {{ record.root ? '是' : '否' }}</Tag> |
@@ -84,6 +84,7 @@ | @@ -84,6 +84,7 @@ | ||
84 | encode, | 84 | encode, |
85 | exportJSONFile, | 85 | exportJSONFile, |
86 | searchFormSchema, | 86 | searchFormSchema, |
87 | + paseJSON, | ||
87 | } from './config/config.data'; | 88 | } from './config/config.data'; |
88 | import { | 89 | import { |
89 | deleteRuleChine, | 90 | deleteRuleChine, |
@@ -95,17 +96,45 @@ | @@ -95,17 +96,45 @@ | ||
95 | } from '/@/api/ruleengine/ruleengineApi'; | 96 | } from '/@/api/ruleengine/ruleengineApi'; |
96 | import { useModal } from '/@/components/Modal'; | 97 | import { useModal } from '/@/components/Modal'; |
97 | import { Authority } from '/@/components/Authority'; | 98 | import { Authority } from '/@/components/Authority'; |
98 | - import { Tag, Button, Upload } from 'ant-design-vue'; | 99 | + import { Tag, Button, Upload, Popconfirm } from 'ant-design-vue'; |
99 | import { RuleChainModal } from './component/index'; | 100 | import { RuleChainModal } from './component/index'; |
100 | import { useMessage } from '/@/hooks/web/useMessage'; | 101 | import { useMessage } from '/@/hooks/web/useMessage'; |
101 | import { usePermission } from '/@/hooks/web/usePermission'; | 102 | import { usePermission } from '/@/hooks/web/usePermission'; |
102 | import { useRouter } from 'vue-router'; | 103 | import { useRouter } from 'vue-router'; |
103 | import { ref } from 'vue'; | 104 | import { ref } from 'vue'; |
104 | - import { isObject, isString } from '/@/utils/is'; | 105 | + import { isObject } from '/@/utils/is'; |
105 | // import { ChainDetailDrawer } from './chainDetail/index'; | 106 | // import { ChainDetailDrawer } from './chainDetail/index'; |
106 | // import { useDrawer } from '/@/components/Drawer'; | 107 | // import { useDrawer } from '/@/components/Drawer'; |
107 | 108 | ||
108 | - const [registerTable, { reload, setProps }] = useTable({ | 109 | + const [registerModal, { openModal }] = useModal(); |
110 | + const { createMessage } = useMessage(); | ||
111 | + const { hasPermission } = usePermission(); | ||
112 | + const router = useRouter(); | ||
113 | + | ||
114 | + const isEmptyObject = (value: any) => isObject(value) && !Object.keys(value).length; | ||
115 | + const importLoading = ref<boolean>(false); | ||
116 | + const hasBatchDelete = ref<boolean>(false); | ||
117 | + | ||
118 | + const beforeFetch = (params) => { | ||
119 | + Reflect.set(params, 'page', params.page - 1); | ||
120 | + Reflect.set(params, 'sortProperty', 'createdTime'); | ||
121 | + Reflect.set(params, 'sortOrder', 'DESC'); | ||
122 | + return params; | ||
123 | + }; | ||
124 | + | ||
125 | + const rowSelection = () => { | ||
126 | + return { | ||
127 | + type: 'checkbox', | ||
128 | + getCheckboxProps: (record: Recordable) => { | ||
129 | + return { disabled: record.root }; | ||
130 | + }, | ||
131 | + onChange(rowKeys: string[]) { | ||
132 | + hasBatchDelete.value = rowKeys.length <= 0; | ||
133 | + }, | ||
134 | + }; | ||
135 | + }; | ||
136 | + | ||
137 | + const [registerTable, { reload, setProps, getSelectRowKeys, clearSelectedRowKeys }] = useTable({ | ||
109 | title: '规则链库', | 138 | title: '规则链库', |
110 | api: getRuleChinsList, | 139 | api: getRuleChinsList, |
111 | rowKey: (record) => record.id.id, | 140 | rowKey: (record) => record.id.id, |
@@ -123,19 +152,8 @@ | @@ -123,19 +152,8 @@ | ||
123 | pageField: 'page', | 152 | pageField: 'page', |
124 | listField: 'data', | 153 | listField: 'data', |
125 | }, | 154 | }, |
126 | - beforeFetch(params) { | ||
127 | - Reflect.set(params, 'page', params.page - 1); | ||
128 | - Reflect.set(params, 'sortProperty', 'createdTime'); | ||
129 | - Reflect.set(params, 'sortOrder', 'DESC'); | ||
130 | - return params; | ||
131 | - }, | ||
132 | - rowSelection: { | ||
133 | - type: 'checkbox', | ||
134 | - getCheckboxProps: (record: Recordable) => { | ||
135 | - console.log(record, 'record'); | ||
136 | - return { disabled: record.root }; | ||
137 | - }, | ||
138 | - }, | 155 | + beforeFetch: (params) => beforeFetch(params), |
156 | + rowSelection: rowSelection() as any, | ||
139 | actionColumn: { | 157 | actionColumn: { |
140 | width: 220, | 158 | width: 220, |
141 | title: '操作', | 159 | title: '操作', |
@@ -145,10 +163,6 @@ | @@ -145,10 +163,6 @@ | ||
145 | }, | 163 | }, |
146 | }); | 164 | }); |
147 | 165 | ||
148 | - const [registerModal, { openModal }] = useModal(); | ||
149 | - | ||
150 | - // const [registerDrawer, { openDrawer }] = useDrawer(); | ||
151 | - | ||
152 | const handleSuccess = () => { | 166 | const handleSuccess = () => { |
153 | reload(); | 167 | reload(); |
154 | }; | 168 | }; |
@@ -166,10 +180,6 @@ | @@ -166,10 +180,6 @@ | ||
166 | }); | 180 | }); |
167 | }; | 181 | }; |
168 | 182 | ||
169 | - const { createMessage } = useMessage(); | ||
170 | - const { hasPermission } = usePermission(); | ||
171 | - const router = useRouter(); | ||
172 | - | ||
173 | const handleView = (record: Recordable) => { | 183 | const handleView = (record: Recordable) => { |
174 | const hasDetailPermission = hasPermission(RuleChainPermisssion.DETAIL); | 184 | const hasDetailPermission = hasPermission(RuleChainPermisssion.DETAIL); |
175 | if (hasDetailPermission) { | 185 | if (hasDetailPermission) { |
@@ -178,30 +188,6 @@ | @@ -178,30 +188,6 @@ | ||
178 | } else createMessage.warning('没有权限'); | 188 | } else createMessage.warning('没有权限'); |
179 | }; | 189 | }; |
180 | 190 | ||
181 | - // const handleRowClick = (record) => { | ||
182 | - // openDrawer(true, { record }); | ||
183 | - // console.log('点击行', record); | ||
184 | - // }; | ||
185 | - | ||
186 | - // const handleDetail = (record) => { | ||
187 | - // console.log(record, '详情'); | ||
188 | - // }; | ||
189 | - | ||
190 | - const paseJSON = (string: string) => { | ||
191 | - let data = null; | ||
192 | - let flag = false; | ||
193 | - try { | ||
194 | - if (!isString(string)) return { flag: false, data }; | ||
195 | - data = JSON.parse(string); | ||
196 | - flag = true; | ||
197 | - if (!isObject(data)) flag = false; | ||
198 | - } catch (error) {} | ||
199 | - return { flag, data }; | ||
200 | - }; | ||
201 | - | ||
202 | - const isEmptyObject = (value: any) => isObject(value) && !Object.keys(value).length; | ||
203 | - | ||
204 | - const importLoading = ref<boolean>(false); | ||
205 | const handleImport = (data: { file: File }) => { | 191 | const handleImport = (data: { file: File }) => { |
206 | const fileReader = new FileReader(); | 192 | const fileReader = new FileReader(); |
207 | 193 | ||
@@ -275,18 +261,25 @@ | @@ -275,18 +261,25 @@ | ||
275 | reload(); | 261 | reload(); |
276 | }; | 262 | }; |
277 | 263 | ||
278 | - const handleDeleteOrBatchDelete = async (record: Recordable) => { | 264 | + const handleDeleteOrBatchDelete = async (record: Recordable | null) => { |
279 | setProps({ | 265 | setProps({ |
280 | loading: true, | 266 | loading: true, |
281 | }); | 267 | }); |
282 | try { | 268 | try { |
269 | + if (!record) { | ||
270 | + const ids = getSelectRowKeys(); | ||
271 | + await Promise.all(ids.map((item) => deleteRuleChine(item))); | ||
272 | + return; | ||
273 | + } | ||
283 | await deleteRuleChine(record.id.id); | 274 | await deleteRuleChine(record.id.id); |
284 | - createMessage.success('删除成功'); | ||
285 | } finally { | 275 | } finally { |
286 | setProps({ | 276 | setProps({ |
287 | loading: false, | 277 | loading: false, |
288 | }); | 278 | }); |
279 | + | ||
280 | + createMessage.success('删除成功'); | ||
281 | + clearSelectedRowKeys(); | ||
282 | + reload(); | ||
289 | } | 283 | } |
290 | - reload(); | ||
291 | }; | 284 | }; |
292 | </script> | 285 | </script> |
@@ -126,7 +126,10 @@ | @@ -126,7 +126,10 @@ | ||
126 | password: getDataFlowParams.password ? getDataFlowParams.password : undefined, | 126 | password: getDataFlowParams.password ? getDataFlowParams.password : undefined, |
127 | } | 127 | } |
128 | : undefined, | 128 | : undefined, |
129 | + appendClientIdSuffix: getDataFlowParams.appendClientIdSuffix || undefined, | ||
130 | + type: undefined, | ||
129 | }; | 131 | }; |
132 | + | ||
130 | const rest = isRabbitmq(getDataFlowMethod?.type) | 133 | const rest = isRabbitmq(getDataFlowMethod?.type) |
131 | ? await postAddConvertApi({ ...restData.data, ...data }) | 134 | ? await postAddConvertApi({ ...restData.data, ...data }) |
132 | : await postAddConvertApi({ ...restData.data, ...data, configuration }); | 135 | : await postAddConvertApi({ ...restData.data, ...data, configuration }); |
1 | import { Ref, toRaw, unref } from 'vue'; | 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'; | 2 | +import { BasicNodeBindData, EdgeData, NodeData } from '../types/node'; |
3 | +import { Elements, GraphEdge, GraphNode } from '@vue-flow/core'; | ||
4 | +import { ConnectionItemType, RuleChainType } from '../types/ruleNode'; | ||
5 | import { allComponents } from '../packages'; | 5 | import { allComponents } from '../packages'; |
6 | import { RuleNodeTypeEnum } from '../packages/index.type'; | 6 | import { RuleNodeTypeEnum } from '../packages/index.type'; |
7 | import { buildUUID } from '/@/utils/uuid'; | 7 | import { buildUUID } from '/@/utils/uuid'; |
@@ -9,6 +9,9 @@ import { isNullOrUnDef } from '/@/utils/is'; | @@ -9,6 +9,9 @@ import { isNullOrUnDef } from '/@/utils/is'; | ||
9 | import { useAddNodes } from './useAddNodes'; | 9 | import { useAddNodes } from './useAddNodes'; |
10 | import { useAddEdges } from './useAddEdges'; | 10 | import { useAddEdges } from './useAddEdges'; |
11 | import { RuleChainEntityType } from '../enum/entity'; | 11 | import { RuleChainEntityType } from '../enum/entity'; |
12 | +import { EntryCategoryComponentEnum } from '../enum/category'; | ||
13 | + | ||
14 | +const ignoreNodeKeys: string[] = [EntryCategoryComponentEnum.INPUT]; | ||
12 | 15 | ||
13 | export function useBasicDataTransform() { | 16 | export function useBasicDataTransform() { |
14 | const nodeConfigMap = new Map<string, NodeData>(); | 17 | const nodeConfigMap = new Map<string, NodeData>(); |
@@ -24,7 +27,7 @@ export function useBasicDataTransform() { | @@ -24,7 +27,7 @@ export function useBasicDataTransform() { | ||
24 | } | 27 | } |
25 | 28 | ||
26 | function mergeData(data: NodeData['data'], nodeData: NodeData, node: GraphNode) { | 29 | function mergeData(data: NodeData['data'], nodeData: NodeData, node: GraphNode) { |
27 | - const { x: layoutX, y: layoutY } = node.computedPosition; | 30 | + const { x: layoutX, y: layoutY } = node.position; |
28 | 31 | ||
29 | return { | 32 | return { |
30 | debugMode: !!data?.debugMode, | 33 | debugMode: !!data?.debugMode, |
@@ -172,8 +175,126 @@ export function useBasicDataTransform() { | @@ -172,8 +175,126 @@ export function useBasicDataTransform() { | ||
172 | 175 | ||
173 | initNodeConfigMap(); | 176 | initNodeConfigMap(); |
174 | 177 | ||
178 | + /** | ||
179 | + * @description 保存连接信息 | ||
180 | + */ | ||
181 | + function getConnections( | ||
182 | + nodesRef: Ref<GraphNode[]> | GraphNode[], | ||
183 | + edges: Ref<GraphEdge[]> | GraphEdge[] | ||
184 | + ) { | ||
185 | + const nodeIndexMap = new Map(); | ||
186 | + | ||
187 | + const connections: ConnectionItemType[] = []; | ||
188 | + | ||
189 | + unref(nodesRef).forEach((item, index) => { | ||
190 | + nodeIndexMap.set(item.id, index); | ||
191 | + }); | ||
192 | + | ||
193 | + for (const item of unref(edges)) { | ||
194 | + const { data, target, source } = item; | ||
195 | + const { data: bindData } = data as EdgeData; | ||
196 | + const { type } = bindData || {}; | ||
197 | + const fromIndex = nodeIndexMap.get(source); | ||
198 | + const toIndex = nodeIndexMap.get(target); | ||
199 | + type?.forEach((key) => { | ||
200 | + connections.push({ fromIndex, toIndex, type: key }); | ||
201 | + }); | ||
202 | + } | ||
203 | + | ||
204 | + return connections; | ||
205 | + } | ||
206 | + | ||
207 | + function getNodes(nodesRef: Ref<GraphNode[]> | GraphNode[], removeId: boolean) { | ||
208 | + const nodes: BasicNodeBindData[] = []; | ||
209 | + | ||
210 | + for (const node of unref(nodesRef)) { | ||
211 | + const nodeData = node.data as NodeData; | ||
212 | + | ||
213 | + if (ignoreNodeKeys.includes(nodeData.config?.key as string)) continue; | ||
214 | + | ||
215 | + const data = nodeData.data; | ||
216 | + | ||
217 | + nodes.push( | ||
218 | + Object.assign( | ||
219 | + mergeData(data, nodeData, node), | ||
220 | + nodeData.created && !removeId | ||
221 | + ? ({ | ||
222 | + id: { id: node.id, entityType: RuleChainEntityType.RULE_NODE }, | ||
223 | + } as BasicNodeBindData) | ||
224 | + : {} | ||
225 | + ) | ||
226 | + ); | ||
227 | + } | ||
228 | + | ||
229 | + return nodes; | ||
230 | + } | ||
231 | + | ||
232 | + function getFirsetNodeIndex( | ||
233 | + nodesRef: Ref<GraphNode[]> | GraphNode[], | ||
234 | + edges: Ref<GraphEdge[]> | GraphEdge[] | ||
235 | + ) { | ||
236 | + const inputNode = unref(edges).find( | ||
237 | + (item) => (item.sourceNode.data as NodeData).config?.key === EntryCategoryComponentEnum.INPUT | ||
238 | + ); | ||
239 | + | ||
240 | + if (inputNode) { | ||
241 | + const targetId = inputNode.target; | ||
242 | + const index = unref(nodesRef).findIndex((item) => item.id === targetId); | ||
243 | + return index; | ||
244 | + } | ||
245 | + } | ||
246 | + | ||
247 | + function combineData( | ||
248 | + nodesRef: Ref<GraphNode[]> | GraphNode[] = [], | ||
249 | + edgesRef: Ref<GraphEdge[]> | GraphEdge[] = [], | ||
250 | + removeId = false | ||
251 | + ) { | ||
252 | + const extraIgnoreNodeRef = unref(nodesRef).filter( | ||
253 | + (item) => !ignoreNodeKeys.includes((item.data as NodeData).config?.key as string) | ||
254 | + ); | ||
255 | + | ||
256 | + const connections = getConnections(extraIgnoreNodeRef, edgesRef); | ||
257 | + | ||
258 | + const nodes = getNodes(extraIgnoreNodeRef, removeId); | ||
259 | + | ||
260 | + const firstNodeIndex = getFirsetNodeIndex(extraIgnoreNodeRef, edgesRef); | ||
261 | + | ||
262 | + return { connections, nodes, firstNodeIndex }; | ||
263 | + } | ||
264 | + | ||
265 | + function validateCanCreateRuleChain( | ||
266 | + nodes: Ref<GraphNode[]> | GraphNode[] = [], | ||
267 | + edges: Ref<GraphEdge[]> | GraphEdge[] = [] | ||
268 | + ) { | ||
269 | + const rootNode: GraphNode[] = []; | ||
270 | + | ||
271 | + let flag = true; | ||
272 | + for (const node of unref(nodes)) { | ||
273 | + const list = unref(edges).filter( | ||
274 | + (edge) => edge.source === node.id || edge.target === node.id | ||
275 | + ); | ||
276 | + | ||
277 | + if (!list.length) { | ||
278 | + flag = false; | ||
279 | + break; | ||
280 | + } | ||
281 | + | ||
282 | + if (!list.filter((edge) => edge.target === node.id).length) { | ||
283 | + if (!rootNode.length) rootNode.push(node); | ||
284 | + else { | ||
285 | + flag = false; | ||
286 | + break; | ||
287 | + } | ||
288 | + } | ||
289 | + } | ||
290 | + | ||
291 | + return { flag, firstNode: rootNode[0] || null }; | ||
292 | + } | ||
293 | + | ||
175 | return { | 294 | return { |
176 | mergeData, | 295 | mergeData, |
296 | + combineData, | ||
177 | deconstructionData, | 297 | deconstructionData, |
298 | + validateCanCreateRuleChain, | ||
178 | }; | 299 | }; |
179 | } | 300 | } |
@@ -3,11 +3,19 @@ import { getRuleNodeCache, setRuleNodeCache } from './useRuleChainCache'; | @@ -3,11 +3,19 @@ import { getRuleNodeCache, setRuleNodeCache } from './useRuleChainCache'; | ||
3 | import { RuleContextMenuEnum } from './useRuleChainContextMenu'; | 3 | import { RuleContextMenuEnum } from './useRuleChainContextMenu'; |
4 | import { useAddNodes } from './useAddNodes'; | 4 | import { useAddNodes } from './useAddNodes'; |
5 | import { buildUUID } from '/@/utils/uuid'; | 5 | import { buildUUID } from '/@/utils/uuid'; |
6 | -import { toRaw, unref } from 'vue'; | 6 | +import { Ref, toRaw, unref } from 'vue'; |
7 | import { useSaveAndRedo } from './useSaveAndRedo'; | 7 | import { useSaveAndRedo } from './useSaveAndRedo'; |
8 | import { isUnDef } from '/@/utils/is'; | 8 | import { isUnDef } from '/@/utils/is'; |
9 | import { useAddEdges } from './useAddEdges'; | 9 | import { useAddEdges } from './useAddEdges'; |
10 | import { EdgeData } from '../types/node'; | 10 | import { EdgeData } from '../types/node'; |
11 | +import { CreateNodeModal } from '../src/components/CreateNodeModal'; | ||
12 | +import { CreateEdgeModal } from '../src/components/CreateEdgeModal'; | ||
13 | +import { UpdateNodeDrawer } from '../src/components/UpdateNodeDrawer'; | ||
14 | +import { UpdateEdgeDrawer } from '../src/components/UpdateEdgeDrawer'; | ||
15 | +import { CreateRuleChainModal } from '../src/components/CreateRuleChainModal'; | ||
16 | +import { useBasicDataTransform } from './useBasicDataTransform'; | ||
17 | +import { cloneDeep } from 'lodash-es'; | ||
18 | +import { useNewNode } from './useNewNode'; | ||
11 | 19 | ||
12 | interface HandleContextMenuActionParamsType { | 20 | interface HandleContextMenuActionParamsType { |
13 | menuType: RuleContextMenuEnum; | 21 | menuType: RuleContextMenuEnum; |
@@ -16,18 +24,58 @@ interface HandleContextMenuActionParamsType { | @@ -16,18 +24,58 @@ interface HandleContextMenuActionParamsType { | ||
16 | node?: GraphNode; | 24 | node?: GraphNode; |
17 | edge?: GraphEdge; | 25 | edge?: GraphEdge; |
18 | useSaveAndRedoActionType?: ReturnType<typeof useSaveAndRedo>; | 26 | useSaveAndRedoActionType?: ReturnType<typeof useSaveAndRedo>; |
27 | + modalActionType: { | ||
28 | + createNodeModalActionType: Ref<Nullable<InstanceType<typeof CreateNodeModal>>>; | ||
29 | + createEdgeModalActionType: Ref<Nullable<InstanceType<typeof CreateEdgeModal>>>; | ||
30 | + updateNodeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateNodeDrawer>>>; | ||
31 | + updateEdgeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>; | ||
32 | + createRuleChainModalActionType: Ref<Nullable<InstanceType<typeof CreateRuleChainModal>>>; | ||
33 | + }; | ||
34 | +} | ||
35 | + | ||
36 | +export function transformToRuleChain( | ||
37 | + nodesRef: Ref<GraphNode[]> | GraphNode[] = [], | ||
38 | + edgesRef: Ref<GraphEdge[]> | GraphEdge[] = [] | ||
39 | +) { | ||
40 | + const nodeMap = new Map<string, GraphNode>(); | ||
41 | + const { combineData, validateCanCreateRuleChain } = useBasicDataTransform(); | ||
42 | + | ||
43 | + nodesRef = cloneDeep(unref(nodesRef)); | ||
44 | + edgesRef = cloneDeep(unref(edgesRef)); | ||
45 | + | ||
46 | + unref(nodesRef).forEach((node) => nodeMap.set(node.id, node)); | ||
47 | + const outputEdges = unref(edgesRef).filter((edge) => !nodeMap.has(edge.target)); | ||
48 | + const outputEdgesId = outputEdges.map((edge) => edge.id); | ||
49 | + | ||
50 | + const { getOutputNodeConfig } = useNewNode(); | ||
51 | + const outputNode = outputEdges.map((edge) => { | ||
52 | + const id = buildUUID(); | ||
53 | + const name = (edge.data as EdgeData).data?.type?.join(' / ') || ''; | ||
54 | + edge.target = id; | ||
55 | + return getOutputNodeConfig(name, edge.targetNode.position, id); | ||
56 | + }); | ||
57 | + | ||
58 | + nodesRef = [...nodesRef, ...(outputNode as GraphNode[])]; | ||
59 | + | ||
60 | + const { connections, nodes } = combineData(nodesRef, edgesRef, true); | ||
61 | + | ||
62 | + const { firstNode } = validateCanCreateRuleChain(nodesRef, edgesRef); | ||
63 | + | ||
64 | + const firstNodeIndex = nodesRef.findIndex((node) => node.id === firstNode.id); | ||
65 | + | ||
66 | + return { connections, nodes, firstNodeIndex, outputEdgesId }; | ||
19 | } | 67 | } |
20 | 68 | ||
21 | export const NODE_WIDTH = 176; | 69 | export const NODE_WIDTH = 176; |
22 | export const NODE_HEIGHT = 48; | 70 | export const NODE_HEIGHT = 48; |
23 | 71 | ||
24 | -function getElementsCenter(nodes: GraphNode[]) { | 72 | +function getElementsCenter(nodes: Ref<GraphNode[]> | GraphNode[] = []) { |
25 | let leftTopX: number | undefined; | 73 | let leftTopX: number | undefined; |
26 | let leftTopY: number | undefined; | 74 | let leftTopY: number | undefined; |
27 | let rightBottomX: number | undefined; | 75 | let rightBottomX: number | undefined; |
28 | let rightBottomY: number | undefined; | 76 | let rightBottomY: number | undefined; |
29 | 77 | ||
30 | - for (const node of nodes) { | 78 | + for (const node of unref(nodes)) { |
31 | const { position } = node; | 79 | const { position } = node; |
32 | const { x, y } = position; | 80 | const { x, y } = position; |
33 | if (isUnDef(leftTopX)) { | 81 | if (isUnDef(leftTopX)) { |
@@ -200,6 +248,37 @@ export function useContextMenuAction() { | @@ -200,6 +248,37 @@ export function useContextMenuAction() { | ||
200 | useSaveAndRedoActionType?.handleRedoChange(flowActionType!); | 248 | useSaveAndRedoActionType?.handleRedoChange(flowActionType!); |
201 | }; | 249 | }; |
202 | 250 | ||
251 | + const createRuleChain = async (_params: HandleContextMenuActionParamsType) => { | ||
252 | + // const { useSaveAndRedoActionType, modalActionType, flowActionType } = params; | ||
253 | + // const { createRuleChainModalActionType } = modalActionType; | ||
254 | + // const result = (await unref(createRuleChainModalActionType)?.openCreateRuleChainModal()) as { | ||
255 | + // name: string; | ||
256 | + // additionalInfo: { description: string }; | ||
257 | + // }; | ||
258 | + // const ruleChainDetail = await saveRuleChainDetail( | ||
259 | + // Object.assign(result, { debugger: false, type: 'CORE' }) as Partial<RuleChainDetail> | ||
260 | + // ); | ||
261 | + // const selectedNodes = unref(flowActionType?.getSelectedNodes); | ||
262 | + // const selectedEdges = unref(flowActionType?.getSelectedEdges); | ||
263 | + // const { firstNodeIndex, connections, nodes, outputEdgesId } = transformToRuleChain( | ||
264 | + // selectedNodes, | ||
265 | + // selectedEdges | ||
266 | + // ); | ||
267 | + // await saveRuleChainData({ | ||
268 | + // firstNodeIndex, | ||
269 | + // connections, | ||
270 | + // nodes, | ||
271 | + // ruleChainId: ruleChainDetail.id, | ||
272 | + // }); | ||
273 | + // const outputEdges = outputEdgesId.map((id) => flowActionType?.findEdge(id)); | ||
274 | + // console.log(getElementsCenter(unref(selectedNodes))); | ||
275 | + // const { originX, originY } = getElementsCenter(unref(selectedNodes)); | ||
276 | + // const {} = useNewNode(); | ||
277 | + // flowActionType?.removeNodes(selectedNodes || []); | ||
278 | + // flowActionType?.removeEdges(selectedEdges || []); | ||
279 | + // useSaveAndRedoActionType?.triggerChange(); | ||
280 | + }; | ||
281 | + | ||
203 | const handleContextMenuAction = (params: HandleContextMenuActionParamsType) => { | 282 | const handleContextMenuAction = (params: HandleContextMenuActionParamsType) => { |
204 | const { menuType } = params; | 283 | const { menuType } = params; |
205 | 284 | ||
@@ -213,6 +292,7 @@ export function useContextMenuAction() { | @@ -213,6 +292,7 @@ export function useContextMenuAction() { | ||
213 | [RuleContextMenuEnum.SELECT_COPY]: selectCopy, | 292 | [RuleContextMenuEnum.SELECT_COPY]: selectCopy, |
214 | [RuleContextMenuEnum.APPLY_CHANGE]: applyChange, | 293 | [RuleContextMenuEnum.APPLY_CHANGE]: applyChange, |
215 | [RuleContextMenuEnum.UNDO_CHANGE]: undoChange, | 294 | [RuleContextMenuEnum.UNDO_CHANGE]: undoChange, |
295 | + [RuleContextMenuEnum.CREATE_RULE_CHAIN]: createRuleChain, | ||
216 | }; | 296 | }; |
217 | 297 | ||
218 | if (handlerMapping[menuType]) { | 298 | if (handlerMapping[menuType]) { |
@@ -5,6 +5,7 @@ import type { CreateNodeModal } from '../src/components/CreateNodeModal'; | @@ -5,6 +5,7 @@ import type { CreateNodeModal } from '../src/components/CreateNodeModal'; | ||
5 | import type { CreateEdgeModal } from '../src/components/CreateEdgeModal'; | 5 | import type { CreateEdgeModal } from '../src/components/CreateEdgeModal'; |
6 | import { UpdateNodeDrawer } from '../src/components/UpdateNodeDrawer'; | 6 | import { UpdateNodeDrawer } from '../src/components/UpdateNodeDrawer'; |
7 | import { UpdateEdgeDrawer } from '../src/components/UpdateEdgeDrawer'; | 7 | import { UpdateEdgeDrawer } from '../src/components/UpdateEdgeDrawer'; |
8 | +import { CreateRuleChainModal } from '../src/components/CreateRuleChainModal'; | ||
8 | 9 | ||
9 | const SYMBOL = Symbol('flow-context'); | 10 | const SYMBOL = Symbol('flow-context'); |
10 | 11 | ||
@@ -30,6 +31,11 @@ interface FlowContextOptionsType { | @@ -30,6 +31,11 @@ interface FlowContextOptionsType { | ||
30 | updateEdgeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>; | 31 | updateEdgeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>; |
31 | 32 | ||
32 | /** | 33 | /** |
34 | + * @description 创建规则链 actions | ||
35 | + */ | ||
36 | + createRuleChainModalActionType: Ref<Nullable<InstanceType<typeof CreateRuleChainModal>>>; | ||
37 | + | ||
38 | + /** | ||
33 | * @description vue flow store | 39 | * @description vue flow store |
34 | */ | 40 | */ |
35 | flowActionType: VueFlowStore; | 41 | flowActionType: VueFlowStore; |
src/views/rule/designer/hook/useNewNode.ts
renamed from
src/views/rule/designer/hook/useInputNode.ts
1 | +import { XYPosition } from '@vue-flow/core'; | ||
1 | import { Config as InputConfig } from '../packages/Entry/Input/config'; | 2 | import { Config as InputConfig } from '../packages/Entry/Input/config'; |
3 | +import { Config as OutputConfig } from '../packages/Flow/Output/config'; | ||
4 | +import { Config as RuleChainConfig } from '../packages/Flow/RuleChain/config'; | ||
2 | import { useAddNodes } from './useAddNodes'; | 5 | import { useAddNodes } from './useAddNodes'; |
3 | 6 | ||
4 | -export function useInputNode() { | 7 | +export function useNewNode() { |
5 | const getInputNodeConfig = (id?: string) => { | 8 | const getInputNodeConfig = (id?: string) => { |
6 | const { getAddNodesParams } = useAddNodes(); | 9 | const { getAddNodesParams } = useAddNodes(); |
7 | 10 | ||
@@ -20,5 +23,38 @@ export function useInputNode() { | @@ -20,5 +23,38 @@ export function useInputNode() { | ||
20 | return newNode; | 23 | return newNode; |
21 | }; | 24 | }; |
22 | 25 | ||
23 | - return { getInputNodeConfig }; | 26 | + const getOutputNodeConfig = (name: string, position: XYPosition, id?: string) => { |
27 | + const { getAddNodesParams } = useAddNodes(); | ||
28 | + | ||
29 | + const newNode = getAddNodesParams( | ||
30 | + position, | ||
31 | + { | ||
32 | + ...new OutputConfig(), | ||
33 | + data: { | ||
34 | + name, | ||
35 | + }, | ||
36 | + }, | ||
37 | + { id, draggable: false, selectable: false } | ||
38 | + ); | ||
39 | + | ||
40 | + return newNode; | ||
41 | + }; | ||
42 | + | ||
43 | + const getRuleChainNodeConfig = (name: string, position: XYPosition, id?: string) => { | ||
44 | + const { getAddNodesParams } = useAddNodes(); | ||
45 | + const newNode = getAddNodesParams( | ||
46 | + position, | ||
47 | + { | ||
48 | + ...new RuleChainConfig(), | ||
49 | + data: { name }, | ||
50 | + }, | ||
51 | + { | ||
52 | + id, | ||
53 | + } | ||
54 | + ); | ||
55 | + | ||
56 | + return newNode; | ||
57 | + }; | ||
58 | + | ||
59 | + return { getInputNodeConfig, getOutputNodeConfig, getRuleChainNodeConfig }; | ||
24 | } | 60 | } |
@@ -27,14 +27,19 @@ import { RuleChainDetail } from '../types/ruleNode'; | @@ -27,14 +27,19 @@ import { RuleChainDetail } from '../types/ruleNode'; | ||
27 | import { useContextMenuAction } from './useContextMenuAction'; | 27 | import { useContextMenuAction } from './useContextMenuAction'; |
28 | import { useSaveAndRedo } from './useSaveAndRedo'; | 28 | import { useSaveAndRedo } from './useSaveAndRedo'; |
29 | import { EntryCategoryComponentEnum } from '../enum/category'; | 29 | import { EntryCategoryComponentEnum } from '../enum/category'; |
30 | +import { CreateRuleChainModal } from '../src/components/CreateRuleChainModal'; | ||
31 | +import { useBasicDataTransform } from './useBasicDataTransform'; | ||
30 | 32 | ||
31 | interface UseRuleFlowOptionsType { | 33 | interface UseRuleFlowOptionsType { |
32 | id: string; | 34 | id: string; |
33 | ruleChainDetail: Ref<RuleChainDetail | undefined>; | 35 | 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>>>; | 36 | + modalActionType: { |
37 | + createNodeModalActionType: Ref<Nullable<InstanceType<typeof CreateNodeModal>>>; | ||
38 | + createEdgeModalActionType: Ref<Nullable<InstanceType<typeof CreateEdgeModal>>>; | ||
39 | + updateNodeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateNodeDrawer>>>; | ||
40 | + updateEdgeDrawerActionType: Ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>; | ||
41 | + createRuleChainModalActionType: Ref<Nullable<InstanceType<typeof CreateRuleChainModal>>>; | ||
42 | + }; | ||
38 | useSaveAndRedoActionType: ReturnType<typeof useSaveAndRedo>; | 43 | useSaveAndRedoActionType: ReturnType<typeof useSaveAndRedo>; |
39 | } | 44 | } |
40 | 45 | ||
@@ -47,14 +52,10 @@ const validateInputAndOutput: ValidConnectionFunc = (connection: Connection) => | @@ -47,14 +52,10 @@ const validateInputAndOutput: ValidConnectionFunc = (connection: Connection) => | ||
47 | }; | 52 | }; |
48 | 53 | ||
49 | export function useRuleFlow(options: UseRuleFlowOptionsType) { | 54 | export function useRuleFlow(options: UseRuleFlowOptionsType) { |
50 | - const { | ||
51 | - id, | ||
52 | - ruleChainDetail, | ||
53 | - createEdgeModalActionType, | ||
54 | - updateEdgeDrawerActionType, | ||
55 | - updateNodeDrawerActionType, | ||
56 | - useSaveAndRedoActionType, | ||
57 | - } = options; | 55 | + const { id, ruleChainDetail, modalActionType, useSaveAndRedoActionType } = options; |
56 | + | ||
57 | + const { createEdgeModalActionType, updateEdgeDrawerActionType, updateNodeDrawerActionType } = | ||
58 | + modalActionType; | ||
58 | 59 | ||
59 | const { triggerChange } = useSaveAndRedoActionType; | 60 | const { triggerChange } = useSaveAndRedoActionType; |
60 | 61 | ||
@@ -162,29 +163,35 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { | @@ -162,29 +163,35 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { | ||
162 | 163 | ||
163 | const { handleContextMenuAction } = useContextMenuAction(); | 164 | const { handleContextMenuAction } = useContextMenuAction(); |
164 | 165 | ||
166 | + const { validateCanCreateRuleChain } = useBasicDataTransform(); | ||
167 | + | ||
165 | onNodeContextMenu(async (params) => { | 168 | onNodeContextMenu(async (params) => { |
166 | const menuType = params.node.selected | 169 | const menuType = params.node.selected |
167 | ? await createElementsSelectedContextMenu( | 170 | ? await createElementsSelectedContextMenu( |
168 | params, | 171 | params, |
169 | unref(useSaveAndRedoActionType.changeMarker), | 172 | unref(useSaveAndRedoActionType.changeMarker), |
170 | - validateSelectionElementsCanCreateRuleChain() | 173 | + validateCanCreateRuleChain( |
174 | + flowActionType.getSelectedNodes, | ||
175 | + flowActionType.getSelectedEdges | ||
176 | + ).flag | ||
171 | ) | 177 | ) |
172 | : await createNodeContextMenu(params); | 178 | : await createNodeContextMenu(params); |
173 | 179 | ||
174 | - if (menuType) { | ||
175 | - if (menuType === RuleContextMenuEnum.DETAIL) { | ||
176 | - handleUpdateNode(params.node); | ||
177 | - return; | ||
178 | - } | 180 | + if (!menuType) return; |
179 | 181 | ||
180 | - handleContextMenuAction({ | ||
181 | - menuType, | ||
182 | - flowActionType, | ||
183 | - event: params.event, | ||
184 | - node: params.node, | ||
185 | - useSaveAndRedoActionType, | ||
186 | - }); | 182 | + if (menuType === RuleContextMenuEnum.DETAIL) { |
183 | + handleUpdateNode(params.node); | ||
184 | + return; | ||
187 | } | 185 | } |
186 | + | ||
187 | + handleContextMenuAction({ | ||
188 | + menuType, | ||
189 | + flowActionType, | ||
190 | + event: params.event, | ||
191 | + node: params.node, | ||
192 | + useSaveAndRedoActionType, | ||
193 | + modalActionType, | ||
194 | + }); | ||
188 | }); | 195 | }); |
189 | 196 | ||
190 | onEdgeContextMenu(async (params) => { | 197 | onEdgeContextMenu(async (params) => { |
@@ -207,6 +214,7 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { | @@ -207,6 +214,7 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { | ||
207 | event: params.event, | 214 | event: params.event, |
208 | useSaveAndRedoActionType, | 215 | useSaveAndRedoActionType, |
209 | edge: params.edge, | 216 | edge: params.edge, |
217 | + modalActionType, | ||
210 | }); | 218 | }); |
211 | } | 219 | } |
212 | }); | 220 | }); |
@@ -216,21 +224,25 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { | @@ -216,21 +224,25 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { | ||
216 | ? await createElementsSelectedContextMenu( | 224 | ? await createElementsSelectedContextMenu( |
217 | getCreatePanelContextMenuParams(params), | 225 | getCreatePanelContextMenuParams(params), |
218 | unref(useSaveAndRedoActionType.changeMarker), | 226 | unref(useSaveAndRedoActionType.changeMarker), |
219 | - validateSelectionElementsCanCreateRuleChain() | 227 | + validateCanCreateRuleChain( |
228 | + flowActionType.getSelectedNodes, | ||
229 | + flowActionType.getSelectedEdges | ||
230 | + ).flag | ||
220 | ) | 231 | ) |
221 | : await createPanelContextMenu( | 232 | : await createPanelContextMenu( |
222 | getCreatePanelContextMenuParams(params), | 233 | getCreatePanelContextMenuParams(params), |
223 | unref(useSaveAndRedoActionType.changeMarker) | 234 | unref(useSaveAndRedoActionType.changeMarker) |
224 | ); | 235 | ); |
225 | 236 | ||
226 | - if (menuType) { | ||
227 | - handleContextMenuAction({ | ||
228 | - menuType, | ||
229 | - flowActionType, | ||
230 | - event: params, | ||
231 | - useSaveAndRedoActionType, | ||
232 | - }); | ||
233 | - } | 237 | + if (!menuType) return; |
238 | + | ||
239 | + handleContextMenuAction({ | ||
240 | + menuType, | ||
241 | + flowActionType, | ||
242 | + event: params, | ||
243 | + useSaveAndRedoActionType, | ||
244 | + modalActionType, | ||
245 | + }); | ||
234 | }); | 246 | }); |
235 | 247 | ||
236 | /** | 248 | /** |
@@ -382,17 +394,5 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { | @@ -382,17 +394,5 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { | ||
382 | } as NodeMouseEvent; | 394 | } as NodeMouseEvent; |
383 | } | 395 | } |
384 | 396 | ||
385 | - function validateSelectionElementsCanCreateRuleChain() { | ||
386 | - const nodes = unref(flowActionType.getSelectedNodes); | ||
387 | - const edges = unref(flowActionType.getSelectedEdges); | ||
388 | - | ||
389 | - for (const node of nodes) { | ||
390 | - const index = edges.findIndex((edge) => edge.target === node.id || edge.source === node.id); | ||
391 | - if (!~index) return false; | ||
392 | - } | ||
393 | - | ||
394 | - return true; | ||
395 | - } | ||
396 | - | ||
397 | return { flowActionType }; | 397 | return { flowActionType }; |
398 | } | 398 | } |
1 | -import type { VueFlowStore, Getters, Elements } from '@vue-flow/core'; | ||
2 | -import { ComputedRef, computed, ref, unref } from 'vue'; | ||
3 | -import { BasicNodeBindData, EdgeData, NodeData } from '../types/node'; | ||
4 | -import { EntryCategoryComponentEnum } from '../enum/category'; | 1 | +import type { VueFlowStore, Elements } from '@vue-flow/core'; |
2 | +import { computed, ref, unref } from 'vue'; | ||
3 | +import { BasicNodeBindData, NodeData } from '../types/node'; | ||
5 | import { useBasicDataTransform } from './useBasicDataTransform'; | 4 | import { useBasicDataTransform } from './useBasicDataTransform'; |
6 | import { | 5 | import { |
7 | getRuleChainData, | 6 | getRuleChainData, |
@@ -10,15 +9,13 @@ import { | @@ -10,15 +9,13 @@ import { | ||
10 | saveRuleChainDetail, | 9 | saveRuleChainDetail, |
11 | } from '/@/api/ruleDesigner'; | 10 | } from '/@/api/ruleDesigner'; |
12 | import { ConnectionItemType, RuleChainDetail, RuleChainType } from '../types/ruleNode'; | 11 | import { ConnectionItemType, RuleChainDetail, RuleChainType } from '../types/ruleNode'; |
13 | -import { useInputNode } from './useInputNode'; | 12 | +import { useNewNode } from './useNewNode'; |
14 | import { buildUUID } from '/@/utils/uuid'; | 13 | import { buildUUID } from '/@/utils/uuid'; |
15 | import { useRoute, useRouter } from 'vue-router'; | 14 | import { useRoute, useRouter } from 'vue-router'; |
16 | import { RuleChainEntityType } from '../enum/entity'; | 15 | import { RuleChainEntityType } from '../enum/entity'; |
17 | import { PageEnum } from '/@/enums/pageEnum'; | 16 | import { PageEnum } from '/@/enums/pageEnum'; |
18 | import { clearRuleChainImportCache, getRuleChainImportCache } from './useRuleChainCache'; | 17 | import { clearRuleChainImportCache, getRuleChainImportCache } from './useRuleChainCache'; |
19 | 18 | ||
20 | -const ignoreNodeKeys: string[] = [EntryCategoryComponentEnum.INPUT]; | ||
21 | - | ||
22 | export function useSaveAndRedo() { | 19 | export function useSaveAndRedo() { |
23 | const changeMarker = ref(false); | 20 | const changeMarker = ref(false); |
24 | 21 | ||
@@ -38,7 +35,7 @@ export function useSaveAndRedo() { | @@ -38,7 +35,7 @@ export function useSaveAndRedo() { | ||
38 | 35 | ||
39 | const ruleChainDetail = ref<RuleChainDetail>(); | 36 | const ruleChainDetail = ref<RuleChainDetail>(); |
40 | 37 | ||
41 | - const { mergeData, deconstructionData } = useBasicDataTransform(); | 38 | + const { combineData, deconstructionData } = useBasicDataTransform(); |
42 | 39 | ||
43 | const triggerChange = () => { | 40 | const triggerChange = () => { |
44 | changeMarker.value = true; | 41 | changeMarker.value = true; |
@@ -48,90 +45,14 @@ export function useSaveAndRedo() { | @@ -48,90 +45,14 @@ export function useSaveAndRedo() { | ||
48 | changeMarker.value = false; | 45 | changeMarker.value = false; |
49 | }; | 46 | }; |
50 | 47 | ||
51 | - /** | ||
52 | - * @description 保存连接信息 | ||
53 | - */ | ||
54 | - function getConnections( | ||
55 | - nodesRef: ComputedRef<Getters['getNodes']> | Getters['getNodes'], | ||
56 | - edges: ComputedRef<Getters['getEdges']> | ||
57 | - ) { | ||
58 | - const nodeIndexMap = new Map(); | ||
59 | - | ||
60 | - const connections: ConnectionItemType[] = []; | ||
61 | - | ||
62 | - unref(nodesRef).forEach((item, index) => { | ||
63 | - nodeIndexMap.set(item.id, index); | ||
64 | - }); | ||
65 | - | ||
66 | - for (const item of unref(edges)) { | ||
67 | - const { data, target, source } = item; | ||
68 | - const { data: bindData } = data as EdgeData; | ||
69 | - const { type } = bindData || {}; | ||
70 | - const fromIndex = nodeIndexMap.get(source); | ||
71 | - const toIndex = nodeIndexMap.get(target); | ||
72 | - type?.forEach((key) => { | ||
73 | - connections.push({ fromIndex, toIndex, type: key }); | ||
74 | - }); | ||
75 | - } | ||
76 | - | ||
77 | - return connections; | ||
78 | - } | ||
79 | - | ||
80 | - function getNodes(nodesRef: ComputedRef<Getters['getNodes']> | Getters['getNodes']) { | ||
81 | - const nodes: BasicNodeBindData[] = []; | ||
82 | - | ||
83 | - for (const node of unref(nodesRef)) { | ||
84 | - const nodeData = node.data as NodeData; | ||
85 | - | ||
86 | - if (ignoreNodeKeys.includes(nodeData.config?.key as string)) continue; | ||
87 | - | ||
88 | - const data = nodeData.data; | ||
89 | - | ||
90 | - nodes.push( | ||
91 | - Object.assign( | ||
92 | - mergeData(data, nodeData, node), | ||
93 | - nodeData.created | ||
94 | - ? ({ | ||
95 | - id: { id: node.id, entityType: RuleChainEntityType.RULE_NODE }, | ||
96 | - } as BasicNodeBindData) | ||
97 | - : {} | ||
98 | - ) | ||
99 | - ); | ||
100 | - } | ||
101 | - | ||
102 | - return nodes; | ||
103 | - } | ||
104 | - | ||
105 | - function getFirsetNodeIndex( | ||
106 | - nodesRef: ComputedRef<Getters['getNodes']> | Getters['getNodes'], | ||
107 | - edges: ComputedRef<Getters['getEdges']> | ||
108 | - ) { | ||
109 | - const inputNode = unref(edges).find( | ||
110 | - (item) => (item.sourceNode.data as NodeData).config?.key === EntryCategoryComponentEnum.INPUT | ||
111 | - ); | ||
112 | - | ||
113 | - if (inputNode) { | ||
114 | - const targetId = inputNode.target; | ||
115 | - const index = unref(nodesRef).findIndex((item) => item.id === targetId); | ||
116 | - return index; | ||
117 | - } | ||
118 | - } | ||
119 | - | ||
120 | const handleApplyChange = (flowActionType: VueFlowStore) => { | 48 | const handleApplyChange = (flowActionType: VueFlowStore) => { |
121 | if (!unref(changeMarker)) return; | 49 | if (!unref(changeMarker)) return; |
122 | 50 | ||
123 | - const edgesRef = flowActionType.getEdges; | ||
124 | - | ||
125 | - const extraIgnoreNodeRef = unref(flowActionType.getNodes).filter( | ||
126 | - (item) => !ignoreNodeKeys.includes((item.data as NodeData).config?.key as string) | 51 | + const { connections, nodes, firstNodeIndex } = combineData( |
52 | + flowActionType.getNodes, | ||
53 | + flowActionType.getEdges | ||
127 | ); | 54 | ); |
128 | 55 | ||
129 | - const connections = getConnections(extraIgnoreNodeRef, edgesRef); | ||
130 | - | ||
131 | - const nodes = getNodes(extraIgnoreNodeRef); | ||
132 | - | ||
133 | - const firstNodeIndex = getFirsetNodeIndex(extraIgnoreNodeRef, edgesRef); | ||
134 | - | ||
135 | handleSaveRuleChain(connections, nodes, firstNodeIndex); | 56 | handleSaveRuleChain(connections, nodes, firstNodeIndex); |
136 | }; | 57 | }; |
137 | 58 | ||
@@ -211,7 +132,7 @@ export function useSaveAndRedo() { | @@ -211,7 +132,7 @@ export function useSaveAndRedo() { | ||
211 | function parseRuleChain(ruleChain: RuleChainType) { | 132 | function parseRuleChain(ruleChain: RuleChainType) { |
212 | const inputId = buildUUID(); | 133 | const inputId = buildUUID(); |
213 | 134 | ||
214 | - const { getInputNodeConfig } = useInputNode(); | 135 | + const { getInputNodeConfig } = useNewNode(); |
215 | 136 | ||
216 | const value = deconstructionData(ruleChain, inputId); | 137 | const value = deconstructionData(ruleChain, inputId); |
217 | 138 |
@@ -19,10 +19,11 @@ | @@ -19,10 +19,11 @@ | ||
19 | import { CreateEdgeModal } from './src/components/CreateEdgeModal'; | 19 | import { CreateEdgeModal } from './src/components/CreateEdgeModal'; |
20 | import { useFullScreen } from './hook/useFullScreen'; | 20 | import { useFullScreen } from './hook/useFullScreen'; |
21 | import { useSaveAndRedo } from './hook/useSaveAndRedo'; | 21 | import { useSaveAndRedo } from './hook/useSaveAndRedo'; |
22 | + import { NodeData } from './types/node'; | ||
22 | import { Icon } from '/@/components/Icon'; | 23 | import { Icon } from '/@/components/Icon'; |
23 | import { UpdateNodeDrawer } from './src/components/UpdateNodeDrawer'; | 24 | import { UpdateNodeDrawer } from './src/components/UpdateNodeDrawer'; |
24 | import { UpdateEdgeDrawer } from './src/components/UpdateEdgeDrawer'; | 25 | import { UpdateEdgeDrawer } from './src/components/UpdateEdgeDrawer'; |
25 | - import { NodeData } from './types/node'; | 26 | + import { CreateRuleChainModal } from './src/components/CreateRuleChainModal'; |
26 | 27 | ||
27 | const getId = Number(Math.random().toString().substring(2)).toString(16); | 28 | const getId = Number(Math.random().toString().substring(2)).toString(16); |
28 | 29 | ||
@@ -36,6 +37,9 @@ | @@ -36,6 +37,9 @@ | ||
36 | 37 | ||
37 | const updateEdgeDrawerActionType = ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>(null); | 38 | const updateEdgeDrawerActionType = ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>(null); |
38 | 39 | ||
40 | + const createRuleChainModalActionType = | ||
41 | + ref<Nullable<InstanceType<typeof CreateRuleChainModal>>>(null); | ||
42 | + | ||
39 | const flowElRef = ref<Nullable<FlowElRef>>(null); | 43 | const flowElRef = ref<Nullable<FlowElRef>>(null); |
40 | 44 | ||
41 | const elements = ref([]); | 45 | const elements = ref([]); |
@@ -57,11 +61,14 @@ | @@ -57,11 +61,14 @@ | ||
57 | const { flowActionType } = useRuleFlow({ | 61 | const { flowActionType } = useRuleFlow({ |
58 | id: getId, | 62 | id: getId, |
59 | ruleChainDetail, | 63 | ruleChainDetail, |
60 | - createNodeModalActionType, | ||
61 | - createEdgeModalActionType, | ||
62 | - updateEdgeDrawerActionType, | ||
63 | - updateNodeDrawerActionType, | ||
64 | useSaveAndRedoActionType, | 64 | useSaveAndRedoActionType, |
65 | + modalActionType: { | ||
66 | + createNodeModalActionType, | ||
67 | + createEdgeModalActionType, | ||
68 | + updateEdgeDrawerActionType, | ||
69 | + updateNodeDrawerActionType, | ||
70 | + createRuleChainModalActionType, | ||
71 | + }, | ||
65 | }); | 72 | }); |
66 | 73 | ||
67 | const { handleOnDragOver, handleOnDrop } = useDragCreate({ | 74 | const { handleOnDragOver, handleOnDrop } = useDragCreate({ |
@@ -85,6 +92,8 @@ | @@ -85,6 +92,8 @@ | ||
85 | 92 | ||
86 | const handleDeleteSelectionElements = () => { | 93 | const handleDeleteSelectionElements = () => { |
87 | flowActionType.removeNodes(unref(flowActionType.getSelectedNodes)); | 94 | flowActionType.removeNodes(unref(flowActionType.getSelectedNodes)); |
95 | + flowActionType.removeEdges(unref(flowActionType.getSelectedEdges)); | ||
96 | + useSaveAndRedoActionType.triggerChange?.(); | ||
88 | }; | 97 | }; |
89 | 98 | ||
90 | onMounted(() => { | 99 | onMounted(() => { |
@@ -97,6 +106,7 @@ | @@ -97,6 +106,7 @@ | ||
97 | createNodeModalActionType, | 106 | createNodeModalActionType, |
98 | updateEdgeDrawerActionType, | 107 | updateEdgeDrawerActionType, |
99 | updateNodeDrawerActionType, | 108 | updateNodeDrawerActionType, |
109 | + createRuleChainModalActionType, | ||
100 | flowActionType, | 110 | flowActionType, |
101 | triggerChange, | 111 | triggerChange, |
102 | }); | 112 | }); |
@@ -177,6 +187,8 @@ | @@ -177,6 +187,8 @@ | ||
177 | 187 | ||
178 | <UpdateEdgeDrawer ref="updateEdgeDrawerActionType" /> | 188 | <UpdateEdgeDrawer ref="updateEdgeDrawerActionType" /> |
179 | <UpdateNodeDrawer ref="updateNodeDrawerActionType" /> | 189 | <UpdateNodeDrawer ref="updateNodeDrawerActionType" /> |
190 | + | ||
191 | + <CreateRuleChainModal ref="createRuleChainModalActionType" /> | ||
180 | </main> | 192 | </main> |
181 | </template> | 193 | </template> |
182 | 194 |
1 | +import { FormSchema } from '/@/components/Form'; | ||
2 | + | ||
3 | +export enum FormFieldsEnum { | ||
4 | + NAME = 'name', | ||
5 | + DESCRIPTION = 'description', | ||
6 | + ADDITIONAL_INFO = 'additionalInfo', | ||
7 | +} | ||
8 | + | ||
9 | +export enum FormFieldsNameEnum { | ||
10 | + NAME = '名称', | ||
11 | + DESCRIPTION = '说明', | ||
12 | +} | ||
13 | + | ||
14 | +export const formSchemas: FormSchema[] = [ | ||
15 | + { | ||
16 | + field: FormFieldsEnum.NAME, | ||
17 | + label: FormFieldsNameEnum.NAME, | ||
18 | + component: 'Input', | ||
19 | + required: true, | ||
20 | + componentProps: { | ||
21 | + placeholder: `请输入${FormFieldsNameEnum.NAME}`, | ||
22 | + }, | ||
23 | + }, | ||
24 | + { | ||
25 | + field: FormFieldsEnum.DESCRIPTION, | ||
26 | + label: FormFieldsNameEnum.DESCRIPTION, | ||
27 | + component: 'InputTextArea', | ||
28 | + componentProps: { | ||
29 | + placeholder: `请输入${FormFieldsNameEnum.DESCRIPTION}`, | ||
30 | + }, | ||
31 | + }, | ||
32 | +]; |
1 | +export { default as CreateRuleChainModal } from './index.vue'; |
1 | +<script setup lang="ts"> | ||
2 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | ||
3 | + import { BasicForm, useForm } from '/@/components/Form'; | ||
4 | + import { formSchemas, FormFieldsEnum } from './config'; | ||
5 | + import { ref } from 'vue'; | ||
6 | + | ||
7 | + interface SaveParamsType { | ||
8 | + name: string; | ||
9 | + additional: { description: string }; | ||
10 | + } | ||
11 | + | ||
12 | + const visible = ref(false); | ||
13 | + | ||
14 | + const [register, { closeModal }] = useModalInner(); | ||
15 | + | ||
16 | + const [registerForm, { getFieldsValue, validate }] = useForm({ | ||
17 | + schemas: formSchemas, | ||
18 | + showActionButtonGroup: false, | ||
19 | + layout: 'vertical', | ||
20 | + }); | ||
21 | + | ||
22 | + let resolveFn: undefined | ((value: SaveParamsType) => any); | ||
23 | + | ||
24 | + const openCreateRuleChainModal = async (): Promise<{ | ||
25 | + name: string; | ||
26 | + additionalInfo: { description: string }; | ||
27 | + }> => { | ||
28 | + visible.value = true; | ||
29 | + return new Promise((resolve) => { | ||
30 | + resolveFn = resolve; | ||
31 | + }); | ||
32 | + }; | ||
33 | + | ||
34 | + const handleSave = async () => { | ||
35 | + await validate(); | ||
36 | + const value = getFieldsValue(); | ||
37 | + resolveFn?.({ | ||
38 | + name: value[FormFieldsEnum.NAME], | ||
39 | + additional: { description: value[FormFieldsEnum.DESCRIPTION] || '' }, | ||
40 | + }); | ||
41 | + closeModal(); | ||
42 | + }; | ||
43 | + | ||
44 | + defineExpose({ openCreateRuleChainModal }); | ||
45 | +</script> | ||
46 | + | ||
47 | +<template> | ||
48 | + <BasicModal | ||
49 | + v-model:visible="visible" | ||
50 | + @register="register" | ||
51 | + @ok="handleSave" | ||
52 | + title="Create nested rule chain" | ||
53 | + > | ||
54 | + <BasicForm @register="registerForm" /> | ||
55 | + </BasicModal> | ||
56 | +</template> |
@@ -24,7 +24,7 @@ export interface RuleChainDetail { | @@ -24,7 +24,7 @@ export interface RuleChainDetail { | ||
24 | createdTime: number; | 24 | createdTime: number; |
25 | additionalInfo: AdditionalInfo; | 25 | additionalInfo: AdditionalInfo; |
26 | tenantId: Id; | 26 | tenantId: Id; |
27 | - name: Id; | 27 | + name: string; |
28 | type: string; | 28 | type: string; |
29 | firstRuleNodeId: Id; | 29 | firstRuleNodeId: Id; |
30 | root: boolean; | 30 | root: boolean; |
@@ -35,6 +35,7 @@ | @@ -35,6 +35,7 @@ | ||
35 | const { proxy } = getCurrentInstance() as any; | 35 | const { proxy } = getCurrentInstance() as any; |
36 | const getChildData = ref(null); | 36 | const getChildData = ref(null); |
37 | const editGetId: any = ref(''); | 37 | const editGetId: any = ref(''); |
38 | + const createTime = ref<string>(''); | ||
38 | const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({ | 39 | const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({ |
39 | schemas: formSchema, | 40 | schemas: formSchema, |
40 | showActionButtonGroup: false, | 41 | showActionButtonGroup: false, |
@@ -57,6 +58,7 @@ | @@ -57,6 +58,7 @@ | ||
57 | await setFieldsValue({ | 58 | await setFieldsValue({ |
58 | ...data.record, | 59 | ...data.record, |
59 | }); | 60 | }); |
61 | + createTime.value = data.record.createdTime; | ||
60 | updateStatusSchema(true); | 62 | updateStatusSchema(true); |
61 | } | 63 | } |
62 | }); | 64 | }); |
@@ -79,7 +81,7 @@ | @@ -79,7 +81,7 @@ | ||
79 | ]); | 81 | ]); |
80 | }; | 82 | }; |
81 | 83 | ||
82 | - const getAllFieldsFunc = async () => { | 84 | + const getAllFieldsFunc = async (isUpdate?: boolean) => { |
83 | getValuesFormData = await validate(); | 85 | getValuesFormData = await validate(); |
84 | if (!getValuesFormData) return; | 86 | if (!getValuesFormData) return; |
85 | let getChildValues = proxy.$refs.getChildData.getAllFields(); | 87 | let getChildValues = proxy.$refs.getChildData.getAllFields(); |
@@ -90,10 +92,9 @@ | @@ -90,10 +92,9 @@ | ||
90 | id: unref(isUpdate) ? editGetId.value : '', | 92 | id: unref(isUpdate) ? editGetId.value : '', |
91 | }; | 93 | }; |
92 | 94 | ||
93 | - const createTime = { | ||
94 | - createdTime: Date.now(), | 95 | + const createTime1 = { |
96 | + createdTime: isUpdate ? unref(createTime) : Date.now(), | ||
95 | }; | 97 | }; |
96 | - | ||
97 | Object.assign( | 98 | Object.assign( |
98 | postAllData, | 99 | postAllData, |
99 | { | 100 | { |
@@ -101,7 +102,7 @@ | @@ -101,7 +102,7 @@ | ||
101 | }, | 102 | }, |
102 | getValuesFormData, | 103 | getValuesFormData, |
103 | id, | 104 | id, |
104 | - createTime | 105 | + createTime1 |
105 | ); | 106 | ); |
106 | if (!unref(isUpdate)) { | 107 | if (!unref(isUpdate)) { |
107 | delete postAllData.id; | 108 | delete postAllData.id; |
@@ -119,7 +120,7 @@ | @@ -119,7 +120,7 @@ | ||
119 | emit('success'); | 120 | emit('success'); |
120 | resetFields(); | 121 | resetFields(); |
121 | } else { | 122 | } else { |
122 | - await getAllFieldsFunc(); | 123 | + await getAllFieldsFunc(true); |
123 | await saveTenantProfileApi(postAllData); | 124 | await saveTenantProfileApi(postAllData); |
124 | createMessage.success('租户配置编辑成功'); | 125 | createMessage.success('租户配置编辑成功'); |
125 | closeDrawer(); | 126 | closeDrawer(); |
@@ -173,10 +173,12 @@ | @@ -173,10 +173,12 @@ | ||
173 | const { codeType, customCommand } = unref(getDesign) || {}; | 173 | const { codeType, customCommand } = unref(getDesign) || {}; |
174 | const { transportType } = customCommand || {}; | 174 | const { transportType } = customCommand || {}; |
175 | const sendValue = ref<any>(unref(sliderValue)); | 175 | const sendValue = ref<any>(unref(sliderValue)); |
176 | + const isModbusCommand = ref<boolean>(false); | ||
176 | if (transportType == 'TCP' && codeType == TaskTypeEnum.MODBUS_RTU) { | 177 | if (transportType == 'TCP' && codeType == TaskTypeEnum.MODBUS_RTU) { |
177 | sendValue.value = await getSendValue(unref(sliderValue)); | 178 | sendValue.value = await getSendValue(unref(sliderValue)); |
179 | + isModbusCommand.value = true; | ||
178 | } | 180 | } |
179 | - const flag = await sendCommand(props.config.option, unref(sendValue), true); | 181 | + const flag = await sendCommand(props.config.option, unref(sendValue), unref(isModbusCommand)); |
180 | flag | 182 | flag |
181 | ? ((sliderValue.value = unref(sliderValue)), | 183 | ? ((sliderValue.value = unref(sliderValue)), |
182 | (oldSliderValue.value = sliderValue.value), | 184 | (oldSliderValue.value = sliderValue.value), |
@@ -12,7 +12,7 @@ | @@ -12,7 +12,7 @@ | ||
12 | import { useModalInner } from '/@/components/Modal'; | 12 | import { useModalInner } from '/@/components/Modal'; |
13 | import { getAllDeviceByOrg } from '/@/api/dataBoard'; | 13 | import { getAllDeviceByOrg } from '/@/api/dataBoard'; |
14 | import { useHistoryData } from '/@/views/device/list/hook/useHistoryData'; | 14 | import { useHistoryData } from '/@/views/device/list/hook/useHistoryData'; |
15 | - import { BasicTable, useTable } from '/@/components/Table'; | 15 | + import { BasicColumn, BasicTable, useTable } from '/@/components/Table'; |
16 | import { formatToDateTime } from '/@/utils/dateUtil'; | 16 | import { formatToDateTime } from '/@/utils/dateUtil'; |
17 | import { | 17 | import { |
18 | ModeSwitchButton, | 18 | ModeSwitchButton, |
@@ -112,18 +112,14 @@ | @@ -112,18 +112,14 @@ | ||
112 | return mapping; | 112 | return mapping; |
113 | }); | 113 | }); |
114 | 114 | ||
115 | - const [registerTable] = useTable({ | ||
116 | - showIndexColumn: false, | ||
117 | - showTableSetting: false, | ||
118 | - dataSource: historyData, | ||
119 | - maxHeight: 300, | ||
120 | - size: 'small', | ||
121 | - columns: [ | 115 | + const sortOrder = ref<any>('descend'); |
116 | + const columns: BasicColumn[] | any = computed(() => { | ||
117 | + return [ | ||
122 | { | 118 | { |
123 | title: '属性', | 119 | title: '属性', |
124 | dataIndex: 'name', | 120 | dataIndex: 'name', |
125 | - format: (value) => { | ||
126 | - return unref(getIdentifierNameMapping)[value]; | 121 | + format: (text) => { |
122 | + return unref(getIdentifierNameMapping)[text]; | ||
127 | }, | 123 | }, |
128 | }, | 124 | }, |
129 | { | 125 | { |
@@ -136,10 +132,47 @@ | @@ -136,10 +132,47 @@ | ||
136 | format: (val) => { | 132 | format: (val) => { |
137 | return formatToDateTime(val, 'YYYY-MM-DD HH:mm:ss'); | 133 | return formatToDateTime(val, 'YYYY-MM-DD HH:mm:ss'); |
138 | }, | 134 | }, |
135 | + sorter: true, | ||
136 | + sortOrder: unref(sortOrder), | ||
137 | + sortDirections: ['descend', 'ascend', 'descend'], | ||
139 | }, | 138 | }, |
140 | - ], | 139 | + ]; |
141 | }); | 140 | }); |
142 | 141 | ||
142 | + const [registerTable, { setColumns }] = useTable({ | ||
143 | + showIndexColumn: false, | ||
144 | + showTableSetting: false, | ||
145 | + dataSource: historyData, | ||
146 | + maxHeight: 300, | ||
147 | + size: 'small', | ||
148 | + columns: unref(columns), | ||
149 | + }); | ||
150 | + | ||
151 | + const getTableList = async (orderBy?: string) => { | ||
152 | + // 表单验证 | ||
153 | + await method.validate(); | ||
154 | + const value = method.getFieldsValue(); | ||
155 | + const searchParams = getSearchParams(value); | ||
156 | + if (!hasDeviceAttr()) return; | ||
157 | + // 发送请求 | ||
158 | + loading.value = true; | ||
159 | + const res = await getDeviceHistoryInfo(searchParams, orderBy); | ||
160 | + historyData.value = getTableHistoryData(res); | ||
161 | + loading.value = false; | ||
162 | + }; | ||
163 | + | ||
164 | + const handleTableChange = async (_pag, _filters, sorter: any) => { | ||
165 | + sortOrder.value = sorter.order; | ||
166 | + await setColumns(unref(columns)); | ||
167 | + if (sorter.field == 'ts') { | ||
168 | + if (sorter.order == 'descend') { | ||
169 | + getTableList('DESC'); | ||
170 | + } else { | ||
171 | + getTableList('ASC'); | ||
172 | + } | ||
173 | + } | ||
174 | + }; | ||
175 | + | ||
143 | const getDeviceDataKey = async (record: DeviceOption) => { | 176 | const getDeviceDataKey = async (record: DeviceOption) => { |
144 | const { organizationId, value } = record; | 177 | const { organizationId, value } = record; |
145 | try { | 178 | try { |
@@ -260,7 +293,7 @@ | @@ -260,7 +293,7 @@ | ||
260 | :show-ok-btn="false" | 293 | :show-ok-btn="false" |
261 | cancel-text="关闭" | 294 | cancel-text="关闭" |
262 | width="70%" | 295 | width="70%" |
263 | - title="选择时间" | 296 | + title="历史趋势" |
264 | > | 297 | > |
265 | <section | 298 | <section |
266 | class="flex flex-col p-4 h-full w-full min-w-7/10" | 299 | class="flex flex-col p-4 h-full w-full min-w-7/10" |
@@ -295,7 +328,11 @@ | @@ -295,7 +328,11 @@ | ||
295 | v-show="!isNull" | 328 | v-show="!isNull" |
296 | /> | 329 | /> |
297 | 330 | ||
298 | - <BasicTable v-show="mode === EnumTableChartMode.TABLE" @register="registerTable"> | 331 | + <BasicTable |
332 | + v-show="mode === EnumTableChartMode.TABLE" | ||
333 | + @change="handleTableChange" | ||
334 | + @register="registerTable" | ||
335 | + > | ||
299 | <template #toolbar> | 336 | <template #toolbar> |
300 | <div class="flex h-70px items-center justify-end p-2"> | 337 | <div class="flex h-70px items-center justify-end p-2"> |
301 | <ModeSwitchButton | 338 | <ModeSwitchButton |