Forráskód Böngészése

设置PDA菜单权限

xyh 2 éve
szülő
commit
002538066b

+ 21 - 2
cypress/e2e/role.cy.ts

@@ -13,6 +13,7 @@ import {
   tableBtnClick,
   exportIntercept,
   validateExport,
+  validateModalBtnGroup,
 } from './utils';
 
 describe('角色管理', function() {
@@ -34,6 +35,9 @@ describe('角色管理', function() {
       const page = search.get('page');
       reply({fixture: page === '1' ? 'role/list1' : 'role/list2'});
     });
+    intercept('/menu/getPage', function({reply}) {
+      reply({fixture: 'menu/pda'});
+    });
 
     successIntercept('/role/addRole');
     successIntercept('/role/updateRole');
@@ -94,14 +98,29 @@ describe('角色管理', function() {
           : expect(res.hasClass('ant-tree-treenode-checkbox-checked')).to.false;
       }).should('have.length', 9);
 
-    cy.getTestId('role_tree_modal').find('form').submit();
-
+    validateModalBtnGroup('role_tree_modal');
     cy.getTestId('modal_btn_group').find('.ant-btn-loading').should('exist');
 
     cy.get('.ant-message-notice-content').should('include.text', '设置成功');
     cy.getTestId('role_tree_modal').should('not.exist');
   });
 
+  it.only('设置pda权限', function() {
+    tableBtnClick(TABLE_NAME, 3);
+
+    cy.get('.ant-transfer-list').eq(0).find('.ant-transfer-list-content')
+      .children('.ant-transfer-list-content-item').should('have.length', 4);
+    cy.get('.ant-transfer-list').eq(1).find('.ant-transfer-list-content')
+      .children('.ant-transfer-list-content-item').should('have.length', 2);
+
+    cy.getTestId('role_pda_menu_modal').find('form').submit();
+
+    validateModalBtnGroup('role_pda_menu_modal');
+
+    cy.get('.ant-message-notice-content').should('include.text', '设置成功');
+    cy.getTestId('role_tree_modal').should('not.exist');
+  });
+
   it('导出', function() {
     validateExport();
   });

+ 9 - 9
cypress/e2e/utils/utils.ts

@@ -58,6 +58,13 @@ export function tableBtnClick(tableName: string, index: number) {
     .click();
 }
 
+export function validateModalBtnGroup(modalName: string) {
+  cy.getTestId(modalName).getTestId('modal_btn_group').find('.ant-btn').first()
+    .should('have.class', 'ant-btn-loading');
+  cy.getTestId(modalName).getTestId('modal_btn_group').find('.ant-btn').last()
+    .should('have.attr', 'disabled');
+}
+
 export function validatePut(
   modalName: string,
   label: string,
@@ -65,13 +72,6 @@ export function validatePut(
 ) {
   const {addBtnTestId} = options ?? {};
 
-  function validateBtnGroup() {
-    cy.getTestId('modal_btn_group').find('.ant-btn').first()
-      .should('have.class', 'ant-btn-loading');
-    cy.getTestId('modal_btn_group').find('.ant-btn').last()
-      .should('have.attr', 'disabled');
-  }
-
   function validateAdd(fn: () => void) {
     cy.getTestId(addBtnTestId ?? 'add_btn').click();
 
@@ -83,7 +83,7 @@ export function validatePut(
 
     cy.getTestId(modalName).find('form').submit();
 
-    validateBtnGroup();
+    validateModalBtnGroup(modalName);
 
     cy.get('.ant-message-notice-content').should('include.text', '新增成功');
     cy.getTestId(modalName).should('not.exist');
@@ -99,7 +99,7 @@ export function validatePut(
 
     cy.getTestId(modalName).find('form').submit();
 
-    validateBtnGroup();
+    validateModalBtnGroup(modalName);
 
     cy.get('.ant-message-notice-content').should('include.text', '修改成功');
     cy.getTestId(modalName).should('not.exist');

+ 104 - 0
cypress/fixtures/menu/pda.json

@@ -0,0 +1,104 @@
+{
+  "msg": "200",
+  "data": {
+    "total": 6,
+    "list": [
+      {
+        "id": "31",
+        "name": "收货",
+        "url": "2",
+        "pId": "0",
+        "idCode": null,
+        "type": "PDA",
+        "page": 0,
+        "limit": 0,
+        "orderBy": "0",
+        "menu": null,
+        "pid": "0"
+      },
+      {
+        "id": "33",
+        "name": "上架",
+        "url": "12",
+        "pId": "0",
+        "idCode": null,
+        "type": "PDA",
+        "page": 0,
+        "limit": 0,
+        "orderBy": "0",
+        "menu": null,
+        "pid": "0"
+      },
+      {
+        "id": "34",
+        "name": "下架",
+        "url": "33",
+        "pId": "0",
+        "idCode": null,
+        "type": "PDA",
+        "page": 0,
+        "limit": 0,
+        "orderBy": "0",
+        "menu": null,
+        "pid": "0"
+      },
+      {
+        "id": "35",
+        "name": "出库",
+        "url": "54",
+        "pId": "0",
+        "idCode": null,
+        "type": "PDA",
+        "page": 0,
+        "limit": 0,
+        "orderBy": "0",
+        "menu": null,
+        "pid": "0"
+      },
+      {
+        "id": "36",
+        "name": "入库",
+        "url": "21",
+        "pId": "0",
+        "idCode": null,
+        "type": "PDA",
+        "page": 0,
+        "limit": 0,
+        "orderBy": "0",
+        "menu": null,
+        "pid": "0"
+      },
+      {
+        "id": "37",
+        "name": "AGV",
+        "url": "90",
+        "pId": "0",
+        "idCode": null,
+        "type": "PDA",
+        "page": 0,
+        "limit": 0,
+        "orderBy": "0",
+        "menu": null,
+        "pid": "0"
+      }
+    ],
+    "pageNum": 1,
+    "pageSize": 10000,
+    "size": 6,
+    "startRow": 1,
+    "endRow": 6,
+    "pages": 1,
+    "prePage": 0,
+    "nextPage": 0,
+    "isFirstPage": true,
+    "isLastPage": true,
+    "hasPreviousPage": false,
+    "hasNextPage": false,
+    "navigatePages": 8,
+    "navigatepageNums": [
+      1
+    ],
+    "navigateFirstPage": 1,
+    "navigateLastPage": 1
+  }
+}

+ 1 - 0
cypress/fixtures/role/list1.json

@@ -11,6 +11,7 @@
         "remarks": "cangk",
         "menu": "15,16,23,",
         "menuBefore": "15,16,23",
+        "menuPda": "31,34",
         "page": 0,
         "limit": 0
       },

+ 9 - 0
packages/app/src/apis/menu.ts

@@ -97,3 +97,12 @@ export function getMenuInfo(pId: string, id: string, type: 'PC' | 'PDA'): BaseLi
     url: `${BASE_URL}/getPage`,
   });
 }
+
+/** 获取所有pda菜单 */
+export function getAllPDAMenu(): BaseListResult<MenuListData> {
+  return request({
+    method: 'GET',
+    data: {page: '1', limit: '10000', type: 'PDA'},
+    url: `${BASE_URL}/getPage`,
+  });
+}

+ 10 - 0
packages/app/src/apis/role.ts

@@ -2,6 +2,7 @@ import {
   AddRoleParams,
   BaseListResult,
   BaseResult,
+  EditPDAMenuParams,
   EditRoleMenuParams,
   EditRoleParams,
   GetRoleListParams,
@@ -66,6 +67,15 @@ export function editRoleMenu(params: EditRoleMenuParams): BaseResult {
   });
 }
 
+/** 修改角色PDA菜单权限 */
+export function editRolePDAMenu(params: EditPDAMenuParams): BaseResult {
+  return request({
+    method: 'PUT',
+    data: params,
+    url: `${BASE_URL}/updateRole`,
+  });
+}
+
 /** 查询所有角色 */
 export function getAllRoleList(): BaseResult<RoleListData[]> {
   return request({

+ 6 - 0
packages/app/src/models/request/role.ts

@@ -25,3 +25,9 @@ export type EditRoleMenuParams = {
   /** 菜单管理 antd用 */
   menuBefore: string;
 };
+
+/** 修改pda菜单 */
+export type EditPDAMenuParams = {
+  id: string;
+  menuPda: string;
+};

+ 2 - 0
packages/app/src/models/response/role.ts

@@ -13,6 +13,8 @@ export type RoleListData = {
   menu: null | string;
   /** 菜单管理 antd用 */
   menuBefore: null | string;
+  /** pda菜单 */
+  menuPda: null | string;
   page: number;
   limit: number;
 };

+ 21 - 5
packages/app/src/pages/role/table/hooks.tsx

@@ -1,4 +1,4 @@
-import {useContext, useContextSection} from '@hooks';
+import {useContext, usePage} from '@hooks';
 import {context, pageContext} from '../context';
 import {useMutation, useQuery} from '@tanstack/react-query';
 import {deleteRole, getRoleList} from '@apis';
@@ -10,7 +10,7 @@ import {useBoolean} from 'ahooks';
 import {deleteConfirm} from '@utils';
 
 export function useList() {
-  const {page, pageSize} = useContextSection(pageContext, state => state[0]);
+  const [{page, pageSize}] = usePage(pageContext);
   const [count, setCount] = useState(0);
   const [{name}, dispatch] = useContext(context);
 
@@ -100,6 +100,15 @@ export function useHandle(data: RoleListData[], refetch: () => void) {
     };
   }
 
+  const [pdaId, setPdaId] = useState('');
+  const [pdaVisible, {setTrue: pdaSetTrue, setFalse: onPdaClose}] = useBoolean();
+  function onSetPda(id: string) {
+    return function() {
+      setPdaId(id);
+      pdaSetTrue();
+    };
+  }
+
   const columns: ColumnsType<RoleListData> = [
     {title: '角色编号', dataIndex: 'roleCode', key: 'roleCode'},
     {title: '角色名', dataIndex: 'roleName', key: 'roleName'},
@@ -109,7 +118,7 @@ export function useHandle(data: RoleListData[], refetch: () => void) {
       title: '操作',
       dataIndex: 'id',
       key: 'id',
-      width: 260,
+      width: 400,
       render(_, {id}) {
         return (
           <>
@@ -135,6 +144,13 @@ export function useHandle(data: RoleListData[], refetch: () => void) {
             >
               菜单权限
             </Button>
+            <Button
+              type='text'
+              disabled={deleteId === String(id)}
+              onClick={onSetPda(String(id))}
+            >
+              PDA菜单权限
+            </Button>
           </>
         );
       },
@@ -142,7 +158,7 @@ export function useHandle(data: RoleListData[], refetch: () => void) {
   ];
 
   return [
-    {columns, visible, editId, roleVisible, roleId},
-    {onAdd, onClose: setFalse, onRoleClose},
+    {columns, visible, editId, roleVisible, roleId, pdaVisible, pdaId},
+    {onAdd, onClose: setFalse, onRoleClose, onPdaClose},
   ] as const;
 }

+ 4 - 2
packages/app/src/pages/role/table/index.tsx

@@ -7,13 +7,14 @@ import {PAGE_SIZE_LIST} from '@utils';
 import RoleModal from './modal';
 import TreeModal from './tree-modal';
 import {TableTools} from '@components';
+import PdaMenuModal from './pda-modal';
 
 const TableList: FC = function() {
   const [{data, isFetching, count}, refetch] = useList();
   const [{page, pageSize}, {onPageChange}] = usePage(pageContext);
   const [
-    {columns, visible, editId, roleVisible, roleId},
-    {onAdd, onClose, onRoleClose},
+    {columns, visible, editId, roleVisible, roleId, pdaId, pdaVisible},
+    {onAdd, onClose, onRoleClose, onPdaClose},
   ] = useHandle(data, refetch);
 
   return (
@@ -39,6 +40,7 @@ const TableList: FC = function() {
       </Card>
       <RoleModal visible={visible} onClose={onClose} onFetch={refetch} id={editId} />
       <TreeModal visible={roleVisible} onClose={onRoleClose} onFetch={refetch} id={roleId} />
+      <PdaMenuModal visible={pdaVisible} onClose={onPdaClose} onFetch={refetch} id={pdaId} />
     </>
   );
 };

+ 25 - 0
packages/app/src/pages/role/table/pda-modal/Info.tsx

@@ -0,0 +1,25 @@
+import {FC} from 'react';
+import {useMenuList} from './hooks';
+import {Transfer} from 'antd';
+
+type Props = {
+  selected: string[],
+  onChange: (e: string[]) => void,
+};
+
+const Info: FC<Props> = function({selected, onChange}) {
+  const data = useMenuList();
+
+  return (
+    <Transfer
+      dataSource={data}
+      targetKeys={selected}
+      titles={['未选', '已选']}
+      rowKey={item => item.id}
+      render={item => item.name}
+      onChange={onChange}
+    />
+  );
+};
+
+export default Info;

+ 86 - 0
packages/app/src/pages/role/table/pda-modal/hooks.ts

@@ -0,0 +1,86 @@
+import {editRolePDAMenu, getAllPDAMenu, getRoleList} from '@apis';
+import {useContextSection, usePage} from '@hooks';
+import {RoleListData} from '@models';
+import {context, pageContext} from '@pages/role/context';
+import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
+import {message} from 'antd';
+import {FormEvent, useEffect, useState} from 'react';
+
+export function useMenuList() {
+  const {data} = useQuery(
+    [getAllPDAMenu.name],
+    async function() {
+      const data = await getAllPDAMenu();
+
+      if (data.msg === '200') {
+        if (!data.data.list.length) throw new Error('未获取到菜单信息');
+
+        return data.data.list;
+      }
+
+      throw new Error(data.errMsg);
+    },
+    {suspense: true},
+  );
+
+  return data;
+}
+
+export function useTransfer(id: string) {
+  const [selected, setSelected] = useState<string[]>([]);
+
+  function onChange(targetKeys: string[]) {
+    setSelected(targetKeys);
+  }
+
+  const client = useQueryClient();
+  const [{page, pageSize}] = usePage(pageContext);
+  const name = useContextSection(context, state => state[0].name);
+  useEffect(function() {
+    if (!id) return;
+
+    const data = client.getQueryData<RoleListData[]>(
+      [getRoleList.name, page, pageSize, name],
+    ) ?? [];
+    const temp = data.find(val => String(val.id) === id);
+    if (!temp) return;
+
+    temp.menuPda
+      ? setSelected(temp.menuPda.split(','))
+      : setSelected([]);
+  }, [client, id, name, page, pageSize]);
+
+  return [selected, onChange] as const;
+}
+
+function useEditMenu(refetch: () => void, close: () => void) {
+  return useMutation(
+    editRolePDAMenu,
+    {
+      onSuccess({msg}) {
+        if (msg === '200') {
+          refetch();
+          close();
+          message.success('设置成功');
+        }
+      },
+    },
+  );
+}
+
+export function useSubmit(
+  {id, onFetch, selected, onClose}:
+  {id: string, onFetch: () => void, selected: string[], onClose: () => void},
+) {
+  const {isLoading, mutate} = useEditMenu(onFetch, onClose);
+
+  function onSubmit(e: FormEvent) {
+    e.preventDefault();
+    mutate({
+      id,
+      menuPda: selected.join(','),
+    });
+  }
+
+  return [isLoading, onSubmit] as const;
+}

+ 42 - 0
packages/app/src/pages/role/table/pda-modal/index.tsx

@@ -0,0 +1,42 @@
+import {ErrorBoundary, Loading, Modal, ModalBtnGroup} from '@components';
+import {FC, Suspense} from 'react';
+import ReactModal from 'react-modal';
+import Info from './Info';
+import {useSubmit, useTransfer} from './hooks';
+
+const modalStyle: ReactModal.Styles = {
+  content: {width: '600px', height: '420px'},
+};
+
+type Props = {
+  id: string;
+  onClose: () => void;
+  onFetch: () => void;
+  visible: boolean;
+};
+
+const PdaMenuModal: FC<Props> = function({id, onClose, onFetch, visible}) {
+  const [selected, onChange] = useTransfer(id);
+  const [isLoading, onSubmit] = useSubmit({selected, id, onFetch, onClose});
+
+  return (
+    <Modal
+      title='PDA菜单权限'
+      visible={visible}
+      style={modalStyle}
+      hideBtnGroup
+      testId='role_pda_menu_modal'
+      onSubmit={onSubmit}
+      onClose={onClose}
+    >
+      <ErrorBoundary>
+        <Suspense fallback={<Loading tip='正在获取菜单' height='200px' />}>
+          <Info selected={selected} onChange={onChange} />
+          <ModalBtnGroup onClose={onClose} isLoading={isLoading} />
+        </Suspense>
+      </ErrorBoundary>
+    </Modal>
+  );
+};
+
+export default PdaMenuModal;