Showing
13 changed files
with
342 additions
and
51 deletions
1 | +import { DeviceRecord } from '../device/model/deviceModel'; | ||
1 | import { | 2 | import { |
2 | AddDataBoardParams, | 3 | AddDataBoardParams, |
3 | AddDataComponentParams, | 4 | AddDataComponentParams, |
@@ -183,7 +184,7 @@ export const getAllDeviceByOrg = (organizationId: string, deviceProfileId?: stri | @@ -183,7 +184,7 @@ export const getAllDeviceByOrg = (organizationId: string, deviceProfileId?: stri | ||
183 | * @returns | 184 | * @returns |
184 | */ | 185 | */ |
185 | export const getMeetTheConditionsDevice = (params: GetMeetTheConditionsDeviceParams) => { | 186 | export const getMeetTheConditionsDevice = (params: GetMeetTheConditionsDeviceParams) => { |
186 | - return defHttp.get({ | 187 | + return defHttp.get<DeviceRecord[]>({ |
187 | url: DeviceUrl.GET_DEVICE, | 188 | url: DeviceUrl.GET_DEVICE, |
188 | params, | 189 | params, |
189 | }); | 190 | }); |
@@ -40,6 +40,11 @@ enum DeviceManagerApi { | @@ -40,6 +40,11 @@ enum DeviceManagerApi { | ||
40 | DEVICE_PUBLIC = '/customer/public/device', | 40 | DEVICE_PUBLIC = '/customer/public/device', |
41 | 41 | ||
42 | DEVICE_PRIVATE = '/customer/device', | 42 | DEVICE_PRIVATE = '/customer/device', |
43 | + | ||
44 | + /** | ||
45 | + * @description 通过设备列表获取设备信息 | ||
46 | + */ | ||
47 | + QUERY_DEVICES = '/device/get/devices', | ||
43 | } | 48 | } |
44 | 49 | ||
45 | export const devicePage = (params: DeviceQueryParam) => { | 50 | export const devicePage = (params: DeviceQueryParam) => { |
@@ -330,3 +335,10 @@ export const privateDevice = (tbDeviceId: string) => { | @@ -330,3 +335,10 @@ export const privateDevice = (tbDeviceId: string) => { | ||
330 | { joinPrefix: false } | 335 | { joinPrefix: false } |
331 | ); | 336 | ); |
332 | }; | 337 | }; |
338 | + | ||
339 | +export const getDevicesByDeviceIds = (ids: string[]) => { | ||
340 | + return defHttp.post<Record<'data', DeviceModel[]>>({ | ||
341 | + url: DeviceManagerApi.QUERY_DEVICES, | ||
342 | + data: ids, | ||
343 | + }); | ||
344 | +}; |
@@ -2,6 +2,7 @@ import { | @@ -2,6 +2,7 @@ import { | ||
2 | CreateTaskRecordType, | 2 | CreateTaskRecordType, |
3 | GenModbusCommandType, | 3 | GenModbusCommandType, |
4 | GetTaskListParamsType, | 4 | GetTaskListParamsType, |
5 | + ImmediateExecuteTaskType, | ||
5 | TaskRecordType, | 6 | TaskRecordType, |
6 | } from './model'; | 7 | } from './model'; |
7 | import { PaginationResult } from '/#/axios'; | 8 | import { PaginationResult } from '/#/axios'; |
@@ -16,6 +17,8 @@ enum Api { | @@ -16,6 +17,8 @@ enum Api { | ||
16 | CANCEL_TASK = '/task_center', | 17 | CANCEL_TASK = '/task_center', |
17 | 18 | ||
18 | GEN_MODBUS_COMMAND = '/js/modbus', | 19 | GEN_MODBUS_COMMAND = '/js/modbus', |
20 | + | ||
21 | + IMMEDIATE_EXECUTE = '/task_center/immediate/execute', | ||
19 | } | 22 | } |
20 | 23 | ||
21 | export const getTaskCenterList = (params: GetTaskListParamsType) => { | 24 | export const getTaskCenterList = (params: GetTaskListParamsType) => { |
@@ -76,3 +79,13 @@ export const genModbusCommand = (data: GenModbusCommandType) => { | @@ -76,3 +79,13 @@ export const genModbusCommand = (data: GenModbusCommandType) => { | ||
76 | data, | 79 | data, |
77 | }); | 80 | }); |
78 | }; | 81 | }; |
82 | + | ||
83 | +export const immediateExecute = (data: ImmediateExecuteTaskType) => { | ||
84 | + return defHttp.post<Record<'data', boolean>>( | ||
85 | + { | ||
86 | + url: Api.IMMEDIATE_EXECUTE, | ||
87 | + params: data, | ||
88 | + }, | ||
89 | + { joinParamsToUrl: true } | ||
90 | + ); | ||
91 | +}; |
@@ -62,3 +62,11 @@ export interface GenModbusCommandType { | @@ -62,3 +62,11 @@ export interface GenModbusCommandType { | ||
62 | registerNum?: number; | 62 | registerNum?: number; |
63 | registerValues?: number[]; | 63 | registerValues?: number[]; |
64 | } | 64 | } |
65 | + | ||
66 | +export interface ImmediateExecuteTaskType { | ||
67 | + executeTarget: TaskTargetEnum; | ||
68 | + id: string; | ||
69 | + cronExpression: string; | ||
70 | + targetIds: string[]; | ||
71 | + name: string; | ||
72 | +} |
@@ -124,6 +124,7 @@ export type ComponentType = | @@ -124,6 +124,7 @@ export type ComponentType = | ||
124 | | 'TransferTableModal' | 124 | | 'TransferTableModal' |
125 | | 'ObjectModelValidateForm' | 125 | | 'ObjectModelValidateForm' |
126 | | 'DevicePicker' | 126 | | 'DevicePicker' |
127 | + | 'ProductPicker' | ||
127 | | 'PollCommandInput' | 128 | | 'PollCommandInput' |
128 | | 'RegisterAddressInput' | 129 | | 'RegisterAddressInput' |
129 | | 'ControlGroup'; | 130 | | 'ControlGroup'; |
@@ -9,13 +9,13 @@ import { | @@ -9,13 +9,13 @@ import { | ||
9 | import { PollCommandInput, ModeEnum } from '../PollCommandInput'; | 9 | import { PollCommandInput, ModeEnum } from '../PollCommandInput'; |
10 | import { DeviceProfileModel } from '/@/api/device/model/deviceModel'; | 10 | import { DeviceProfileModel } from '/@/api/device/model/deviceModel'; |
11 | import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; | 11 | import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; |
12 | -import { getDeviceProfile } from '/@/api/alarm/position'; | ||
13 | import { JSONEditorValidator } from '/@/components/CodeEditor/src/JSONEditor'; | 12 | import { JSONEditorValidator } from '/@/components/CodeEditor/src/JSONEditor'; |
14 | import { TimeUnitEnum, TimeUnitNameEnum } from '/@/enums/toolEnum'; | 13 | import { TimeUnitEnum, TimeUnitNameEnum } from '/@/enums/toolEnum'; |
15 | -import { createPickerSearch } from '/@/utils/pickerSearch'; | ||
16 | import { dateUtil } from '/@/utils/dateUtil'; | 14 | import { dateUtil } from '/@/utils/dateUtil'; |
15 | +import { ProductPicker, validateProductPicker } from '../ProductPicker'; | ||
17 | 16 | ||
18 | useComponentRegister('DevicePicker', DevicePicker); | 17 | useComponentRegister('DevicePicker', DevicePicker); |
18 | +useComponentRegister('ProductPicker', ProductPicker); | ||
19 | useComponentRegister('PollCommandInput', PollCommandInput); | 19 | useComponentRegister('PollCommandInput', PollCommandInput); |
20 | 20 | ||
21 | export enum FormFieldsEnum { | 21 | export enum FormFieldsEnum { |
@@ -108,27 +108,26 @@ export const formSchemas: FormSchema[] = [ | @@ -108,27 +108,26 @@ export const formSchemas: FormSchema[] = [ | ||
108 | }, | 108 | }, |
109 | { | 109 | { |
110 | field: FormFieldsEnum.DEVICE_PROFILE, | 110 | field: FormFieldsEnum.DEVICE_PROFILE, |
111 | - component: 'ApiSelect', | 111 | + component: 'ProductPicker', |
112 | label: '产品', | 112 | label: '产品', |
113 | ifShow: ({ model }) => model[FormFieldsEnum.TARGET_TYPE] === TaskTargetEnum.PRODUCTS, | 113 | ifShow: ({ model }) => model[FormFieldsEnum.TARGET_TYPE] === TaskTargetEnum.PRODUCTS, |
114 | + valueField: 'value', | ||
115 | + changeEvent: 'update:value', | ||
116 | + rules: [validateProductPicker()], | ||
117 | + helpMessage: ['任务可以对目标产品按预设的时间策略执行任务。'], | ||
114 | componentProps: ({ formActionType }) => { | 118 | componentProps: ({ formActionType }) => { |
115 | const { setFieldsValue } = formActionType; | 119 | const { setFieldsValue } = formActionType; |
116 | return { | 120 | return { |
117 | - api: getDeviceProfile, | ||
118 | - placeholder: '请选择产品', | ||
119 | - labelField: 'name', | ||
120 | - valueField: 'id', | ||
121 | - onChange(value: string, option: DeviceProfileModel) { | ||
122 | - if (value) { | ||
123 | - const isTCP = option.transportType === TransportTypeEnum.TCP; | 121 | + onChange(key: string, _value: string | string[], option: DeviceProfileModel) { |
122 | + if (key === DeviceCascadePickerFieldsEnum.DEVICE_PROFILE) { | ||
123 | + const isTCP = (option || {}).transportType === TransportTypeEnum.TCP; | ||
124 | setFieldsValue({ | 124 | setFieldsValue({ |
125 | - [FormFieldsEnum.TRANSPORT_TYPE]: isTCP ? PushWayEnum.TCP : PushWayEnum.MQTT, | 125 | + [FormFieldsEnum.TRANSPORT_TYPE]: _value ? option.transportType : null, |
126 | [FormFieldsEnum.PUSH_WAY]: isTCP ? PushWayEnum.TCP : PushWayEnum.MQTT, | 126 | [FormFieldsEnum.PUSH_WAY]: isTCP ? PushWayEnum.TCP : PushWayEnum.MQTT, |
127 | ...(isTCP ? {} : { [FormFieldsEnum.EXECUTE_CONTENT_TYPE]: TaskTypeEnum.CUSTOM }), | 127 | ...(isTCP ? {} : { [FormFieldsEnum.EXECUTE_CONTENT_TYPE]: TaskTypeEnum.CUSTOM }), |
128 | }); | 128 | }); |
129 | } | 129 | } |
130 | }, | 130 | }, |
131 | - ...createPickerSearch(), | ||
132 | getPopupContainer: () => document.body, | 131 | getPopupContainer: () => document.body, |
133 | }; | 132 | }; |
134 | }, | 133 | }, |
@@ -5,9 +5,11 @@ import { CreateTaskRecordType, TaskRecordType } from '/@/api/task/model'; | @@ -5,9 +5,11 @@ import { CreateTaskRecordType, TaskRecordType } from '/@/api/task/model'; | ||
5 | import { DeviceCascadePickerValueType } from '../DevicePicker'; | 5 | import { DeviceCascadePickerValueType } from '../DevicePicker'; |
6 | import { TaskTargetEnum } from '../../config'; | 6 | import { TaskTargetEnum } from '../../config'; |
7 | import { TimeUnitEnum } from '/@/enums/toolEnum'; | 7 | import { TimeUnitEnum } from '/@/enums/toolEnum'; |
8 | +import { ProductCascadePickerValueType } from '../ProductPicker'; | ||
8 | 9 | ||
9 | export interface FormValueType extends Partial<Record<FormFieldsEnum, any>> { | 10 | export interface FormValueType extends Partial<Record<FormFieldsEnum, any>> { |
10 | [FormFieldsEnum.EXECUTE_TARGET_DATA]: DeviceCascadePickerValueType; | 11 | [FormFieldsEnum.EXECUTE_TARGET_DATA]: DeviceCascadePickerValueType; |
12 | + [FormFieldsEnum.DEVICE_PROFILE]: ProductCascadePickerValueType; | ||
11 | } | 13 | } |
12 | 14 | ||
13 | type CanWrite<T> = { | 15 | type CanWrite<T> = { |
@@ -95,6 +97,12 @@ export const composeData = (result: Required<FormValueType>): CreateTaskRecordTy | @@ -95,6 +97,12 @@ export const composeData = (result: Required<FormValueType>): CreateTaskRecordTy | ||
95 | 97 | ||
96 | const { organizationId, deviceType, deviceId, deviceProfileId } = executeTargetData || {}; | 98 | const { organizationId, deviceType, deviceId, deviceProfileId } = executeTargetData || {}; |
97 | 99 | ||
100 | + const { | ||
101 | + organizationId: productOrg, | ||
102 | + deviceProfileId: productId, | ||
103 | + deviceType: productDeviceType, | ||
104 | + } = deviceProfile || {}; | ||
105 | + | ||
98 | const { expression } = genCronExpression(time, period); | 106 | const { expression } = genCronExpression(time, period); |
99 | 107 | ||
100 | const cron = | 108 | const cron = |
@@ -111,10 +119,10 @@ export const composeData = (result: Required<FormValueType>): CreateTaskRecordTy | @@ -111,10 +119,10 @@ export const composeData = (result: Required<FormValueType>): CreateTaskRecordTy | ||
111 | type: executeContentType, | 119 | type: executeContentType, |
112 | }, | 120 | }, |
113 | executeTarget: { | 121 | executeTarget: { |
114 | - data: targetType === TaskTargetEnum.PRODUCTS ? [deviceProfile] : (deviceId as string[]), | ||
115 | - deviceType, | ||
116 | - organizationId, | ||
117 | - deviceProfileId: targetType === TaskTargetEnum.PRODUCTS ? deviceProfile : deviceProfileId, | 122 | + data: targetType === TaskTargetEnum.PRODUCTS ? [productId] : (deviceId as string[]), |
123 | + deviceType: targetType === TaskTargetEnum.PRODUCTS ? productDeviceType : deviceType, | ||
124 | + organizationId: targetType === TaskTargetEnum.PRODUCTS ? productOrg : organizationId, | ||
125 | + deviceProfileId: targetType === TaskTargetEnum.PRODUCTS ? productId : deviceProfileId, | ||
118 | }, | 126 | }, |
119 | executeTime: { | 127 | executeTime: { |
120 | type: executeTimeType, | 128 | type: executeTimeType, |
@@ -147,7 +155,14 @@ export const parseData = (result: TaskRecordType): Required<FormValueType> => { | @@ -147,7 +155,14 @@ export const parseData = (result: TaskRecordType): Required<FormValueType> => { | ||
147 | deviceType, | 155 | deviceType, |
148 | organizationId, | 156 | organizationId, |
149 | }, | 157 | }, |
150 | - deviceProfile: targetType === TaskTargetEnum.PRODUCTS ? data : null, | 158 | + deviceProfile: |
159 | + targetType === TaskTargetEnum.PRODUCTS | ||
160 | + ? { | ||
161 | + deviceProfileId: data[0], | ||
162 | + deviceType, | ||
163 | + organizationId, | ||
164 | + } | ||
165 | + : ({} as unknown as ProductCascadePickerValueType), | ||
151 | executeTimeType, | 166 | executeTimeType, |
152 | period, | 167 | period, |
153 | periodType: executeTimeType === ExecuteTimeTypeEnum.CUSTOM ? periodType : null, | 168 | periodType: executeTimeType === ExecuteTimeTypeEnum.CUSTOM ? periodType : null, |
1 | +export { default as ProductPicker } from './index.vue'; | ||
2 | + | ||
3 | +export enum FormFieldsEnum { | ||
4 | + DEVICE_TYPE = 'deviceType', | ||
5 | + DEVICE_PROFILE = 'deviceProfileId', | ||
6 | + ORGANIZATION = 'organizationId', | ||
7 | +} | ||
8 | + | ||
9 | +export type ProductCascadePickerValueType = Record<FormFieldsEnum, string>; | ||
10 | + | ||
11 | +export { validateProductPicker } from './utils'; |
1 | +<script lang="ts" setup> | ||
2 | + import { getOrganizationList } from '/@/api/system/system'; | ||
3 | + import { BasicForm, useForm } from '/@/components/Form'; | ||
4 | + import { copyTransFun } from '/@/utils/fnUtils'; | ||
5 | + import { watch } from 'vue'; | ||
6 | + import { nextTick } from 'vue'; | ||
7 | + import { getDeviceProfile } from '/@/api/alarm/position'; | ||
8 | + import { findDictItemByCode } from '/@/api/system/dict'; | ||
9 | + import { DictEnum } from '/@/enums/dictEnum'; | ||
10 | + import { FormFieldsEnum } from '.'; | ||
11 | + import { isObject } from '/@/utils/is'; | ||
12 | + import { createPickerSearch } from '/@/utils/pickerSearch'; | ||
13 | + | ||
14 | + const props = withDefaults( | ||
15 | + defineProps<{ | ||
16 | + value?: Recordable; | ||
17 | + }>(), | ||
18 | + { | ||
19 | + value: () => ({}), | ||
20 | + } | ||
21 | + ); | ||
22 | + | ||
23 | + const emit = defineEmits(['update:value', 'change']); | ||
24 | + | ||
25 | + const handleChange = (key: string, value: string | string[], option: Recordable) => { | ||
26 | + emit('change', key, value, option); | ||
27 | + }; | ||
28 | + | ||
29 | + const handleEmit = async (key: string, value: string | string[], option: Recordable) => { | ||
30 | + await nextTick(); | ||
31 | + let _value = getFieldsValue(); | ||
32 | + _value = { | ||
33 | + ..._value, | ||
34 | + | ||
35 | + ...(key === FormFieldsEnum.DEVICE_TYPE | ||
36 | + ? { | ||
37 | + [FormFieldsEnum.DEVICE_PROFILE]: null, | ||
38 | + } | ||
39 | + : {}), | ||
40 | + }; | ||
41 | + handleChange(key, value, option); | ||
42 | + emit('update:value', { ..._value }); | ||
43 | + }; | ||
44 | + | ||
45 | + const [register, { setFieldsValue, getFieldsValue, resetFields }] = useForm({ | ||
46 | + schemas: [ | ||
47 | + { | ||
48 | + field: FormFieldsEnum.DEVICE_TYPE, | ||
49 | + component: 'ApiSelect', | ||
50 | + label: '', | ||
51 | + componentProps: () => { | ||
52 | + return { | ||
53 | + api: findDictItemByCode, | ||
54 | + params: { | ||
55 | + dictCode: DictEnum.DEVICE_TYPE, | ||
56 | + }, | ||
57 | + labelField: 'itemText', | ||
58 | + valueField: 'itemValue', | ||
59 | + placeholder: '请选择设备类型', | ||
60 | + onChange(value: string, option: Recordable) { | ||
61 | + handleEmit(FormFieldsEnum.DEVICE_TYPE, value, option); | ||
62 | + }, | ||
63 | + getPopupContainer: () => document.body, | ||
64 | + ...createPickerSearch(), | ||
65 | + }; | ||
66 | + }, | ||
67 | + }, | ||
68 | + { | ||
69 | + field: FormFieldsEnum.ORGANIZATION, | ||
70 | + component: 'ApiTreeSelect', | ||
71 | + label: '', | ||
72 | + componentProps: () => { | ||
73 | + return { | ||
74 | + api: async () => { | ||
75 | + try { | ||
76 | + const data = await getOrganizationList(); | ||
77 | + copyTransFun(data as any); | ||
78 | + return data; | ||
79 | + } catch (error) { | ||
80 | + console.log(error); | ||
81 | + return []; | ||
82 | + } | ||
83 | + }, | ||
84 | + placeholder: '请选择组织', | ||
85 | + labelField: 'name', | ||
86 | + valueField: 'id', | ||
87 | + childField: 'children', | ||
88 | + onChange(value: string, option: Recordable) { | ||
89 | + handleEmit(FormFieldsEnum.ORGANIZATION, value, option); | ||
90 | + }, | ||
91 | + getPopupContainer: () => document.body, | ||
92 | + }; | ||
93 | + }, | ||
94 | + }, | ||
95 | + { | ||
96 | + field: FormFieldsEnum.DEVICE_PROFILE, | ||
97 | + component: 'ApiSelect', | ||
98 | + label: '', | ||
99 | + componentProps: ({ formModel }) => { | ||
100 | + const deviceType = Reflect.get(formModel, FormFieldsEnum.DEVICE_TYPE); | ||
101 | + return { | ||
102 | + api: async () => { | ||
103 | + try { | ||
104 | + return await getDeviceProfile(deviceType); | ||
105 | + } catch (error) { | ||
106 | + return []; | ||
107 | + } | ||
108 | + }, | ||
109 | + placeholder: '请选择产品', | ||
110 | + labelField: 'name', | ||
111 | + valueField: 'id', | ||
112 | + onChange(value: string, options: Recordable) { | ||
113 | + handleEmit(FormFieldsEnum.DEVICE_PROFILE, value, options); | ||
114 | + }, | ||
115 | + getPopupContainer: () => document.body, | ||
116 | + ...createPickerSearch(), | ||
117 | + }; | ||
118 | + }, | ||
119 | + }, | ||
120 | + ], | ||
121 | + showActionButtonGroup: false, | ||
122 | + layout: 'inline', | ||
123 | + baseColProps: { span: 8 }, | ||
124 | + }); | ||
125 | + | ||
126 | + const setValue = async () => { | ||
127 | + await nextTick(); | ||
128 | + if (!props.value || (isObject(props.value) && !Object.values(props.value).length)) { | ||
129 | + resetFields(); | ||
130 | + return; | ||
131 | + } | ||
132 | + setFieldsValue(props.value); | ||
133 | + }; | ||
134 | + | ||
135 | + watch( | ||
136 | + () => props.value, | ||
137 | + () => { | ||
138 | + setValue(); | ||
139 | + }, | ||
140 | + { | ||
141 | + immediate: true, | ||
142 | + } | ||
143 | + ); | ||
144 | +</script> | ||
145 | + | ||
146 | +<template> | ||
147 | + <BasicForm @register="register" class="device-picker" /> | ||
148 | +</template> | ||
149 | + | ||
150 | +<style lang="less" scoped> | ||
151 | + .device-picker { | ||
152 | + :deep(.ant-row) { | ||
153 | + width: 100%; | ||
154 | + } | ||
155 | + | ||
156 | + :deep(.ant-form-item-control-input-content) { | ||
157 | + div > div { | ||
158 | + width: 100%; | ||
159 | + } | ||
160 | + } | ||
161 | + } | ||
162 | +</style> |
1 | +import { FormFieldsEnum } from '.'; | ||
2 | +import { Rule } from '/@/components/Form'; | ||
3 | + | ||
4 | +export const validateProductPicker = () => { | ||
5 | + return { | ||
6 | + required: true, | ||
7 | + validateTrigger: 'blur', | ||
8 | + validator(_rule: Recordable, value: Recordable, _callback: Fn) { | ||
9 | + const product = Reflect.get(value || {}, FormFieldsEnum.DEVICE_PROFILE); | ||
10 | + const org = Reflect.get(value || {}, FormFieldsEnum.ORGANIZATION); | ||
11 | + if (!product) return Promise.reject('请选择产品'); | ||
12 | + if (!org) return Promise.reject('请选择组织'); | ||
13 | + return Promise.resolve(); | ||
14 | + }, | ||
15 | + } as Rule; | ||
16 | +}; |
1 | import { TaskTargetEnum } from '../../config'; | 1 | import { TaskTargetEnum } from '../../config'; |
2 | +import { getMeetTheConditionsDevice } from '/@/api/dataBoard'; | ||
3 | +import { getDevicesByDeviceIds } from '/@/api/device/deviceManager'; | ||
4 | +import { TaskRecordType } from '/@/api/task/model'; | ||
2 | import { FormSchema } from '/@/components/Form'; | 5 | import { FormSchema } from '/@/components/Form'; |
6 | +import { createPickerSearch } from '/@/utils/pickerSearch'; | ||
7 | + | ||
8 | +export interface FormValue extends Record<FormFieldsEnum, any> { | ||
9 | + [FormFieldsEnum.TASK_RECORD]: string; | ||
10 | +} | ||
3 | 11 | ||
4 | export enum FormFieldsEnum { | 12 | export enum FormFieldsEnum { |
5 | - RUN_TARGET_TYPE = 'runTargetType', | 13 | + EXECUTE_TARGET_TYPE = 'executeTarget', |
6 | TASK_TYPE = 'taskType', | 14 | TASK_TYPE = 'taskType', |
7 | - ASSIGN_TARGET = 'assignTarget', | ||
8 | - TASK_TARGET_TYPE = 'taskTargetType', | ||
9 | - TASK_TARGET_VALUE = 'taskTargetValue', | 15 | + TARGET_IDS = 'targetIds', |
16 | + TASK_RECORD = 'taskRecord', | ||
10 | } | 17 | } |
11 | 18 | ||
12 | export enum TargetType { | 19 | export enum TargetType { |
@@ -33,26 +40,13 @@ export const formSchemas: FormSchema[] = [ | @@ -33,26 +40,13 @@ export const formSchemas: FormSchema[] = [ | ||
33 | slot: 'taskType', | 40 | slot: 'taskType', |
34 | }, | 41 | }, |
35 | { | 42 | { |
36 | - field: FormFieldsEnum.TASK_TARGET_TYPE, | ||
37 | - component: 'Input', | ||
38 | - label: '目标类型', | ||
39 | - show: false, | ||
40 | - }, | ||
41 | - { | ||
42 | - field: FormFieldsEnum.TASK_TARGET_VALUE, | 43 | + field: FormFieldsEnum.TASK_RECORD, |
43 | component: 'Input', | 44 | component: 'Input', |
44 | - label: '目标值', | ||
45 | - show: false, | ||
46 | - }, | ||
47 | - { | ||
48 | - field: FormFieldsEnum.TASK_TYPE, | ||
49 | - component: 'Input', | ||
50 | - label: '任务类型', | ||
51 | - renderComponentContent: 'taskType', | 45 | + label: '任务详情', |
52 | show: false, | 46 | show: false, |
53 | }, | 47 | }, |
54 | { | 48 | { |
55 | - field: FormFieldsEnum.RUN_TARGET_TYPE, | 49 | + field: FormFieldsEnum.EXECUTE_TARGET_TYPE, |
56 | component: 'RadioGroup', | 50 | component: 'RadioGroup', |
57 | label: '选择目标类型', | 51 | label: '选择目标类型', |
58 | helpMessage: [ | 52 | helpMessage: [ |
@@ -67,23 +61,36 @@ export const formSchemas: FormSchema[] = [ | @@ -67,23 +61,36 @@ export const formSchemas: FormSchema[] = [ | ||
67 | }, | 61 | }, |
68 | }, | 62 | }, |
69 | { | 63 | { |
70 | - field: FormFieldsEnum.ASSIGN_TARGET, | 64 | + field: FormFieldsEnum.TARGET_IDS, |
71 | component: 'ApiSelect', | 65 | component: 'ApiSelect', |
72 | label: '制定目标设备', | 66 | label: '制定目标设备', |
73 | - ifShow: ({ model }) => model[FormFieldsEnum.RUN_TARGET_TYPE] === TargetType.ASSIGN, | 67 | + ifShow: ({ model }) => model[FormFieldsEnum.EXECUTE_TARGET_TYPE] === TargetType.ASSIGN, |
74 | componentProps: ({ formModel }) => { | 68 | componentProps: ({ formModel }) => { |
75 | - const taskTargetType = formModel[FormFieldsEnum.TASK_TARGET_TYPE]; | ||
76 | - const isDevices = taskTargetType === TaskTargetEnum.DEVICES; | 69 | + const record = JSON.parse(formModel[FormFieldsEnum.TASK_RECORD]) as TaskRecordType; |
70 | + const isDevices = record.targetType === TaskTargetEnum.DEVICES; | ||
71 | + const { executeTarget } = record; | ||
72 | + const { organizationId, data } = executeTarget; | ||
77 | return { | 73 | return { |
78 | api: async () => { | 74 | api: async () => { |
79 | try { | 75 | try { |
80 | if (isDevices) { | 76 | if (isDevices) { |
77 | + const result = await getDevicesByDeviceIds(data!); | ||
78 | + return result.data; | ||
81 | } else { | 79 | } else { |
80 | + return await getMeetTheConditionsDevice({ | ||
81 | + organizationId, | ||
82 | + deviceProfileId: data![0], | ||
83 | + }); | ||
82 | } | 84 | } |
83 | } catch (error) { | 85 | } catch (error) { |
84 | return []; | 86 | return []; |
85 | } | 87 | } |
86 | }, | 88 | }, |
89 | + mode: 'multiple', | ||
90 | + labelField: 'name', | ||
91 | + valueField: 'tbDeviceId', | ||
92 | + ...createPickerSearch(), | ||
93 | + placeholder: '请选择设备', | ||
87 | getPopupContainer: () => document.body, | 94 | getPopupContainer: () => document.body, |
88 | }; | 95 | }; |
89 | }, | 96 | }, |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | import { ref } from 'vue'; | 2 | import { ref } from 'vue'; |
3 | - import { TaskRecordType } from '/@/api/task/model'; | 3 | + import { ImmediateExecuteTaskType, TaskRecordType } from '/@/api/task/model'; |
4 | import { BasicForm, useForm } from '/@/components/Form'; | 4 | import { BasicForm, useForm } from '/@/components/Form'; |
5 | import { BasicModal, useModalInner } from '/@/components/Modal'; | 5 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
6 | - import { TaskTypeNameEnum } from '../../config'; | ||
7 | - import { formSchemas } from './config'; | 6 | + import { TaskTargetEnum, TaskTypeNameEnum } from '../../config'; |
7 | + import { FormValue, TargetType, formSchemas } from './config'; | ||
8 | + import { unref } from 'vue'; | ||
9 | + import { immediateExecute } from '/@/api/task'; | ||
10 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
11 | + const props = defineProps<{ | ||
12 | + reload: Fn; | ||
13 | + }>(); | ||
8 | 14 | ||
9 | defineEmits(['register']); | 15 | defineEmits(['register']); |
10 | 16 | ||
11 | const dataSource = ref<TaskRecordType>(); | 17 | const dataSource = ref<TaskRecordType>(); |
12 | 18 | ||
13 | - const [registerModal] = useModalInner((record: TaskRecordType) => { | 19 | + const [registerModal, { closeModal }] = useModalInner((record: TaskRecordType) => { |
20 | + resetFields(); | ||
14 | dataSource.value = record; | 21 | dataSource.value = record; |
15 | if (record) { | 22 | if (record) { |
16 | - setFieldsValue(record); | 23 | + setFieldsValue({ taskRecord: JSON.stringify(record) } as FormValue); |
17 | } | 24 | } |
18 | }); | 25 | }); |
19 | 26 | ||
20 | - const [registerForm, { setFieldsValue }] = useForm({ | 27 | + const [registerForm, { setFieldsValue, getFieldsValue, resetFields }] = useForm({ |
21 | schemas: formSchemas, | 28 | schemas: formSchemas, |
22 | showActionButtonGroup: false, | 29 | showActionButtonGroup: false, |
23 | }); | 30 | }); |
31 | + | ||
32 | + const composeData = (record: FormValue): ImmediateExecuteTaskType => { | ||
33 | + const { executeTarget, targetIds } = record; | ||
34 | + return { | ||
35 | + executeTarget: | ||
36 | + executeTarget === TargetType.ASSIGN | ||
37 | + ? TaskTargetEnum.DEVICES | ||
38 | + : unref(dataSource)!.targetType, | ||
39 | + id: unref(dataSource)!.id, | ||
40 | + targetIds, | ||
41 | + cronExpression: unref(dataSource)!.executeTime.cron, | ||
42 | + name: unref(dataSource)!.name, | ||
43 | + }; | ||
44 | + }; | ||
45 | + | ||
46 | + const loading = ref(false); | ||
47 | + const { createMessage } = useMessage(); | ||
48 | + const handleOk = async () => { | ||
49 | + const record = getFieldsValue() as FormValue; | ||
50 | + const value = composeData(record); | ||
51 | + try { | ||
52 | + loading.value = true; | ||
53 | + const { data } = await immediateExecute(value); | ||
54 | + data ? createMessage.success('运行成功') : createMessage.error('运行失败'); | ||
55 | + if (data) { | ||
56 | + closeModal(); | ||
57 | + props.reload?.(); | ||
58 | + } | ||
59 | + } catch (error) { | ||
60 | + throw error; | ||
61 | + } finally { | ||
62 | + loading.value = false; | ||
63 | + } | ||
64 | + }; | ||
24 | </script> | 65 | </script> |
25 | 66 | ||
26 | <template> | 67 | <template> |
27 | - <BasicModal @register="registerModal" title="运行任务"> | 68 | + <BasicModal |
69 | + @register="registerModal" | ||
70 | + title="运行任务" | ||
71 | + :okButtonProps="{ loading }" | ||
72 | + @ok="handleOk" | ||
73 | + > | ||
28 | <BasicForm @register="registerForm"> | 74 | <BasicForm @register="registerForm"> |
29 | <template #taskName> | 75 | <template #taskName> |
30 | <div class="font-semibold"> | 76 | <div class="font-semibold"> |
@@ -100,7 +100,7 @@ | @@ -100,7 +100,7 @@ | ||
100 | <section | 100 | <section |
101 | class="bg-light-50 flex p-4 justify-between items-center x dark:text-gray-300 dark:bg-dark-900" | 101 | class="bg-light-50 flex p-4 justify-between items-center x dark:text-gray-300 dark:bg-dark-900" |
102 | > | 102 | > |
103 | - <div class="text-2xl">任务</div> | 103 | + <div class="text-2xl">任务中心</div> |
104 | <Authority :value="PermissionEnum.CREATE"> | 104 | <Authority :value="PermissionEnum.CREATE"> |
105 | <Button | 105 | <Button |
106 | type="primary" | 106 | type="primary" |
@@ -143,7 +143,7 @@ | @@ -143,7 +143,7 @@ | ||
143 | </List> | 143 | </List> |
144 | </section> | 144 | </section> |
145 | <DetailModal @register="registerModal" :reload="reload" /> | 145 | <DetailModal @register="registerModal" :reload="reload" /> |
146 | - <RunTaskModal @register="registerRunTaskModal" /> | 146 | + <RunTaskModal :reload="reload" @register="registerRunTaskModal" /> |
147 | </PageWrapper> | 147 | </PageWrapper> |
148 | </template> | 148 | </template> |
149 | 149 |