Pārlūkot izejas kodu

feat(merge): merge xyh

Next xyh
Lind 3 gadi atpakaļ
vecāks
revīzija
31f57a1997

+ 5 - 5
src/pages/rule-engine/Scene/Save/action/VariableItems/builtIn.tsx

@@ -17,6 +17,7 @@ interface BuiltInProps {
   type?: string;
   notifyType?: string;
   onChange?: (value: ChangeType) => void;
+  trigger?: any;
 }
 
 export default (props: BuiltInProps) => {
@@ -35,12 +36,11 @@ export default (props: BuiltInProps) => {
   });
 
   useEffect(() => {
-    if (source === 'upper') {
-      getBuiltInList({
-        trigger: { type: props.type },
-      });
+    console.log(props.trigger);
+    if (source === 'upper' && props.trigger) {
+      getBuiltInList({ ...props.trigger });
     }
-  }, [source, props.type]);
+  }, [source, props.trigger]);
 
   useEffect(() => {
     setSource(props.value?.source);

+ 29 - 10
src/pages/rule-engine/Scene/Save/action/VariableItems/user.tsx

@@ -54,7 +54,11 @@ export default (props: UserProps) => {
     };
     const resp1 = await queryPlatformUsers();
     if (resp1.status === 200) {
-      _userList.platform = resp1.result.map((item: any) => ({ label: item.name, value: item.id }));
+      _userList.platform = resp1.result.map((item: any) => ({
+        label: item.name,
+        value: item.id,
+        username: item.username,
+      }));
     }
 
     const resp2 = await queryRelationUsers();
@@ -62,6 +66,7 @@ export default (props: UserProps) => {
       _userList.relation = resp2.result.map((item: any) => ({
         label: item.name,
         value: item.relation,
+        username: '',
       }));
     }
 
@@ -172,7 +177,7 @@ export default (props: UserProps) => {
   };
 
   const filterOption = (input: string, option: any) => {
-    return option.children ? option.children.toLowerCase().includes(input.toLowerCase()) : false;
+    return option.label ? option.label.toLowerCase().includes(input.toLowerCase()) : false;
   };
 
   const userSelect =
@@ -187,12 +192,16 @@ export default (props: UserProps) => {
         placeholder={'请选择收信人'}
         listHeight={200}
         filterOption={filterOption}
+        optionLabelProp="label"
       >
         {userList.platform.length ? (
           <Select.OptGroup label={'平台用户'}>
             {userList.platform.map((item: any) => (
-              <Select.Option value={item.value} isRelation={false}>
-                {item.label}
+              <Select.Option value={item.value} isRelation={false} label={item.label}>
+                <div style={{ display: 'flex', justifyContent: 'space-between' }}>
+                  <span>{item.label}</span>
+                  <span style={{ color: '#cfcfcf' }}>{item.username}</span>
+                </div>
               </Select.Option>
             ))}
           </Select.OptGroup>
@@ -200,8 +209,11 @@ export default (props: UserProps) => {
         {userList.relation.length ? (
           <Select.OptGroup label={'关系用户'}>
             {userList.relation.map((item: any) => (
-              <Select.Option value={item.value} isRelation={true}>
-                {item.label}
+              <Select.Option value={item.value} isRelation={false} label={item.label}>
+                <div style={{ display: 'flex', justifyContent: 'space-between' }}>
+                  <span>{item.label}</span>
+                  <span style={{ color: '#cfcfcf' }}>{item.username}</span>
+                </div>
               </Select.Option>
             ))}
           </Select.OptGroup>
@@ -237,12 +249,16 @@ export default (props: UserProps) => {
         placeholder={'请选择收信人'}
         listHeight={200}
         filterOption={filterOption}
+        optionLabelProp="label"
       >
         {userList.platform.length ? (
           <Select.OptGroup label={'平台用户'}>
             {userList.platform.map((item: any) => (
-              <Select.Option value={item.value} isRelation={false}>
-                {item.label}
+              <Select.Option value={item.value} isRelation={false} label={item.label}>
+                <div style={{ display: 'flex', justifyContent: 'space-between' }}>
+                  <span>{item.label}</span>
+                  <span style={{ color: '#cfcfcf' }}>{item.username}</span>
+                </div>
               </Select.Option>
             ))}
           </Select.OptGroup>
@@ -250,8 +266,11 @@ export default (props: UserProps) => {
         {userList.relation.length ? (
           <Select.OptGroup label={'关系用户'}>
             {userList.relation.map((item: any) => (
-              <Select.Option value={item.value} isRelation={true}>
-                {item.label}
+              <Select.Option value={item.value} isRelation={true} label={item.label}>
+                <div style={{ display: 'flex', justifyContent: 'space-between' }}>
+                  <span>{item.label}</span>
+                  <span style={{ color: '#cfcfcf' }}>{item.username}</span>
+                </div>
               </Select.Option>
             ))}
           </Select.OptGroup>

+ 2 - 0
src/pages/rule-engine/Scene/Save/action/action.tsx

@@ -25,6 +25,7 @@ interface ActionProps {
   triggerType: string;
   onRemove: () => void;
   actionItemData?: any;
+  trigger?: any;
 }
 
 export default observer((props: ActionProps) => {
@@ -265,6 +266,7 @@ export default observer((props: ActionProps) => {
           form={props.form}
           template={templateData}
           name={props.name}
+          trigger={props.trigger}
           notifyType={notifyType}
           triggerType={props.triggerType}
           configId={configId}

+ 0 - 1
src/pages/rule-engine/Scene/Save/action/device/AllDevice.tsx

@@ -10,7 +10,6 @@ interface AllDeviceProps {
 
 export default (props: AllDeviceProps) => {
   useEffect(() => {
-    console.log(props.productId);
     queryAllDevice({
       terms: [{ column: 'productId', value: props.productId }],
       paging: false,

+ 6 - 1
src/pages/rule-engine/Scene/Save/action/device/WriteProperty/index.tsx

@@ -124,7 +124,12 @@ export default (props: WritePropertyProps) => {
       <Col span={4}>
         <Select
           value={propertiesKey}
-          options={props.properties}
+          options={props.properties.filter((item) => {
+            if (item.expands && item.expands.type) {
+              return item.expands.type.includes('write');
+            }
+            return false;
+          })}
           fieldNames={{ label: 'name', value: 'id' }}
           style={{ width: '100%' }}
           onSelect={(key: any) => {

+ 14 - 6
src/pages/rule-engine/Scene/Save/action/device/deviceModal.tsx

@@ -1,4 +1,4 @@
-import { Badge, Input, message, Modal } from 'antd';
+import { Badge, Button, Input, message, Modal } from 'antd';
 import { useEffect, useRef, useState } from 'react';
 import ProTable, { ActionType, ProColumns } from '@jetlinks/pro-table';
 import { DeviceItem } from '@/pages/system/Department/typings';
@@ -38,7 +38,6 @@ export default (props: DeviceModelProps) => {
   const [selectKeys, setSelectKeys] = useState<ChangeValueType[]>(props.value || []);
   const [searchParam, setSearchParam] = useState({});
   const [value, setValue] = useState<ChangeValueType[]>(props.value || []);
-  const oldAllSelect = useRef<any[]>([]);
 
   useEffect(() => {
     setValue(props.value || []);
@@ -159,21 +158,30 @@ export default (props: DeviceModelProps) => {
                 }
                 setSelectKeys(newSelectKeys);
               },
-              onSelectAll: (selected, selectedRows) => {
+              onSelectAll: (selected, _, changeRows) => {
                 let newSelectKeys = [...selectKeys];
                 if (selected) {
-                  oldAllSelect.current = selectedRows;
-                  selectedRows.forEach((item) => {
+                  changeRows.forEach((item) => {
                     newSelectKeys.push({ name: item.name, value: item.id });
                   });
                 } else {
                   newSelectKeys = newSelectKeys.filter((a) => {
-                    return !oldAllSelect.current.some((b) => b.id === a.value);
+                    return !changeRows.some((b) => b.id === a.value);
                   });
                 }
                 setSelectKeys(newSelectKeys);
               },
             }}
+            tableAlertOptionRender={() => (
+              <Button
+                type={'link'}
+                onClick={() => {
+                  setSelectKeys([]);
+                }}
+              >
+                取消选择
+              </Button>
+            )}
             request={(params) => queryDevice(params)}
             params={searchParam}
           ></ProTable>

+ 1 - 5
src/pages/rule-engine/Scene/Save/action/device/functionCall.tsx

@@ -24,10 +24,6 @@ export default (props: FunctionCallProps) => {
 
   useEffect(() => {
     setEditableRowKeys(props.functionData.map((d) => d.id));
-    console.log('functionData', props.functionData);
-    formRef.current?.setFieldsValue({
-      table: props.functionData,
-    });
   }, [props.functionData]);
 
   useEffect(() => {
@@ -45,7 +41,7 @@ export default (props: FunctionCallProps) => {
         }),
       });
     }
-  }, []);
+  }, [props.value, props.functionData]);
 
   const getItemNode = (record: any) => {
     const type = record.type;

+ 6 - 2
src/pages/rule-engine/Scene/Save/action/device/index.tsx

@@ -185,7 +185,11 @@ export default (props: DeviceProps) => {
             initialValue={props.value ? props.value.selector : SourceEnum.fixed}
             {...props.restField}
           >
-            <Select options={sourceList} style={{ width: 120 }} />
+            <Select
+              options={sourceList}
+              style={{ width: 120 }}
+              onSelect={(key: string) => setSelector(key)}
+            />
           </Form.Item>
           {selector === SourceEnum.fixed && (
             <Form.Item
@@ -211,7 +215,7 @@ export default (props: DeviceProps) => {
               {...props.restField}
               rules={[{ required: true, message: '请选择关系人' }]}
             >
-              <Select style={{ width: 300 }} />
+              <Select style={{ width: '100%' }} placeholder={'请选择关系'} />
             </Form.Item>
           )}
         </ItemGroup>

+ 6 - 1
src/pages/rule-engine/Scene/Save/action/device/readProperty.tsx

@@ -10,7 +10,12 @@ export default (props: ReadPropertyProps) => {
   return (
     <Select
       value={props.value ? props.value[0] : undefined}
-      options={props.properties}
+      options={props.properties.filter((item) => {
+        if (item.expands && item.expands.type) {
+          return item.expands.type.includes('read');
+        }
+        return false;
+      })}
       fieldNames={{ label: 'name', value: 'id' }}
       style={{ width: '100%' }}
       onSelect={(key: any) => {

+ 1 - 1
src/pages/rule-engine/Scene/Save/action/device/tagModal.tsx

@@ -151,7 +151,7 @@ export default (props: TagModalProps) => {
     <>
       <Modal
         visible={visible}
-        title={'设备'}
+        title={'标签'}
         width={660}
         onOk={() => {
           const newValue = tagList

+ 6 - 3
src/pages/rule-engine/Scene/Save/action/messageContent.tsx

@@ -16,6 +16,7 @@ interface MessageContentProps {
   notifyType: string;
   triggerType: string;
   configId: string;
+  trigger?: any;
 }
 
 const rowGutter = 12;
@@ -44,8 +45,10 @@ export default (props: MessageContentProps) => {
         } else {
           rules.push({
             validator: async (_: any, value: any) => {
-              if (type === 'file' && !value) {
-                return Promise.reject(new Error('请输入' + item.name));
+              if (type === 'file' || type === 'link') {
+                if (!value) {
+                  return Promise.reject(new Error('请输入' + item.name));
+                }
               } else {
                 if (!value || !value.value) {
                   if (['date', 'org'].includes(type)) {
@@ -146,7 +149,7 @@ export default (props: MessageContentProps) => {
                       ) : type === 'link' ? (
                         <Input placeholder={'请输入' + item.name} />
                       ) : (
-                        <BuiltIn type={props.triggerType} data={item} />
+                        <BuiltIn type={props.triggerType} trigger={props.trigger} data={item} />
                       )}
                     </Form.Item>
                   </Col>

+ 8 - 2
src/pages/rule-engine/Scene/Save/action/service.ts

@@ -50,7 +50,10 @@ export const queryRelationUsers = () =>
 
 // 钉钉用户
 export const queryDingTalkUsers = (id: string) =>
-  request(`${SystemConst.API_BASE}/notifier/dingtalk/corp/${id}/users`, { method: 'GET' });
+  request(
+    `${SystemConst.API_BASE}/notifier/dingtalk/corp/${id}/users?sorts[0].name='name'&sorts[0].order=asc`,
+    { method: 'GET' },
+  );
 
 // 钉钉部门
 export const queryDingTalkDepartments = (id: string) =>
@@ -60,7 +63,10 @@ export const queryDingTalkDepartments = (id: string) =>
 
 // 微信用户
 export const queryWechatUsers = (id: string) =>
-  request(`${SystemConst.API_BASE}/notifier/wechat/corp/${id}/users`, { method: 'GET' });
+  request(
+    `${SystemConst.API_BASE}/notifier/wechat/corp/${id}/users?sorts[0].name='name'&sorts[0].order=asc`,
+    { method: 'GET' },
+  );
 
 // 微信部门
 export const queryWechatDepartments = (id: string) =>

+ 4 - 4
src/pages/rule-engine/Scene/Save/components/TimingTrigger/index.tsx

@@ -193,7 +193,7 @@ export default (props: TimingTrigger) => {
                   value={
                     data.period?.from
                       ? [moment(data.period?.from, 'HH:mm:ss'), moment(data.period?.to, 'hh:mm:ss')]
-                      : undefined
+                      : [moment(new Date(), 'HH:mm:ss'), moment(new Date(), 'HH:mm:ss')]
                   }
                   onChange={(_, dateString) => {
                     onChange({
@@ -208,8 +208,8 @@ export default (props: TimingTrigger) => {
                 />
               ) : (
                 <TimePicker
-                  format={'hh:mm:ss'}
-                  value={data.once?.time ? moment(data.once?.time, 'hh:mm:ss') : undefined}
+                  format={'HH:mm:ss'}
+                  value={moment(data.once?.time || new Date(), 'HH:mm:ss')}
                   onChange={(_, dateString) => {
                     onChange({
                       ...data,
@@ -233,7 +233,7 @@ export default (props: TimingTrigger) => {
                     addonAfter={TimeTypeAfter}
                     style={{ flex: 1 }}
                     min={0}
-                    max={9999}
+                    max={59}
                     onChange={(e) => {
                       onChange({
                         ...data,

+ 48 - 33
src/pages/rule-engine/Scene/Save/index.tsx

@@ -35,7 +35,7 @@ type ShakeLimitType = {
 
 const DefaultShakeLimit = {
   enabled: false,
-  alarmFirst: true,
+  alarmFirst: false,
 };
 
 export let FormModel = model<FormModelType>({});
@@ -59,6 +59,7 @@ export default () => {
 
   const [requestParams, setRequestParams] = useState<any>(undefined);
   const [triggerValue, setTriggerValue] = useState<any>([]);
+  const [actionParams, setActionParams] = useState<any>(undefined);
 
   const [actionsData, setActionsData] = useState<any[]>([]);
   const [isEdit, setIsEdit] = useState(false);
@@ -72,10 +73,11 @@ export default () => {
         FormModel = _data;
         form.setFieldsValue(_data);
         setParallel(_data.parallel);
-        setShakeLimit(_data.shakeLimit || DefaultShakeLimit);
 
         setTriggerValue({ trigger: _data.terms || [] });
-
+        if (_data.trigger?.shakeLimit) {
+          setShakeLimit(_data.trigger?.shakeLimit || DefaultShakeLimit);
+        }
         if (_data.trigger?.device) {
           setRequestParams({ trigger: _data.trigger });
         }
@@ -95,7 +97,7 @@ export default () => {
     }
   }, [location]);
 
-  const saveData = async () => {
+  const saveData = useCallback(async () => {
     const formData = await form.validateFields();
     let triggerData = undefined;
     // 获取触发条件数据
@@ -107,6 +109,12 @@ export default () => {
     }
     console.log('save', formData);
     if (formData) {
+      if (shakeLimit.enabled) {
+        formData.trigger = {
+          ...formData.trigger,
+          shakeLimit: shakeLimit,
+        };
+      }
       setLoading(true);
       const resp = formData.id ? await service.updateScene(formData) : await service.save(formData);
 
@@ -126,7 +134,7 @@ export default () => {
         message.error(resp.message);
       }
     }
-  };
+  }, [shakeLimit]);
 
   const AntiShake = (
     <Space>
@@ -136,34 +144,36 @@ export default () => {
         checkedChildren="开启防抖"
         unCheckedChildren="关闭防抖"
         onChange={(e) => {
-          setShakeLimit({
+          const newShake = {
             ...shakeLimit,
             enabled: e,
-          });
-          form.setFieldsValue({ shakeLimit });
+          };
+          setShakeLimit(newShake);
         }}
       />
       {shakeLimit.enabled && (
         <>
           <InputNumber
             value={shakeLimit.time}
+            min={0}
             onChange={(e: number) => {
-              setShakeLimit({
+              const newShake = {
                 ...shakeLimit,
                 time: e,
-              });
-              form.setFieldsValue({ shakeLimit });
+              };
+              setShakeLimit(newShake);
             }}
           />
           <span> 秒内发生 </span>
           <InputNumber
             value={shakeLimit.threshold}
+            min={0}
             onChange={(e: number) => {
-              setShakeLimit({
+              const newShake = {
                 ...shakeLimit,
                 threshold: e,
-              });
-              form.setFieldsValue({ shakeLimit });
+              };
+              setShakeLimit(newShake);
             }}
           />
           <span>次及以上时,处理</span>
@@ -175,12 +185,11 @@ export default () => {
             ]}
             optionType="button"
             onChange={(e) => {
-              console.log(e);
-              setShakeLimit({
+              const newShake = {
                 ...shakeLimit,
                 alarmFirst: e.target.value,
-              });
-              form.setFieldsValue({ shakeLimit });
+              };
+              setShakeLimit(newShake);
             }}
           ></Radio.Group>
         </>
@@ -199,16 +208,21 @@ export default () => {
           preserve={false}
           className={'scene-save'}
           onValuesChange={(changeValue, allValues) => {
-            if (changeValue.trigger && changeValue.trigger.device) {
-              if (
-                changeValue.trigger.device.selectorValues ||
-                (changeValue.trigger.device.operation &&
-                  changeValue.trigger.device.operation.operator)
-              ) {
-                setTriggerValue([]);
-                setRequestParams({ trigger: allValues.trigger });
+            if (changeValue.trigger) {
+              if (changeValue.trigger.type === 'device' && changeValue.trigger.device) {
+                if (
+                  changeValue.trigger.device.selectorValues ||
+                  (changeValue.trigger.device.operation &&
+                    changeValue.trigger.device.operation.operator)
+                ) {
+                  setTriggerValue([]);
+                  setRequestParams({ trigger: allValues.trigger });
+                }
+              } else if (['timer', 'manual'].includes(changeValue.trigger.type)) {
+                setActionParams({ trigger: allValues.trigger });
               }
             }
+
             if (allValues.actions) {
               setActionsData(allValues.actions);
             }
@@ -380,6 +394,7 @@ export default () => {
                         form={form}
                         restField={restField}
                         name={name}
+                        trigger={actionParams}
                         triggerType={triggerType}
                         onRemove={() => remove(name)}
                         actionItemData={actionsData.length && actionsData[name]}
@@ -402,13 +417,13 @@ export default () => {
           >
             <Input.TextArea showCount maxLength={200} placeholder={'请输入说明'} rows={4} />
           </Form.Item>
-          {triggerType === TriggerWayType.device &&
-          requestParams &&
-          requestParams.trigger?.device?.productId ? (
-            <Form.Item hidden name={'shakeLimit'} initialValue={DefaultShakeLimit}>
-              <Input />
-            </Form.Item>
-          ) : null}
+          {/*{triggerType === TriggerWayType.device &&*/}
+          {/*requestParams &&*/}
+          {/*requestParams.trigger?.device?.productId ? (*/}
+          {/*  <Form.Item hidden name={['trigger','shakeLimit']}>*/}
+          {/*    <Input />*/}
+          {/*  </Form.Item>*/}
+          {/*) : null}*/}
           <Form.Item hidden name={'id'}>
             <Input />
           </Form.Item>

+ 8 - 8
src/pages/rule-engine/Scene/Save/trigger/device.tsx

@@ -362,14 +362,14 @@ export default (props: TriggerProps) => {
                 }
                 return false;
               })}
-              maxTagCount={0}
-              maxTagPlaceholder={(values) => {
-                return (
-                  <div style={{ maxWidth: 'calc(100% - 8px)' }}>
-                    {values.map((item) => item.label).toString()}
-                  </div>
-                );
-              }}
+              maxTagCount={'responsive'}
+              // maxTagPlaceholder={(values) => {
+              //   return (
+              //     <div style={{ maxWidth: 'calc(100% - 8px)' }}>
+              //       {values.map((item) => item.label).toString()}
+              //     </div>
+              //   );
+              // }}
               placeholder={'请选择属性'}
               style={{ width: '100%' }}
               fieldNames={{ label: 'name', value: 'id' }}

+ 32 - 32
src/pages/rule-engine/Scene/Save/trigger/index.tsx

@@ -98,6 +98,29 @@ export default observer((props: TriggerProps) => {
     [selector],
   );
 
+  useEffect(() => {
+    if (FormModel.trigger?.device?.operation?.functionId && functions.length) {
+      const fcItem: any = functions.find(
+        (_fcItem: any) => _fcItem.id === FormModel.trigger?.device?.operation?.functionId,
+      );
+      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);
+      }
+    }
+  }, [functions, FormModel]);
+
   const getProducts = async () => {
     const resp = await getProductList({ paging: false });
     if (resp && resp.status === 200) {
@@ -108,7 +131,7 @@ export default observer((props: TriggerProps) => {
         );
 
         if (productItem) {
-          productIdChange(FormModel.trigger!.device.productId, productItem.metadata);
+          await productIdChange(FormModel.trigger!.device.productId, productItem.metadata);
         }
       }
     }
@@ -133,10 +156,6 @@ export default observer((props: TriggerProps) => {
     }
   }, [props.value]);
 
-  useEffect(() => {
-    console.log('FormModel-device', FormModel);
-  }, [FormModel]);
-
   return (
     <div className={classNames(props.className)}>
       <Row gutter={24}>
@@ -186,6 +205,9 @@ export default observer((props: TriggerProps) => {
                       { label: '按部门', value: 'org' },
                     ]}
                     // fieldNames={{ label: 'name', value: 'id' }}
+                    onSelect={(key: string) => {
+                      setSelector(key);
+                    }}
                     style={{ width: 120 }}
                   />
                 </Form.Item>
@@ -306,21 +328,6 @@ export default observer((props: TriggerProps) => {
                   }}
                   style={{ width: '100%' }}
                   placeholder={'请选择功能'}
-                  onSelect={(_: any, data: any) => {
-                    const _properties = data.valueType ? data.valueType.properties : data.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);
-                  }}
                   filterOption={(input: string, option: any) =>
                     option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }
@@ -347,8 +354,8 @@ export default observer((props: TriggerProps) => {
             >
               <Operation
                 propertiesList={properties.filter((item) => {
-                  if (item.expands) {
-                    return item.expands.type ? item.expands.type.includes('write') : false;
+                  if (item.expands && item.expands.type) {
+                    return item.expands.type.includes('write');
                   }
                   return false;
                 })}
@@ -368,19 +375,12 @@ export default observer((props: TriggerProps) => {
               <Select
                 mode={'multiple'}
                 options={properties.filter((item) => {
-                  if (item.expands) {
-                    return item.expands.type ? item.expands.type.includes('read') : false;
+                  if (item.expands && item.expands.type) {
+                    return item.expands.type.includes('read');
                   }
                   return false;
                 })}
-                maxTagCount={0}
-                maxTagPlaceholder={(values) => {
-                  return (
-                    <div style={{ maxWidth: 'calc(100% - 8px)' }}>
-                      {values.map((item) => item.label).toString()}
-                    </div>
-                  );
-                }}
+                maxTagCount={'responsive'}
                 placeholder={'请选择属性'}
                 style={{ width: '100%' }}
                 fieldNames={{ label: 'name', value: 'id' }}

+ 1 - 0
src/pages/rule-engine/Scene/Save/trigger/operation.tsx

@@ -76,6 +76,7 @@ export default (props: OperatorProps) => {
             label: 'name',
             value: 'id',
           }}
+          maxTagCount={'responsive'}
           style={{ width: '100%' }}
           placeholder={'请选择属性'}
           onSelect={(id: any) => {

+ 57 - 8
src/pages/system/Platforms/Api/basePage.tsx

@@ -1,27 +1,76 @@
 import { Button, Table } from 'antd';
+import { useCallback, useEffect, useState } from 'react';
+import { service } from '../index';
 
-export default () => {
-  // const [selectKeys, setSelectKeys] = useState<string[]>([])
+interface TableProps {
+  parentId: string;
+  onJump: (id: string) => void;
+}
 
-  const save = () => {};
+export default (props: TableProps) => {
+  const [selectKeys, setSelectKeys] = useState<string[]>([]);
+  const [dataSource, setDataSource] = useState([]);
+
+  const queryData = async (pId: string) => {
+    const resp: any = service.queryRoleList(pId);
+    if (resp.status === 200) {
+      setDataSource(resp.result);
+    }
+  };
+
+  useEffect(() => {
+    queryData(props.parentId);
+  }, [props.parentId]);
+
+  const save = useCallback(async () => {}, [selectKeys]);
 
   return (
-    <div>
-      <Table
+    <div className={'platforms-api-table'}>
+      <Table<any>
         columns={[
           {
             title: 'API',
             dataIndex: 'name',
+            render: (text: string, record) => {
+              return (
+                <Button
+                  type={'link'}
+                  style={{ padding: 0 }}
+                  onClick={() => {
+                    props.onJump(record.id);
+                  }}
+                >
+                  {text}
+                </Button>
+              );
+            },
           },
           {
             title: '说明',
             dataIndex: '',
           },
         ]}
+        dataSource={dataSource}
+        rowSelection={{
+          selectedRowKeys: selectKeys,
+          onSelect: (record, selected) => {
+            if (selected) {
+              const newArr = [...selectKeys, record];
+              setSelectKeys(newArr);
+            } else {
+              setSelectKeys([...selectKeys.filter((key) => key !== record)]);
+            }
+          },
+          onSelectAll: (_, selectedRows) => {
+            setSelectKeys(selectedRows);
+          },
+        }}
       />
-      <Button type={'primary'} onClick={save}>
-        保存
-      </Button>
+      <div className={'platforms-api-save'}>
+        <Button type={'primary'} onClick={save}>
+          保存
+        </Button>
+      </div>
     </div>
   );
 };

+ 20 - 0
src/pages/system/Platforms/Api/index.less

@@ -0,0 +1,20 @@
+.platforms-api {
+  display: flex;
+  padding: 24px;
+  background-color: #fff;
+
+  .platforms-api-tree {
+    width: 320px;
+  }
+
+  .platforms-api-table {
+    display: flex;
+    flex-direction: column;
+    flex-grow: 1;
+    width: 0;
+
+    .platforms-api-save {
+      margin-top: 12px;
+    }
+  }
+}

+ 15 - 5
src/pages/system/Platforms/Api/index.tsx

@@ -1,15 +1,25 @@
 import { PageContainer } from '@ant-design/pro-layout';
-import { Tree } from 'antd';
 import Table from './basePage';
+import Tree from './leftTree';
+import './index.less';
+import { useState } from 'react';
 
 export default () => {
+  const [jumpId, setJumpId] = useState('');
+  const [parentId, setParentId] = useState('');
+
   return (
     <PageContainer>
-      <div>
-        <div>
-          <Tree />
+      <div className={'platforms-api'}>
+        <div className={'platforms-api-tree'}>
+          <Tree
+            onSelect={(id) => {
+              setJumpId('');
+              setParentId(id);
+            }}
+          />
         </div>
-        <Table />
+        {!jumpId ? <Table parentId={parentId} onJump={setJumpId} /> : <></>}
       </div>
     </PageContainer>
   );

+ 119 - 0
src/pages/system/Platforms/Api/leftTree.tsx

@@ -0,0 +1,119 @@
+import { Tree } from 'antd';
+import React, { useState } from 'react';
+import { queryChannel } from '@/pages/media/SplitScreen/service';
+
+type LeftTreeType = {
+  onSelect: (id: string) => void;
+};
+
+interface DataNode {
+  name: string;
+  id: string;
+  isLeaf?: boolean;
+  icon?: React.ReactNode;
+  children?: DataNode[];
+}
+
+export default (props: LeftTreeType) => {
+  const [treeData, setTreeData] = useState<DataNode[]>([]);
+
+  /**
+   * 是否为子节点
+   * @param node
+   */
+  const isLeaf = (node: DataNode): boolean => {
+    if (node.children) {
+      return false;
+    }
+    return true;
+  };
+
+  const updateTreeData = (list: DataNode[], key: React.Key, children: DataNode[]): DataNode[] => {
+    return list.map((node) => {
+      if (node.id === key) {
+        return {
+          ...node,
+          children: node.children ? [...node.children, ...children] : children,
+        };
+      }
+
+      if (node.children) {
+        return {
+          ...node,
+          children: updateTreeData(node.children, key, children),
+        };
+      }
+      return node;
+    });
+  };
+
+  const getChildren = (key: React.Key, params: any): Promise<any> => {
+    return new Promise(async (resolve) => {
+      const resp = await queryChannel(params);
+      if (resp.status === 200) {
+        const { total, pageIndex, pageSize } = resp.result;
+        setTreeData((origin) => {
+          const data = updateTreeData(
+            origin,
+            key,
+            resp.result.data.map((item: DataNode) => ({
+              ...item,
+              isLeaf: isLeaf(item),
+            })),
+          );
+
+          if (total > (pageIndex + 1) * pageSize) {
+            setTimeout(() => {
+              getChildren(key, {
+                ...params,
+                pageIndex: params.pageIndex + 1,
+              });
+            }, 50);
+          }
+
+          return data;
+        });
+        resolve(resp.result);
+      }
+    });
+  };
+
+  const onLoadData = ({ key, children }: any): Promise<void> => {
+    return new Promise(async (resolve) => {
+      if (children) {
+        resolve();
+        return;
+      }
+      await getChildren(key, {
+        pageIndex: 0,
+        pageSize: 100,
+        terms: [
+          {
+            column: 'deviceId',
+            value: key,
+          },
+        ],
+      });
+      resolve();
+    });
+  };
+
+  return (
+    <Tree
+      showIcon
+      showLine={{ showLeafIcon: false }}
+      height={550}
+      fieldNames={{
+        title: 'name',
+        key: 'id',
+      }}
+      onSelect={(_, { node }: any) => {
+        if (props.onSelect && node.isLeaf) {
+          props.onSelect(node.id);
+        }
+      }}
+      loadData={onLoadData}
+      treeData={treeData}
+    />
+  );
+};

+ 3 - 0
src/utils/menu/index.ts

@@ -53,6 +53,9 @@ const extraRouteObj = {
   demo: {
     children: [{ code: 'AMap', name: '地图' }],
   },
+  'system/Platforms': {
+    children: [{ code: 'Api', name: '赋权' }],
+  },
 };
 //额外路由
 export const extraRouteArr = [