Przeglądaj źródła

fix: bug#8839、8545、8499、8346、8348、8344、8343、8339、8338

xieyonghong 3 lat temu
rodzic
commit
e7327bd8e2

+ 2 - 1
src/components/FMonacoEditor/index.tsx

@@ -5,6 +5,7 @@ import { useRef, useState } from 'react';
 export const JMonacoEditor = (props: any) => {
   const [loading, setLoading] = useState(false);
   const monacoRef = useRef<any>();
+  console.log(props);
 
   return (
     <div
@@ -15,7 +16,7 @@ export const JMonacoEditor = (props: any) => {
       }}
       style={{ height: '100%', width: '100%' }}
     >
-      {loading && <MonacoEditor ref={monacoRef} {...props} />}
+      {loading && <MonacoEditor ref={monacoRef} {...props} options={{ wordWrap: 'on' }} />}
     </div>
   );
 };

+ 27 - 4
src/components/FRuleEditor/Advance/index.tsx

@@ -3,15 +3,20 @@ import Debug from '../Debug';
 import Operator from '../Operator';
 import styles from './index.less';
 import Editor from '@/components/FRuleEditor/Editor';
+import { useRef, useState } from 'react';
+import { Store } from 'jetlinks-store';
 
 interface Props {
   model: 'advance' | 'simple';
   onChange: (value: 'advance' | 'simple') => void;
   virtualRule?: any;
+  id?: string;
 }
 
 const Advance = (props: Props) => {
   const { model, onChange, virtualRule } = props;
+  const [success, setSuccess] = useState(false);
+  const cacheRef = useRef();
   return (
     <Modal
       maskClosable={false}
@@ -19,15 +24,33 @@ const Advance = (props: Props) => {
       width="70vw"
       title="设置属性规则"
       onCancel={() => onChange('simple')}
-      onOk={() => onChange('simple')}
+      onOk={() => {
+        Store.set('rule-editor-value', cacheRef.current);
+        onChange('simple');
+      }}
+      okButtonProps={{
+        disabled: !success,
+      }}
     >
       <div className={styles.box}>
         <div className={styles.left}>
-          <Editor mode="advance" />
-          <Debug virtualRule={virtualRule} />
+          <Editor
+            mode="advance"
+            onValueChange={(v) => {
+              cacheRef.current = v;
+              setSuccess(false);
+            }}
+          />
+          <Debug
+            virtualRule={virtualRule}
+            onSuccess={() => {
+              setSuccess(true);
+            }}
+            id={props.id}
+          />
         </div>
         <div className={styles.right}>
-          <Operator />
+          <Operator id={props.id} />
         </div>
       </div>
     </Modal>

+ 14 - 2
src/components/FRuleEditor/Debug/index.tsx

@@ -6,7 +6,7 @@ import type { Field } from '@formily/core';
 import { createForm } from '@formily/core';
 import type { ISchema } from '@formily/json-schema';
 import FAutoComplete from '@/components/FAutoComplete';
-import { Descriptions, Tooltip } from 'antd';
+import { Descriptions, message, Tooltip } from 'antd';
 import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
 import type { WebsocketPayload } from '@/hooks/websocket/typings';
 import { State } from '@/components/FRuleEditor';
@@ -17,6 +17,8 @@ import { action } from '@formily/reactive';
 
 interface Props {
   virtualRule?: any;
+  onSuccess?: () => void;
+  id?: string;
 }
 
 const Debug = observer((props: Props) => {
@@ -43,7 +45,10 @@ const Debug = observer((props: Props) => {
     );
   };
 
-  const getProperty = async () => DB.getDB().table('properties').toArray();
+  const getProperty = async () => {
+    const _p: PropertyMetadata[] = await DB.getDB().table('properties').toArray();
+    return _p.filter((p) => p.id !== props.id);
+  };
   const virtualIdRef = useRef(new Date().getTime());
   const ws = useRef<any>();
   const wsAgain = useRef<any>();
@@ -155,6 +160,11 @@ const Debug = observer((props: Props) => {
     if (ws.current) {
       ws.current.unsubscribe();
     }
+    if (!props.virtualRule.script) {
+      setIsBeginning(true);
+      message.warning('请编辑规则');
+      return;
+    }
     ws.current = subscribeTopic?.(
       `virtual-property-debug-${State.property}-${new Date().getTime()}`,
       '/virtual-property-debug',
@@ -169,6 +179,7 @@ const Debug = observer((props: Props) => {
     )?.subscribe(
       (data: WebsocketPayload) => {
         State.log.push({ time: new Date().getTime(), content: JSON.stringify(data.payload) });
+        props.onSuccess?.();
       },
       // () => { },
       // () => {
@@ -202,6 +213,7 @@ const Debug = observer((props: Props) => {
   };
   useEffect(() => {
     return () => {
+      setIsBeginning(true);
       if (ws.current) {
         ws.current.unsubscribe();
       }

+ 36 - 15
src/components/FRuleEditor/Editor/index.tsx

@@ -1,8 +1,8 @@
 import styles from '@/components/FRuleEditor/index.less';
-import { Dropdown, Menu } from 'antd';
+import { Dropdown, Menu, Tooltip } from 'antd';
 import { FullscreenOutlined, MoreOutlined } from '@ant-design/icons';
 import MonacoEditor, { monaco } from 'react-monaco-editor';
-import { useEffect, useRef } from 'react';
+import { useEffect, useRef, useState } from 'react';
 import type * as monacoEditor from 'monaco-editor';
 import { Store } from 'jetlinks-store';
 import { State } from '@/components/FRuleEditor';
@@ -85,9 +85,12 @@ const symbolList = [
 interface Props {
   mode?: 'advance' | 'simple';
   onChange?: (value: 'advance' | 'simple') => void;
+  id?: string;
+  onValueChange?: (v: any) => void;
 }
 
 const Editor = (props: Props) => {
+  const [loading, setLoading] = useState(false);
   const editorRef = useRef<monacoEditor.editor.IStandaloneCodeEditor>();
   const editorDidMountHandle = (editor: monacoEditor.editor.IStandaloneCodeEditor) => {
     editor.getAction('editor.action.formatDocument').run();
@@ -116,9 +119,15 @@ const Editor = (props: Props) => {
     const subscription = Store.subscribe('add-operator-value', handleInsertCode);
     return () => subscription.unsubscribe();
   }, [props.mode]);
-
   return (
-    <div className={styles.box}>
+    <div
+      className={styles.box}
+      ref={() => {
+        setTimeout(() => {
+          setLoading(true);
+        }, 100);
+      }}
+    >
       <div className={styles.top}>
         <div className={styles.left}>
           {symbolList
@@ -161,21 +170,33 @@ const Editor = (props: Props) => {
         <div className={styles.right}>
           {props.mode !== 'advance' && (
             <span>
-              <FullscreenOutlined onClick={() => props.onChange?.('advance')} />
+              <Tooltip title={!props.id ? '请先输入标识' : '设置属性规则'}>
+                <FullscreenOutlined
+                  className={!props.id ? styles.disabled : ''}
+                  onClick={() => {
+                    if (props.id) {
+                      props.onChange?.('advance');
+                    }
+                  }}
+                />
+              </Tooltip>
             </span>
           )}
         </div>
       </div>
-      <MonacoEditor
-        editorDidMount={(editor) => editorDidMountHandle(editor)}
-        language={'javascript'}
-        height={300}
-        onChange={(c) => {
-          State.code = c;
-          Store.set('rule-editor-value', State.code);
-        }}
-        value={State.code}
-      />
+      {loading && (
+        <MonacoEditor
+          editorDidMount={(editor) => editorDidMountHandle(editor)}
+          language={'javascript'}
+          height={300}
+          onChange={(c) => {
+            State.code = c;
+            // Store.set('rule-editor-value', State.code);
+            props.onValueChange?.(c);
+          }}
+          value={State.code}
+        />
+      )}
     </div>
   );
 };

+ 18 - 10
src/components/FRuleEditor/Operator/index.tsx

@@ -11,26 +11,33 @@ import type { PropertyMetadata } from '@/pages/device/Product/typings';
 
 const service = new Service();
 
-const Operator = () => {
+interface Props {
+  id?: string;
+}
+
+const Operator = (props: Props) => {
   const [data, setData] = useState<OperatorItem[]>([]);
   const [item, setItem] = useState<Partial<OperatorItem>>({});
   const dataRef = useRef<OperatorItem[]>([]);
-  const getData = async () => {
+
+  const getData = async (id?: string) => {
     const _properties = (await DB.getDB().table('properties').toArray()) as PropertyMetadata[];
     const properties = {
       id: 'property',
       name: '属性',
       description: '',
       code: '',
-      children: _properties.map((p) => ({
-        id: p.id,
-        name: p.name,
-        description: `### ${p.name}
+      children: _properties
+        .filter((p) => p.id !== id)
+        .map((p) => ({
+          id: p.id,
+          name: p.name,
+          description: `### ${p.name}
         \n 数据类型: ${p.valueType?.type}
         \n 是否只读: ${p.expands?.readOnly || 'false'}
         \n 可写数值范围: `,
-        type: 'property',
-      })),
+          type: 'property',
+        })),
     };
     const response = await service.getOperator();
     if (response.status === 200) {
@@ -38,9 +45,10 @@ const Operator = () => {
       dataRef.current = [properties, ...response.result];
     }
   };
+
   useEffect(() => {
-    getData();
-  }, []);
+    getData(props.id);
+  }, [props.id]);
 
   const search = (value: string) => {
     if (value) {

+ 5 - 0
src/components/FRuleEditor/index.less

@@ -34,5 +34,10 @@
         margin: 0 5px;
       }
     }
+
+    .disabled {
+      color: rgba(#000, 0.5);
+      cursor: not-allowed;
+    }
   }
 }

+ 3 - 0
src/components/FRuleEditor/index.tsx

@@ -24,6 +24,7 @@ interface Props {
   onChange: (value: string) => void;
   property?: string;
   virtualRule?: any;
+  id?: string;
 }
 
 const FRuleEditor = observer((props: Props) => {
@@ -44,10 +45,12 @@ const FRuleEditor = observer((props: Props) => {
         onChange={(v) => {
           State.model = v;
         }}
+        id={props.id}
       />
       <Advance
         model={State.model}
         virtualRule={virtualRule}
+        id={props.id}
         onChange={(v) => {
           State.model = v;
         }}

+ 5 - 1
src/pages/device/Instance/Detail/Functions/AdvancedMode.tsx

@@ -1,6 +1,6 @@
 import type { FunctionMetadata } from '@/pages/device/Product/typings';
 import { useCallback, useEffect, useRef, useState } from 'react';
-import { Button, Input } from 'antd';
+import { Button, Input, message } from 'antd';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { InstanceModel, service } from '@/pages/device/Instance';
 import { isObject } from 'lodash';
@@ -40,6 +40,10 @@ export default (props: FunctionProps) => {
       } catch (err) {
         console.error(err);
       }
+    } else {
+      if (!value) {
+        message.warning('请输入内容');
+      }
     }
   }, [value]);
 

+ 8 - 2
src/pages/device/Instance/Detail/Functions/form.tsx

@@ -64,6 +64,8 @@ export default (props: FunctionProps) => {
         return <GeoPoint />;
       case 'object':
         return <MetadataJsonInput json={record.json} />;
+      case 'password':
+        return <Input type={'password'} />;
       case 'date':
         return (
           // <>
@@ -76,7 +78,11 @@ export default (props: FunctionProps) => {
           //   }
           // </>
           // @ts-ignore
-          <DatePicker format={'YYYY-MM-DD HH:mm:ss'} style={{ width: '100%' }} showTime />
+          <DatePicker
+            format={record.format || 'YYYY-MM-DD HH:mm:ss'}
+            style={{ width: '100%' }}
+            showTime
+          />
         );
       default:
         return <Input placeholder={'请输入' + name} />;
@@ -219,7 +225,7 @@ export default (props: FunctionProps) => {
       formData.table.forEach((d: any) => {
         if (d.value) {
           if (d.type === 'date') {
-            data[d.id] = moment(d.value).format('YYYY-MM-DD HH:mm:ss');
+            data[d.id] = moment(d.value).format(d.format || 'YYYY-MM-DD HH:mm:ss');
           } else if (d.type === 'object') {
             data[d.id] = JSON.parse(d.value);
           } else {

+ 1 - 0
src/pages/device/Product/Detail/index.tsx

@@ -306,6 +306,7 @@ const ProductDetail = observer(() => {
                   if (url) {
                     const params = new URLSearchParams();
                     params.append('q', JSON.stringify(searchParams));
+                    params.append('target', 'device-instance');
                     history.push(`${url}?${params.toString()}`);
                   }
                 }}

+ 6 - 0
src/pages/device/components/Metadata/Base/Edit/index.tsx

@@ -581,6 +581,9 @@ const Edit = observer((props: Props) => {
           'virtualRule.script': {
             type: 'string',
             'x-component': 'FRuleEditor',
+            'x-component-props': {
+              id: (MetadataModel.item as any)?.id,
+            },
             'x-visible': false,
             'x-reactions': [
               {
@@ -588,6 +591,9 @@ const Edit = observer((props: Props) => {
                 fulfill: {
                   state: {
                     visible: '{{$deps[0]==="rule"}}',
+                    componentProps: {
+                      id: '{{$deps[1]}}',
+                    },
                   },
                   schema: {
                     'x-component-props.property': '{{$deps[1]}}',

+ 1 - 1
src/pages/device/components/Metadata/Import/index.tsx

@@ -234,7 +234,7 @@ const Import = (props: Props) => {
           theme: 'vs',
           language: 'json',
           editorDidMount: (editor1: any) => {
-            editor1.onDidScrollChange?.(() => {
+            editor1.onDidContentSizeChange?.(() => {
               editor1.getAction('editor.action.formatDocument').run();
             });
           },

+ 1 - 1
src/pages/device/components/Metadata/index.tsx

@@ -66,7 +66,7 @@ const Metadata = observer((props: Props) => {
         className={styles.metadataNav}
         tabBarExtraContent={
           <Space>
-            {props.type === 'device' && (
+            {InstanceModel.detail?.independentMetadata && props.type === 'device' && (
               <PermissionButton
                 isPermission={permission.update}
                 popConfirm={{