Wzyyy98 3 år sedan
förälder
incheckning
8713a07118

BIN
public/images/scene/invokeFunction.png


BIN
public/images/scene/offline.png


BIN
public/images/scene/online.png


BIN
public/images/scene/readProperty.png


BIN
public/images/scene/reportProperty.png


BIN
public/images/scene/writeProperty.png


+ 1 - 1
src/pages/rule-engine/Scene/Save/action/ListItem/List.tsx

@@ -5,7 +5,7 @@ import './index.less';
 import type { ActionsType } from '@/pages/rule-engine/Scene/typings';
 import Item from './Item';
 import type { ParallelType } from './Item';
-import { FormModel } from '../..';
+import { FormModel } from '@/pages/rule-engine/Scene/Save';
 interface ListProps {
   type: ParallelType;
   actions: ActionsType[];

+ 2 - 1
src/pages/rule-engine/Scene/Save/components/Buttons/AddButton.tsx

@@ -1,7 +1,8 @@
 import type { CSSProperties } from 'react';
+import React from 'react';
 
 interface ButtonProps {
-  children?: React.ReactDOM | string;
+  children?: React.ReactChild[] | React.ReactChild | string;
   onClick?: () => void;
   style?: CSSProperties;
 }

+ 21 - 0
src/pages/rule-engine/Scene/Save/components/TimingTrigger/index.less

@@ -0,0 +1,21 @@
+.timer-when-warp {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 16px;
+  padding: 16px;
+  background: #fafafa;
+}
+
+.when-item {
+  width: 76px;
+  padding: 6px 0;
+  text-align: center;
+  border: 1px solid #e6e6e6;
+  border-radius: 2px;
+  cursor: pointer;
+}
+
+.active {
+  color: #233dd7;
+  border-color: #233dd7;
+}

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 132 - 244
src/pages/rule-engine/Scene/Save/components/TimingTrigger/index.tsx


+ 86 - 0
src/pages/rule-engine/Scene/Save/components/TimingTrigger/whenOption.tsx

@@ -0,0 +1,86 @@
+import classNames from 'classnames';
+import { useEffect, useState } from 'react';
+import Styles from './index.less';
+
+interface TimerWhenProps {
+  value?: number[];
+  onChange?: (value?: number[]) => void;
+  type?: string;
+}
+
+export const numberToString = {
+  1: '星期一',
+  2: '星期二',
+  3: '星期三',
+  4: '星期四',
+  5: '星期五',
+  6: '星期六',
+  7: '星期日',
+};
+
+export default (props: TimerWhenProps) => {
+  const [value, setValue] = useState<number[] | undefined>(undefined);
+
+  const [options, setOptions] = useState<any[]>([]);
+
+  useEffect(() => {
+    if (props.type === 'month') {
+      setOptions(
+        new Array(31).fill(1).map((_, index) => ({ label: index + 1 + '号', value: index + 1 })),
+      );
+    } else {
+      setOptions(
+        new Array(7)
+          .fill(1)
+          .map((_, index) => ({ label: numberToString[index + 1], value: index + 1 })),
+      );
+    }
+  }, [props.type]);
+
+  useEffect(() => {
+    setValue(props.value);
+  }, [props.value]);
+
+  return (
+    <div className={Styles['timer-when-warp']}>
+      <div
+        className={classNames(Styles['when-item'], { [Styles.active]: value && !value.length })}
+        onClick={() => {
+          if (value && !value.length) {
+            setValue(undefined);
+            props.onChange?.(undefined);
+          } else if (!value || (value && value.length)) {
+            setValue([]);
+            props.onChange?.([]);
+          }
+        }}
+      >
+        全部
+      </div>
+      {options.map((item) => {
+        return (
+          <div
+            className={classNames(Styles['when-item'], {
+              [Styles.active]: value && value.includes(item.value),
+            })}
+            key={item}
+            onClick={() => {
+              const _value = value ? [...value] : [];
+              const indexof = _value.findIndex((t) => t === item.value);
+              if (indexof === -1) {
+                _value.push(item.value);
+              } else {
+                _value.splice(indexof, 1);
+              }
+
+              setValue(_value.length ? [..._value] : undefined);
+              props.onChange?.(_value.length ? _value : undefined);
+            }}
+          >
+            {item.label}
+          </div>
+        );
+      })}
+    </div>
+  );
+};

+ 3 - 1
src/pages/rule-engine/Scene/Save/device/TopCard.tsx

@@ -9,6 +9,7 @@ interface Props {
   onChange?: (type: string) => void;
   onSelect?: (type: string) => void;
   disabled?: boolean;
+  labelBottom?: boolean;
 }
 
 const TopCard = (props: Props) => {
@@ -35,6 +36,7 @@ const TopCard = (props: Props) => {
           key={item.value}
           className={classNames('trigger-way-item', {
             active: type === item.value,
+            labelBottom: props.labelBottom,
           })}
           onClick={() => {
             onSelect(item.value);
@@ -42,7 +44,7 @@ const TopCard = (props: Props) => {
         >
           <div className={'way-item-title'}>
             <p>{item.label}</p>
-            <span>{item.tip}</span>
+            {item.tip && <span>{item.tip}</span>}
           </div>
           <div className={'way-item-image'}>
             <img width={48} src={item.image} />

+ 106 - 6
src/pages/rule-engine/Scene/Save/device/addModel.tsx

@@ -1,16 +1,19 @@
 import { Modal, Button, Steps } from 'antd';
 import { observer } from '@formily/react';
 import { model } from '@formily/reactive';
-import { useEffect } from 'react';
+import { useEffect, useRef } from 'react';
 import { onlyMessage } from '@/utils/util';
-import type { TriggerDevice } from '@/pages/rule-engine/Scene/typings';
+import type { TriggerDevice, TriggerDeviceOptions } from '@/pages/rule-engine/Scene/typings';
 import Product from './product';
 import Device from './device';
+import Type from './type';
+import { numberToString } from '../components/TimingTrigger/whenOption';
+import { timeUnitEnum } from '../components/TimingTrigger';
 
 interface AddProps {
-  value?: any;
+  value?: TriggerDevice;
   onCancel?: () => void;
-  onSave?: (data: any) => void;
+  onSave?: (data: TriggerDevice, options: any) => void;
 }
 
 interface DeviceModelProps extends Partial<TriggerDevice> {
@@ -18,8 +21,15 @@ interface DeviceModelProps extends Partial<TriggerDevice> {
   stepNumber: number;
   productId: string;
   productDetail: any;
+  metadata: {
+    properties?: any[];
+    events?: any[];
+    functions?: any[];
+  };
   deviceId: string;
   orgId: string;
+  operation: TriggerDeviceOptions;
+  options: any;
 }
 
 export const DeviceModel = model<DeviceModelProps>({
@@ -43,13 +53,89 @@ export const DeviceModel = model<DeviceModelProps>({
   deviceId: '',
   orgId: '',
   selector: 'custom',
+  metadata: {},
+  operation: {
+    operator: 'online',
+  },
+  options: {},
 });
 
 export default observer((props: AddProps) => {
+  const typeRef = useRef<{ validateFields?: any }>();
+
+  useEffect(() => {
+    DeviceModel.stepNumber = 0;
+  }, []);
+
+  useEffect(() => {
+    Object.assign(DeviceModel, props.value);
+  }, [props.value]);
+
   const prev = () => {
     DeviceModel.stepNumber -= 1;
   };
 
+  const handleOptions = (data: TriggerDeviceOptions) => {
+    console.log(data);
+
+    const _options: any = {
+      name: '', // 名称
+      onlyName: false,
+      type: '', // 触发类型
+      productName: '',
+      time: undefined,
+      when: undefined,
+      extraTime: undefined,
+      action: DeviceModel.options.action,
+    };
+    if (DeviceModel.selector === 'custom') {
+      _options.name = DeviceModel.selectorValues?.map((item) => item.name).join(',');
+    } else if (DeviceModel.selector === 'org') {
+      _options.name = DeviceModel.selectorValues?.[0].name + '的';
+      _options.productName = DeviceModel.productDetail.name; // 产品名称
+    } else {
+      _options.name = '所有的' + DeviceModel.productDetail.name;
+    }
+
+    if (data.timer) {
+      const _timer = data.timer;
+      _options.when =
+        _timer.when!.length === 0
+          ? '每天'
+          : `每${_timer
+              .when!.map((item) => {
+                if (_timer!.trigger === 'week') {
+                  return numberToString[item];
+                } else {
+                  return item + '号';
+                }
+              })
+              .join(',')}`;
+      if (_timer.once) {
+        _options.time = _timer.once;
+      } else if (_timer.period) {
+        _options.time = _timer.period.from + '-' + _timer.period.to;
+        _options.extraTime = `每${_timer.period.every}${timeUnitEnum[_timer.period.unit]}执行1次`;
+      }
+    }
+
+    if (data.operator === 'online') {
+      _options.type = '上线';
+      _options.action = '';
+    }
+
+    if (data.operator === 'offline') {
+      _options.type = '离线';
+      _options.action = '';
+    }
+
+    if (data.operator === 'reportProperty') {
+      _options.type = '属性上报';
+      _options.action = '';
+    }
+    return _options;
+  };
+
   const next = async () => {
     if (DeviceModel.stepNumber === 0) {
       if (DeviceModel.productId) {
@@ -61,12 +147,26 @@ export default observer((props: AddProps) => {
       if (DeviceModel.selector === 'custom' && !DeviceModel.selectorValues?.length) {
         onlyMessage('请选择设备', 'error');
         return;
-      } else if (DeviceModel.selector && !DeviceModel.selectorValues?.length) {
+      } else if (DeviceModel.selector === 'org' && !DeviceModel.selectorValues?.length) {
         onlyMessage('请选择部门', 'error');
         return;
       }
       DeviceModel.stepNumber = 2;
     } else if (DeviceModel.stepNumber === 2) {
+      // TODO 验证类型数据
+      const operationData = await typeRef.current?.validateFields();
+      if (operationData) {
+        const _options = handleOptions(operationData);
+        props.onSave?.(
+          {
+            operation: operationData,
+            selectorValues: DeviceModel.selectorValues,
+            selector: DeviceModel.selector!,
+            productId: DeviceModel.productId,
+          },
+          _options,
+        );
+      }
     }
   };
 
@@ -75,7 +175,7 @@ export default observer((props: AddProps) => {
       case 'device':
         return <Device />;
       case 'type':
-        return;
+        return <Type ref={typeRef} />;
       default:
         return <Product />;
     }

+ 9 - 3
src/pages/rule-engine/Scene/Save/device/device.tsx

@@ -30,11 +30,17 @@ const TypeList = [
 export default observer(() => {
   const [form] = Form.useForm();
 
-  const selector = Form.useWatch('type', form);
+  const selector = Form.useWatch('selector', form);
 
   useEffect(() => {
-    form.setFieldsValue({ type: DeviceModel.selector });
-  }, [DeviceModel.selector]);
+    if (form) {
+      form.setFieldsValue({ selector: DeviceModel.selector });
+    }
+  }, []);
+
+  useEffect(() => {
+    DeviceModel.selector = selector;
+  }, [selector]);
 
   const contentRender = (type?: string) => {
     switch (type) {

+ 12 - 0
src/pages/rule-engine/Scene/Save/device/index.less

@@ -55,6 +55,18 @@
       border-color: @primary-color-active;
       opacity: 1;
     }
+
+    &.labelBottom {
+      flex-direction: column-reverse;
+      grid-gap: 16px;
+      gap: 0;
+      align-items: center;
+      width: auto;
+      padding: 8px 16px;
+      p {
+        margin: 0;
+      }
+    }
   }
 
   &.disabled {

+ 60 - 12
src/pages/rule-engine/Scene/Save/device/index.tsx

@@ -1,26 +1,74 @@
+import type { ReactChild } from 'react';
 import Terms from '@/pages/rule-engine/Scene/Save/terms';
 import { AddButton } from '@/pages/rule-engine/Scene/Save/components/Buttons';
 import { useState } from 'react';
+import { Observer, observer } from '@formily/react';
 import AddModel from './addModel';
+import { FormModel } from '@/pages/rule-engine/Scene/Save';
 
-export default () => {
+export default observer(() => {
   const [visible, setVisible] = useState(false);
-  const [label] = useState('点击配置设备触发');
+
+  const handleLabel = (options: any): ReactChild | ReactChild[] => {
+    if (!options || !Object.keys(options).length) return '点击配置设备触发';
+
+    const _label = [<span className="trigger-options-name">{options.name}</span>];
+    if (!options.onlyName) {
+      if (options.productName) {
+        _label.push(<span className="trigger-options-type">{options.productName}</span>);
+      }
+      if (options.when) {
+        _label.push(<span className="trigger-options-when">{options.when}</span>);
+      }
+      if (options.time) {
+        _label.push(<span className="trigger-options-time">{options.time}</span>);
+      }
+      if (options.extraTime) {
+        _label.push(<span className="trigger-options-extraTime">{options.extraTime}</span>);
+      }
+      if (options.action) {
+        _label.push(<span className="trigger-options-action">{options.action}</span>);
+      }
+      if (options.type) {
+        _label.push(<span className="trigger-options-type">{options.type}</span>);
+      }
+    }
+    return _label;
+  };
 
   return (
     <div>
-      <div>
-        <AddButton
-          style={{ width: '100%' }}
-          onClick={() => {
-            setVisible(true);
+      <div style={{ marginBottom: 16 }}>
+        <Observer>
+          {() => {
+            const label = handleLabel(FormModel.options);
+            return (
+              <AddButton
+                style={{ width: '100%' }}
+                onClick={() => {
+                  setVisible(true);
+                }}
+              >
+                <div className="trigger-options-content">{label}</div>
+              </AddButton>
+            );
           }}
-        >
-          {label}
-        </AddButton>
+        </Observer>
       </div>
       <Terms />
-      {visible && <AddModel />}
+      {visible && (
+        <AddModel
+          value={FormModel.trigger?.device}
+          onSave={(data, options) => {
+            setVisible(false);
+            FormModel['options'] = options;
+            FormModel.trigger!.device = data;
+          }}
+          onCancel={() => {
+            setVisible(false);
+          }}
+        />
+      )}
     </div>
   );
-};
+});

+ 9 - 0
src/pages/rule-engine/Scene/Save/device/product.tsx

@@ -17,6 +17,14 @@ export default observer(() => {
   const intl = useIntl();
   const [searchParam, setSearchParam] = useState({});
 
+  const handleMetadata = (metadata?: string) => {
+    try {
+      DeviceModel.metadata = JSON.parse(metadata || '{}');
+    } catch (error) {
+      DeviceModel.metadata = {};
+    }
+  };
+
   const columns: ProColumns<ProductItem>[] = [
     {
       title: 'ID',
@@ -223,6 +231,7 @@ export default observer(() => {
               // console.log(selectedRowKeys,selectedRows)
               DeviceModel.productId = selectedRows.map((item) => item.id)[0];
               DeviceModel.productDetail = selectedRows?.[0];
+              handleMetadata(DeviceModel.productDetail.metadata);
             },
           }}
           request={(params) =>

+ 240 - 22
src/pages/rule-engine/Scene/Save/device/type.tsx

@@ -1,37 +1,255 @@
-import { Form } from 'antd';
+import { Col, Form, Row, Select } from 'antd';
+import { useEffect, useState, forwardRef, useImperativeHandle } from 'react';
 import TopCard from './TopCard';
+import { DeviceModel } from './addModel';
+import TimingTrigger from '../components/TimingTrigger';
+import Operation from '../trigger/operation';
+import FunctionCall from '../action/device/functionCall';
 
-const TypeList = [
-  {
-    label: '自定义',
-    value: 'custom',
-    image: require('/public/images/scene/device-custom.png'),
-    tip: '自定义选择当前产品下的任意设备',
+export enum OperatorType {
+  'online' = 'online',
+  'offline' = 'offline',
+  'reportEvent' = 'reportEvent',
+  'reportProperty' = 'reportProperty',
+  'readProperty' = 'readProperty',
+  'writeProperty' = 'writeProperty',
+  'invokeFunction' = 'invokeFunction',
+}
+
+export const TypeName = {
+  online: '设备上线',
+  offline: '设备离线',
+  reportEvent: '事件上报',
+  reportProperty: '属性上报',
+  readProperty: '读取属性',
+  writeProperty: '修改属性',
+  invokeFunction: '功能调用',
+};
+
+const TypeEnum = {
+  reportProperty: {
+    label: '属性上报',
+    value: OperatorType.reportProperty,
+    image: require('/public/images/scene/reportProperty.png'),
   },
-  {
-    label: '全部',
-    value: 'all',
-    image: require('/public/images/scene/trigger-device-all.png'),
-    tip: '产品下的所有设备',
+  reportEvent: {
+    label: '事件上报',
+    value: OperatorType.reportEvent,
+    image: require('/public/images/scene/reportProperty.png'),
   },
-  {
-    label: '按组织',
-    value: 'org',
-    image: require('/public/images/scene/trigger-device-org.png'),
-    tip: '选择产品下归属于具体组织的设备',
+  readProperty: {
+    label: '读取属性',
+    value: OperatorType.readProperty,
+    image: require('/public/images/scene/readProperty.png'),
   },
-];
+  writeProperty: {
+    label: '修改属性',
+    value: OperatorType.writeProperty,
+    image: require('/public/images/scene/writeProperty.png'),
+  },
+  invokeFunction: {
+    label: '功能调用',
+    value: OperatorType.invokeFunction,
+    image: require('/public/images/scene/invokeFunction.png'),
+  },
+};
+
+type OperatorTypeKeys = keyof typeof OperatorType;
+
+export default forwardRef((props, ref) => {
+  console.log(props);
 
-export default () => {
   const [form] = Form.useForm();
 
+  const operator: OperatorTypeKeys = Form.useWatch('operator', form);
+
+  const [readProperty, setReadProperty] = useState<any[]>([]);
+  const [writeProperty, setWriteProperty] = useState<any[]>([]);
+  const [events, setEvents] = useState<any[]>([]);
+  const [functions, setFunctions] = useState<any[]>([]);
+  const [functionItem, setFunctionItem] = useState<any[]>([]);
+
+  const [TypeList, setTypeList] = useState([
+    {
+      label: '设备上线',
+      value: 'online',
+      image: require('/public/images/scene/online.png'),
+    },
+    {
+      label: '设备离线',
+      value: 'offline',
+      image: require('/public/images/scene/offline.png'),
+    },
+  ]);
+
+  const TimeFilterArray: OperatorTypeKeys[] = [
+    OperatorType.readProperty,
+    OperatorType.writeProperty,
+    OperatorType.invokeFunction,
+  ];
+
+  useEffect(() => {
+    form.setFieldsValue({
+      ...DeviceModel.operation,
+    });
+
+    const newTypeList = [...TypeList];
+
+    if (DeviceModel.metadata.events?.length) {
+      newTypeList.push(TypeEnum.reportEvent);
+      setEvents(DeviceModel.metadata.events);
+    }
+
+    if (DeviceModel.metadata.properties?.length) {
+      const _readProperty = DeviceModel.metadata.properties.filter((item) =>
+        item.expands.type.includes('read'),
+      );
+      const _writeProperty = DeviceModel.metadata.properties.filter((item) =>
+        item.expands.type.includes('write'),
+      );
+      setReadProperty(_readProperty);
+      setWriteProperty(_writeProperty);
+      if (_readProperty.length) {
+        newTypeList.push(TypeEnum.readProperty);
+      }
+      if (_writeProperty.length) {
+        newTypeList.push(TypeEnum.writeProperty);
+      }
+    }
+
+    if (DeviceModel.metadata.functions?.length) {
+      newTypeList.push(TypeEnum.invokeFunction);
+      setFunctions(DeviceModel.metadata.functions);
+    }
+
+    setTypeList(newTypeList);
+  }, []);
+
+  useEffect(() => {
+    if (TimeFilterArray.includes(operator)) {
+      form.setFieldsValue({
+        timer: {
+          trigger: 'week',
+          mod: 'period',
+        },
+      });
+    }
+  }, [operator]);
+
+  useImperativeHandle(ref, () => ({
+    validateFields: form.validateFields,
+  }));
+
   return (
     <div>
       <Form form={form} layout={'vertical'}>
-        <Form.Item name="type" label="触发类型" required>
-          <TopCard typeList={TypeList} />
+        <Form.Item name="operator" label="触发类型" required initialValue={'online'}>
+          <TopCard typeList={TypeList} labelBottom={true} />
         </Form.Item>
+        {TimeFilterArray.includes(operator) && <TimingTrigger name={['timer']} form={form} />}
+        {operator === OperatorType.readProperty && (
+          <Row>
+            <Col span={8}>
+              <Form.Item
+                name={'readProperties'}
+                rules={[{ required: true, message: '请选择属性' }]}
+              >
+                <Select
+                  mode={'multiple'}
+                  options={readProperty}
+                  maxTagCount={'responsive'}
+                  placeholder={'请选择属性'}
+                  style={{ width: '100%' }}
+                  fieldNames={{ label: 'name', value: 'id' }}
+                  onSelect={(v: any, propertyItem: any) => {
+                    console.log(v);
+                    DeviceModel.options.action = '读取' + propertyItem.name;
+                  }}
+                />
+              </Form.Item>
+            </Col>
+            <Col span={16}>
+              <Form.Item>定时读取所选属性值</Form.Item>
+            </Col>
+          </Row>
+        )}
+        {operator === OperatorType.writeProperty && (
+          <Form.Item name={'writeProperties'} rules={[{ required: true, message: '请输入修改值' }]}>
+            <Operation
+              propertiesList={writeProperty}
+              onSelect={(a, item) => {
+                console.log(a);
+                DeviceModel.options.action = '修改' + item.name;
+              }}
+            />
+          </Form.Item>
+        )}
+        {operator === OperatorType.reportEvent && (
+          <Form.Item name={'eventId'} rules={[{ required: true, message: '请选择事件' }]}>
+            <Select
+              options={events}
+              placeholder={'请选择事件'}
+              style={{ width: '100%' }}
+              fieldNames={{ label: 'name', value: 'id' }}
+              onSelect={(v: any, evenItem: any) => {
+                console.log(v);
+                DeviceModel.options.action = evenItem.name + '上报';
+              }}
+            />
+          </Form.Item>
+        )}
+        {operator === OperatorType.invokeFunction && (
+          <Row gutter={24}>
+            <Col span={6}>
+              <Form.Item name={'functionId'} rules={[{ required: true, message: '请选择功能' }]}>
+                <Select
+                  showSearch
+                  allowClear
+                  options={functions}
+                  fieldNames={{
+                    label: 'name',
+                    value: 'id',
+                  }}
+                  style={{ width: '100%' }}
+                  placeholder={'请选择功能'}
+                  filterOption={(input: string, option: any) =>
+                    option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  }
+                  onSelect={(v: any, fcItem: any) => {
+                    console.log(v);
+                    DeviceModel.options.action = '执行' + fcItem.name;
+                    if (fcItem) {
+                      const _properties = fcItem.valueType
+                        ? fcItem.valueType.properties
+                        : fcItem.inputs;
+                      const array = [];
+                      for (const datum of _properties) {
+                        array.push({
+                          id: datum.id,
+                          name: datum.name,
+                          type: datum.valueType ? datum.valueType.type : '-',
+                          format: datum.valueType ? datum.valueType.format : undefined,
+                          options: datum.valueType ? datum.valueType.elements : undefined,
+                          value: undefined,
+                        });
+                      }
+                      setFunctionItem(array);
+                    }
+                  }}
+                />
+              </Form.Item>
+            </Col>
+            <Col span={18}>
+              <Form.Item>定时调用所选功能</Form.Item>
+            </Col>
+            <Col span={24}>
+              <Form.Item name={'functionParameters'}>
+                <FunctionCall functionData={functionItem} name={'functionForm'} />
+              </Form.Item>
+            </Col>
+          </Row>
+        )}
       </Form>
     </div>
   );
-};
+});

+ 4 - 0
src/pages/rule-engine/Scene/Save/index.less

@@ -0,0 +1,4 @@
+.trigger-options-content {
+  display: flex;
+  gap: 16px;
+}

+ 5 - 0
src/pages/rule-engine/Scene/Save/index.tsx

@@ -9,9 +9,14 @@ import { observable } from '@formily/reactive';
 import type { FormModelType } from '@/pages/rule-engine/Scene/typings';
 import { useEffect } from 'react';
 import { service } from '@/pages/rule-engine/Scene';
+import './index.less';
 
 export const FormModel = observable<FormModelType>({
+  trigger: {
+    type: '',
+  },
   actions: [],
+  options: {},
   branches: [
     {
       when: [

+ 50 - 7
src/pages/rule-engine/Scene/Save/timer/TimerTrigger/index.tsx

@@ -1,13 +1,48 @@
-import { SceneItem } from '@/pages/rule-engine/Scene/typings';
-import { Modal } from 'antd';
+import type { OperationTimer } from '@/pages/rule-engine/Scene/typings';
+import { Modal, Form } from 'antd';
+import TimingTrigger, {
+  timeUnitEnum,
+} from '@/pages/rule-engine/Scene/Save/components/TimingTrigger';
+import { numberToString } from '@/pages/rule-engine/Scene/Save/components/TimingTrigger/whenOption';
 
 interface Props {
   close: () => void;
-  data: Partial<SceneItem>;
-  save: (data: any) => void;
+  data?: Partial<OperationTimer>;
+  save: (data: OperationTimer, options: any) => void;
 }
 
 export default (props: Props) => {
+  const [form] = Form.useForm();
+
+  const handleOptions = (value: OperationTimer) => {
+    const _options: any = {
+      time: undefined,
+      when: undefined,
+      extraTime: undefined,
+    };
+
+    const _timer = value;
+    _options.when =
+      _timer.when!.length === 0
+        ? '每天'
+        : `每${_timer
+            .when!.map((item) => {
+              if (_timer!.trigger === 'week') {
+                return numberToString[item];
+              } else {
+                return item + '号';
+              }
+            })
+            .join(',')}`;
+    if (_timer.once) {
+      _options.time = _timer.once;
+    } else if (_timer.period) {
+      _options.time = _timer.period.from + '-' + _timer.period.to;
+      _options.extraTime = `每${_timer.period.every}${timeUnitEnum[_timer.period.unit]}执行1次`;
+    }
+    return _options;
+  };
+
   return (
     <Modal
       title={'定时触发'}
@@ -17,12 +52,20 @@ export default (props: Props) => {
         props.close();
       }}
       onOk={async () => {
-        // const values = await form.validateFields();
-        // props.close();
+        const values = await form.validateFields();
+        console.log(values);
+
+        if (values) {
+          const _options = handleOptions(values);
+          props.save(values, _options);
+          props.close();
+        }
       }}
       width={700}
     >
-      123
+      <Form form={form} layout={'vertical'}>
+        <TimingTrigger name={[]} form={form} />
+      </Form>
     </Modal>
   );
 };

+ 45 - 13
src/pages/rule-engine/Scene/Save/timer/index.tsx

@@ -1,29 +1,61 @@
+import type { ReactChild } from 'react';
 import { AddButton } from '@/pages/rule-engine/Scene/Save/components/Buttons';
 import { useState } from 'react';
+import { Observer, observer } from '@formily/react';
+import { FormModel } from '@/pages/rule-engine/Scene/Save';
 import TimerTrigger from './TimerTrigger';
 import Action from '../action';
 
-export default () => {
+export default observer(() => {
   const [visible, setVisible] = useState<boolean>(false);
 
+  const handleLabel = (options: any): ReactChild | ReactChild[] => {
+    if (!options || !Object.keys(options).length) return '点击配置定时触发规则';
+
+    const _label = [];
+    if (options.when) {
+      _label.push(<span className="trigger-options-when">{options.when}</span>);
+    }
+    if (options.time) {
+      _label.push(<span className="trigger-options-time">{options.time}</span>);
+    }
+    if (options.extraTime) {
+      _label.push(<span className="trigger-options-extraTime">{options.extraTime}</span>);
+    }
+    return _label;
+  };
+
   return (
-    <div style={{ marginLeft: 40 }}>
-      <div
-        style={{ width: 200 }}
-        onClick={() => {
-          setVisible(true);
-        }}
-      >
-        <AddButton>点击配置定时触发规则</AddButton>
+    <div>
+      <div style={{ marginBottom: 16 }}>
+        <Observer>
+          {() => {
+            console.log(FormModel.options);
+
+            const label = handleLabel(FormModel.options);
+            return (
+              <AddButton
+                style={{ width: '100%' }}
+                onClick={() => {
+                  setVisible(true);
+                }}
+              >
+                <div className="trigger-options-content">{label}</div>
+              </AddButton>
+            );
+          }}
+        </Observer>
       </div>
       <div>
         <Action />
       </div>
       {visible && (
         <TimerTrigger
-          data={{}}
-          save={(data: any) => {
-            console.log(data);
+          data={FormModel.trigger?.timer}
+          save={(data, options) => {
+            setVisible(false);
+            FormModel['options'] = options;
+            FormModel.trigger!.timer = data;
           }}
           close={() => {
             setVisible(false);
@@ -32,4 +64,4 @@ export default () => {
       )}
     </div>
   );
-};
+});

+ 4 - 2
src/pages/rule-engine/Scene/Save/trigger/operation.tsx

@@ -8,6 +8,7 @@ interface OperatorProps {
   value?: any;
   onChange?: (value: any) => void;
   id?: string;
+  onSelect?: (value: string, item: any) => void;
 }
 
 export default (props: OperatorProps) => {
@@ -82,7 +83,7 @@ export default (props: OperatorProps) => {
     <Row gutter={24}>
       <Col span={6}>
         <Select
-          mode="multiple"
+          // mode="multiple"
           id={props.id}
           options={props.propertiesList || []}
           value={key}
@@ -93,10 +94,11 @@ export default (props: OperatorProps) => {
           maxTagCount={'responsive'}
           style={{ width: '100%' }}
           placeholder={'请选择属性'}
-          onSelect={(id: any) => {
+          onSelect={(id: any, item: any) => {
             if (props.onChange) {
               props.onChange({ [id]: undefined });
             }
+            props.onSelect?.(id, item);
           }}
           onDeselect={(id: any) => {
             const _value: any = { ...props.value };

+ 1 - 1
src/pages/rule-engine/Scene/index.tsx

@@ -376,7 +376,7 @@ const Scene = () => {
                 <EyeOutlined />
               </PermissionButton>
             }
-            tools={Tools(record, 'card')}
+            // tools={Tools(record, 'card')}
           />
         )}
       />