فهرست منبع

fix: bug#3798、3780、3739、3733、3731、3722、3717、3712、3710

xieyonghong 3 سال پیش
والد
کامیت
6fd184aaa4

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

@@ -12,7 +12,7 @@ export interface DeviceCardProps extends DeviceInstance {
 
 
 export default (props: DeviceCardProps) => {
 export default (props: DeviceCardProps) => {
   return (
   return (
-    <Card style={{ width: 340 }} cover={null} actions={props.actions}>
+    <Card style={{ width: '100%' }} cover={null} actions={props.actions}>
       <div className={'pro-table-card-item'}>
       <div className={'pro-table-card-item'}>
         <div className={'card-item-avatar'}>
         <div className={'card-item-avatar'}>
           <Avatar size={props.avatarSize || 64} src={props.photoUrl} />
           <Avatar size={props.avatarSize || 64} src={props.photoUrl} />

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

@@ -15,7 +15,7 @@ export default (props: ProductCardProps) => {
   const intl = useIntl();
   const intl = useIntl();
 
 
   return (
   return (
-    <Card style={{ width: 340 }} cover={null} actions={props.actions}>
+    <Card style={{ width: '100%' }} cover={null} actions={props.actions}>
       <div className={'pro-table-card-item'}>
       <div className={'pro-table-card-item'}>
         <div className={'card-item-avatar'}>
         <div className={'card-item-avatar'}>
           <Avatar size={props.avatarSize || 64} src={props.photoUrl} />
           <Avatar size={props.avatarSize || 64} src={props.photoUrl} />

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

@@ -20,7 +20,7 @@
   .pro-table-card-items {
   .pro-table-card-items {
     display: grid;
     display: grid;
     grid-gap: 26px;
     grid-gap: 26px;
-    grid-template-columns: repeat(auto-fit, 340px);
+    grid-template-columns: repeat(4, 1fr);
     //display: flex;
     //display: flex;
     //flex-wrap: wrap;
     //flex-wrap: wrap;
     padding-bottom: 38px;
     padding-bottom: 38px;

+ 6 - 3
src/pages/device/Instance/Detail/index.tsx

@@ -16,7 +16,7 @@ import type { DeviceMetadata } from '@/pages/device/Product/typings';
 import MetadataAction from '@/pages/device/components/Metadata/DataBaseAction';
 import MetadataAction from '@/pages/device/components/Metadata/DataBaseAction';
 import { Store } from 'jetlinks-store';
 import { Store } from 'jetlinks-store';
 import SystemConst from '@/utils/const';
 import SystemConst from '@/utils/const';
-import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
+import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 
 
 export const deviceStatus = new Map();
 export const deviceStatus = new Map();
 deviceStatus.set('online', <Badge status="success" text={'在线'} />);
 deviceStatus.set('online', <Badge status="success" text={'在线'} />);
@@ -159,8 +159,11 @@ const InstanceDetail = observer(() => {
               type={'link'}
               type={'link'}
               size={'small'}
               size={'small'}
               onClick={() => {
               onClick={() => {
-                const url = getMenuPathByCode(MENUS_CODE['device/Product']);
-                history.push(`${url}?id=${InstanceModel.detail.productId}`);
+                const url = getMenuPathByParams(
+                  MENUS_CODE['device/Product/Detail'],
+                  InstanceModel.detail.productId,
+                );
+                history.replace(url);
               }}
               }}
             >
             >
               {InstanceModel.detail.productName}
               {InstanceModel.detail.productName}

+ 1 - 0
src/pages/device/Instance/Save/index.tsx

@@ -205,6 +205,7 @@ const Save = (props: Props) => {
                     productName: node.label,
                     productName: node.label,
                   });
                   });
                 }}
                 }}
+                filterOption={(input, option) => option.label.includes(input)}
               />
               />
             </Form.Item>
             </Form.Item>
             <Form.Item hidden={true} name={'productName'}>
             <Form.Item hidden={true} name={'productName'}>

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

@@ -88,6 +88,7 @@ const Instance = () => {
       </Button>
       </Button>
     </Tooltip>,
     </Tooltip>,
     <Popconfirm
     <Popconfirm
+      key={'state'}
       title={intl.formatMessage({
       title={intl.formatMessage({
         id: `pages.data.option.${record.state.value !== 'notActive' ? 'disabled' : 'enabled'}.tips`,
         id: `pages.data.option.${record.state.value !== 'notActive' ? 'disabled' : 'enabled'}.tips`,
         defaultMessage: '确认禁用?',
         defaultMessage: '确认禁用?',
@@ -125,6 +126,7 @@ const Instance = () => {
             ? 'pages.data.option.remove.tips'
             ? 'pages.data.option.remove.tips'
             : 'pages.device.instance.deleteTip',
             : 'pages.device.instance.deleteTip',
       })}
       })}
+      key={'delete'}
       onConfirm={async () => {
       onConfirm={async () => {
         if (record.state.value === 'notActive') {
         if (record.state.value === 'notActive') {
           await service.remove(record.id);
           await service.remove(record.id);

+ 43 - 9
src/pages/device/Product/index.tsx

@@ -1,5 +1,5 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import { PageContainer } from '@ant-design/pro-layout';
-import { Badge, Button, message, Popconfirm, Space, Tooltip } from 'antd';
+import { Badge, Button, message, Popconfirm, Space, Tooltip, Upload } from 'antd';
 import type { ProductItem } from '@/pages/device/Product/typings';
 import type { ProductItem } from '@/pages/device/Product/typings';
 import {
 import {
   DeleteOutlined,
   DeleteOutlined,
@@ -22,6 +22,7 @@ import SearchComponent from '@/components/SearchComponent';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { ProTableCard } from '@/components';
 import { ProTableCard } from '@/components';
 import ProductCard from '@/components/ProTableCard/CardItems/product';
 import ProductCard from '@/components/ProTableCard/CardItems/product';
+import { downloadObject } from '@/utils/util';
 
 
 export const service = new Service('device-product');
 export const service = new Service('device-product');
 export const statusMap = {
 export const statusMap = {
@@ -151,11 +152,12 @@ const Product = observer(() => {
       <Button type={'link'} style={{ padding: 0 }}>
       <Button type={'link'} style={{ padding: 0 }}>
         <DownloadOutlined
         <DownloadOutlined
           onClick={async () => {
           onClick={async () => {
-            await message.success(
-              `${intl.formatMessage({
-                id: 'pages.data.option.download',
-                defaultMessage: '下载',
-              })}`,
+            downloadObject(
+              record,
+              intl.formatMessage({
+                id: 'pages.device.product',
+                defaultMessage: '产品',
+              }),
             );
             );
           }}
           }}
         />
         />
@@ -305,9 +307,41 @@ const Product = observer(() => {
               defaultMessage: '新增',
               defaultMessage: '新增',
             })}
             })}
           </Button>,
           </Button>,
-          <Button onClick={() => {}} key={'import'} type={'primary'}>
-            导入
-          </Button>,
+          <Upload
+            key={'import'}
+            showUploadList={false}
+            beforeUpload={(file) => {
+              const reader = new FileReader();
+              reader.readAsText(file);
+              reader.onload = async (result) => {
+                const text = result.target?.result as string;
+                if (!file.type.includes('json')) {
+                  message.warning('文件内容格式错误');
+                  return;
+                }
+                try {
+                  const data = JSON.parse(text || '{}');
+                  // 设置导入的产品状态为未发布
+                  data.state = 0;
+                  if (Array.isArray(data)) {
+                    message.warning('文件内容格式错误');
+                    return;
+                  }
+
+                  const res = await service.update(data);
+                  if (res.status === 200) {
+                    message.success('操作成功');
+                    actionRef.current?.reload();
+                  }
+                } catch {
+                  message.warning('文件内容格式错误');
+                }
+              };
+              return false;
+            }}
+          >
+            <Button style={{ marginLeft: 12 }}>导入</Button>
+          </Upload>,
         ]}
         ]}
         cardRender={(record) => <ProductCard {...record} actions={tools(record)} />}
         cardRender={(record) => <ProductCard {...record} actions={tools(record)} />}
       />
       />

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

@@ -38,23 +38,27 @@ export default observer(() => {
    * 解除资产绑定
    * 解除资产绑定
    */
    */
   const handleUnBind = () => {
   const handleUnBind = () => {
-    service
-      .unBind('device', [
-        {
-          targetType: 'org',
-          targetId: param.id,
-          assetType: 'device',
-          assetIdList: Models.unBindKeys,
-        },
-      ])
-      .subscribe({
-        next: () => message.success('操作成功'),
-        error: () => message.error('操作失败'),
-        complete: () => {
-          Models.unBindKeys = [];
-          actionRef.current?.reload();
-        },
-      });
+    if (Models.unBindKeys.length) {
+      service
+        .unBind('device', [
+          {
+            targetType: 'org',
+            targetId: param.id,
+            assetType: 'device',
+            assetIdList: Models.unBindKeys,
+          },
+        ])
+        .subscribe({
+          next: () => message.success('操作成功'),
+          error: () => message.error('操作失败'),
+          complete: () => {
+            Models.unBindKeys = [];
+            actionRef.current?.reload();
+          },
+        });
+    } else {
+      message.warning('请勾选需要解绑的数据');
+    }
   };
   };
 
 
   const singleUnBind = (key: string) => {
   const singleUnBind = (key: string) => {

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

@@ -26,23 +26,27 @@ export default observer(() => {
    * 解除资产绑定
    * 解除资产绑定
    */
    */
   const handleUnBind = () => {
   const handleUnBind = () => {
-    service
-      .unBind('product', [
-        {
-          targetType: 'org',
-          targetId: param.id,
-          assetType: 'product',
-          assetIdList: Models.unBindKeys,
-        },
-      ])
-      .subscribe({
-        next: () => message.success('操作成功'),
-        error: () => message.error('操作失败'),
-        complete: () => {
-          Models.unBindKeys = [];
-          actionRef.current?.reload();
-        },
-      });
+    if (Models.unBindKeys.length) {
+      service
+        .unBind('product', [
+          {
+            targetType: 'org',
+            targetId: param.id,
+            assetType: 'product',
+            assetIdList: Models.unBindKeys,
+          },
+        ])
+        .subscribe({
+          next: () => message.success('操作成功'),
+          error: () => message.error('操作失败'),
+          complete: () => {
+            Models.unBindKeys = [];
+            actionRef.current?.reload();
+          },
+        });
+    } else {
+      message.warning('请勾选需要解绑的数据');
+    }
   };
   };
 
 
   const singleUnBind = (key: string) => {
   const singleUnBind = (key: string) => {

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

@@ -39,23 +39,27 @@ export default observer(() => {
    * 解除资产绑定
    * 解除资产绑定
    */
    */
   const handleUnBind = () => {
   const handleUnBind = () => {
-    service
-      .unBind('deviceCategory', [
-        {
-          targetType: 'org',
-          targetId: param.id,
-          assetType: 'deviceCategory',
-          assetIdList: Models.unBindKeys,
-        },
-      ])
-      .subscribe({
-        next: () => message.success('操作成功'),
-        error: () => message.error('操作失败'),
-        complete: () => {
-          Models.unBindKeys = [];
-          actionRef.current?.reload();
-        },
-      });
+    if (Models.unBindKeys.length) {
+      service
+        .unBind('deviceCategory', [
+          {
+            targetType: 'org',
+            targetId: param.id,
+            assetType: 'deviceCategory',
+            assetIdList: Models.unBindKeys,
+          },
+        ])
+        .subscribe({
+          next: () => message.success('操作成功'),
+          error: () => message.error('操作失败'),
+          complete: () => {
+            Models.unBindKeys = [];
+            actionRef.current?.reload();
+          },
+        });
+    } else {
+      message.warning('请勾选需要解绑的数据');
+    }
   };
   };
 
 
   const singleUnBind = (key: string) => {
   const singleUnBind = (key: string) => {

+ 12 - 8
src/pages/system/Department/Member/index.tsx

@@ -24,14 +24,18 @@ const Member = observer(() => {
   const [searchParam, setSearchParam] = useState({});
   const [searchParam, setSearchParam] = useState({});
 
 
   const handleUnBind = () => {
   const handleUnBind = () => {
-    service.handleUser(param.id, MemberModel.unBindUsers, 'unbind').subscribe({
-      next: () => message.success('操作成功'),
-      error: () => message.error('操作失败'),
-      complete: () => {
-        MemberModel.unBindUsers = [];
-        actionRef.current?.reload();
-      },
-    });
+    if (MemberModel.unBindUsers.length) {
+      service.handleUser(param.id, MemberModel.unBindUsers, 'unbind').subscribe({
+        next: () => message.success('操作成功'),
+        error: () => message.error('操作失败'),
+        complete: () => {
+          MemberModel.unBindUsers = [];
+          actionRef.current?.reload();
+        },
+      });
+    } else {
+      message.warning('请勾选需要解绑的数据');
+    }
   };
   };
 
 
   const singleUnBind = (key: string) => {
   const singleUnBind = (key: string) => {

+ 30 - 22
src/pages/system/Menu/Detail/buttons.tsx

@@ -8,7 +8,6 @@ import { DeleteOutlined, EditOutlined, PlusOutlined, SearchOutlined } from '@ant
 import type { MenuButtonInfo, MenuItem } from '@/pages/system/Menu/typing';
 import type { MenuButtonInfo, MenuItem } from '@/pages/system/Menu/typing';
 import Permission from '@/pages/system/Menu/components/permission';
 import Permission from '@/pages/system/Menu/components/permission';
 import { useRequest } from '@@/plugin-request/request';
 import { useRequest } from '@@/plugin-request/request';
-import { debounce } from 'lodash';
 
 
 type ButtonsProps = {
 type ButtonsProps = {
   data: MenuItem;
   data: MenuItem;
@@ -49,15 +48,15 @@ export default (props: ButtonsProps) => {
     setDisabled(false);
     setDisabled(false);
   };
   };
 
 
-  const filterThree = (e: any) => {
-    const _data: any = {
-      paging: false,
-    };
-    if (e.target.value) {
-      _data.terms = [{ column: 'name', value: e.target.value }];
-    }
-    queryPermissions(_data);
-  };
+  // const filterThree = (e: any) => {
+  //   const _data: any = {
+  //     paging: false,
+  //   };
+  //   if (e.target.value) {
+  //     _data.terms = [{ column: 'name', value: e.target.value }];
+  //   }
+  //   queryPermissions(_data);
+  // };
 
 
   /**
   /**
    * 更新菜单信息
    * 更新菜单信息
@@ -65,17 +64,19 @@ export default (props: ButtonsProps) => {
    */
    */
   const updateMenuInfo = useCallback(
   const updateMenuInfo = useCallback(
     async (data: MenuButtonInfo[]) => {
     async (data: MenuButtonInfo[]) => {
-      const response = await service.update({
-        ...props.data,
-        buttons: data,
-      });
-      if (response.status === 200) {
-        message.success('操作成功!');
-        props.onLoad();
-        resetForm();
-        setVisible(false);
-      } else {
-        message.error('操作失败!');
+      if (props.data.id) {
+        const response = await service.update({
+          ...props.data,
+          buttons: data,
+        });
+        if (response.status === 200) {
+          message.success('操作成功!');
+          props.onLoad();
+          resetForm();
+          setVisible(false);
+        } else {
+          message.error('操作失败!');
+        }
       }
       }
       /* eslint-disable */
       /* eslint-disable */
     },
     },
@@ -153,6 +154,10 @@ export default (props: ButtonsProps) => {
         defaultMessage: '备注说明',
         defaultMessage: '备注说明',
       }),
       }),
       dataIndex: 'describe',
       dataIndex: 'describe',
+      // render: (_, row) => () => {
+      //   console.log(row)
+      //   return (<> {row.describe || '-'}</>)
+      // }
     },
     },
     {
     {
       title: intl.formatMessage({
       title: intl.formatMessage({
@@ -234,6 +239,10 @@ export default (props: ButtonsProps) => {
         toolBarRender={() => [
         toolBarRender={() => [
           <Button
           <Button
             onClick={() => {
             onClick={() => {
+              if (!props.data) {
+                message.warning('请先新增菜单基本信息');
+                return;
+              }
               form.resetFields();
               form.resetFields();
               setVisible(true);
               setVisible(true);
             }}
             }}
@@ -310,7 +319,6 @@ export default (props: ButtonsProps) => {
             })}
             })}
             required={true}
             required={true}
           >
           >
-            <Input disabled={disabled} onChange={debounce(filterThree, 300)} />
             <Form.Item name="permissions" rules={[{ required: true, message: '请选择权限' }]}>
             <Form.Item name="permissions" rules={[{ required: true, message: '请选择权限' }]}>
               <Permission
               <Permission
                 title={intl.formatMessage({
                 title={intl.formatMessage({

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

@@ -225,6 +225,7 @@ export default (props: PermissionType) => {
    */
    */
   const initialState = (data: PermissionDataType[]) => {
   const initialState = (data: PermissionDataType[]) => {
     const _list = data.map((item) => {
     const _list = data.map((item) => {
+      console.log(item.name, item.actions);
       const propsPermission =
       const propsPermission =
         props.value && props.value.length
         props.value && props.value.length
           ? props.value.find((p) => p.permission === item.id)
           ? props.value.find((p) => p.permission === item.id)
@@ -232,7 +233,9 @@ export default (props: PermissionType) => {
       const propsActions = propsPermission ? propsPermission.actions : [];
       const propsActions = propsPermission ? propsPermission.actions : [];
       return {
       return {
         ...item,
         ...item,
-        actions: item.actions.map((a) => ({ ...a, checked: propsActions.includes(a.action) })),
+        actions: item.actions
+          .filter((action) => Object.keys(action).length)
+          .map((a) => ({ ...a, checked: propsActions.includes(a.action) })),
         state: false, // 是否为半选中状态
         state: false, // 是否为半选中状态
         checked: false, // 是否为全选
         checked: false, // 是否为全选
       };
       };

+ 1 - 0
src/pages/system/Menu/typing.d.ts

@@ -78,5 +78,6 @@ export type MenuButtonInfo = {
   name: string;
   name: string;
   permissions: PermissionInfo;
   permissions: PermissionInfo;
   createTime: number;
   createTime: number;
+  describe?: string;
   options: Record<string, any>;
   options: Record<string, any>;
 };
 };