Просмотр исходного кода

fix(bug): bug#3734、5025、5349、5252

xieyonghong 3 лет назад
Родитель
Сommit
2d72723c91

+ 1 - 1
src/components/FRuleEditor/Advance/index.less

@@ -4,7 +4,7 @@
   width: 100%;
 
   .left {
-    width: 1000px;
+    width: 70%;
   }
 
   .right {

+ 30 - 7
src/components/SearchComponent/index.tsx

@@ -141,6 +141,12 @@ const sortField = (field: ProColumns[]) => {
 
 // 场景二:高级模式
 // 默认六组搜索条件。根据字段index排序
+// const nodeFor = <T extends Record<string, any>>(props: Props<T>, ref) => {
+//   console.log(props,ref)
+//   return (<></>)
+// }
+//
+// export const node = forwardRef(nodeFor) as <RecordType extends Record<string, any>>(props: Props<RecordType>, ref?: React.Ref<HTMLDivElement>) => React.ReactElement
 
 const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
   const { field, target, onSearch, defaultParam, enableSave = true, initParam, model } = props;
@@ -197,6 +203,9 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
               f.setFieldState(typeFiled.query('.termType'), async (state) => {
                 state.value = 'eq';
               });
+              f.setFieldState(typeFiled.query('.value'), async (state) => {
+                state.componentType = 'Input';
+              });
             } else {
               switch (_field?.valueType) {
                 case 'select':
@@ -213,6 +222,7 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
                     state.value = 'eq';
                   });
                   f.setFieldState(typeFiled.query('.value'), async (state) => {
+                    console.log(state.value);
                     state.componentType = 'Select';
                     state.dataSource = __option;
                   });
@@ -257,6 +267,9 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
                   });
                   break;
                 default:
+                  f.setFieldState(typeFiled.query('.termType'), async (state) => {
+                    state.value = 'like';
+                  });
                   f.setFieldState(typeFiled.query('.value'), async (state) => {
                     state.componentType = 'Input';
                   });
@@ -266,7 +279,9 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
           });
           onFieldValueChange('*.*.column', (field1, form1) => {
             form1.setFieldState(field1.query('.value'), (state1) => {
-              state1.value = undefined;
+              if (field1.modified) {
+                state1.value = undefined;
+              }
             });
           });
         },
@@ -509,7 +524,7 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
   };
 
   const [url, setUrl] = useUrlState();
-  const handleSearch = async () => {
+  const handleSearch = async (type: boolean = true) => {
     const value = form.values;
     const filterTerms = (data: Partial<Term>[] | undefined) =>
       data && data.filter((item) => item.column != null).filter((item) => item.value !== undefined);
@@ -517,14 +532,16 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
     _terms.terms1 = filterTerms(_terms.terms1);
     _terms.terms2 = filterTerms(_terms.terms2);
     const _temp = formatValue(_terms);
-    setUrl({ q: JSON.stringify(value) });
+    if (type) {
+      setUrl({ q: JSON.stringify(value) });
+    }
     onSearch({ terms: _temp });
   };
 
   useEffect(() => {
     if (url.q) {
       form.setValues(JSON.parse(url.q));
-      handleSearch();
+      handleSearch(false);
     }
   }, [url]);
 
@@ -564,15 +581,21 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
 
   const SearchBtn = {
     simple: (
-      <Button icon={<SearchOutlined />} onClick={handleSearch} type="primary">
-        搜索
-      </Button>
+      <>
+        {
+          // @ts-ignore
+          <Button icon={<SearchOutlined />} onClick={handleSearch} type="primary">
+            搜索
+          </Button>
+        }
+      </>
     ),
     advance: (
       <Dropdown.Button
         icon={<SearchOutlined />}
         placement={'bottomLeft'}
         destroyPopupOnHide
+        // @ts-ignore
         onClick={handleSearch}
         visible={logVisible}
         onVisibleChange={async (visible) => {

+ 2 - 8
src/pages/device/Instance/index.tsx

@@ -72,7 +72,6 @@ const Instance = () => {
   const [bindKeys, setBindKeys] = useState<any[]>([]);
   const history = useHistory<Record<string, string>>();
   const { permission } = PermissionButton.usePermission('device/Instance');
-  const [jumpParams, setJumpParams] = useState<SearchTermsServer | undefined>(undefined);
 
   const intl = useIntl();
   const location = useLocation();
@@ -86,12 +85,7 @@ const Instance = () => {
           value: location.state[key],
         });
       });
-      setJumpParams([
-        {
-          terms: _terms,
-          type: 'or',
-        },
-      ]);
+
       if (location.state && location.state?.save) {
         setVisible(true);
         setCurrent({});
@@ -521,7 +515,7 @@ const Instance = () => {
       <SearchComponent<DeviceInstance>
         field={columns}
         target="device-instance"
-        initParam={jumpParams}
+        // initParam={jumpParams}
         onSearch={(data) => {
           actionRef.current?.reset?.();
           setSearchParams(data);

+ 14 - 5
src/pages/device/Product/Detail/index.tsx

@@ -1,11 +1,11 @@
 import { PageContainer } from '@ant-design/pro-layout';
-import { useIntl, useParams } from 'umi';
+import { useIntl, useParams, useHistory } from 'umi';
 import { Badge, Card, Descriptions, message, Popconfirm, Space, Spin, Switch, Tooltip } from 'antd';
 import BaseInfo from '@/pages/device/Product/Detail/BaseInfo';
 import { observer } from '@formily/react';
 import { productModel, service } from '@/pages/device/Product';
 import { useCallback, useEffect, useState } from 'react';
-import { useDomFullHeight, useHistory, useLocation } from '@/hooks';
+import { useDomFullHeight, useLocation } from '@/hooks';
 import Metadata from '@/pages/device/components/Metadata';
 import Access from '@/pages/device/Product/Detail/Access';
 import type { DeviceMetadata } from '@/pages/device/Product/typings';
@@ -271,11 +271,20 @@ const ProductDetail = observer(() => {
                 style={{ padding: 0, height: 'auto' }}
                 onClick={() => {
                   const url = getMenuPathByCode(MENUS_CODE['device/Instance']);
-                  const params = {
-                    productId: productModel.current?.id,
+                  const searchParams = {
+                    terms1: [
+                      {
+                        column: 'productId',
+                        termType: 'eq',
+                        value: productModel.current?.id,
+                      },
+                    ],
+                    terms2: undefined,
+                    type: 'and',
                   };
                   if (url) {
-                    history.push(url, params);
+                    console.log(`${url}?q=${JSON.stringify(searchParams)}`);
+                    history.push(`${url}?q=${JSON.stringify(searchParams)}`);
                   }
                 }}
               >

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

@@ -88,7 +88,9 @@ const BaseMetadata = observer((props: Props) => {
             MetadataModel.item = record;
             MetadataModel.type = type;
             MetadataModel.action = 'edit';
-            message.warning('修改物模型后会脱离产品物模型');
+            if (!InstanceModel.detail?.independentMetadata && props.target === 'device') {
+              message.warning('修改物模型后会脱离产品物模型');
+            }
           }}
           tooltip={{
             title: operateLimits('add', type) ? '暂不支持' : '编辑',

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

@@ -49,20 +49,20 @@ const Metadata = observer((props: Props) => {
 
   return (
     <div className={'device-detail-metadata'} style={{ position: 'relative', minHeight }}>
-      <div className={styles.tips}>
+      <div className={styles.tips} style={{ width: '40%' }}>
         <Tooltip
           title={
-            InstanceModel.detail?.independentMetadata
+            InstanceModel.detail?.independentMetadata && props.type === 'device'
               ? '该设备已脱离产品物模型,修改产品物模型对该设备无影响'
               : '设备会默认继承产品的物模型,修改设备物模型后将脱离产品物模型'
           }
         >
-          <span>
+          <div className={'ellipsis'}>
             <InfoCircleOutlined style={{ marginRight: '3px' }} />
-            {InstanceModel.detail?.independentMetadata
+            {InstanceModel.detail?.independentMetadata && props.type === 'device'
               ? '该设备已脱离产品物模型,修改产品物模型对该设备无影响'
               : '设备会默认继承产品的物模型,修改设备物模型后将脱离产品物模型'}
-          </span>
+          </div>
         </Tooltip>
       </div>
       <Tabs

+ 16 - 9
src/pages/media/Device/Channel/Save.tsx

@@ -51,7 +51,9 @@ const Save = (props: SaveModalProps) => {
           address: data.address,
           ptzType: data.ptzType ? data.ptzType.value : 0,
           description: data.description,
-          media_url: data.other ? data.other['media_url'] : '',
+          media_url: data.others ? data.others['media_url'] : '',
+          username: data.others ? data.others['media_username'] : '',
+          password: data.others ? data.others['media_password'] : '',
         });
       } else {
         form.setValues({
@@ -84,6 +86,7 @@ const Save = (props: SaveModalProps) => {
             },
             'x-decorator-props': {
               gridSpan: 1,
+              tooltip: '若不填写,系统将自动生成唯一ID',
             },
           },
           name: {
@@ -107,6 +110,7 @@ const Save = (props: SaveModalProps) => {
             ],
             'x-decorator-props': {
               gridSpan: 1,
+              tooltip: '不同厂家的RTSP固定地址规则不同,请按对应厂家的规则填写',
             },
           },
           manufacturer: {
@@ -128,9 +132,10 @@ const Save = (props: SaveModalProps) => {
               gridSpan: 2,
             },
           },
-          'others.media_url': {
+          media_url: {
             type: 'string',
             title: '视频地址',
+            required: true,
             'x-visible': props.type === ProviderValue.FIXED,
             'x-decorator': 'FormItem',
             'x-component': 'Input',
@@ -139,8 +144,8 @@ const Save = (props: SaveModalProps) => {
             },
             'x-validator': [
               {
-                max: 128,
-                message: '最多可输入128个字符',
+                required: true,
+                message: '请输入视频地址',
               },
               {
                 validator: (value: string) => {
@@ -267,17 +272,19 @@ const Save = (props: SaveModalProps) => {
   const saveData = async () => {
     const formData: any = await form.submit();
     if (formData) {
-      const { media_url, ...extraFormData } = formData;
-      if (media_url) {
-        extraFormData.other = {
+      const { media_url, password, username, ...extraFormData } = formData;
+      if (media_url || password || username) {
+        extraFormData.others = {
           media_url,
+          media_password: password,
+          media_username: username,
         };
       }
       setLoading(true);
       const resp =
         props.model === 'edit'
-          ? await service.updateChannel(formData.id, formData)
-          : await service.saveChannel(formData);
+          ? await service.updateChannel(formData.id, extraFormData)
+          : await service.saveChannel(extraFormData);
       setLoading(false);
 
       if (resp.status === 200) {

+ 16 - 6
src/pages/media/Device/index.tsx

@@ -244,13 +244,17 @@ const Device = () => {
         </Tooltip>,
         <PermissionButton
           tooltip={
-            record.state.value === 'offline' || record.provider === providerType['fixed-media']
+            record.state.value === 'offline' ||
+            record.state.value === 'notActive' ||
+            record.provider === providerType['fixed-media']
               ? {
                   title:
                     record.provider === providerType['fixed-media']
                       ? '固定地址无法更新通道'
                       : record.state.value === 'offline'
                       ? '设备已离线'
+                      : record.state.value === 'notActive'
+                      ? '设备已禁用'
                       : '',
                 }
               : undefined
@@ -258,7 +262,9 @@ const Device = () => {
           key={'updateChannel'}
           isPermission={permission.update}
           disabled={
-            record.state.value === 'offline' || record.provider === providerType['fixed-media']
+            record.state.value === 'offline' ||
+            record.state.value === 'notActive' ||
+            record.provider === providerType['fixed-media']
           }
           style={{ padding: 0 }}
           type={'link'}
@@ -393,6 +399,7 @@ const Device = () => {
                 isPermission={permission.update}
                 tooltip={
                   record.state.value === 'offline' ||
+                  record.state.value === 'notActive' ||
                   record.provider === providerType['fixed-media']
                     ? {
                         title:
@@ -400,12 +407,15 @@ const Device = () => {
                             ? '固定地址无法更新通道'
                             : record.state.value === 'offline'
                             ? '设备已离线'
+                            : record.state.value === 'notActive'
+                            ? '设备已禁用'
                             : '',
                       }
                     : undefined
                 }
                 disabled={
                   record.state.value === 'offline' ||
+                  record.state.value === 'notActive' ||
                   record.provider === providerType['fixed-media']
                 }
                 onClick={() => {
@@ -420,13 +430,13 @@ const Device = () => {
                 popConfirm={{
                   title: intl.formatMessage({
                     id:
-                      record.state.value !== 'offline'
-                        ? 'pages.device.instance.deleteTip'
-                        : 'page.table.isDelete',
+                      record.state.value === 'online'
+                        ? 'page.table.isDelete'
+                        : 'pages.device.instance.deleteTip',
                     defaultMessage: '是否删除?',
                   }),
                   onConfirm: async () => {
-                    if (record.state.value === 'offline') {
+                    if (record.state.value === 'offline' || record.state.value === 'notActive') {
                       await deleteItem(record.id);
                     } else {
                       onlyMessage('在线设备不能进行删除操作', 'error');

+ 3 - 1
src/pages/rule-engine/DashBoard/index.less

@@ -107,7 +107,8 @@
 }
 
 .alarmRank {
-  padding: 0 32px 32px 72px;
+  width: 250px;
+  padding-left: 12px;
 }
 
 .rankingList {
@@ -162,6 +163,7 @@
     .rankingItemTitle {
       flex: 1;
       margin-right: 8px;
+      padding-left: 8px;
       overflow: hidden;
       white-space: nowrap;
       text-overflow: ellipsis;

+ 19 - 2
src/pages/rule-engine/DashBoard/index.tsx

@@ -1,7 +1,7 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import { EChartsOption } from 'echarts';
 import { useEffect, useRef, useState } from 'react';
-import { Badge, Card, Col, Tooltip } from 'antd';
+import { Badge, Card, Col, Tooltip, Select } from 'antd';
 import './index.less';
 import Service from './service';
 import { observer } from '@formily/react';
@@ -216,7 +216,7 @@ const Dashboard = observer(() => {
       params: {
         // time: '1h',
         time: params.time.type === 'today' ? '1h' : '1d',
-        targetType: 'device',
+        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'),
         limit: 9,
@@ -350,8 +350,25 @@ const Dashboard = observer(() => {
           height={600}
           showTimeTool={true}
           options={options}
+          initialValues={{
+            targetType: 'device',
+          }}
+          extraParams={{
+            key: 'targetType',
+            Children: (
+              <Select
+                options={[
+                  { label: '设备', value: 'device' },
+                  { label: '产品', value: 'product' },
+                  { label: '部门', value: 'org' },
+                  { label: '其它', value: 'other' },
+                ]}
+              />
+            ),
+          }}
           onParamsChange={getEcharts}
           ref={alarmCountRef}
+          defaultTime={'week'}
           echartsAfter={
             <div className={styles.alarmRank}>
               <h4>告警排名</h4>

+ 11 - 2
src/pages/system/Department/Assets/deivce/bind.tsx

@@ -44,6 +44,15 @@ const Bind = observer((props: Props) => {
         defaultMessage: '所属产品',
       }),
       dataIndex: 'configuration',
+      valueType: 'select',
+      filterMultiple: true,
+      request: async () => {
+        const res = await service.getProductList();
+        if (res.status === 200) {
+          return res.result.map((pItem: any) => ({ label: pItem.name, value: pItem.id }));
+        }
+        return [];
+      },
       render: (_, row) => {
         return row.productName;
       },
@@ -118,7 +127,7 @@ const Bind = observer((props: Props) => {
       visible={props.visible}
       onOk={handleBind}
       onCancel={props.onCancel}
-      width={1300}
+      width={800}
       title="绑定"
     >
       <PermissionModal
@@ -136,7 +145,7 @@ const Bind = observer((props: Props) => {
       <SearchComponent<DeviceItem>
         field={columns}
         enableSave={false}
-        // pattern={'simple'}
+        model={'simple'}
         defaultParam={[
           {
             column: 'id',

+ 7 - 0
src/pages/system/Department/Assets/deivce/index.tsx

@@ -40,6 +40,10 @@ export default observer((props: { parentId: string }) => {
     if (AssetsModel.tabsIndex === ASSETS_TABS_ENUM.Device && actionRef.current) {
       actionRef.current.reload();
     }
+
+    if (AssetsModel.tabsIndex === ASSETS_TABS_ENUM.Device && AssetsModel.bindModal) {
+      Models.bind = true;
+    }
   }, [AssetsModel.tabsIndex]);
   /**
    * 解除资产绑定
@@ -191,6 +195,9 @@ export default observer((props: { parentId: string }) => {
   const closeModal = () => {
     Models.bind = false;
     Models.bindKeys = [];
+    if (AssetsModel.bindModal) {
+      AssetsModel.bindModal = false;
+    }
   };
 
   const getData = (params: any, parentId: string) => {

+ 17 - 12
src/pages/system/Department/Assets/index.tsx

@@ -1,7 +1,6 @@
 // 部门-资产分配
 import { Tabs } from 'antd';
 import { useIntl } from '@@/plugin-locale/localeExports';
-import ProductCategory from './productCategory';
 import Product from './product';
 import Device from '@/pages/system/Department/Assets/deivce';
 import Member from '@/pages/system/Department/Member';
@@ -20,8 +19,12 @@ export enum ASSETS_TABS_ENUM {
   'User' = 'User',
 }
 
-export const AssetsModel = model<{ tabsIndex: string }>({
-  tabsIndex: ASSETS_TABS_ENUM.ProductCategory,
+export const AssetsModel = model<{
+  tabsIndex: string;
+  bindModal: boolean;
+}>({
+  tabsIndex: ASSETS_TABS_ENUM.Product,
+  bindModal: false,
 });
 
 const Assets = observer((props: AssetsProps) => {
@@ -29,12 +32,12 @@ const Assets = observer((props: AssetsProps) => {
 
   // 资产类型
   const TabsArray = [
-    {
-      intlTitle: '1',
-      defaultMessage: '产品分类',
-      key: ASSETS_TABS_ENUM.ProductCategory,
-      components: ProductCategory,
-    },
+    // {
+    //   intlTitle: '1',
+    //   defaultMessage: '产品分类',
+    //   key: ASSETS_TABS_ENUM.ProductCategory,
+    //   components: ProductCategory,
+    // },
     {
       intlTitle: '2',
       defaultMessage: '产品',
@@ -55,14 +58,16 @@ const Assets = observer((props: AssetsProps) => {
     },
   ];
 
+  console.log(AssetsModel.tabsIndex);
+
   return (
-    <div style={{ position: 'relative' }}>
-      <div style={{ position: 'absolute', top: 12, left: 270 }}>
+    <div style={{ position: 'relative', width: '100%' }}>
+      <div style={{ position: 'absolute', top: 12, left: 180 }}>
         <ExclamationCircleOutlined style={{ marginRight: 12 }} />
         部门拥有的资产为所有类型资产的并集
       </div>
       <Tabs
-        accessKey={AssetsModel.tabsIndex}
+        activeKey={AssetsModel.tabsIndex}
         onChange={(key) => {
           AssetsModel.tabsIndex = key;
         }}

+ 23 - 4
src/pages/system/Department/Assets/product/bind.tsx

@@ -11,6 +11,7 @@ import type { ProductItem } from '@/pages/system/Department/typings';
 import SearchComponent from '@/components/SearchComponent';
 import { ExtraProductCard } from '@/components/ProTableCard/CardItems/product';
 import { ProTableCard } from '@/components';
+import { ASSETS_TABS_ENUM, AssetsModel } from '@/pages/system/Department/Assets';
 
 interface Props {
   reload: () => void;
@@ -24,6 +25,7 @@ const Bind = observer((props: Props) => {
   const actionRef = useRef<ActionType>();
   const [searchParam, setSearchParam] = useState({});
   const saveRef = useRef<{ saveData: Function }>();
+  const [deviceVisible, setDeviceVisible] = useState(false);
 
   const columns: ProColumns<ProductItem>[] = [
     {
@@ -71,9 +73,27 @@ const Bind = observer((props: Props) => {
       visible={props.visible}
       onOk={handleBind}
       onCancel={props.onCancel}
-      width={1300}
+      width={800}
       title="绑定"
     >
+      <Modal
+        visible={deviceVisible}
+        width={600}
+        onCancel={() => {
+          setDeviceVisible(false);
+          props.reload();
+          props.onCancel();
+        }}
+        onOk={() => {
+          setDeviceVisible(false);
+          AssetsModel.tabsIndex = ASSETS_TABS_ENUM.Device;
+          AssetsModel.bindModal = true;
+          props.onCancel();
+        }}
+        title={'绑定'}
+      >
+        是否继续分配产品下的具体设备
+      </Modal>
       <PermissionModal
         type="product"
         parentId={props.parentId}
@@ -81,14 +101,13 @@ const Bind = observer((props: Props) => {
         ref={saveRef}
         onCancel={(type) => {
           if (type) {
-            props.reload();
-            props.onCancel();
+            setDeviceVisible(true);
           }
         }}
       />
       <SearchComponent<ProductItem>
         field={columns}
-        // pattern={'simple'}
+        model={'simple'}
         enableSave={false}
         defaultParam={[
           {

+ 7 - 0
src/pages/system/Department/Assets/service.ts

@@ -38,6 +38,13 @@ class Service<T> extends BaseService<T> {
     });
   };
 
+  // 查询产品列表
+  getProductList = (params?: any) =>
+    request(`/${SystemConst.API_BASE}/device/product/_query/no-paging?paging=false`, {
+      method: 'GET',
+      params,
+    });
+
   queryDeviceList2 = (params: any, parentId: string) =>
     from(
       request(`${SystemConst.API_BASE}/device/instance/_query`, { method: 'POST', data: params }),

+ 2 - 2
src/pages/system/Department/Member/bind.tsx

@@ -73,11 +73,11 @@ const Bind = observer((props: Props) => {
       visible={props.visible}
       onOk={handleBind}
       onCancel={props.onCancel}
-      width={1300}
+      width={800}
       title="绑定"
     >
       <SearchComponent<UserItem>
-        // pattern={'simple'}
+        model={'simple'}
         enableSave={false}
         field={columns}
         defaultParam={[{ column: 'id$in-dimension$org$not', value: props.parentId }]}

+ 1 - 1
src/pages/system/Menu/Detail/buttons.tsx

@@ -348,7 +348,7 @@ export default (props: ButtonsProps) => {
               <Permission
                 title={intl.formatMessage({
                   id: 'page.system.menu.permissions.operate',
-                  defaultMessage: '操作权限',
+                  defaultMessage: '权限操作',
                 })}
                 disabled={disabled}
                 data={permissions}

+ 1 - 1
src/pages/system/Menu/Detail/edit.tsx

@@ -303,7 +303,7 @@ export default (props: EditProps) => {
                     <Permission
                       title={intl.formatMessage({
                         id: 'page.system.menu.permissions.operate',
-                        defaultMessage: '操作权限',
+                        defaultMessage: '权限操作',
                       })}
                       // disabled={disabled}
                       data={permissions}

+ 4 - 1
src/pages/system/Menu/components/permission.tsx

@@ -253,7 +253,10 @@ export default (props: PermissionType) => {
 
   return (
     <div className="permission-container">
-      <div className="permission-header">{props.title}</div>
+      <div className="permission-header">
+        <span style={{ width: 180, display: 'inline-block' }}>权限名称</span>
+        <span>权限操作</span>
+      </div>
       <div className="permission-content">
         <div className="permission-items">
           <div className="permission-parent">