瀏覽代碼

Merge xyh

Next xyh
XieYongHong 3 年之前
父節點
當前提交
a59685c79c

+ 1 - 1
src/components/DashBoard/echarts.tsx

@@ -87,7 +87,7 @@ export default (props: EchartsProps) => {
     if (chartsRef.current && props.options) {
       chartsRef.current.setOption(props.options);
     }
-  }, [props.options]);
+  }, [props.options, chartsRef.current]);
 
   return (
     <div

+ 0 - 1
src/components/Player/ScreenPlayer.tsx

@@ -297,7 +297,6 @@ export default forwardRef((props: ScreenProps, ref) => {
         {props.showScreen !== false && (
           <div className={'player-screen-tool'}>
             <>
-              <div></div>
               <div>
                 <Radio.Group
                   options={[

+ 3 - 3
src/components/ProTableCard/CardItems/device.tsx

@@ -67,11 +67,11 @@ export const ExtraDeviceCard = (props: DeviceCardProps) => {
         </div>
         <div className={'card-item-body'}>
           <div className={'card-item-header'}>
-            <span className={'card-item-header-name'}>
+            <div className={'card-item-header-name'}>
               <Tooltip title={props.name}>
-                <span className={'ellipsis'}>{props.name}</span>
+                <div className={'ellipsis'}>{props.name}</div>
               </Tooltip>
-            </span>
+            </div>
           </div>
           <div className={'card-item-content-flex'}>
             <div className={'flex-auto'}>

+ 3 - 3
src/components/ProTableCard/CardItems/product.tsx

@@ -69,11 +69,11 @@ export const ExtraProductCard = (props: ProductCardProps) => {
         </div>
         <div className={'card-item-body'}>
           <div className={'card-item-header'}>
-            <span className={'card-item-header-name'}>
+            <div className={'card-item-header-name'}>
               <Tooltip title={props.name}>
-                <span className={'ellipsis'}>{props.name}</span>
+                <div className={'ellipsis'}>{props.name}</div>
               </Tooltip>
-            </span>
+            </div>
           </div>
           <div className={'card-item-content-items'} style={{ display: 'flex', gap: 12 }}>
             {props.content}

+ 0 - 1
src/components/ProTableCard/index.less

@@ -46,7 +46,6 @@
           margin-bottom: 12px;
 
           .card-item-header-name {
-            flex: 1;
             font-weight: bold;
             font-size: 16px;
           }

+ 4 - 2
src/pages/Northbound/DuerOS/Detail/index.tsx

@@ -61,12 +61,13 @@ const Save = () => {
     return _productTypes?.find((item: any) => item.id === _id);
   };
 
-  const getProduct = () =>
-    service.getProduct().then((resp) => {
+  const getProduct = (f: Field) => {
+    return service.getProduct(f?.value).then((resp) => {
       const _temp = resp.result.map((item: any) => ({ label: item.name, value: item.id }));
       Store.set('product-list', _temp);
       return _temp;
     });
+  };
 
   const getTypes = () =>
     service.getTypes().then((resp) => {
@@ -171,6 +172,7 @@ const Save = () => {
             switch (value) {
               case 'date':
                 format.setComponent(DatePicker);
+                format.value = new Date();
                 break;
               case 'string':
                 format.setComponent(Input);

+ 11 - 8
src/pages/Northbound/DuerOS/service.ts

@@ -9,19 +9,22 @@ class Service extends BaseService<DuerOSItem> {
       method: 'GET',
     });
 
-  public getProduct = () =>
-    request(`/${SystemConst.API_BASE}/device-product/_query/no-paging`, {
+  public getProduct = (id?: string) => {
+    const defaultData = {
+      column: 'id$dueros-product$not',
+      value: 1,
+    };
+
+    const data = id ? [defaultData, { column: 'id', type: 'or', value: id }] : [defaultData];
+
+    return request(`/${SystemConst.API_BASE}/device-product/_query/no-paging`, {
       method: 'POST',
       data: {
         paging: false,
-        terms: [
-          {
-            column: 'id$dueros-product$not',
-            value: 1,
-          },
-        ],
+        terms: data,
       },
     });
+  };
 
   public changeState = (id: string, state: 'enable' | 'disable') =>
     request(`/${SystemConst.API_BASE}/dueros/product/${id}/_${state}`, { method: 'POST' });

+ 2 - 0
src/pages/device/DashBoard/index.tsx

@@ -268,6 +268,7 @@ const DeviceBoard = () => {
         setOptions({
           xAxis: {
             type: 'category',
+            boundaryGap: false,
             data: x,
           },
           yAxis: {
@@ -339,6 +340,7 @@ const DeviceBoard = () => {
         setOptions({
           xAxis: {
             type: 'category',
+            boundaryGap: false,
             data: x,
           },
           yAxis: {

+ 23 - 0
src/pages/link/DashBoard/index.less

@@ -14,6 +14,8 @@
       background-color: #fff;
 
       .echarts-item-left {
+        display: flex;
+        flex-direction: column;
         width: 45%;
       }
 
@@ -31,6 +33,27 @@
         font-weight: bold;
         font-size: 36px;
       }
+
+      .echarts-item-bottom {
+        position: relative;
+        display: flex;
+        flex-direction: column;
+        flex-grow: 1;
+        justify-content: center;
+        height: 0;
+        padding-left: 12px;
+
+        &::before {
+          position: absolute;
+          top: 50%;
+          left: 0;
+          width: 4px;
+          height: 12px;
+          background-color: #ff595e;
+          transform: translateY(-50%);
+          content: ' ';
+        }
+      }
     }
   }
 }

+ 39 - 13
src/pages/link/DashBoard/index.tsx

@@ -16,7 +16,10 @@ type RefType = {
 };
 type TopEchartsItemNodeType = {
   value: any;
+  max?: any;
   title: string;
+  formatter?: string;
+  bottom?: string;
 };
 
 const service = new Service('dashboard');
@@ -27,7 +30,7 @@ const TopEchartsItemNode = (props: TopEchartsItemNodeType) => {
       {
         type: 'gauge',
         min: 0,
-        max: 100,
+        max: props.max || 100,
         startAngle: 200,
         endAngle: -20,
         center: ['50%', '65%'],
@@ -50,9 +53,10 @@ const TopEchartsItemNode = (props: TopEchartsItemNodeType) => {
           },
         },
         axisLabel: {
-          distance: -18,
+          distance: -22,
           color: 'auto',
           fontSize: 12,
+          formatter: '{value}' + (props.formatter || '%'),
         },
         pointer: {
           length: '80%',
@@ -132,7 +136,11 @@ const TopEchartsItemNode = (props: TopEchartsItemNodeType) => {
     <div className={'echarts-item'}>
       <div className={'echarts-item-left'}>
         <div className={'echarts-item-title'}>{props.title}</div>
-        <div className={'echarts-item-value'}>{props.value}%</div>
+        <div className={'echarts-item-value'}>
+          {props.value}
+          {props.formatter || '%'}
+        </div>
+        {props.bottom && <div className={'echarts-item-bottom'}>{props.bottom}</div>}
       </div>
       <div className={'echarts-item-right'}>
         <>
@@ -160,8 +168,10 @@ export default () => {
   const [topValues, setTopValues] = useState({
     cpu: 0,
     jvm: 0,
+    jvmTotal: 0,
     usage: 0,
     systemUsage: 0,
+    systemUsageTotal: 0,
   });
 
   const NETWORKRef = useRef<RefType>(); // 网络流量
@@ -187,9 +197,8 @@ export default () => {
       case 'year':
         return 'YYYY-MM-DD';
       case 'month':
-        return 'MM-DD';
       case 'week':
-        return 'MM-DD HH';
+        return 'MM-DD';
       case 'hour':
         return 'HH:mm';
       default:
@@ -201,12 +210,11 @@ export default () => {
     switch (type) {
       case 'year':
         return '30d';
+      case 'month':
       case 'week':
         return '1d';
-      case 'month':
-        return '1h';
       default:
-        return '1m';
+        return '1h';
     }
   };
 
@@ -215,6 +223,7 @@ export default () => {
       xAxis: {
         type: 'category',
         data: xAxis,
+        boundaryGap: false,
       },
       tooltip: {
         trigger: 'axis',
@@ -259,6 +268,7 @@ export default () => {
     setJvmOptions({
       xAxis: {
         type: 'category',
+        boundaryGap: false,
         data: arrayReverse(xAxis),
       },
       tooltip: {
@@ -315,6 +325,7 @@ export default () => {
     setCpuOptions({
       xAxis: {
         type: 'category',
+        boundaryGap: false,
         data: arrayReverse(xAxis),
       },
       tooltip: {
@@ -610,12 +621,15 @@ export default () => {
         const cpu = value.cpu;
         const memory = value.memory;
         const disk = value.disk;
-
         setTopValues({
           cpu: cpu.systemUsage,
-          jvm: memory.jvmHeapUsage,
+          jvm: Number(((memory.jvmHeapUsage / 100) * (memory.jvmHeapTotal / 1024)).toFixed(1)),
+          jvmTotal: Math.ceil(memory.jvmHeapTotal / 1024),
           usage: disk.usage,
-          systemUsage: memory.systemUsage,
+          systemUsage: Number(
+            ((memory.systemTotal / 1024) * (memory.systemUsage / 100)).toFixed(1),
+          ),
+          systemUsageTotal: Math.ceil(memory.systemTotal / 1024),
         });
       });
 
@@ -645,9 +659,21 @@ export default () => {
         ) : null}
         <div className={'echarts-items'}>
           <TopEchartsItemNode title={'CPU使用率'} value={topValues.cpu} />
-          <TopEchartsItemNode title={'JVM内存'} value={topValues.jvm} />
+          <TopEchartsItemNode
+            title={'JVM内存'}
+            formatter={'G'}
+            value={topValues.jvm}
+            max={topValues.jvmTotal}
+            bottom={`总JVM内存  ${topValues.jvmTotal}G`}
+          />
           <TopEchartsItemNode title={'磁盘占用率'} value={topValues.usage} />
-          <TopEchartsItemNode title={'系统内存'} value={topValues.systemUsage} />
+          <TopEchartsItemNode
+            title={'系统内存'}
+            formatter={'G'}
+            value={topValues.systemUsage}
+            max={topValues.systemUsageTotal}
+            bottom={`系统内存  ${topValues.systemUsageTotal}G`}
+          />
           {/*<div className={'echarts-item'}>*/}
           {/*  */}
           {/*  <Progress*/}

+ 1 - 0
src/pages/media/DashBoard/index.tsx

@@ -96,6 +96,7 @@ export default () => {
       setOptions({
         xAxis: {
           type: 'category',
+          boundaryGap: false,
           data: xData,
         },
         yAxis: {

+ 6 - 0
src/pages/media/Device/Save/index.tsx

@@ -240,6 +240,7 @@ const Save = () => {
                     >
                       <Form.Item name={'productId'} noStyle>
                         <Select
+                          showSearch
                           fieldNames={{
                             label: 'name',
                             value: 'id',
@@ -248,6 +249,11 @@ const Save = () => {
                           options={productList}
                           placeholder={'请选择所属产品'}
                           style={{ width: id ? '100%' : 'calc(100% - 36px)' }}
+                          filterOption={(input, option) =>
+                            (option!.name as unknown as string)
+                              .toLowerCase()
+                              .includes(input.toLowerCase())
+                          }
                           onSelect={(_: any, node: any) => {
                             const pwd = node.configuration ? node.configuration.access_pwd : '';
                             form.setFieldsValue({

+ 1 - 1
src/pages/media/Home/index.tsx

@@ -108,7 +108,7 @@ export default () => {
             data={[
               {
                 name: '设备数量',
-                value: deviceTotal,
+                value: deviceTotal || 0,
                 children: require('/public/images/home/top-1.png'),
               },
               {

+ 2 - 1
src/pages/media/Home/service.tsx

@@ -5,7 +5,8 @@ import type { DeviceItem } from '@/pages/media/Device/typings';
 class Service extends BaseService<DeviceItem> {
   deviceCount = (data?: any) => request(`${this.uri}/_count`, { methods: 'GET', params: data });
 
-  channelCount = (data?: any) => request(`${this.uri}/channel/_count`, { method: 'POST', data });
+  channelCount = (data?: any) =>
+    request(`${this.uri}/channel/_count`, { method: 'GET', params: data });
 }
 
 export default Service;

+ 18 - 7
src/pages/rule-engine/DashBoard/index.tsx

@@ -10,6 +10,7 @@ import DashBoard, { DashBoardTopCard } from '@/components/DashBoard';
 import styles from './index.less';
 import moment from 'moment';
 import Echarts from '@/components/DashBoard/echarts';
+import encodeQuery from '@/utils/encodeQuery';
 
 const service = new Service();
 export const state = model<{
@@ -51,7 +52,7 @@ const Dashboard = observer(() => {
     dimension: 'agg',
     group: 'today',
     params: {
-      time: '1d',
+      time: '1h',
       targetType: 'device',
       format: 'HH:mm:ss',
       from: moment(new Date(new Date().setHours(0, 0, 0, 0))).format('YYYY-MM-DD HH:mm:ss'),
@@ -67,7 +68,7 @@ const Dashboard = observer(() => {
     dimension: 'agg',
     group: 'thisMonth',
     params: {
-      time: '1M',
+      time: '1d',
       targetType: 'device',
       format: 'yyyy-MM',
       limit: 1,
@@ -164,8 +165,8 @@ const Dashboard = observer(() => {
 
   const getCurrentAlarm = async () => {
     const alarmLevel = await service.getAlarmLevel();
-
-    const currentAlarm = await service.getAlarm({});
+    const sorts = { alarmTime: 'desc' };
+    const currentAlarm = await service.getAlarm(encodeQuery({ sorts }));
     if (currentAlarm.status === 200) {
       if (alarmLevel.status === 200) {
         const levels = alarmLevel.result.levels;
@@ -185,6 +186,16 @@ const Dashboard = observer(() => {
   }, []);
 
   const getEcharts = async (params: any) => {
+    let time = '1h';
+    let format = 'HH';
+    if (params.time.type === 'week' || params.time.type === 'month') {
+      time = '1d';
+      format = 'M月dd日';
+    } else if (params.time.type === 'year') {
+      time = '1M';
+      format = 'yyyy年-M月';
+    }
+
     // 告警趋势
     const chartData = {
       dashboard: 'alarm',
@@ -194,8 +205,8 @@ const Dashboard = observer(() => {
       group: 'alarmTrend',
       params: {
         targetType: 'device', // product、device、org、other
-        format: 'yyyy年-M月',
-        time: '1M',
+        format: format,
+        time: time,
         // from: 'now-1y', // now-1d、now-1w、now-1M、now-1y
         // to: 'now',
         limit: 12,
@@ -215,7 +226,7 @@ const Dashboard = observer(() => {
       group: 'alarmRank',
       params: {
         // time: '1h',
-        time: params.time.type === 'today' ? '1h' : '1d',
+        time: time,
         targetType: params.targetType,
         from: moment(params.time.start).format('YYYY-MM-DD HH:mm:ss'),
         to: moment(params.time.end).format('YYYY-MM-DD HH:mm:ss'),

+ 52 - 0
src/pages/rule-engine/Scene/Save/Explanation.less

@@ -0,0 +1,52 @@
+@import '~antd/es/style/themes/default.less';
+
+.doc {
+  padding: 24px;
+  color: rgba(#000, 0.8);
+  font-size: 14px;
+  background-color: #fafafa;
+
+  .url {
+    padding: 8px 16px;
+    color: #2f54eb;
+    background-color: rgba(#a7bdf7, 0.2);
+  }
+
+  h1 {
+    margin: 16px 0;
+    color: rgba(#000, 0.85);
+    font-weight: bold;
+    font-size: 14px;
+
+    &:first-child {
+      margin-top: 0;
+    }
+  }
+
+  h2 {
+    margin: 6px 0;
+    color: rgba(0, 0, 0, 0.8);
+    font-size: 14px;
+  }
+
+  .image {
+    margin: 16px 0;
+  }
+
+  div {
+    margin: 12px 0;
+    border-radius: 2px;
+  }
+}
+
+.notice {
+  padding: 8px 12px;
+  color: rgba(#000, 0.8);
+  background-color: #f0f5ff;
+  border: 1px solid @primary-color;
+
+  > span {
+    padding-right: 12px;
+    color: @primary-color;
+  }
+}

+ 79 - 0
src/pages/rule-engine/Scene/Save/Explanation.tsx

@@ -0,0 +1,79 @@
+// 说明文档
+import styles from './Explanation.less';
+import { ExclamationCircleFilled } from '@ant-design/icons';
+
+export default () => {
+  return (
+    <div className={styles.doc} style={{ marginLeft: 12 }}>
+      <h1>1.概述</h1>
+      <div>
+        场景联动是规则引擎中,一种业务逻辑的可视化编程方式,您可以通过可视化的方式定义设备之间联动规则。当触发条件指定的事件或属性变化事件发生时,系统通过判断执行条件是否已满足,来决定是否执行规则中定义的执行动作。如果满足执行条件,则执行定义的执行动作;反之则不执行。
+      </div>
+      <div>场景联动的规则可用于告警规则的引用,达到触发条件时将生成对应的告警记录。</div>
+      <h1>2.配置说明</h1>
+      <h2>1、触发方式</h2>
+      <div>
+        包含<b>手动触发</b>、<b>定时触发</b>、<b>设备触发</b>3种方式
+      </div>
+      <h3>a. 手动触发</h3>
+      <div>适用于第三方平台向物联网平台下发指令控制设备。</div>
+      <div>
+        <b>例如:</b>用户通过智能家居APP开启或关闭设备。
+      </div>
+
+      <h3>b. 定时触发</h3>
+      <div>
+        <b>例如:</b>每天早上9点打开空调,并将空调开到26度。
+      </div>
+
+      <h3>c. 设备触发</h3>
+      <div>
+        适用于多个不同设备间执行动作的联动。选择具体设备时支持指定产品下属的固定设备、全部设备或选择产品下归属于具体部门的设备
+      </div>
+      <div>
+        <b>例如:</b>打开综合办部门房间门的时候,打开电灯、空调。
+      </div>
+
+      <h2>2、触发条件</h2>
+      <div>
+        选择设备触发时,可对设备触发条件进行详细配置。触发条件支持多组条件,条件之间支持并且/或者的关系配置。每一个分组内可以添加多个条件,条件之间支持并且/或者的关系配置。
+      </div>
+      <div>
+        触发条件支持以属性指标(需在产品物模型tab页进行属性指标定义,定义后在对应设备的运行状态页填写阈值)作为判断阈值。
+      </div>
+
+      <h2>3、执行动作</h2>
+      <div>支持消息通知、设备输出、延迟执行3种方式,延迟执行只在执行动作为串行时显示。</div>
+      <h3>a.消息通知</h3>
+      <div>
+        通过系统外的渠道给相关人员发送对应的通知模板内容。若钉钉消息、微信企业消息的通知模板中没有定义固定通知人,可在当前页面进行配置。同时“收信人”字段支持同步平台与微信、钉钉用户映射关系(对应类型的通知配置列表页配置),实现选择平台用户即可通知到对应的微信、钉钉用户。
+      </div>
+      <div className={styles.notice}>
+        <ExclamationCircleFilled />
+        注:只有设备触发时,收信人可选择关系用户。
+      </div>
+      <div>
+        <b>例如:</b>
+        设备下线时,以微信或钉钉的方式通知该“设备负责人”(需管理员先在“关系配置”菜单中定义设备与用户的关系,然后到设备实例信息页面填写值)。
+      </div>
+
+      <h3>b.设备输出</h3>
+      <div>
+        联动其他设备进行功能调用、读取属性、设置属性操作。
+        选择设备时支持固定设备、按标签(需在设备物模型中自定义配置)、按关系(需管理员先在“关系配置”菜单中定义设备与用户的关系,然后到设备实例信息页面填写值)3种方式。
+      </div>
+      <div className={styles.notice}>
+        <ExclamationCircleFilled />
+        注:只有设备触发时,被联动设备支持按关系选择。
+      </div>
+      <div>
+        <b>例如:</b>
+        {`温度传感器>30度时,与该设备相同“设备负责人”(自定义关系名)的空调执行打开操作。即可实现张三的温度传感器>30度时自动打开张三的空调,李四的温度传感器>30度时自动打开李四的空调。`}
+      </div>
+
+      <h3>c.延迟执行</h3>
+      <div>设置延时时间后,设备执行动作将保持当前状态,时间结束后再执行下一条动作。</div>
+      <div>房间门打开时,摄像头开启录像,延迟执行5s后,停止录像。</div>
+    </div>
+  );
+};

+ 202 - 171
src/pages/rule-engine/Scene/Save/index.tsx

@@ -1,5 +1,17 @@
 import { PageContainer } from '@ant-design/pro-layout';
-import { Button, Card, Form, Input, InputNumber, Radio, Space, Switch, Tooltip } from 'antd';
+import {
+  Button,
+  Card,
+  Col,
+  Form,
+  Input,
+  InputNumber,
+  Radio,
+  Row,
+  Space,
+  Switch,
+  Tooltip,
+} from 'antd';
 import { useIntl, useLocation } from 'umi';
 import { useCallback, useEffect, useRef, useState } from 'react';
 import { PermissionButton, TitleComponent } from '@/components';
@@ -14,6 +26,7 @@ import './index.less';
 import { model } from '@formily/reactive';
 import type { FormModelType } from '@/pages/rule-engine/Scene/typings';
 import { onlyMessage } from '@/utils/util';
+import Explanation from './Explanation';
 
 type ShakeLimitType = {
   enabled: boolean;
@@ -196,181 +209,199 @@ export default () => {
   return (
     <PageContainer>
       <Card>
-        <Form
-          scrollToFirstError={{
-            behavior: 'smooth',
-            block: 'end',
-          }}
-          form={form}
-          colon={false}
-          name="basicForm"
-          layout={'vertical'}
-          preserve={false}
-          className={'scene-save'}
-          initialValues={{
-            actions: [undefined],
-          }}
-          onValuesChange={(changeValue, allValues) => {
-            if (changeValue.trigger) {
-              if (changeValue.trigger.device) {
-                if (
-                  changeValue.trigger.device.productId ||
-                  changeValue.trigger.device.selectorValues ||
-                  (changeValue.trigger.device.operation &&
-                    hasKeyInObject(
-                      ['operator', 'eventId', 'functionId'],
-                      changeValue.trigger.device.operation,
-                    ))
-                ) {
-                  setTriggerValue([]);
-                  setRequestParams({ trigger: allValues.trigger });
-                  setTriggerDatas(allValues.trigger);
-                }
+        <Row>
+          <Col span={16}>
+            <Form
+              scrollToFirstError={{
+                behavior: 'smooth',
+                block: 'end',
+              }}
+              form={form}
+              colon={false}
+              name="basicForm"
+              layout={'vertical'}
+              preserve={false}
+              className={'scene-save'}
+              initialValues={{
+                actions: [undefined],
+              }}
+              onValuesChange={(changeValue, allValues) => {
+                if (changeValue.trigger) {
+                  if (changeValue.trigger.device) {
+                    if (
+                      changeValue.trigger.device.productId ||
+                      changeValue.trigger.device.selectorValues ||
+                      (changeValue.trigger.device.operation &&
+                        hasKeyInObject(
+                          ['operator', 'eventId', 'functionId'],
+                          changeValue.trigger.device.operation,
+                        ))
+                    ) {
+                      setTriggerValue([]);
+                      setRequestParams({ trigger: allValues.trigger });
+                      setTriggerDatas(allValues.trigger);
+                    }
 
-                if (
-                  hasKeyInObject(['productId'], changeValue.trigger.device) ||
-                  (changeValue.trigger.device.operation &&
-                    hasKeyInObject(
-                      ['operator', 'eventId', 'functionId'],
-                      changeValue.trigger.device.operation,
-                    ))
-                ) {
-                  setActionParams({ trigger: allValues.trigger }); // 用于内置参数请求
+                    if (
+                      hasKeyInObject(['productId'], changeValue.trigger.device) ||
+                      (changeValue.trigger.device.operation &&
+                        hasKeyInObject(
+                          ['operator', 'eventId', 'functionId'],
+                          changeValue.trigger.device.operation,
+                        ))
+                    ) {
+                      setActionParams({ trigger: allValues.trigger }); // 用于内置参数请求
+                    }
+                  } else if (['timer', 'manual'].includes(changeValue.trigger.type)) {
+                    setActionParams({ trigger: allValues.trigger }); // 用于内置参数请求
+                  }
                 }
-              } else if (['timer', 'manual'].includes(changeValue.trigger.type)) {
-                setActionParams({ trigger: allValues.trigger }); // 用于内置参数请求
-              }
-            }
 
-            if (allValues.actions) {
-              setActionsData(allValues.actions);
-            }
-            FormModel = { ...allValues };
-          }}
-        >
-          <Form.Item
-            name={'name'}
-            label={<TitleComponent data={'名称'} style={{ margin: 0 }} />}
-            rules={[
-              { required: true, message: '请输入名称' },
-              {
-                max: 64,
-                message: intl.formatMessage({
-                  id: 'pages.form.tip.max64',
-                  defaultMessage: '最多输入64个字符',
-                }),
-              },
-            ]}
-          >
-            <Input placeholder={'请输入名称'} />
-          </Form.Item>
-          <Form.Item label={<TitleComponent data={'触发方式'} style={{ margin: 0 }} />} required>
-            <Form.Item
-              name={['trigger', 'type']}
-              rules={[{ required: true, message: '请选择触发方式' }]}
+                if (allValues.actions) {
+                  setActionsData(allValues.actions);
+                }
+                FormModel = { ...allValues };
+              }}
             >
-              <TriggerWay onSelect={setTriggerType} disabled={isEdit} />
-            </Form.Item>
-            {triggerType === TriggerWayType.timing && (
-              <TimingTrigger name={['trigger']} form={form} className={'trigger-type-content'} />
-            )}
-            {triggerType === TriggerWayType.device && (
-              <TriggerDevice value={triggerDatas} className={'trigger-type-content'} form={form} />
-            )}
-          </Form.Item>
-          {triggerType === TriggerWayType.device &&
-          requestParams &&
-          requestParams.trigger?.device?.productId ? (
-            <Form.Item label={AntiShake}>
-              <TriggerTerm ref={triggerRef} params={requestParams} value={triggerValue} />
-            </Form.Item>
-          ) : null}
-          <Form.Item hidden name={'parallel'} initialValue={true}>
-            <Input />
-          </Form.Item>
-          <Form.Item
-            label={
-              <Space>
-                <TitleComponent data={<span>执行动作</span>} style={{ margin: 0 }} />
-                <Tooltip
-                  title={
-                    <div>
-                      <div>串行:按顺序依次执行动作</div>
-                      <div>并行:同时执行所有动作</div>
-                    </div>
-                  }
+              <Form.Item
+                name={'name'}
+                label={<TitleComponent data={'名称'} style={{ margin: 0 }} />}
+                rules={[
+                  { required: true, message: '请输入名称' },
+                  {
+                    max: 64,
+                    message: intl.formatMessage({
+                      id: 'pages.form.tip.max64',
+                      defaultMessage: '最多输入64个字符',
+                    }),
+                  },
+                ]}
+              >
+                <Input placeholder={'请输入名称'} />
+              </Form.Item>
+              <Form.Item
+                label={<TitleComponent data={'触发方式'} style={{ margin: 0 }} />}
+                required
+              >
+                <Form.Item
+                  name={['trigger', 'type']}
+                  rules={[{ required: true, message: '请选择触发方式' }]}
                 >
-                  <QuestionCircleOutlined style={{ margin: '0 8px', fontSize: 14 }} />
-                </Tooltip>
-                <Radio.Group
-                  value={parallel}
-                  options={[
-                    { label: '串行', value: false },
-                    { label: '并行', value: true },
-                  ]}
-                  optionType="button"
-                  onChange={(e) => {
-                    setParallel(e.target.value);
-                    form.setFieldsValue({ parallel: e.target.value });
-                  }}
-                ></Radio.Group>
-              </Space>
-            }
-          >
-            <Form.List name="actions">
-              {(fields, { add, remove }, { errors }) => (
-                <>
-                  <div className={'scene-actions'} style={{ paddingBottom: 24 }}>
-                    {fields.map(({ key, name, ...restField }) => (
-                      <ActionItems
-                        key={key}
-                        form={form}
-                        restField={restField}
-                        name={name}
-                        trigger={actionParams}
-                        triggerType={triggerType}
-                        onRemove={() => remove(name)}
-                        actionItemData={actionsData.length && actionsData[name]}
-                        parallel={parallel}
-                      />
-                    ))}
-                    <Form.Item noStyle>
-                      <Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
-                        新增
-                      </Button>
-                    </Form.Item>
-                  </div>
-                  <Form.ErrorList errors={errors} />
-                </>
-              )}
-            </Form.List>
-          </Form.Item>
-          <Form.Item
-            label={<TitleComponent data={'说明'} style={{ margin: 0 }} />}
-            name={'description'}
-          >
-            <Input.TextArea showCount maxLength={200} placeholder={'请输入说明'} rows={4} />
-          </Form.Item>
-          {/*{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>
-          <PermissionButton
-            isPermission={getOtherPermission(['add', 'update'])}
-            onClick={saveData}
-            type={'primary'}
-            loading={loading}
-            htmlType="submit"
-          >
-            保存
-          </PermissionButton>
-        </Form>
+                  <TriggerWay onSelect={setTriggerType} disabled={isEdit} />
+                </Form.Item>
+                {triggerType === TriggerWayType.timing && (
+                  <TimingTrigger
+                    name={['trigger']}
+                    form={form}
+                    className={'trigger-type-content'}
+                  />
+                )}
+                {triggerType === TriggerWayType.device && (
+                  <TriggerDevice
+                    value={triggerDatas}
+                    className={'trigger-type-content'}
+                    form={form}
+                  />
+                )}
+              </Form.Item>
+              {triggerType === TriggerWayType.device &&
+              requestParams &&
+              requestParams.trigger?.device?.productId ? (
+                <Form.Item label={AntiShake}>
+                  <TriggerTerm ref={triggerRef} params={requestParams} value={triggerValue} />
+                </Form.Item>
+              ) : null}
+              <Form.Item hidden name={'parallel'} initialValue={true}>
+                <Input />
+              </Form.Item>
+              <Form.Item
+                label={
+                  <Space>
+                    <TitleComponent data={<span>执行动作</span>} style={{ margin: 0 }} />
+                    <Tooltip
+                      title={
+                        <div>
+                          <div>串行:按顺序依次执行动作</div>
+                          <div>并行:同时执行所有动作</div>
+                        </div>
+                      }
+                    >
+                      <QuestionCircleOutlined style={{ margin: '0 8px', fontSize: 14 }} />
+                    </Tooltip>
+                    <Radio.Group
+                      value={parallel}
+                      options={[
+                        { label: '串行', value: false },
+                        { label: '并行', value: true },
+                      ]}
+                      optionType="button"
+                      onChange={(e) => {
+                        setParallel(e.target.value);
+                        form.setFieldsValue({ parallel: e.target.value });
+                      }}
+                    ></Radio.Group>
+                  </Space>
+                }
+              >
+                <Form.List name="actions">
+                  {(fields, { add, remove }, { errors }) => (
+                    <>
+                      <div className={'scene-actions'} style={{ paddingBottom: 24 }}>
+                        {fields.map(({ key, name, ...restField }) => (
+                          <ActionItems
+                            key={key}
+                            form={form}
+                            restField={restField}
+                            name={name}
+                            trigger={actionParams}
+                            triggerType={triggerType}
+                            onRemove={() => remove(name)}
+                            actionItemData={actionsData.length && actionsData[name]}
+                            parallel={parallel}
+                          />
+                        ))}
+                        <Form.Item noStyle>
+                          <Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
+                            新增
+                          </Button>
+                        </Form.Item>
+                      </div>
+                      <Form.ErrorList errors={errors} />
+                    </>
+                  )}
+                </Form.List>
+              </Form.Item>
+              <Form.Item
+                label={<TitleComponent data={'说明'} style={{ margin: 0 }} />}
+                name={'description'}
+              >
+                <Input.TextArea showCount maxLength={200} placeholder={'请输入说明'} rows={4} />
+              </Form.Item>
+              {/*{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>
+              <PermissionButton
+                isPermission={getOtherPermission(['add', 'update'])}
+                onClick={saveData}
+                type={'primary'}
+                loading={loading}
+                htmlType="submit"
+              >
+                保存
+              </PermissionButton>
+            </Form>
+          </Col>
+          <Col span={8}>
+            <Explanation />
+          </Col>
+        </Row>
       </Card>
     </PageContainer>
   );

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

@@ -135,6 +135,9 @@ const TriggerTerm = (props: Props, ref: any) => {
                   : [{ label: '手动输入', value: 'manual' }];
               state.value = 'manual';
             });
+            form1.setFieldState(field.query('.value.value[0]'), (state) => {
+              state.value = undefined;
+            });
           });
           onFieldReact('trigger.*.terms.*.value.source', (field, form1) => {
             const params = field.query('..column').value();
@@ -311,7 +314,7 @@ const TriggerTerm = (props: Props, ref: any) => {
                         'x-decorator': 'FormItem',
                         'x-component': 'TreeSelect',
                         'x-decorator-props': {
-                          gridSpan: 6,
+                          gridSpan: 5,
                         },
                         required: true,
                         'x-component-props': {

+ 6 - 3
src/pages/system/Department/Assets/deivce/index.tsx

@@ -81,8 +81,9 @@ export default observer((props: { parentId: string }) => {
     {
       dataIndex: 'id',
       title: 'ID',
-      width: 220,
+      width: 180,
       fixed: 'left',
+      ellipsis: true,
     },
     {
       dataIndex: 'name',
@@ -90,7 +91,8 @@ export default observer((props: { parentId: string }) => {
         id: 'pages.table.name',
         defaultMessage: '名称',
       }),
-      width: 200,
+      width: 180,
+      ellipsis: true,
     },
     {
       title: intl.formatMessage({
@@ -102,6 +104,7 @@ export default observer((props: { parentId: string }) => {
         return row.productName;
       },
       width: 200,
+      ellipsis: true,
     },
     {
       title: '资产权限',
@@ -164,7 +167,7 @@ export default observer((props: { parentId: string }) => {
       }),
       valueType: 'option',
       align: 'center',
-      width: 200,
+      width: 60,
       fixed: 'right',
       render: (text, record) => [
         <Popconfirm

+ 6 - 3
src/pages/system/Department/Assets/product/index.tsx

@@ -68,8 +68,9 @@ export default observer((props: { parentId: string }) => {
     {
       dataIndex: 'id',
       title: 'ID',
-      width: 220,
+      width: 180,
       fixed: 'left',
+      ellipsis: true,
     },
     {
       dataIndex: 'name',
@@ -80,7 +81,8 @@ export default observer((props: { parentId: string }) => {
       search: {
         transform: (value) => ({ name$LIKE: value }),
       },
-      width: 200,
+      width: 180,
+      ellipsis: true,
     },
     {
       title: '资产权限',
@@ -98,6 +100,7 @@ export default observer((props: { parentId: string }) => {
       }),
       dataIndex: 'describe',
       hideInSearch: true,
+      ellipsis: true,
       width: 200,
     },
     {
@@ -107,7 +110,7 @@ export default observer((props: { parentId: string }) => {
       }),
       valueType: 'option',
       align: 'center',
-      width: 200,
+      width: 60,
       fixed: 'right',
       render: (text, record) => [
         <Popconfirm

+ 2 - 1
src/pages/system/Department/Member/index.tsx

@@ -122,7 +122,8 @@ const Member = observer((props: { parentId: string }) => {
         defaultMessage: '操作',
       }),
       valueType: 'option',
-      width: 200,
+      width: 60,
+      ellipsis: true,
       fixed: 'right',
       render: (text, record) => [
         <Popconfirm