index.tsx 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { useIntl } from '@umijs/max';
  2. import { Checkbox, Input, Tabs } from 'antd';
  3. import { useMemo, useState } from 'react';
  4. import { TabContent } from './components/TabContent';
  5. import { usePermTree } from './hooks/usePermTree';
  6. export interface PermTreeProps {
  7. mode: 'view' | 'edit';
  8. allPerms: API.PermItem[];
  9. checkedPermIds?: number[];
  10. onChange?: (ids: number[]) => void;
  11. }
  12. const TAB_KEYS = ['api', 'data'] as const;
  13. export const PermTree = ({ mode, allPerms, checkedPermIds = [], onChange }: PermTreeProps) => {
  14. const intl = useIntl();
  15. const {
  16. keyword,
  17. setKeyword,
  18. checkedIds,
  19. grouped: allGroups,
  20. filteredGroups,
  21. toggle,
  22. selectAll,
  23. invert,
  24. isAllSelected,
  25. isIndeterminate,
  26. } = usePermTree({ allPerms, initialCheckedIds: checkedPermIds, onChange });
  27. const [activeTab, setActiveTab] = useState<'api' | 'data'>('api');
  28. const tabItems = useMemo(
  29. () =>
  30. TAB_KEYS.map((key) => ({
  31. key,
  32. label: intl.formatMessage({ id: `admin.permTree.${key}Tab` }),
  33. children: (
  34. <TabContent
  35. tab={key}
  36. filteredGroups={filteredGroups}
  37. allGroups={allGroups}
  38. checkedIds={checkedIds}
  39. mode={mode}
  40. onToggle={toggle}
  41. />
  42. ),
  43. })),
  44. [intl, filteredGroups, allGroups, checkedIds, mode, toggle],
  45. );
  46. return (
  47. <div className="flex flex-col gap-2">
  48. {mode === 'edit' && (
  49. <div className="flex items-center gap-2">
  50. <Input.Search
  51. placeholder={intl.formatMessage({ id: 'admin.permTree.search' })}
  52. value={keyword}
  53. onChange={(e) => setKeyword(e.target.value)}
  54. allowClear
  55. className="flex-1"
  56. />
  57. <Checkbox
  58. checked={isAllSelected(activeTab)}
  59. indeterminate={isIndeterminate(activeTab)}
  60. onChange={() => selectAll(activeTab)}
  61. >
  62. {intl.formatMessage({ id: 'admin.permTree.selectAll' })}
  63. </Checkbox>
  64. <a onClick={() => invert(activeTab)} className="text-sm whitespace-nowrap">
  65. {intl.formatMessage({ id: 'admin.permTree.invert' })}
  66. </a>
  67. </div>
  68. )}
  69. <Tabs
  70. activeKey={activeTab}
  71. onChange={(k) => setActiveTab(k as 'api' | 'data')}
  72. items={tabItems}
  73. />
  74. </div>
  75. );
  76. };