Showing
40 changed files
with
1214 additions
and
724 deletions
... | ... | @@ -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 | 16 | return defHttp.get<HistoryData>( |
17 | 17 | { |
18 | 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 | 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 | 230 | |
231 | 231 | function setFormModel(key: string, value: any) { |
232 | 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 | 239 | function handleEnterPress(e: KeyboardEvent) { | ... | ... |
... | ... | @@ -242,7 +242,7 @@ |
242 | 242 | const value = target ? (isCheck ? target.checked : target.value) : e; |
243 | 243 | props.setFormModel(field, value); |
244 | 244 | }, |
245 | - onBlur: (...args) => { | |
245 | + onBlur: (...args: any[]) => { | |
246 | 246 | unref(getComponentsProps)?.onBlur?.(...args); |
247 | 247 | props.validateFields([field], { triggerName: 'blur' }).catch((_) => {}); |
248 | 248 | }, | ... | ... |
... | ... | @@ -38,7 +38,7 @@ export const basicProps = { |
38 | 38 | }, |
39 | 39 | autoSetPlaceHolder: propTypes.bool.def(true), |
40 | 40 | // 在INPUT组件上单击回车时,是否自动提交 |
41 | - autoSubmitOnEnter: propTypes.bool.def(false), | |
41 | + autoSubmitOnEnter: propTypes.bool.def(true), | |
42 | 42 | submitOnReset: propTypes.bool, |
43 | 43 | size: propTypes.oneOf(['default', 'small', 'large']).def('default'), |
44 | 44 | // 禁用表单 | ... | ... |
... | ... | @@ -116,7 +116,7 @@ |
116 | 116 | const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); |
117 | 117 | const [registerModal, { openModal }] = useModal(); |
118 | 118 | // 表格hooks |
119 | - const [registerTable, { reload, setProps }] = useTable({ | |
119 | + const [registerTable, { reload, setProps, clearSelectedRowKeys }] = useTable({ | |
120 | 120 | title: '视频列表', |
121 | 121 | api: cameraPage, |
122 | 122 | columns, |
... | ... | @@ -145,6 +145,7 @@ |
145 | 145 | // 刷新 |
146 | 146 | const handleSuccess = () => { |
147 | 147 | reload(); |
148 | + clearSelectedRowKeys(); | |
148 | 149 | }; |
149 | 150 | const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( |
150 | 151 | deleteCameraManage, | ... | ... |
... | ... | @@ -2,9 +2,10 @@ |
2 | 2 | <div ref="chartRef" :style="{ height, width }"></div> |
3 | 3 | </template> |
4 | 4 | <script lang="ts" setup> |
5 | - import { ref, Ref, withDefaults, onMounted, watch } from 'vue'; | |
5 | + import { ref, Ref, onMounted, watch } from 'vue'; | |
6 | 6 | import { useECharts } from '/@/hooks/web/useECharts'; |
7 | 7 | import { getTrendData } from '/@/api/dashboard'; |
8 | + import { getDateByShortcutQueryKey, ShortcutQueryKeyEnum } from '../hooks/useDate'; | |
8 | 9 | |
9 | 10 | interface Props { |
10 | 11 | width?: string; |
... | ... | @@ -77,11 +78,8 @@ |
77 | 78 | const chartRef = ref<HTMLDivElement | null>(null); |
78 | 79 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
79 | 80 | onMounted(async () => { |
80 | - const endTs = Date.now(); | |
81 | 81 | const res = await getTrendData({ |
82 | - startTs: endTs - 2592000000, | |
83 | - endTs, | |
84 | - interval: 86400000, | |
82 | + ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_30_DAY), | |
85 | 83 | trend: 'CUSTOMER_TREND', |
86 | 84 | }); |
87 | 85 | ... | ... |
... | ... | @@ -95,6 +95,20 @@ |
95 | 95 | > |
96 | 96 | <template #extra> |
97 | 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 | 112 | <template v-for="(item, index) in TenantOrCustomerDateList" :key="item.value"> |
99 | 113 | <span |
100 | 114 | @click="quickQueryTenantOrCustomerTime(index, item.value)" | ... | ... |
... | ... | @@ -80,6 +80,20 @@ |
80 | 80 | > |
81 | 81 | <template #extra> |
82 | 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 | 97 | <template v-for="(item, index) in TenantOrCustomerDateList" :key="item.value"> |
84 | 98 | <span |
85 | 99 | @click="quickQueryTenantOrCustomerTime(index, item.value, 'tenant')" |
... | ... | @@ -445,7 +459,7 @@ |
445 | 459 | if (activeIndex.value === index) return; |
446 | 460 | activeIndex.value = index; |
447 | 461 | dateValue.value = ''; |
448 | - console.log(interval); | |
462 | + | |
449 | 463 | if (isCustomer) { |
450 | 464 | if (activeKey.value === '1') { |
451 | 465 | const data = await getTrendData({ | ... | ... |
... | ... | @@ -2,9 +2,10 @@ |
2 | 2 | <div ref="chartRef" :style="{ height, width }"></div> |
3 | 3 | </template> |
4 | 4 | <script lang="ts" setup> |
5 | - import { ref, Ref, withDefaults, onMounted, watch } from 'vue'; | |
5 | + import { ref, Ref, onMounted, watch } from 'vue'; | |
6 | 6 | import { useECharts } from '/@/hooks/web/useECharts'; |
7 | 7 | import { getTrendData } from '/@/api/dashboard/index'; |
8 | + import { getDateByShortcutQueryKey, ShortcutQueryKeyEnum } from '../hooks/useDate'; | |
8 | 9 | interface Props { |
9 | 10 | width?: string; |
10 | 11 | height?: string; |
... | ... | @@ -77,11 +78,8 @@ |
77 | 78 | const chartRef = ref<HTMLDivElement | null>(null); |
78 | 79 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
79 | 80 | onMounted(async () => { |
80 | - const endTs = Date.now(); | |
81 | 81 | const res = await getTrendData({ |
82 | - startTs: endTs - 2592000000, | |
83 | - endTs, | |
84 | - interval: 86400000, | |
82 | + ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_30_DAY), | |
85 | 83 | trend: 'TENANT_TREND', |
86 | 84 | }); |
87 | 85 | const transferResult = res.map((item) => [item.ts, item.value]); | ... | ... |
1 | -import { formatToDateTime } from '/@/utils/dateUtil'; | |
1 | +import { dateUtil, formatToDateTime } from '/@/utils/dateUtil'; | |
2 | 2 | import { ref } from 'vue'; |
3 | 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 | 41 | export function useDate() { |
6 | 42 | const tenantDateValue = ref([]); |
7 | 43 | const customerDateValue = ref([]); |
... | ... | @@ -10,26 +46,23 @@ export function useDate() { |
10 | 46 | const activeTenantIndex = ref(0); |
11 | 47 | const activeCustomerIndex = ref(0); |
12 | 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 | 55 | async function quickQueryTenantOrCustomerTime( |
20 | 56 | index: number, |
21 | - value: number, | |
57 | + value: ShortcutQueryKeyEnum, | |
22 | 58 | flag: 'tenant' | 'customer' |
23 | 59 | ) { |
24 | - const endTs = Date.now(); | |
25 | 60 | if (flag === 'tenant') { |
26 | 61 | if (activeTenantIndex.value === index) return; |
27 | 62 | activeTenantIndex.value = index; |
28 | 63 | tenantDateValue.value = []; |
29 | 64 | const res = await getTrendData({ |
30 | - startTs: endTs - value, | |
31 | - endTs, | |
32 | - interval: value === 2592000000 ? 86400000 : value === 7776000000 ? 172800000 : 2592000000, | |
65 | + ...getDateByShortcutQueryKey(value), | |
33 | 66 | trend: 'TENANT_TREND', |
34 | 67 | }); |
35 | 68 | tenantTrendList.value = res.map((item) => [item.ts, item.value]); |
... | ... | @@ -38,9 +71,7 @@ export function useDate() { |
38 | 71 | activeCustomerIndex.value = index; |
39 | 72 | customerDateValue.value = []; |
40 | 73 | const res = await getTrendData({ |
41 | - startTs: endTs - value, | |
42 | - endTs, | |
43 | - interval: value === 2592000000 ? 86400000 : value === 7776000000 ? 172800000 : 2592000000, | |
74 | + ...getDateByShortcutQueryKey(value), | |
44 | 75 | trend: 'CUSTOMER_TREND', |
45 | 76 | }); |
46 | 77 | customerTrendList.value = res.map((item) => [item.ts, item.value]); | ... | ... |
... | ... | @@ -7,7 +7,7 @@ import { JSONEditor } from '/@/components/CodeEditor'; |
7 | 7 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
8 | 8 | import { getModelServices } from '/@/api/device/modelOfMatter'; |
9 | 9 | import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; |
10 | -import { toRaw, unref } from 'vue'; | |
10 | +import { nextTick, toRaw, unref } from 'vue'; | |
11 | 11 | import ObjectModelValidateForm from '/@/components/Form/src/externalCompns/components/ObjectModelValidateForm/ObjectModelValidateForm.vue'; |
12 | 12 | import { CommandDeliveryWayEnum, ServiceCallTypeEnum } from '/@/enums/toolEnum'; |
13 | 13 | import { TaskTypeEnum } from '/@/views/task/center/config'; |
... | ... | @@ -246,8 +246,9 @@ export const step1Schemas: FormSchema[] = [ |
246 | 246 | required: true, |
247 | 247 | component: 'ApiSelect', |
248 | 248 | ifShow: ({ values }) => values.deviceType === 'SENSOR' && values.organizationId, |
249 | - componentProps: ({ formModel }) => { | |
249 | + componentProps: ({ formModel, formActionType }) => { | |
250 | 250 | const { organizationId, transportType } = formModel; |
251 | + const { validateFields } = formActionType; | |
251 | 252 | if (![organizationId, transportType].every(Boolean)) return {}; |
252 | 253 | return { |
253 | 254 | api: async (params: Recordable) => { |
... | ... | @@ -266,6 +267,10 @@ export const step1Schemas: FormSchema[] = [ |
266 | 267 | }, |
267 | 268 | valueField: 'tbDeviceId', |
268 | 269 | labelField: 'alias', |
270 | + onChange: async () => { | |
271 | + await nextTick(); | |
272 | + validateFields(['gatewayId']); | |
273 | + }, | |
269 | 274 | }; |
270 | 275 | }, |
271 | 276 | }, | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | 2 | import { Upload, Button } from 'ant-design-vue'; |
3 | 3 | import { InboxOutlined } from '@ant-design/icons-vue'; |
4 | - import { computed, ref } from 'vue'; | |
4 | + import { computed } from 'vue'; | |
5 | 5 | import StepContainer from './StepContainer.vue'; |
6 | 6 | import XLSX, { CellObject } from 'xlsx'; |
7 | 7 | import { basicProps } from './props'; |
8 | 8 | import { UploadFileParseValue } from './type'; |
9 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
9 | 10 | |
10 | 11 | const props = defineProps({ |
11 | 12 | ...basicProps, |
13 | + fileList: { | |
14 | + required: true, | |
15 | + type: Array as PropType<(Record<'uid' | 'name', string> & File)[]>, | |
16 | + }, | |
12 | 17 | value: { |
13 | 18 | require: true, |
14 | 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 | 25 | interface FileRequestParams { |
23 | 26 | file: File & { uid: string }; |
... | ... | @@ -48,23 +51,30 @@ |
48 | 51 | return new Promise((resolve, reject) => { |
49 | 52 | const fileReader = new FileReader(); |
50 | 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 | 80 | fileReader.onerror = () => { |
... | ... | @@ -75,19 +85,19 @@ |
75 | 85 | }; |
76 | 86 | |
77 | 87 | const handleParseFile = async ({ file, onSuccess, onError }: FileRequestParams) => { |
78 | - fileList.value = []; | |
79 | 88 | const value = await readFile(file); |
80 | 89 | if (!value) { |
81 | 90 | onError(); |
82 | 91 | return; |
83 | 92 | } |
84 | - fileList.value = [file]; | |
93 | + | |
94 | + emit('update:fileList', [file]); | |
85 | 95 | emit('update:value', value); |
86 | 96 | onSuccess({}, file); |
87 | 97 | }; |
88 | 98 | |
89 | 99 | const canGoNextStep = computed(() => { |
90 | - return !!fileList.value.length; | |
100 | + return !!props.fileList.length; | |
91 | 101 | }); |
92 | 102 | |
93 | 103 | const handlePreviousStep = () => { |
... | ... | @@ -97,16 +107,22 @@ |
97 | 107 | const handleNextStep = () => { |
98 | 108 | props.goNextStep?.(); |
99 | 109 | }; |
110 | + | |
111 | + const handleRemove = () => { | |
112 | + emit('update:fileList', []); | |
113 | + return true; | |
114 | + }; | |
100 | 115 | </script> |
101 | 116 | |
102 | 117 | <template> |
103 | 118 | <StepContainer> |
104 | 119 | <div class="">设备文件</div> |
105 | 120 | <Upload.Dragger |
106 | - v-model:fileList="fileList" | |
121 | + :fileList="fileList" | |
107 | 122 | :customRequest="handleParseFile" |
108 | 123 | accept=".csv" |
109 | 124 | name="file" |
125 | + :remove="handleRemove" | |
110 | 126 | > |
111 | 127 | <section class="cursor-pointer flex flex-col justify-center items-center"> |
112 | 128 | <InboxOutlined class="text-[4rem] !text-blue-400" /> | ... | ... |
... | ... | @@ -17,6 +17,8 @@ |
17 | 17 | |
18 | 18 | const basicInfo = ref({}); |
19 | 19 | |
20 | + const fileList = ref<(File & Record<'uid' | 'name', string>)[]>([]); | |
21 | + | |
20 | 22 | const fileParseValue = ref<UploadFileParseValue>({ header: [], content: [] }); |
21 | 23 | |
22 | 24 | const columnConfiguration = ref<Record<'type', string>[]>([]); |
... | ... | @@ -61,6 +63,7 @@ |
61 | 63 | |
62 | 64 | const reset = () => { |
63 | 65 | basicInfo.value = {}; |
66 | + fileList.value = []; | |
64 | 67 | fileParseValue.value = { header: [], content: [] }; |
65 | 68 | columnConfiguration.value = []; |
66 | 69 | importResult.value = {} as unknown as ImportDeviceResponse; |
... | ... | @@ -109,6 +112,7 @@ |
109 | 112 | /> |
110 | 113 | <ImportCsv |
111 | 114 | v-if="StepsEnum[item] === StepsEnum.IMPORT_FILE && StepsEnum[item] === currentStep" |
115 | + v-model:fileList="fileList" | |
112 | 116 | v-model:value="fileParseValue" |
113 | 117 | :go-next-step="goNextStep" |
114 | 118 | :go-previous-step="goPreviousStep" | ... | ... |
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 | import { ColEx } from '/@/components/Form/src/types'; |
12 | 12 | import { useHistoryData } from '../../hook/useHistoryData'; |
13 | 13 | import { formatToDateTime } from '/@/utils/dateUtil'; |
14 | - import { useTable, BasicTable } from '/@/components/Table'; | |
14 | + import { useTable, BasicTable, BasicColumn } from '/@/components/Table'; | |
15 | 15 | import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; |
16 | 16 | import { |
17 | 17 | ModeSwitchButton, |
... | ... | @@ -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 | 67 | title: '属性', |
72 | 68 | dataIndex: 'name', |
... | ... | @@ -84,18 +80,50 @@ |
84 | 80 | format: (val) => { |
85 | 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 | 122 | if (sorter.field == 'ts') { |
95 | 123 | if (sorter.order == 'descend') { |
96 | - openHistoryPanel('ASC'); | |
124 | + getTableList('DESC'); | |
97 | 125 | } else { |
98 | - openHistoryPanel('DESC'); | |
126 | + getTableList('ASC'); | |
99 | 127 | } |
100 | 128 | } |
101 | 129 | }; |
... | ... | @@ -214,7 +242,7 @@ |
214 | 242 | setOptions(setChartOptions(res, selectedKeys)); |
215 | 243 | }; |
216 | 244 | |
217 | - const switchMode = (flag: EnumTableChartMode) => { | |
245 | + const switchMode = async (flag: EnumTableChartMode) => { | |
218 | 246 | mode.value = flag; |
219 | 247 | }; |
220 | 248 | ... | ... |
... | ... | @@ -12,6 +12,23 @@ export interface BasicCreateFormParams { |
12 | 12 | |
13 | 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 | 32 | export const useGenDynamicForm = () => { |
16 | 33 | const createInputNumber = ({ |
17 | 34 | identifier, |
... | ... | @@ -30,19 +47,19 @@ export const useGenDynamicForm = () => { |
30 | 47 | type: 'number', |
31 | 48 | trigger: 'change', |
32 | 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 | 54 | return Promise.resolve(value); |
40 | 55 | }, |
41 | 56 | }, |
42 | 57 | ], |
43 | 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 | 63 | step, |
47 | 64 | placeholder: `请输入${functionName}`, |
48 | 65 | precision: type === DataTypeEnum.IS_NUMBER_INT ? 0 : 2, |
... | ... | @@ -136,7 +153,7 @@ export const useGenDynamicForm = () => { |
136 | 153 | fieldTypeMap.clear(); |
137 | 154 | const formSchema = schemas.map((item) => { |
138 | 155 | const { functionName, identifier, dataType } = item; |
139 | - console.log(item, 'item'); | |
156 | + | |
140 | 157 | const { type } = dataType || {}; |
141 | 158 | |
142 | 159 | fieldTypeMap.set(identifier!, dataType!.type); | ... | ... |
... | ... | @@ -84,6 +84,7 @@ |
84 | 84 | import DeviceConfigurationStep from './step/DeviceConfigurationStep.vue'; |
85 | 85 | import TransportConfigurationStep from './step/TransportConfigurationStep.vue'; |
86 | 86 | import PhysicalModelManagementStep from './step/PhysicalModelManagementStep.vue'; |
87 | + import { DeviceProfileDetail } from '/@/api/device/model/deviceConfigModel'; | |
87 | 88 | |
88 | 89 | const emits = defineEmits(['success', 'register']); |
89 | 90 | const activeKey = ref('1'); |
... | ... | @@ -105,15 +106,22 @@ |
105 | 106 | }); |
106 | 107 | const transportTypeStr = ref(''); |
107 | 108 | const dynamicWidth = ref('55rem'); |
109 | + | |
110 | + const isDefault = ref(false); | |
108 | 111 | const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { |
109 | 112 | setModalProps({ confirmLoading: false }); |
110 | 113 | current.value = 0; |
111 | 114 | isUpdate.value = data.isUpdate; |
112 | 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 | 120 | isEditId.value = data.record !== undefined ? data.record.id : null; |
115 | 121 | isEditCreatTime.value = data.record !== undefined ? data.record.createTime : null; |
116 | 122 | |
123 | + isDefault.value = res.default; | |
124 | + | |
117 | 125 | const title = unref(isUpdate) ? '编辑产品' : '新增产品'; |
118 | 126 | setModalProps({ title, showOkBtn: true, showCancelBtn: true }); |
119 | 127 | if (unref(isUpdate)) { |
... | ... | @@ -183,6 +191,7 @@ |
183 | 191 | ...{ profileData: !isEmptyObj ? transportConfData.profileData : null }, |
184 | 192 | ...{ id: isUpdate.value ? isEditId.value : null }, |
185 | 193 | ...{ createTime: isUpdate.value ? isEditCreatTime.value : null }, |
194 | + default: !!unref(isDefault), | |
186 | 195 | }); |
187 | 196 | createMessage.success(isUpdate.value ? `编辑成功` : `新增成功`); |
188 | 197 | handleCancel(); | ... | ... |
... | ... | @@ -70,7 +70,7 @@ |
70 | 70 | formConfig: { |
71 | 71 | labelWidth: 120, |
72 | 72 | schemas: searchFormSchema, |
73 | - fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'YYYY-MM-DD HH:mm:ss']], | |
73 | + fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']], | |
74 | 74 | }, |
75 | 75 | useSearchForm: true, |
76 | 76 | showTableSetting: true, | ... | ... |
... | ... | @@ -67,7 +67,7 @@ |
67 | 67 | formConfig: { |
68 | 68 | labelWidth: 120, |
69 | 69 | schemas: searchFormSchema, |
70 | - fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'YYYY-MM-DD HH:mm:ss']], | |
70 | + fieldMapToTime: [['sendTime', ['startTime', 'endTime'], 'x']], | |
71 | 71 | }, |
72 | 72 | useSearchForm: true, |
73 | 73 | showTableSetting: true, | ... | ... |
1 | 1 | import { BasicColumn, FormSchema } from '/@/components/Table'; |
2 | 2 | import { transformTime } from '/@/hooks/web/useDateToLocaleString'; |
3 | +import { isObject, isString } from '/@/utils/is'; | |
3 | 4 | |
4 | 5 | export const columns: BasicColumn[] = [ |
5 | 6 | { |
... | ... | @@ -55,6 +56,18 @@ export const exportJSONFile = (value: Recordable, name: string) => { |
55 | 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 | 71 | export enum RuleChainPermisssion { |
59 | 72 | DETAIL = 'rule:chain:detail', |
60 | 73 | } | ... | ... |
... | ... | @@ -8,7 +8,7 @@ |
8 | 8 | <Upload :show-upload-list="false" :customRequest="handleImport"> |
9 | 9 | <Button type="primary" :loading="importLoading"> 导入规则链 </Button> |
10 | 10 | </Upload> |
11 | - <!-- <Authority> | |
11 | + <Authority> | |
12 | 12 | <Popconfirm |
13 | 13 | title="您确定要批量删除数据" |
14 | 14 | ok-text="确定" |
... | ... | @@ -17,7 +17,7 @@ |
17 | 17 | > |
18 | 18 | <a-button color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> |
19 | 19 | </Popconfirm> |
20 | - </Authority> --> | |
20 | + </Authority> | |
21 | 21 | </template> |
22 | 22 | <template #root="{ record }"> |
23 | 23 | <Tag :color="record.root ? 'green' : 'red'"> {{ record.root ? '是' : '否' }}</Tag> |
... | ... | @@ -84,6 +84,7 @@ |
84 | 84 | encode, |
85 | 85 | exportJSONFile, |
86 | 86 | searchFormSchema, |
87 | + paseJSON, | |
87 | 88 | } from './config/config.data'; |
88 | 89 | import { |
89 | 90 | deleteRuleChine, |
... | ... | @@ -95,17 +96,45 @@ |
95 | 96 | } from '/@/api/ruleengine/ruleengineApi'; |
96 | 97 | import { useModal } from '/@/components/Modal'; |
97 | 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 | 100 | import { RuleChainModal } from './component/index'; |
100 | 101 | import { useMessage } from '/@/hooks/web/useMessage'; |
101 | 102 | import { usePermission } from '/@/hooks/web/usePermission'; |
102 | 103 | import { useRouter } from 'vue-router'; |
103 | 104 | import { ref } from 'vue'; |
104 | - import { isObject, isString } from '/@/utils/is'; | |
105 | + import { isObject } from '/@/utils/is'; | |
105 | 106 | // import { ChainDetailDrawer } from './chainDetail/index'; |
106 | 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 | 138 | title: '规则链库', |
110 | 139 | api: getRuleChinsList, |
111 | 140 | rowKey: (record) => record.id.id, |
... | ... | @@ -123,19 +152,8 @@ |
123 | 152 | pageField: 'page', |
124 | 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 | 157 | actionColumn: { |
140 | 158 | width: 220, |
141 | 159 | title: '操作', |
... | ... | @@ -145,10 +163,6 @@ |
145 | 163 | }, |
146 | 164 | }); |
147 | 165 | |
148 | - const [registerModal, { openModal }] = useModal(); | |
149 | - | |
150 | - // const [registerDrawer, { openDrawer }] = useDrawer(); | |
151 | - | |
152 | 166 | const handleSuccess = () => { |
153 | 167 | reload(); |
154 | 168 | }; |
... | ... | @@ -166,10 +180,6 @@ |
166 | 180 | }); |
167 | 181 | }; |
168 | 182 | |
169 | - const { createMessage } = useMessage(); | |
170 | - const { hasPermission } = usePermission(); | |
171 | - const router = useRouter(); | |
172 | - | |
173 | 183 | const handleView = (record: Recordable) => { |
174 | 184 | const hasDetailPermission = hasPermission(RuleChainPermisssion.DETAIL); |
175 | 185 | if (hasDetailPermission) { |
... | ... | @@ -178,30 +188,6 @@ |
178 | 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 | 191 | const handleImport = (data: { file: File }) => { |
206 | 192 | const fileReader = new FileReader(); |
207 | 193 | |
... | ... | @@ -275,18 +261,25 @@ |
275 | 261 | reload(); |
276 | 262 | }; |
277 | 263 | |
278 | - const handleDeleteOrBatchDelete = async (record: Recordable) => { | |
264 | + const handleDeleteOrBatchDelete = async (record: Recordable | null) => { | |
279 | 265 | setProps({ |
280 | 266 | loading: true, |
281 | 267 | }); |
282 | 268 | try { |
269 | + if (!record) { | |
270 | + const ids = getSelectRowKeys(); | |
271 | + await Promise.all(ids.map((item) => deleteRuleChine(item))); | |
272 | + return; | |
273 | + } | |
283 | 274 | await deleteRuleChine(record.id.id); |
284 | - createMessage.success('删除成功'); | |
285 | 275 | } finally { |
286 | 276 | setProps({ |
287 | 277 | loading: false, |
288 | 278 | }); |
279 | + | |
280 | + createMessage.success('删除成功'); | |
281 | + clearSelectedRowKeys(); | |
282 | + reload(); | |
289 | 283 | } |
290 | - reload(); | |
291 | 284 | }; |
292 | 285 | </script> | ... | ... |
... | ... | @@ -126,7 +126,10 @@ |
126 | 126 | password: getDataFlowParams.password ? getDataFlowParams.password : undefined, |
127 | 127 | } |
128 | 128 | : undefined, |
129 | + appendClientIdSuffix: getDataFlowParams.appendClientIdSuffix || undefined, | |
130 | + type: undefined, | |
129 | 131 | }; |
132 | + | |
130 | 133 | const rest = isRabbitmq(getDataFlowMethod?.type) |
131 | 134 | ? await postAddConvertApi({ ...restData.data, ...data }) |
132 | 135 | : await postAddConvertApi({ ...restData.data, ...data, configuration }); | ... | ... |
1 | 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 | 5 | import { allComponents } from '../packages'; |
6 | 6 | import { RuleNodeTypeEnum } from '../packages/index.type'; |
7 | 7 | import { buildUUID } from '/@/utils/uuid'; |
... | ... | @@ -9,6 +9,9 @@ import { isNullOrUnDef } from '/@/utils/is'; |
9 | 9 | import { useAddNodes } from './useAddNodes'; |
10 | 10 | import { useAddEdges } from './useAddEdges'; |
11 | 11 | import { RuleChainEntityType } from '../enum/entity'; |
12 | +import { EntryCategoryComponentEnum } from '../enum/category'; | |
13 | + | |
14 | +const ignoreNodeKeys: string[] = [EntryCategoryComponentEnum.INPUT]; | |
12 | 15 | |
13 | 16 | export function useBasicDataTransform() { |
14 | 17 | const nodeConfigMap = new Map<string, NodeData>(); |
... | ... | @@ -24,7 +27,7 @@ export function useBasicDataTransform() { |
24 | 27 | } |
25 | 28 | |
26 | 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 | 32 | return { |
30 | 33 | debugMode: !!data?.debugMode, |
... | ... | @@ -172,8 +175,126 @@ export function useBasicDataTransform() { |
172 | 175 | |
173 | 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 | 294 | return { |
176 | 295 | mergeData, |
296 | + combineData, | |
177 | 297 | deconstructionData, |
298 | + validateCanCreateRuleChain, | |
178 | 299 | }; |
179 | 300 | } | ... | ... |
... | ... | @@ -3,11 +3,19 @@ import { getRuleNodeCache, setRuleNodeCache } from './useRuleChainCache'; |
3 | 3 | import { RuleContextMenuEnum } from './useRuleChainContextMenu'; |
4 | 4 | import { useAddNodes } from './useAddNodes'; |
5 | 5 | import { buildUUID } from '/@/utils/uuid'; |
6 | -import { toRaw, unref } from 'vue'; | |
6 | +import { Ref, toRaw, unref } from 'vue'; | |
7 | 7 | import { useSaveAndRedo } from './useSaveAndRedo'; |
8 | 8 | import { isUnDef } from '/@/utils/is'; |
9 | 9 | import { useAddEdges } from './useAddEdges'; |
10 | 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 | 20 | interface HandleContextMenuActionParamsType { |
13 | 21 | menuType: RuleContextMenuEnum; |
... | ... | @@ -16,18 +24,58 @@ interface HandleContextMenuActionParamsType { |
16 | 24 | node?: GraphNode; |
17 | 25 | edge?: GraphEdge; |
18 | 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 | 69 | export const NODE_WIDTH = 176; |
22 | 70 | export const NODE_HEIGHT = 48; |
23 | 71 | |
24 | -function getElementsCenter(nodes: GraphNode[]) { | |
72 | +function getElementsCenter(nodes: Ref<GraphNode[]> | GraphNode[] = []) { | |
25 | 73 | let leftTopX: number | undefined; |
26 | 74 | let leftTopY: number | undefined; |
27 | 75 | let rightBottomX: number | undefined; |
28 | 76 | let rightBottomY: number | undefined; |
29 | 77 | |
30 | - for (const node of nodes) { | |
78 | + for (const node of unref(nodes)) { | |
31 | 79 | const { position } = node; |
32 | 80 | const { x, y } = position; |
33 | 81 | if (isUnDef(leftTopX)) { |
... | ... | @@ -200,6 +248,37 @@ export function useContextMenuAction() { |
200 | 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 | 282 | const handleContextMenuAction = (params: HandleContextMenuActionParamsType) => { |
204 | 283 | const { menuType } = params; |
205 | 284 | |
... | ... | @@ -213,6 +292,7 @@ export function useContextMenuAction() { |
213 | 292 | [RuleContextMenuEnum.SELECT_COPY]: selectCopy, |
214 | 293 | [RuleContextMenuEnum.APPLY_CHANGE]: applyChange, |
215 | 294 | [RuleContextMenuEnum.UNDO_CHANGE]: undoChange, |
295 | + [RuleContextMenuEnum.CREATE_RULE_CHAIN]: createRuleChain, | |
216 | 296 | }; |
217 | 297 | |
218 | 298 | if (handlerMapping[menuType]) { | ... | ... |
... | ... | @@ -5,6 +5,7 @@ import type { CreateNodeModal } from '../src/components/CreateNodeModal'; |
5 | 5 | import type { CreateEdgeModal } from '../src/components/CreateEdgeModal'; |
6 | 6 | import { UpdateNodeDrawer } from '../src/components/UpdateNodeDrawer'; |
7 | 7 | import { UpdateEdgeDrawer } from '../src/components/UpdateEdgeDrawer'; |
8 | +import { CreateRuleChainModal } from '../src/components/CreateRuleChainModal'; | |
8 | 9 | |
9 | 10 | const SYMBOL = Symbol('flow-context'); |
10 | 11 | |
... | ... | @@ -30,6 +31,11 @@ interface FlowContextOptionsType { |
30 | 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 | 39 | * @description vue flow store |
34 | 40 | */ |
35 | 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 | 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 | 5 | import { useAddNodes } from './useAddNodes'; |
3 | 6 | |
4 | -export function useInputNode() { | |
7 | +export function useNewNode() { | |
5 | 8 | const getInputNodeConfig = (id?: string) => { |
6 | 9 | const { getAddNodesParams } = useAddNodes(); |
7 | 10 | |
... | ... | @@ -20,5 +23,38 @@ export function useInputNode() { |
20 | 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 | 27 | import { useContextMenuAction } from './useContextMenuAction'; |
28 | 28 | import { useSaveAndRedo } from './useSaveAndRedo'; |
29 | 29 | import { EntryCategoryComponentEnum } from '../enum/category'; |
30 | +import { CreateRuleChainModal } from '../src/components/CreateRuleChainModal'; | |
31 | +import { useBasicDataTransform } from './useBasicDataTransform'; | |
30 | 32 | |
31 | 33 | interface UseRuleFlowOptionsType { |
32 | 34 | id: string; |
33 | 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 | 43 | useSaveAndRedoActionType: ReturnType<typeof useSaveAndRedo>; |
39 | 44 | } |
40 | 45 | |
... | ... | @@ -47,14 +52,10 @@ const validateInputAndOutput: ValidConnectionFunc = (connection: Connection) => |
47 | 52 | }; |
48 | 53 | |
49 | 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 | 60 | const { triggerChange } = useSaveAndRedoActionType; |
60 | 61 | |
... | ... | @@ -162,29 +163,35 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { |
162 | 163 | |
163 | 164 | const { handleContextMenuAction } = useContextMenuAction(); |
164 | 165 | |
166 | + const { validateCanCreateRuleChain } = useBasicDataTransform(); | |
167 | + | |
165 | 168 | onNodeContextMenu(async (params) => { |
166 | 169 | const menuType = params.node.selected |
167 | 170 | ? await createElementsSelectedContextMenu( |
168 | 171 | params, |
169 | 172 | unref(useSaveAndRedoActionType.changeMarker), |
170 | - validateSelectionElementsCanCreateRuleChain() | |
173 | + validateCanCreateRuleChain( | |
174 | + flowActionType.getSelectedNodes, | |
175 | + flowActionType.getSelectedEdges | |
176 | + ).flag | |
171 | 177 | ) |
172 | 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 | 197 | onEdgeContextMenu(async (params) => { |
... | ... | @@ -207,6 +214,7 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { |
207 | 214 | event: params.event, |
208 | 215 | useSaveAndRedoActionType, |
209 | 216 | edge: params.edge, |
217 | + modalActionType, | |
210 | 218 | }); |
211 | 219 | } |
212 | 220 | }); |
... | ... | @@ -216,21 +224,25 @@ export function useRuleFlow(options: UseRuleFlowOptionsType) { |
216 | 224 | ? await createElementsSelectedContextMenu( |
217 | 225 | getCreatePanelContextMenuParams(params), |
218 | 226 | unref(useSaveAndRedoActionType.changeMarker), |
219 | - validateSelectionElementsCanCreateRuleChain() | |
227 | + validateCanCreateRuleChain( | |
228 | + flowActionType.getSelectedNodes, | |
229 | + flowActionType.getSelectedEdges | |
230 | + ).flag | |
220 | 231 | ) |
221 | 232 | : await createPanelContextMenu( |
222 | 233 | getCreatePanelContextMenuParams(params), |
223 | 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 | 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 | 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 | 4 | import { useBasicDataTransform } from './useBasicDataTransform'; |
6 | 5 | import { |
7 | 6 | getRuleChainData, |
... | ... | @@ -10,15 +9,13 @@ import { |
10 | 9 | saveRuleChainDetail, |
11 | 10 | } from '/@/api/ruleDesigner'; |
12 | 11 | import { ConnectionItemType, RuleChainDetail, RuleChainType } from '../types/ruleNode'; |
13 | -import { useInputNode } from './useInputNode'; | |
12 | +import { useNewNode } from './useNewNode'; | |
14 | 13 | import { buildUUID } from '/@/utils/uuid'; |
15 | 14 | import { useRoute, useRouter } from 'vue-router'; |
16 | 15 | import { RuleChainEntityType } from '../enum/entity'; |
17 | 16 | import { PageEnum } from '/@/enums/pageEnum'; |
18 | 17 | import { clearRuleChainImportCache, getRuleChainImportCache } from './useRuleChainCache'; |
19 | 18 | |
20 | -const ignoreNodeKeys: string[] = [EntryCategoryComponentEnum.INPUT]; | |
21 | - | |
22 | 19 | export function useSaveAndRedo() { |
23 | 20 | const changeMarker = ref(false); |
24 | 21 | |
... | ... | @@ -38,7 +35,7 @@ export function useSaveAndRedo() { |
38 | 35 | |
39 | 36 | const ruleChainDetail = ref<RuleChainDetail>(); |
40 | 37 | |
41 | - const { mergeData, deconstructionData } = useBasicDataTransform(); | |
38 | + const { combineData, deconstructionData } = useBasicDataTransform(); | |
42 | 39 | |
43 | 40 | const triggerChange = () => { |
44 | 41 | changeMarker.value = true; |
... | ... | @@ -48,90 +45,14 @@ export function useSaveAndRedo() { |
48 | 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 | 48 | const handleApplyChange = (flowActionType: VueFlowStore) => { |
121 | 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 | 56 | handleSaveRuleChain(connections, nodes, firstNodeIndex); |
136 | 57 | }; |
137 | 58 | |
... | ... | @@ -211,7 +132,7 @@ export function useSaveAndRedo() { |
211 | 132 | function parseRuleChain(ruleChain: RuleChainType) { |
212 | 133 | const inputId = buildUUID(); |
213 | 134 | |
214 | - const { getInputNodeConfig } = useInputNode(); | |
135 | + const { getInputNodeConfig } = useNewNode(); | |
215 | 136 | |
216 | 137 | const value = deconstructionData(ruleChain, inputId); |
217 | 138 | ... | ... |
... | ... | @@ -19,10 +19,11 @@ |
19 | 19 | import { CreateEdgeModal } from './src/components/CreateEdgeModal'; |
20 | 20 | import { useFullScreen } from './hook/useFullScreen'; |
21 | 21 | import { useSaveAndRedo } from './hook/useSaveAndRedo'; |
22 | + import { NodeData } from './types/node'; | |
22 | 23 | import { Icon } from '/@/components/Icon'; |
23 | 24 | import { UpdateNodeDrawer } from './src/components/UpdateNodeDrawer'; |
24 | 25 | import { UpdateEdgeDrawer } from './src/components/UpdateEdgeDrawer'; |
25 | - import { NodeData } from './types/node'; | |
26 | + import { CreateRuleChainModal } from './src/components/CreateRuleChainModal'; | |
26 | 27 | |
27 | 28 | const getId = Number(Math.random().toString().substring(2)).toString(16); |
28 | 29 | |
... | ... | @@ -36,6 +37,9 @@ |
36 | 37 | |
37 | 38 | const updateEdgeDrawerActionType = ref<Nullable<InstanceType<typeof UpdateEdgeDrawer>>>(null); |
38 | 39 | |
40 | + const createRuleChainModalActionType = | |
41 | + ref<Nullable<InstanceType<typeof CreateRuleChainModal>>>(null); | |
42 | + | |
39 | 43 | const flowElRef = ref<Nullable<FlowElRef>>(null); |
40 | 44 | |
41 | 45 | const elements = ref([]); |
... | ... | @@ -57,11 +61,14 @@ |
57 | 61 | const { flowActionType } = useRuleFlow({ |
58 | 62 | id: getId, |
59 | 63 | ruleChainDetail, |
60 | - createNodeModalActionType, | |
61 | - createEdgeModalActionType, | |
62 | - updateEdgeDrawerActionType, | |
63 | - updateNodeDrawerActionType, | |
64 | 64 | useSaveAndRedoActionType, |
65 | + modalActionType: { | |
66 | + createNodeModalActionType, | |
67 | + createEdgeModalActionType, | |
68 | + updateEdgeDrawerActionType, | |
69 | + updateNodeDrawerActionType, | |
70 | + createRuleChainModalActionType, | |
71 | + }, | |
65 | 72 | }); |
66 | 73 | |
67 | 74 | const { handleOnDragOver, handleOnDrop } = useDragCreate({ |
... | ... | @@ -85,6 +92,8 @@ |
85 | 92 | |
86 | 93 | const handleDeleteSelectionElements = () => { |
87 | 94 | flowActionType.removeNodes(unref(flowActionType.getSelectedNodes)); |
95 | + flowActionType.removeEdges(unref(flowActionType.getSelectedEdges)); | |
96 | + useSaveAndRedoActionType.triggerChange?.(); | |
88 | 97 | }; |
89 | 98 | |
90 | 99 | onMounted(() => { |
... | ... | @@ -97,6 +106,7 @@ |
97 | 106 | createNodeModalActionType, |
98 | 107 | updateEdgeDrawerActionType, |
99 | 108 | updateNodeDrawerActionType, |
109 | + createRuleChainModalActionType, | |
100 | 110 | flowActionType, |
101 | 111 | triggerChange, |
102 | 112 | }); |
... | ... | @@ -177,6 +187,8 @@ |
177 | 187 | |
178 | 188 | <UpdateEdgeDrawer ref="updateEdgeDrawerActionType" /> |
179 | 189 | <UpdateNodeDrawer ref="updateNodeDrawerActionType" /> |
190 | + | |
191 | + <CreateRuleChainModal ref="createRuleChainModalActionType" /> | |
180 | 192 | </main> |
181 | 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> | ... | ... |
... | ... | @@ -35,6 +35,7 @@ |
35 | 35 | const { proxy } = getCurrentInstance() as any; |
36 | 36 | const getChildData = ref(null); |
37 | 37 | const editGetId: any = ref(''); |
38 | + const createTime = ref<string>(''); | |
38 | 39 | const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({ |
39 | 40 | schemas: formSchema, |
40 | 41 | showActionButtonGroup: false, |
... | ... | @@ -57,6 +58,7 @@ |
57 | 58 | await setFieldsValue({ |
58 | 59 | ...data.record, |
59 | 60 | }); |
61 | + createTime.value = data.record.createdTime; | |
60 | 62 | updateStatusSchema(true); |
61 | 63 | } |
62 | 64 | }); |
... | ... | @@ -79,7 +81,7 @@ |
79 | 81 | ]); |
80 | 82 | }; |
81 | 83 | |
82 | - const getAllFieldsFunc = async () => { | |
84 | + const getAllFieldsFunc = async (isUpdate?: boolean) => { | |
83 | 85 | getValuesFormData = await validate(); |
84 | 86 | if (!getValuesFormData) return; |
85 | 87 | let getChildValues = proxy.$refs.getChildData.getAllFields(); |
... | ... | @@ -90,10 +92,9 @@ |
90 | 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 | 98 | Object.assign( |
98 | 99 | postAllData, |
99 | 100 | { |
... | ... | @@ -101,7 +102,7 @@ |
101 | 102 | }, |
102 | 103 | getValuesFormData, |
103 | 104 | id, |
104 | - createTime | |
105 | + createTime1 | |
105 | 106 | ); |
106 | 107 | if (!unref(isUpdate)) { |
107 | 108 | delete postAllData.id; |
... | ... | @@ -119,7 +120,7 @@ |
119 | 120 | emit('success'); |
120 | 121 | resetFields(); |
121 | 122 | } else { |
122 | - await getAllFieldsFunc(); | |
123 | + await getAllFieldsFunc(true); | |
123 | 124 | await saveTenantProfileApi(postAllData); |
124 | 125 | createMessage.success('租户配置编辑成功'); |
125 | 126 | closeDrawer(); | ... | ... |
... | ... | @@ -173,10 +173,12 @@ |
173 | 173 | const { codeType, customCommand } = unref(getDesign) || {}; |
174 | 174 | const { transportType } = customCommand || {}; |
175 | 175 | const sendValue = ref<any>(unref(sliderValue)); |
176 | + const isModbusCommand = ref<boolean>(false); | |
176 | 177 | if (transportType == 'TCP' && codeType == TaskTypeEnum.MODBUS_RTU) { |
177 | 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 | 182 | flag |
181 | 183 | ? ((sliderValue.value = unref(sliderValue)), |
182 | 184 | (oldSliderValue.value = sliderValue.value), | ... | ... |
... | ... | @@ -12,7 +12,7 @@ |
12 | 12 | import { useModalInner } from '/@/components/Modal'; |
13 | 13 | import { getAllDeviceByOrg } from '/@/api/dataBoard'; |
14 | 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 | 16 | import { formatToDateTime } from '/@/utils/dateUtil'; |
17 | 17 | import { |
18 | 18 | ModeSwitchButton, |
... | ... | @@ -112,18 +112,14 @@ |
112 | 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 | 119 | title: '属性', |
124 | 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 | 132 | format: (val) => { |
137 | 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 | 176 | const getDeviceDataKey = async (record: DeviceOption) => { |
144 | 177 | const { organizationId, value } = record; |
145 | 178 | try { |
... | ... | @@ -260,7 +293,7 @@ |
260 | 293 | :show-ok-btn="false" |
261 | 294 | cancel-text="关闭" |
262 | 295 | width="70%" |
263 | - title="选择时间" | |
296 | + title="历史趋势" | |
264 | 297 | > |
265 | 298 | <section |
266 | 299 | class="flex flex-col p-4 h-full w-full min-w-7/10" |
... | ... | @@ -295,7 +328,11 @@ |
295 | 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 | 336 | <template #toolbar> |
300 | 337 | <div class="flex h-70px items-center justify-end p-2"> |
301 | 338 | <ModeSwitchButton | ... | ... |