فهرست منبع

feat: 应用管理修改

wzyyy 3 سال پیش
والد
کامیت
ffa05994d7

+ 0 - 16
src/app.tsx

@@ -375,22 +375,6 @@ export function render(oldRender: any) {
               },
             ],
           },
-          {
-            terms: [
-              {
-                column: 'owner',
-                termType: 'notnull',
-                value: '1',
-              },
-              {
-                column: 'appId',
-                termType: 'notnull',
-                value: '1',
-                type: 'and',
-              },
-            ],
-            type: 'or',
-          },
         ],
       },
     ];

+ 83 - 0
src/pages/system/Apply/Menu/index.tsx

@@ -0,0 +1,83 @@
+import { Modal, Tree } from 'antd';
+import { useEffect, useState } from 'react';
+import { service } from '../index';
+
+interface Props {
+  close: Function;
+  data: string;
+}
+
+const MenuPage = (props: Props) => {
+  const [treeData, setTreeData] = useState<undefined | any[]>(undefined);
+  const [keys, setKeys] = useState<any>([]);
+  const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
+
+  const getTree = async () => {
+    const res = await service.queryOwner(['iot']);
+    if (res.status === 200) {
+      const resp = await service.queryOwnerTree(res.result?.[0]);
+      if (resp.status === 200) {
+        setTreeData(resp.result);
+        // console.log(resp.result)
+      }
+    }
+  };
+
+  // const filterTree = (tree:any[],parms: any[]) => {
+  //     return tree.filter(item=>{
+  //         console.log(item)
+  //         return parms?.indexOf(item.id) > -1
+  //     }).map(i=>{
+  //         i = Object.assign({},i)
+  //         if(i.children){
+  //             i.children = filterTree(i.children,parms)
+  //         }
+  //         return i
+  //     })
+  // }
+
+  useEffect(() => {
+    getTree();
+  }, []);
+
+  return (
+    <Modal
+      visible
+      maskClosable={false}
+      title="集成菜单"
+      width={800}
+      onCancel={() => {
+        props.close();
+      }}
+      onOk={() => {
+        // if(treeData && treeData.length!==0){
+        //     const item = filterTree(treeData,keys.checked)
+        //     console.log(item)
+        // }
+        // console.log(keys)
+      }}
+    >
+      <Tree
+        fieldNames={{
+          title: 'name',
+          key: 'id',
+        }}
+        checkable
+        // checkStrictly={true}
+        treeData={treeData}
+        checkedKeys={keys}
+        autoExpandParent={true}
+        onCheck={(_keys: any, e) => {
+          console.log(e);
+          setKeys(_keys);
+        }}
+        expandedKeys={expandedKeys}
+        onExpand={(_keys: any[]) => {
+          setExpandedKeys(_keys);
+        }}
+      />
+    </Modal>
+  );
+};
+
+export default MenuPage;

+ 140 - 21
src/pages/system/Apply/Save/index.tsx

@@ -20,7 +20,7 @@ import {
 import { TreeSelect as ATreeSelect } from 'antd';
 import { useEffect, useState } from 'react';
 import { createSchemaField } from '@formily/react';
-import { createForm, Field, onFieldValueChange, onFormInit } from '@formily/core';
+import { createForm, Field, onFieldReact, onFieldValueChange, onFormInit } from '@formily/core';
 import { onlyMessage, randomString, useAsyncDataSource } from '@/utils/util';
 import { service } from '../index';
 import { PlusOutlined } from '@ant-design/icons';
@@ -155,32 +155,34 @@ const Save = () => {
           switch (value) {
             case 'internal-standalone':
               form1.setFieldState('integrationModes', (f1) => {
-                f1.hidden = false;
                 f1.value = [];
+                f1.dataSource = integrationModesList;
               });
               break;
             case 'internal-integrated':
               form1.setFieldState('integrationModes', (f2) => {
-                f2.hidden = true;
-                f2.value = ['page'];
+                f2.value = [];
+                f2.dataSource = integrationModesList?.filter(
+                  (item) => item.value === 'apiClient' || item.value === 'page',
+                );
               });
               break;
             case 'dingtalk-ent-app':
               form1.setFieldState('integrationModes', (f3) => {
-                f3.hidden = true;
                 f3.value = ['ssoClient'];
+                f3.dataSource = integrationModesList?.filter((item) => item.value === 'ssoClient');
               });
               break;
             case 'wechat-webapp':
               form1.setFieldState('integrationModes', (f4) => {
-                f4.hidden = true;
                 f4.value = ['ssoClient'];
+                f4.dataSource = integrationModesList?.filter((item) => item.value === 'ssoClient');
               });
               break;
             case 'third-party':
               form1.setFieldState('integrationModes', (f5) => {
-                f5.hidden = false;
                 f5.value = [];
+                f5.dataSource = integrationModesList;
               });
               break;
             default:
@@ -189,10 +191,11 @@ const Save = () => {
         }
       });
       onFieldValueChange('integrationModes', (field, form2) => {
+        const value = field.value;
         formCollapse.activeKeys = field.value;
         const modes = ['page', 'apiClient', 'apiServer', 'ssoClient'];
-        const items = modes.concat(field.value).filter((item) => !field.value?.includes(item)); //未被选中
-        // console.log(items);
+        const items = modes.concat(field.value).filter((item) => !value?.includes(item)); //未被选中
+        // console.log(value);
         items.forEach((i) => {
           form2.setFieldState(`config.${i}`, (state) => {
             state.visible = false;
@@ -203,12 +206,43 @@ const Save = () => {
             state.visible = true;
           });
         });
+        // const array = ['apiClient', 'apiServer'];
+        // const isSome = array.length ===value.length&& array.filter(t=>!value.includes(t))
+        // if(isSome){
+        //   // console.log(isSome,value)
+        //   console.log(11111)
+        //   form2.setFieldState('config.apiServer.appId',(state)=>{
+        //     state.visible=true
+        //   })
+        // }
+      });
+      onFieldReact('apiClient.authConfig.oauth2.clientId', (filed) => {
+        const parms = filed.query('provider').get('value');
+        console.log(parms);
+        if (id && parms === 'internal-standalone') {
+          filed.componentProps = {
+            disabled: true,
+          };
+        }
       });
     },
   });
 
   const handleSave = async () => {
     const data: any = await form.submit();
+
+    //独立应用-api客户端 id?clientId:appId
+    if (data.provider === 'internal-standalone') {
+      if (data.integrationModes.includes('apiClient')) {
+        data.id = data.apiClient.authConfig.oauth2.clientId;
+      }
+      if (
+        data.integrationModes.includes('apiServer') &&
+        !data.integrationModes.includes('apiClient')
+      ) {
+        data.id = data.apiServer.appId;
+      }
+    }
     if (id) {
       const resp: any = await service.modify(id, data);
       if (resp.status === 200) {
@@ -224,7 +258,7 @@ const Save = () => {
         history.push(url);
       }
     }
-    // console.log(data);
+    console.log(data);
   };
 
   //单点登录
@@ -929,6 +963,30 @@ const Save = () => {
               header: 'API服务',
             },
             properties: {
+              'apiServer.appId': {
+                type: 'string',
+                title: 'appId',
+                default: randomString(16),
+                'x-decorator': 'FormItem',
+                'x-decorator-props': {
+                  gridSpan: 2,
+                  layout: 'vertical',
+                  labelAlign: 'left',
+                },
+                required: true,
+                'x-component': 'Input',
+                'x-component-props': {
+                  disabled: true,
+                },
+                'x-reactions': {
+                  dependencies: ['integrationModes'],
+                  fulfill: {
+                    state: {
+                      visible: '{{!$deps[0].includes("apiClient")}}',
+                    },
+                  },
+                },
+              },
               'apiServer.secureKey': {
                 type: 'string',
                 title: 'secureKey',
@@ -945,6 +1003,21 @@ const Save = () => {
                   placeholder: '请输入secureKey',
                 },
               },
+              'apiServer.redirectUri': {
+                type: 'string',
+                title: '回调地址',
+                'x-decorator': 'FormItem',
+                'x-decorator-props': {
+                  gridSpan: 2,
+                  layout: 'vertical',
+                  labelAlign: 'left',
+                },
+                required: true,
+                'x-component': 'Input',
+                'x-component-props': {
+                  placeholder: '请输入回调地址',
+                },
+              },
               'apiServer.roleIdList': {
                 title: '角色',
                 'x-decorator': 'FormItem',
@@ -1066,13 +1139,51 @@ const Save = () => {
                 },
                 properties: { ...clientThird },
               },
+              integratedConfig: {
+                type: 'void',
+                'x-reactions': {
+                  dependencies: ['provider'],
+                  fulfill: {
+                    state: {
+                      visible: '{{$deps[0]==="internal-integrated"}}',
+                    },
+                  },
+                },
+                properties: {
+                  'apiClient.baseUrl': {
+                    type: 'string',
+                    title: '接口地址',
+                    'x-decorator': 'FormItem',
+                    'x-decorator-props': {
+                      gridSpan: 2,
+                      layout: 'vertical',
+                      labelAlign: 'left',
+                      tooltip: '访问Api服务的地址',
+                    },
+                    required: true,
+                    'x-component': 'Input',
+                    'x-component-props': {
+                      placeholder: '请输入接口地址',
+                    },
+                  },
+                },
+              },
+
               'apiClient.headers': {
                 type: 'array',
                 default: [{}],
                 title: '请求头',
                 'x-decorator': 'FormItem',
-                required: true,
+                // required: true,
                 'x-component': 'ArrayTable',
+                'x-reactions': {
+                  dependencies: ['provider'],
+                  fulfill: {
+                    state: {
+                      visible: '{{$deps[0] && $deps[0]!=="internal-integrated"}}',
+                    },
+                  },
+                },
                 'x-decorator-props': {
                   gridSpan: 2,
                   layout: 'vertical',
@@ -1083,12 +1194,12 @@ const Save = () => {
                   properties: {
                     column1: {
                       type: 'void',
-                      required: true,
+                      // required: true,
                       'x-component': 'ArrayTable.Column',
                       'x-component-props': { width: 100, title: 'key' },
                       properties: {
                         key: {
-                          required: true,
+                          // required: true,
                           'x-decorator': 'FormItem',
                           'x-component': 'Input',
                         },
@@ -1100,7 +1211,7 @@ const Save = () => {
                       'x-component-props': { width: 100, title: 'value' },
                       properties: {
                         value: {
-                          required: true,
+                          // required: true,
                           'x-decorator': 'FormItem',
                           'x-component': 'Input',
                         },
@@ -1131,8 +1242,16 @@ const Save = () => {
                 type: 'array',
                 default: [{}],
                 title: '参数',
+                'x-reactions': {
+                  dependencies: ['provider'],
+                  fulfill: {
+                    state: {
+                      visible: '{{$deps[0] && $deps[0]!=="internal-integrated"}}',
+                    },
+                  },
+                },
                 'x-decorator': 'FormItem',
-                required: true,
+                // required: true,
                 'x-component': 'ArrayTable',
                 'x-decorator-props': {
                   gridSpan: 2,
@@ -1144,12 +1263,12 @@ const Save = () => {
                   properties: {
                     column1: {
                       type: 'void',
-                      required: true,
+                      // required: true,
                       'x-component': 'ArrayTable.Column',
                       'x-component-props': { width: 100, title: 'key' },
                       properties: {
                         key: {
-                          required: true,
+                          // required: true,
                           'x-decorator': 'FormItem',
                           'x-component': 'Input',
                         },
@@ -1161,7 +1280,7 @@ const Save = () => {
                       'x-component-props': { width: 100, title: 'value' },
                       properties: {
                         value: {
-                          required: true,
+                          // required: true,
                           'x-decorator': 'FormItem',
                           'x-component': 'Input',
                         },
@@ -1264,12 +1383,12 @@ const Save = () => {
                   properties: {
                     column1: {
                       type: 'void',
-                      required: true,
+                      // required: true,
                       'x-component': 'ArrayTable.Column',
                       'x-component-props': { width: 100, title: 'key' },
                       properties: {
                         key: {
-                          required: true,
+                          // required: true,
                           'x-decorator': 'FormItem',
                           'x-component': 'Input',
                         },
@@ -1281,7 +1400,7 @@ const Save = () => {
                       'x-component-props': { width: 100, title: 'value' },
                       properties: {
                         value: {
-                          required: true,
+                          // required: true,
                           'x-decorator': 'FormItem',
                           'x-component': 'AutoComplete',
                           'x-component-props': {

+ 127 - 41
src/pages/system/Apply/index.tsx

@@ -7,16 +7,20 @@ import { onlyMessage } from '@/utils/util';
 import {
   DeleteOutlined,
   EditOutlined,
+  ExclamationCircleOutlined,
   EyeOutlined,
+  MenuUnfoldOutlined,
   PlayCircleOutlined,
   PlusOutlined,
+  SmallDashOutlined,
   StopOutlined,
 } from '@ant-design/icons';
 import { PageContainer } from '@ant-design/pro-layout';
 import { ActionType, ProColumns } from '@jetlinks/pro-table';
-import { Badge } from 'antd';
+import { Badge, Dropdown, Menu } from 'antd';
 import { useRef, useState } from 'react';
 import { useIntl } from 'umi';
+import MenuPage from './Menu';
 import Service from './service';
 
 export const service = new Service('application');
@@ -27,6 +31,8 @@ const Apply = () => {
   const [searchParams, setSearchParams] = useState<any>({});
   const { permission } = PermissionButton.usePermission('system/Apply');
   const intl = useIntl();
+  const [menuVisiable, setMenuVisiable] = useState<boolean>(false);
+  const [data, setData] = useState<any>({});
 
   const providerType = new Map();
   providerType.set('internal-standalone', '内部独立应用');
@@ -35,8 +41,8 @@ const Apply = () => {
   providerType.set('dingtalk-ent-app', '钉钉企业内部应用');
   providerType.set('third-party', '第三方应用');
 
-  const _action = (id: string, data: any) => {
-    service.modify(id, data).then((res) => {
+  const _action = (id: string, parms: any) => {
+    service.modify(id, parms).then((res) => {
       if (res.status === 200) {
         onlyMessage('操作成功');
         actionRef.current?.reload();
@@ -50,6 +56,10 @@ const Apply = () => {
     const res = params?.map((item) => item.value).includes('apiServer');
     return res;
   };
+  const isPage = (params: any[]) => {
+    const res = params?.map((item) => item.value).includes('page');
+    return res;
+  };
 
   const columns: ProColumns<any>[] = [
     {
@@ -135,6 +145,23 @@ const Apply = () => {
         >
           <EditOutlined />
         </PermissionButton>,
+        isPage(record.integrationModes) ? (
+          <PermissionButton
+            isPermission={permission.update}
+            key="edit"
+            onClick={() => {
+              setData(record);
+              setMenuVisiable(true);
+            }}
+            type={'link'}
+            style={{ padding: 0 }}
+            tooltip={{
+              title: '集成菜单',
+            }}
+          >
+            <MenuUnfoldOutlined />
+          </PermissionButton>
+        ) : null,
         isApiService(record.integrationModes) ? (
           <PermissionButton
             key={'empowerment'}
@@ -233,9 +260,9 @@ const Apply = () => {
       <SearchComponent
         field={columns}
         target="Apply"
-        onSearch={(data) => {
+        onSearch={(item) => {
           actionRef.current?.reset?.();
-          setSearchParams(data);
+          setSearchParams(item);
         }}
       />
       <ProTableCard
@@ -273,6 +300,18 @@ const Apply = () => {
           >
             新增
           </PermissionButton>,
+          <div
+            style={{
+              paddingLeft: 24,
+              background: '#fff',
+              fontSize: 14,
+            }}
+          >
+            <span style={{ marginRight: 8, fontSize: 16 }}>
+              <ExclamationCircleOutlined />
+            </span>
+            应用管理将多个应用系统的登录简化为一次登录,实现多处访问、集中管控的业务场景。
+          </div>,
         ]}
         gridColumn={3}
         cardRender={(record) => (
@@ -312,42 +351,6 @@ const Apply = () => {
                 <EditOutlined />
                 编辑
               </PermissionButton>,
-              isApiService(record.integrationModes) ? (
-                <PermissionButton
-                  key={'empowerment'}
-                  type={'link'}
-                  style={{ padding: 0 }}
-                  isPermission={permission.empowerment}
-                  tooltip={{
-                    title: '赋权',
-                  }}
-                  onClick={() => {
-                    const url = getMenuPathByCode('system/Apply/Api');
-                    history.push(`${url}?code=${record.id}`);
-                  }}
-                >
-                  <AIcon type={'icon-fuquan'} />
-                  赋权
-                </PermissionButton>
-              ) : null,
-              isApiService(record.integrationModes) ? (
-                <PermissionButton
-                  key={'api'}
-                  type={'link'}
-                  style={{ padding: 0 }}
-                  isPermission={permission.api}
-                  tooltip={{
-                    title: '查看API',
-                  }}
-                  onClick={() => {
-                    const url = getMenuPathByCode('system/Apply/View');
-                    history.push(`${url}?code=${record.id}`);
-                  }}
-                >
-                  <AIcon type={'icon-chakanAPI'} />
-                  查看API
-                </PermissionButton>
-              ) : null,
               <PermissionButton
                 isPermission={permission.action}
                 key="action"
@@ -374,6 +377,81 @@ const Apply = () => {
                 {record.state !== 'disabled' ? <StopOutlined /> : <PlayCircleOutlined />}
                 {record.state !== 'disabled' ? '禁用' : '启用'}
               </PermissionButton>,
+              (isPage(record.integrationModes) || isApiService(record.integrationModes)) && (
+                <Dropdown
+                  key={'more'}
+                  placement="bottom"
+                  overlay={
+                    <Menu>
+                      {isPage(record.integrationModes) && (
+                        <Menu.Item key="menu">
+                          <PermissionButton
+                            isPermission={permission.update}
+                            key="edit"
+                            onClick={() => {
+                              setData(record);
+                              setMenuVisiable(true);
+                            }}
+                            type={'link'}
+                            style={{ padding: 0 }}
+                            tooltip={{
+                              title: '集成菜单',
+                            }}
+                          >
+                            <MenuUnfoldOutlined />
+                            集成菜单
+                          </PermissionButton>
+                        </Menu.Item>
+                      )}
+                      {isApiService(record.integrationModes) && (
+                        <Menu.Item key="empowerment">
+                          <PermissionButton
+                            key={'empowerment'}
+                            type={'link'}
+                            style={{ padding: 0 }}
+                            isPermission={permission.empowerment}
+                            tooltip={{
+                              title: '赋权',
+                            }}
+                            onClick={() => {
+                              const url = getMenuPathByCode('system/Apply/Api');
+                              history.push(`${url}?code=${record.id}`);
+                            }}
+                          >
+                            <AIcon type={'icon-fuquan'} />
+                            赋权
+                          </PermissionButton>
+                        </Menu.Item>
+                      )}
+                      {isApiService(record.integrationModes) && (
+                        <Menu.Item key="empowerment">
+                          <PermissionButton
+                            key={'api'}
+                            type={'link'}
+                            style={{ padding: 0 }}
+                            isPermission={permission.api}
+                            tooltip={{
+                              title: '查看API',
+                            }}
+                            onClick={() => {
+                              const url = getMenuPathByCode('system/Apply/View');
+                              history.push(`${url}?code=${record.id}`);
+                            }}
+                          >
+                            <AIcon type={'icon-chakanAPI'} />
+                            查看API
+                          </PermissionButton>
+                        </Menu.Item>
+                      )}
+                    </Menu>
+                  }
+                >
+                  <PermissionButton type={'link'} isPermission={true} key="other">
+                    <SmallDashOutlined />
+                    其他
+                  </PermissionButton>
+                </Dropdown>
+              ),
               <PermissionButton
                 isPermission={permission.delete}
                 tooltip={{
@@ -407,6 +485,14 @@ const Apply = () => {
           />
         )}
       />
+      {menuVisiable && (
+        <MenuPage
+          data={data}
+          close={() => {
+            setMenuVisiable(false);
+          }}
+        />
+      )}
     </PageContainer>
   );
 };

+ 5 - 0
src/pages/system/Apply/service.ts

@@ -26,6 +26,11 @@ class Service extends BaseService<any> {
       method: 'POST',
       data,
     });
+  queryOwnerTree = (owner: string) =>
+    request(`${SystemConst.API_BASE}/menu/owner/tree/${owner}`, {
+      method: 'POST',
+      data: {},
+    });
 }
 
 export default Service;

+ 2 - 4
src/pages/system/Menu/Detail/edit.tsx

@@ -57,10 +57,8 @@ export default (props: EditProps) => {
   const saveData = async () => {
     const formData = await form.validateFields();
     if (formData) {
-      // formData.options = {
-      //   switch: show,
-      // };
-
+      formData.owner = 'iot';
+      // console.log(formData)
       setLoading(true);
       const response: any = !formData.id
         ? await service.save(formData)

+ 16 - 30
src/pages/system/Menu/Setting/index.tsx

@@ -151,36 +151,22 @@ export default observer(() => {
   };
 
   const getSystemMenu = () => {
-    const item = {
-      terms: [
-        {
-          terms: [
-            {
-              column: 'owner',
-              termType: 'eq',
-              value: 'iot',
-            },
-          ],
-        },
-        {
-          terms: [
-            {
-              column: 'owner',
-              termType: 'notnull',
-              value: '1',
-            },
-            {
-              column: 'appId',
-              termType: 'notnull',
-              value: '1',
-              type: 'and',
-            },
-          ],
-          type: 'or',
-        },
-      ],
-    };
-    service.queryMenuThree({ paging: false, terms: [item] }).then((res) => {
+    const item = [
+      {
+        terms: [
+          {
+            terms: [
+              {
+                column: 'owner',
+                termType: 'eq',
+                value: 'iot',
+              },
+            ],
+          },
+        ],
+      },
+    ];
+    service.queryMenuThree({ paging: false, terms: item }).then((res) => {
       if (res.status === 200) {
         MenuSettingModel.menuData = [...res.result];
         MenuSettingModel.notDragKeys = getKeys(res.result);

+ 0 - 16
src/pages/system/Menu/index.tsx

@@ -278,22 +278,6 @@ export default observer(() => {
                   },
                 ],
               },
-              {
-                terms: [
-                  {
-                    column: 'owner',
-                    termType: 'notnull',
-                    value: '1',
-                  },
-                  {
-                    column: 'appId',
-                    termType: 'notnull',
-                    value: '1',
-                    type: 'and',
-                  },
-                ],
-                type: 'or',
-              },
             ],
           };
           if (params.terms && params.length !== 0) {

+ 1 - 1
src/pages/system/Platforms/Api/leftTree.tsx

@@ -95,7 +95,7 @@ export default (props: LeftTreeType) => {
               }
               return undefined;
             }),
-            map((resp: any) => resp && updateTreeData(resp, item)),
+            map((resp: any) => updateTreeData(resp, item)),
           ),
         ),
       );

+ 1 - 1
src/utils/menu/index.ts

@@ -225,7 +225,7 @@ export const handleRoutes = (routes?: MenuItem[], level = 1): MenuItem[] => {
  * @param level 路由层级
  */
 const getRoutes = (extraRoutes: MenuItem[], level = 1): IRouteProps[] => {
-  console.log(extraRoutes, 1111111111);
+  // console.log(extraRoutes, 1111111111);
   const allComponents = findComponents(require.context('@/pages', true, /index(\.tsx)$/));
   return extraRoutes.map((route) => {
     const component = allComponents[route.code] || null;