Explorar el Código

feat(merge): merge xyh

Next xyh
Lind hace 3 años
padre
commit
611d4169b2

+ 3 - 3
src/pages/device/Instance/Detail/Running/Property/PropertyCard.less

@@ -12,11 +12,11 @@
 
   .card-title {
     width: 60%;
-    margin-right: 10;
+    margin-right: 10px;
     overflow: hidden;
-    color: 'rgba(0, 0, 0, .65)';
+    color: rgba(0, 0, 0, 0.65);
     font-weight: 400;
-    font-size: 12;
+    font-size: 12px;
     white-space: nowrap;
     text-overflow: ellipsis;
   }

+ 26 - 9
src/pages/rule-engine/Scene/Save/action/action.tsx

@@ -1,12 +1,19 @@
-import { Button, Form, InputNumber, Select } from 'antd';
+import { Button, InputNumber, Select, Form } from 'antd';
+import type { FormInstance } from 'antd';
 import { useEffect, useState } from 'react';
 import { useRequest } from 'umi';
-import { queryMessageConfig, queryMessageTemplate, queryMessageType } from './service';
+import {
+  queryMessageType,
+  queryMessageConfig,
+  queryMessageTemplate,
+  queryMessageTemplateDetail,
+} from './service';
 import MessageContent from './messageContent';
 
 interface ActionProps {
   restField: any;
   name: number;
+  form: FormInstance;
   title?: string;
   onRemove: () => void;
 }
@@ -49,6 +56,8 @@ const ActionItem = (props: ActionProps) => {
           style={{ width: 140 }}
           onChange={async (key: string) => {
             setTemplateData(undefined);
+            props.form.resetFields([['actions', name, 'notify', 'notifierId']]);
+            props.form.resetFields([['actions', name, 'notify', 'templateId']]);
             await queryMessageConfigs({
               terms: [{ column: 'type$IN', value: key }],
             });
@@ -62,6 +71,7 @@ const ActionItem = (props: ActionProps) => {
           fieldNames={{ value: 'id', label: 'name' }}
           onChange={async (key: string) => {
             setTemplateData(undefined);
+            props.form.resetFields([['actions', name, 'notify', 'templateId']]);
             await queryMessageTemplates({
               terms: [{ column: 'configId', value: key }],
             });
@@ -77,8 +87,11 @@ const ActionItem = (props: ActionProps) => {
           fieldNames={{ value: 'id', label: 'name' }}
           style={{ width: 160 }}
           placeholder={'请选择通知模板'}
-          onChange={async (key: string, nodeData: any) => {
-            setTemplateData(nodeData);
+          onChange={async (key: string) => {
+            const resp = await queryMessageTemplateDetail(key);
+            if (resp.status === 200) {
+              setTemplateData(resp.result);
+            }
           }}
         />
       </Form.Item>
@@ -130,7 +143,10 @@ const ActionItem = (props: ActionProps) => {
   return (
     <div className={'actions-item'}>
       <div className={'actions-item-title'}>
-        执行动作 {props.title} <Button onClick={props.onRemove}>删除</Button>
+        执行动作 {props.name + 1}
+        <Button type={'link'} onClick={props.onRemove}>
+          删除
+        </Button>
       </div>
       <div style={{ display: 'flex', gap: 12 }}>
         <Form.Item {...props.restField} name={[name, 'executor']}>
@@ -140,7 +156,8 @@ const ActionItem = (props: ActionProps) => {
               { label: '设备输出', value: 'device' },
               { label: '延迟执行', value: 'delay' },
             ]}
-            style={{ width: 100 }}
+            placeholder={'请选择动作方式'}
+            style={{ width: 140 }}
             onSelect={(key: string) => {
               setType1(key);
             }}
@@ -151,10 +168,10 @@ const ActionItem = (props: ActionProps) => {
         {type1 === 'delay' && (
           <InputNumber addonAfter={TimeTypeAfter} style={{ width: 150 }} min={0} max={9999} />
         )}
-        {type1 === 'message' && templateData ? (
-          <MessageContent template={templateData} name={props.name} />
-        ) : null}
       </div>
+      {type1 === 'message' && templateData ? (
+        <MessageContent form={props.form} template={templateData} name={props.name} />
+      ) : null}
     </div>
   );
 };

+ 133 - 29
src/pages/rule-engine/Scene/Save/action/messageContent.tsx

@@ -1,26 +1,65 @@
-import { Col, Form, Input, Row, Select, TimePicker } from 'antd';
-import { ItemGroup } from '@/pages/rule-engine/Scene/Save/components';
+import { Col, Form, Row, Select, Input, DatePicker, InputNumber } from 'antd';
+import type { FormInstance } from 'antd';
+import { ItemGroup, InputFile } from '@/pages/rule-engine/Scene/Save/components';
+import { useEffect, useState } from 'react';
+import { TriggerWayType } from '@/pages/rule-engine/Scene/Save/components/TriggerWay';
 
 interface MessageContentProps {
   name: number;
   template?: any;
+  form: FormInstance;
 }
 
 const rowGutter = 12;
 
+const BuiltInSelectOptions = {
+  [TriggerWayType.timing]: [
+    { label: '设备名称', value: 'device-name' },
+    { label: '设备ID', value: 'device-id' },
+    { label: '产品名称', value: 'product-name' },
+    { label: '产品ID', value: 'product-id' },
+    { label: '系统时间', value: 'device-name' },
+    { label: '设备名称', value: 'device-name' },
+  ],
+  [TriggerWayType.manual]: [],
+  [TriggerWayType.device]: [],
+};
+
 export default (props: MessageContentProps) => {
-  const inputNodeByType = (data: any) => {
-    switch (data.type) {
-      case 'enum':
-        return <Select placeholder={`请选择${data.name}`} style={{ width: '100%' }} />;
-      case 'timmer':
-        return <TimePicker style={{ width: '100%' }} />;
-      case 'number':
-        return <Input placeholder={`请输入${data.name}`} style={{ width: '100%' }} />;
-      default:
-        return <Input placeholder={`请输入${data.name}`} />;
+  const [triggerType, setTriggerType] = useState('');
+
+  useEffect(() => {
+    const trigger = props.form.getFieldsValue([['trigger', 'type']]);
+    if (trigger) {
+      setTriggerType(trigger.type);
     }
-  };
+  }, []);
+
+  // const inputNodeByType = useCallback((data: any) => {
+  //   const { actions } = props.form.getFieldsValue([['actions',props.name, 'notify']])
+  //   console.log(actions);
+  //   if (actions && actions[props.name].notify && actions[props.name].notify.variables) {
+  //     const type = actions[props.name].notify.variables[data.id].type
+  //
+  //     if (type === 2) {
+  //       return <Select options={BuiltInSelectOptions[triggerType] || []} style={{ width: '100%'}} />
+  //     }
+  //   }
+  //
+  //   switch (data.type) {
+  //     case 'enum':
+  //       return <Select placeholder={`请选择${data.name}`} style={{ width: '100%' }} />;
+  //     case 'date':
+  //       // @ts-ignore
+  //       return <DatePicker style={{ width: '100%' }} format={data.format || 'YYYY-MM-DD HH:mm:ss'} />;
+  //     case 'number':
+  //       return <InputNumber placeholder={`请输入${data.name}`} style={{ width: '100%' }} />;
+  //     case 'file':
+  //       return <InputFile />;
+  //     default:
+  //       return <Input placeholder={`请输入${data.name}`} />;
+  //   }
+  // }, [triggerType]);
 
   return (
     <>
@@ -28,24 +67,89 @@ export default (props: MessageContentProps) => {
         <div className={'template-variable'}>
           {props.template.variableDefinitions ? (
             <Row gutter={rowGutter}>
-              {props.template.variableDefinitions.map((item: any) => {
-                // const rules = !item.required ? [{ required: true, message: '请输入'+ item.name }] : undefined
+              {props.template.variableDefinitions.map((item: any, index: number) => {
                 return (
-                  <Col span={12} key={item.id}>
-                    <Form.Item
-                      name={[props.name, 'notify', 'variables', item.id]}
-                      label={item.name}
-                    >
+                  <Col span={12} key={`${item.id}_${index}`}>
+                    <Form.Item label={item.name} style={{ margin: 0 }}>
                       <ItemGroup>
-                        <Select
-                          defaultValue={'1'}
-                          options={[
-                            { label: '手动输入', value: '1' },
-                            { label: '内置参数', value: '2' },
-                          ]}
-                          style={{ width: 120 }}
-                        />
-                        {inputNodeByType(item)}
+                        <Form.Item
+                          name={[props.name, 'notify', 'variables', item.id, 'type']}
+                          initialValue={'1'}
+                        >
+                          <Select
+                            options={[
+                              { label: '手动输入', value: '1' },
+                              { label: '内置参数', value: '2' },
+                            ]}
+                            style={{ width: 120 }}
+                          />
+                        </Form.Item>
+                        <Form.Item
+                          name={[props.name, 'notify', 'variables', item.id, 'value']}
+                          shouldUpdate={(prevValues, curValues) => {
+                            const oldNotify = prevValues.actions[props.name].notify.variables;
+                            const curNotify = curValues.actions[props.name].notify.variables;
+
+                            if (oldNotify && curNotify) {
+                              if (oldNotify[item.id] && curNotify[item.id]) {
+                                return oldNotify[item.id].type !== curNotify[item.id].type;
+                              }
+                            }
+                            return false;
+                          }}
+                        >
+                          {() => {
+                            const { actions } = props.form.getFieldsValue([
+                              ['actions', props.name, 'notify'],
+                            ]);
+                            console.log(actions);
+                            if (
+                              actions &&
+                              actions[props.name].notify &&
+                              actions[props.name].notify.variables
+                            ) {
+                              const type = actions[props.name].notify.variables[item.id].type;
+
+                              if (type === 2) {
+                                return (
+                                  <Select
+                                    options={BuiltInSelectOptions[triggerType] || []}
+                                    style={{ width: '100%' }}
+                                  />
+                                );
+                              }
+                            }
+
+                            switch (item.type) {
+                              case 'enum':
+                                return (
+                                  <Select
+                                    placeholder={`请选择${item.name}`}
+                                    style={{ width: '100%' }}
+                                  />
+                                );
+                              case 'date':
+                                return (
+                                  // @ts-ignore
+                                  <DatePicker
+                                    style={{ width: '100%' }}
+                                    format={item.format || 'YYYY-MM-DD HH:mm:ss'}
+                                  />
+                                );
+                              case 'number':
+                                return (
+                                  <InputNumber
+                                    placeholder={`请输入${item.name}`}
+                                    style={{ width: '100%' }}
+                                  />
+                                );
+                              case 'file':
+                                return <InputFile />;
+                              default:
+                                return <Input placeholder={`请输入${item.name}`} />;
+                            }
+                          }}
+                        </Form.Item>
                       </ItemGroup>
                     </Form.Item>
                   </Col>

+ 3 - 0
src/pages/rule-engine/Scene/Save/action/service.ts

@@ -18,6 +18,9 @@ export const queryMessageTemplate = (data: any) =>
     data,
   });
 
+export const queryMessageTemplateDetail = (id: string) =>
+  request(`${SystemConst.API_BASE}/notifier/template/${id}/detail`);
+
 export const queryProductList = (data?: any) =>
   request(`${SystemConst.API_BASE}/device-product/_query/no-paging?paging=false`, {
     method: 'POST',

+ 76 - 0
src/pages/rule-engine/Scene/Save/components/InputUpload/index.tsx

@@ -0,0 +1,76 @@
+import { useEffect, useState } from 'react';
+import { Upload, Input, Button } from 'antd';
+import { UploadChangeParam } from 'antd/lib/upload/interface';
+import SystemConst from '@/utils/const';
+import Token from '@/utils/token';
+import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
+
+interface InputUploadProps {
+  value?: string;
+  onChange?: (value?: string) => void;
+}
+
+export default (props: InputUploadProps) => {
+  const { onChange } = props;
+
+  const [url, setUrl] = useState('');
+  const [loading, setLoading] = useState<boolean>(false);
+
+  useEffect(() => {
+    setUrl(url);
+  }, [props.value]);
+
+  const handleChange = (info: UploadChangeParam) => {
+    if (info.file.status === 'uploading') {
+      setLoading(true);
+    }
+    if (info.file.status === 'done') {
+      info.file.url = info.file.response?.result;
+      setLoading(false);
+      setUrl(info.file.response?.result);
+    }
+  };
+
+  // const beforeUpload = (file: RcFile) => {
+  //   const isType = imageTypes.includes(file.type);
+  //   if (!isType) {
+  //     message.error(`图片格式错误,必须是${imageTypes.toString()}格式`);
+  //     return false;
+  //   }
+  //   const isSize = file.size / 1024 / 1024 < (extraProps.size || 4);
+  //   if (!isSize) {
+  //     message.error(`图片大小必须小于${extraProps.size || 4}M`);
+  //   }
+  //   return isType && isSize;
+  // };
+
+  const UploadNode = (
+    <Upload
+      action={`/${SystemConst.API_BASE}/file/static`}
+      headers={{
+        'X-Access-Token': Token.get(),
+      }}
+      showUploadList={false}
+      onChange={handleChange}
+      disabled={loading}
+    >
+      <Button type={'link'} style={{ height: 30 }}>
+        {loading ? <LoadingOutlined /> : <PlusOutlined />}
+        上传附件
+      </Button>
+    </Upload>
+  );
+
+  return (
+    <Input
+      value={url}
+      onChange={(e) => {
+        if (onChange) {
+          onChange(e.target.value);
+        }
+      }}
+      addonAfter={UploadNode}
+      placeholder={'请上传文件'}
+    />
+  );
+};

+ 5 - 2
src/pages/rule-engine/Scene/Save/components/ItemGroup/index.less

@@ -1,7 +1,10 @@
 .group-item-compact {
   display: flex;
+  gap: 12px;
 
-  &:nth-last-child(1) {
-    flex: 1;
+  > div {
+    &:last-child {
+      flex: 1;
+    }
   }
 }

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

@@ -7,7 +7,7 @@ interface TriggerWayProps {
   onChange?: (type: string) => void;
 }
 
-enum TriggerWayType {
+export enum TriggerWayType {
   manual = 'manual',
   timing = 'timer',
   device = 'device',

+ 1 - 0
src/pages/rule-engine/Scene/Save/components/index.ts

@@ -2,3 +2,4 @@ export { default as TimeSelect } from './TimeSelect';
 export { default as TimingTrigger } from './TimingTrigger';
 export { default as TriggerWay } from './TriggerWay';
 export { default as ItemGroup } from './ItemGroup';
+export { default as InputFile } from './InputUpload';

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

@@ -1,10 +1,11 @@
 import { PageContainer } from '@ant-design/pro-layout';
-import { Button, Card, Form } from 'antd';
+import { Button, Card, Form, Input } from 'antd';
 import { useLocation } from 'umi';
 import { useEffect } from 'react';
 import { PermissionButton } from '@/components';
 import ActionItems from './action/action';
 import { PlusOutlined } from '@ant-design/icons';
+import { TriggerWay } from './components';
 import TriggerTerm from '@/pages/rule-engine/Scene/TriggerTerm';
 
 export default () => {
@@ -33,30 +34,36 @@ export default () => {
   return (
     <PageContainer>
       <Card>
-        <Form form={form} autoComplete="off">
-          <Form.List name="users">
-            {(fields, { add, remove }) => (
-              <>
-                {fields.map(({ key, name, ...restField }) => (
-                  <ActionItems
-                    key={key}
-                    restField={restField}
-                    onRemove={() => remove(name)}
-                    name={name}
-                  />
-                ))}
-                <Form.Item>
-                  <Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
-                    新增
-                  </Button>
-                </Form.Item>
-              </>
-            )}
-          </Form.List>
-          <Form.Item>
-            <Button type="primary" htmlType="submit">
-              Submit
-            </Button>
+        <Form form={form} colon={false} layout={'vertical'} preserve={false}>
+          <Form.Item name={'name'} label={'名称'}>
+            <Input placeholder={'请输入名称'} />
+          </Form.Item>
+          <Form.Item label={'触发方式'}>
+            <Form.Item name={['trigger', 'type']}>
+              <TriggerWay />
+            </Form.Item>
+          </Form.Item>
+          <Form.Item label={'执行动作'}>
+            <Form.List name="actions">
+              {(fields, { add, remove }) => (
+                <>
+                  {fields.map(({ key, name, ...restField }) => (
+                    <ActionItems
+                      key={key}
+                      form={form}
+                      restField={restField}
+                      onRemove={() => remove(name)}
+                      name={name}
+                    />
+                  ))}
+                  <Form.Item>
+                    <Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
+                      新增
+                    </Button>
+                  </Form.Item>
+                </>
+              )}
+            </Form.List>
           </Form.Item>
         </Form>
         <PermissionButton isPermission={getOtherPermission(['add', 'update'])} onClick={saveData}>