Commit 3d1616dcfb1eb8f7a642b2da04db705f0b8eacf3

Authored by ww
1 parent 66212522

feat: 完成任务中心立即实行实现

  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