100011797 před 3 roky
rodič
revize
7a1e7f332a

+ 6 - 4
src/components/FIndicators/index.tsx

@@ -73,10 +73,12 @@ const FIndicators = (props: Props) => {
               ]
             }
             onChange={(_: any, date: string[]) => {
-              onChange({
-                ...value,
-                value: [...date],
-              });
+              if (date[0] !== date[1]) {
+                onChange({
+                  ...value,
+                  value: [...date],
+                });
+              }
             }}
           />
         );

+ 2 - 1
src/components/Metadata/EditTable/index.tsx

@@ -168,7 +168,8 @@ Editable.Popover = observer((props) => {
         </div>
         <CloseOutlined
           onClick={() => {
-            setVisible(false);
+            // setVisible(false);
+            closePopover();
           }}
         />
       </div>

+ 53 - 22
src/components/NoticeIcon/index.tsx

@@ -1,4 +1,4 @@
-import { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef } from 'react';
 import { Button, message, notification } from 'antd';
 import { groupBy } from 'lodash';
 import moment from 'moment';
@@ -8,8 +8,10 @@ import styles from './index.less';
 import encodeQuery from '@/utils/encodeQuery';
 import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
 import useHistory from '@/hooks/route/useHistory';
-import { throttleTime } from 'rxjs/operators';
+// import { throttleTime } from 'rxjs/operators';
 import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
+import { observer } from '@formily/react';
+import { model } from '@formily/reactive';
 
 export type GlobalHeaderRightProps = {
   fetchingNotices?: boolean;
@@ -62,13 +64,25 @@ const getNoticeData = (notices: API.NoticeIconItem[]): Record<string, API.Notice
 
 export const service = new Service('notifications');
 
-const NoticeIconView = () => {
+export const NoticeIconViewModel = model<{
+  unreadCount: number;
+  notices: API.NoticeIconItem[];
+  visible: boolean;
+  loading: boolean;
+}>({
+  unreadCount: 0,
+  notices: [],
+  visible: false,
+  loading: true,
+});
+
+const NoticeIconView = observer(() => {
   // const { initialState } = useModel('@@initialState');
   // const { currentUser } = initialState || {};
-  const [notices, setNotices] = useState<API.NoticeIconItem[]>([]);
-  const [unreadCount, setUnreadCount] = useState<number>(0);
-  const [visible, setVisible] = useState<boolean>(false);
-  const [loading, setLoading] = useState<boolean>(true);
+  // const [notices, setNotices] = useState<API.NoticeIconItem[]>([]);
+  // const [unreadCount, setUnreadCount] = useState<number>(0);
+  // const [visible, setVisible] = useState<boolean>(false);
+  // const [loading, setLoading] = useState<boolean>(true);
   // const { data } = useRequest(getNotices);
 
   const history = useHistory();
@@ -78,7 +92,8 @@ const NoticeIconView = () => {
   const [subscribeTopic] = useSendWebsocketMessage();
 
   const getUnread = () => {
-    setLoading(true);
+    // setLoading(true);
+    NoticeIconViewModel.loading = true;
     service
       .fetchNotices(
         encodeQuery({
@@ -88,20 +103,26 @@ const NoticeIconView = () => {
       )
       .then((resp) => {
         if (resp.status === 200) {
-          setNotices(resp.result?.data || []);
-          setUnreadCount(resp.result?.total || 0);
+          NoticeIconViewModel.notices = resp.result?.data || [];
+          NoticeIconViewModel.unreadCount = resp.result?.total || 0;
+          // setNotices(resp.result?.data || []);
+          // setUnreadCount(resp.result?.total || 0);
         }
-        setLoading(false);
+        NoticeIconViewModel.loading = false;
+        // setLoading(false);
       });
   };
 
   const changeReadState = async (item: any, type?: 'notice' | 'icon') => {
+    console.log(item, type);
     const resp = await service.changeNoticeReadState(item.id);
     if (resp.status === 200) {
+      getUnread();
       const url = getMenuPathByCode(MENUS_CODE['account/NotificationRecord']);
       historyRef.current?.push(url, { ...item });
       if (type === 'icon') {
-        setVisible(false);
+        // setVisible(false);
+        NoticeIconViewModel.visible = false;
       } else {
         notification.close(item.id);
       }
@@ -147,9 +168,13 @@ const NoticeIconView = () => {
     const id = `notification`;
     const topic = `/notifications`;
     subscribeTopic!(id, topic, {})
-      ?.pipe(throttleTime(2000))
+      ?.pipe() // throttleTime(2000)
       .subscribe((resp: any) => {
-        getUnread();
+        // setUnreadCount(unreadCount + 1);
+        NoticeIconViewModel.unreadCount += 1;
+        // setTimeout(() => {
+        //   getUnread();
+        // }, 500)
         openNotification(resp);
       });
   };
@@ -159,11 +184,12 @@ const NoticeIconView = () => {
     subscribeNotice();
   }, []);
 
-  const noticeData = getNoticeData(notices);
+  const noticeData = getNoticeData(NoticeIconViewModel.notices);
   // const unreadMsg = getUnreadData(noticeData || {})
 
   const clearReadState = async (title: string) => {
-    const clearIds = (getNoticeData(notices).unread || []).map((item) => item.id) || [];
+    const clearIds =
+      (getNoticeData(NoticeIconViewModel.notices).unread || []).map((item) => item.id) || [];
     const resp = await service.clearNotices(clearIds);
     if (resp.status === 200) {
       message.success(`${'清空了'} ${title}`);
@@ -174,22 +200,27 @@ const NoticeIconView = () => {
   return (
     <NoticeIcon
       className={styles.action}
-      count={unreadCount}
+      count={NoticeIconViewModel.unreadCount}
       onItemClick={(item) => {
         changeReadState(item!, 'icon');
       }}
       onClear={(title: string) => clearReadState(title)}
-      loading={loading}
+      loading={NoticeIconViewModel.loading}
       clearText="当前标记为已读"
       viewMoreText="查看更多"
       onViewMore={() => {
         const url = getMenuPathByCode(MENUS_CODE['account/NotificationRecord']);
         history.push(url);
-        setVisible(false);
+        // setVisible(false);
+        NoticeIconViewModel.visible = false;
       }}
-      popupVisible={visible}
+      popupVisible={NoticeIconViewModel.visible}
       onPopupVisibleChange={(see: boolean) => {
-        setVisible(see);
+        // setVisible(see);
+        NoticeIconViewModel.visible = see;
+        if (see) {
+          getUnread();
+        }
       }}
       clearClose
     >
@@ -211,6 +242,6 @@ const NoticeIconView = () => {
       /> */}
     </NoticeIcon>
   );
-};
+});
 
 export default NoticeIconView;

+ 13 - 14
src/pages/account/NotificationRecord/detail/index.tsx

@@ -1,7 +1,7 @@
 import { Descriptions, Modal } from 'antd';
 import { useEffect, useState } from 'react';
 import moment from 'moment';
-import { service } from '@/pages/account/NotificationRecord';
+// import { service } from '@/pages/account/NotificationRecord';
 import { service as service1 } from '@/pages/rule-engine/Alarm/Log';
 import { Store } from 'jetlinks-store';
 import ReactJson from 'react-json-view';
@@ -15,7 +15,7 @@ const Detail = (props: Props) => {
   const [data, setDada] = useState<any>({});
 
   useEffect(() => {
-    if (props.data.dataId) {
+    if (props.data?.dataId) {
       service1.queryDefaultLevel().then((resp) => {
         if (resp.status === 200) {
           Store.set('default-level', resp.result?.levels || []);
@@ -23,11 +23,7 @@ const Detail = (props: Props) => {
             const detailJson = props.data.detailJson || '{}';
             setDada(JSON.parse(detailJson));
           } else {
-            service.getAlarmList(props.data.dataId).then((res) => {
-              if (res.status === 200) {
-                setDada(res.result);
-              }
-            });
+            setDada(props.data?.detail || props.data);
           }
         }
       });
@@ -63,13 +59,16 @@ const Detail = (props: Props) => {
         </Descriptions.Item>
         <Descriptions.Item label="告警流水" span={2}>
           <div style={{ maxHeight: 400, overflowY: 'auto' }}>
-            <ReactJson
-              enableClipboard={false}
-              displayObjectSize={false}
-              displayDataTypes={false}
-              name={false}
-              src={JSON.parse(data?.alarmInfo || '{}')}
-            />
+            {
+              // @ts-ignore
+              <ReactJson
+                enableClipboard={false}
+                displayObjectSize={false}
+                displayDataTypes={false}
+                name={false}
+                src={JSON.parse(data?.alarmInfo || '{}')}
+              />
+            }
           </div>
         </Descriptions.Item>
       </Descriptions>

+ 10 - 1
src/pages/account/NotificationRecord/index.tsx

@@ -15,6 +15,7 @@ import { onlyMessage } from '@/utils/util';
 import type { CustomIconComponentProps } from '@ant-design/icons/lib/components/Icon';
 import useLocations from '@/hooks/route/useLocation';
 import { observer } from '@formily/reactive-react';
+import { NoticeIconViewModel } from '@/components/NoticeIcon';
 
 export const service = new Service('notifications');
 
@@ -40,7 +41,6 @@ const NotificationRecord = observer(() => {
   }, []);
 
   useEffect(() => {
-    console.log(location.state);
     if (location.state?.id) {
       setVisible(true);
       setCurrent(location.state);
@@ -145,6 +145,15 @@ const NotificationRecord = observer(() => {
               const state = record?.state?.value !== 'read' ? 'read' : 'unread';
               const resp = await service.saveData(state, [record.id]);
               if (resp.status === 200) {
+                if (state === 'read') {
+                  if (NoticeIconViewModel.unreadCount) {
+                    NoticeIconViewModel.unreadCount -= 1;
+                  } else {
+                    NoticeIconViewModel.unreadCount = 0;
+                  }
+                } else {
+                  NoticeIconViewModel.unreadCount += 1;
+                }
                 onlyMessage('操作成功');
                 actionRef.current?.reload();
               }

+ 1 - 0
src/pages/account/NotificationRecord/typings.d.ts

@@ -10,4 +10,5 @@ type NotifitionRecord = {
   topicName: string;
   dataId: string;
   detailJson: string;
+  detail?: any;
 };

+ 1 - 1
src/pages/link/Type/Detail/index.tsx

@@ -672,7 +672,7 @@ const Save = observer(() => {
           { value: 'delimited', label: '分隔符' },
           { value: 'script', label: '自定义脚本' },
           { value: 'fixed_length', label: '固定长度' },
-          { value: 'length', label: '长度' },
+          { value: 'length', label: '长度字段' },
         ],
         'x-reactions': {
           dependencies: ['type'],

+ 51 - 0
src/pages/system/DataSource/Save/index.tsx

@@ -120,6 +120,23 @@ const Save = (props: Props) => {
                 required: true,
                 message: '请输入URL',
               },
+              {
+                triggerType: 'onBlur',
+                validator: (value: string) => {
+                  return new Promise((resolve) => {
+                    if (!value) {
+                      resolve('');
+                    } else {
+                      const arr = value.split(':');
+                      if ((arr?.[0] === 'jdbc' || arr?.[0] === 'r2dbc') && arr?.[1] === 'mysql') {
+                        resolve('');
+                      } else {
+                        resolve('请输入正确的URL');
+                      }
+                    }
+                  });
+                },
+              },
             ],
             required: true,
             'x-reactions': {
@@ -152,6 +169,23 @@ const Save = (props: Props) => {
                 required: true,
                 message: '请输入管理地址',
               },
+              // {
+              //   triggerType: 'onBlur',
+              //   validator: (value: string) => {
+              //     return new Promise((resolve) => {
+              //       if (!value) {
+              //         resolve('');
+              //       } else {
+              //         const arr = value.split('://')
+              //         if (arr[0] === 'http' || arr[0] === 'https') {
+              //           resolve('');
+              //         } else {
+              //           resolve('请输入正确的管理地址')
+              //         }
+              //       }
+              //     });
+              //   },
+              // },
             ],
             required: true,
             'x-reactions': {
@@ -184,6 +218,23 @@ const Save = (props: Props) => {
                 required: true,
                 message: '请输入链接地址',
               },
+              // {
+              //   triggerType: 'onBlur',
+              //   validator: (value: string) => {
+              //     return new Promise((resolve) => {
+              //       if (!value) {
+              //         resolve('');
+              //       } else {
+              //         const reg = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/;
+              //         if (reg.test(value)) {
+              //           resolve('');
+              //         } else {
+              //           resolve('请输入正确的链接地址')
+              //         }
+              //       }
+              //     });
+              //   },
+              // },
             ],
             required: true,
             'x-reactions': {