Browse Source

部门关联用户

CzRger 2 months ago
parent
commit
09f46c6783

+ 15 - 15
web/app/components/header/account-setting/dept-page/detail-modal/index.tsx

@@ -1,5 +1,5 @@
 'use client'
-import { useCallback, useEffect, useState } from 'react'
+import { useEffect, useState } from 'react'
 import { RiCloseLine } from '@remixicon/react'
 import s from './index.module.css'
 import cn from '@/utils/classnames'
@@ -16,42 +16,39 @@ const InviteModal = ({
   onSend,
 }: any) => {
   const [name, setName] = useState<string>(transfer.row?.dept_name || '')
-  const [parent, setParent] = useState<string>(transfer.row?.parent_id || '')
+  const [parent, setParent] = useState<string>(transfer.row?.parent_dept_id || '')
+  console.log(transfer)
   const [options, setOptions] = useState<any>([])
   useEffect(() => {
     fetchDepts({
-      url: '/dept',
-      params: {
-        page: 1,
-        limit: 99999,
-      },
+      url: '/depts',
     }).then((res: any) => {
       setOptions(res.data || [])
     })
   }, [])
-  const handleSave = useCallback(async () => {
+  const handleSave = async () => {
     try {
       let res: any = () => {}
       if (transfer.mode === 'add') {
         res = await addDept({
           url: '/depts',
-          body: { dept_name: name, parent_id: parent },
+          body: { dept_name: name, parent_dept_id: parent },
         })
       }
       else {
         res = await editDept({
-          url: `/depts/${transfer.row.dept_id}`,
-          body: { dept_name: name, parent_id: parent },
+          url: '/depts',
+          body: { dept_name: name, parent_dept_id: parent, dept_id: transfer.row.dept_id },
         })
       }
-      const { id }: any = res
-      if (id) {
+      const { result }: any = res
+      if (result === 'success') {
         onCancel()
         onSend()
       }
     }
     catch (e) { }
-  }, [name, onCancel, onSend, transfer])
+  }
 
   return (
     <div className={cn(s.wrap)}>
@@ -73,7 +70,10 @@ const InviteModal = ({
               placeholder="请选择上级部门"
               allowClear
               treeDefaultExpandAll
-              onChange={v => setParent(v || '')}
+              onChange={(v) => {
+                console.log('dept', v)
+                setParent(v || '')
+              }}
               treeData={options}
               fieldNames={{ label: 'dept_name', value: 'dept_id' }}
             />

+ 5 - 49
web/app/components/header/account-setting/dept-page/index.tsx

@@ -9,7 +9,7 @@ import UserModal from './user-modal'
 import { useContext } from 'use-context-selector'
 import { RiAddLine } from '@remixicon/react'
 import { useTranslation } from 'react-i18next'
-import { delKnowledge, fetchDepts } from '@/service/common'
+import { delDept, fetchDepts } from '@/service/common'
 import I18n from '@/context/i18n'
 import { useAppContext } from '@/context/app-context'
 import LogoEmbeddedChatHeader from '@/app/components/base/logo/logo-embedded-chat-header'
@@ -32,7 +32,7 @@ const DeptsPage = () => {
   const { userProfile, currentWorkspace, isCurrentWorkspaceOwner, isCurrentWorkspaceManager, systemFeatures } = useAppContext()
   const { data, mutate }: any = useSWR(
     {
-      url: '/dept',
+      url: '/depts',
       params: {
       },
     },
@@ -48,13 +48,12 @@ const DeptsPage = () => {
   const { plan, enableBilling } = useProviderContext()
   const isNotUnlimitedMemberPlan = enableBilling && plan.type !== Plan.team && plan.type !== Plan.enterprise
   const isMemberFull = enableBilling && isNotUnlimitedMemberPlan && deptList.length >= plan.total.teamMembers
-
   const [showConfirmDelete, setShowConfirmDelete] = useState(false)
   const [row, setRow] = useState<any>({})
   const handleDel = async () => {
     try {
-      await delKnowledge({
-        url: `/external_applications/${row.id}`,
+      await delDept({
+        url: `/depts/${row.dept_id}`,
         body: {},
       })
       setShowConfirmDelete(false)
@@ -144,49 +143,6 @@ const DeptsPage = () => {
               </AntdSpace>
             )}/>
           </AntdTable>
-          {/* <div className='flex min-w-[480px] items-center border-b border-divider-regular py-[7px]'> */}
-          {/*  <div className='system-xs-medium-uppercase shrink-0 grow text-text-tertiary'>部门名称</div> */}
-          {/*  <div className='system-xs-medium-uppercase shrink-0 w-[200px] text-center text-text-tertiary'>关联用户数量</div> */}
-          {/*  <div className='system-xs-medium-uppercase w-[200px] shrink-0 px-3 text-center text-text-tertiary'>操作</div> */}
-          {/* </div> */}
-          {/* <div className='relative min-w-[480px]'> */}
-          {/*  { */}
-          {/*    deptList.map((dept: any) => ( */}
-          {/*      <div key={dept.id} className='flex justify-between border-b border-divider-subtle'> */}
-          {/*        <div className='system-sm-regular shrink-0 grow py-2 text-text-secondary'>{dept.name}</div> */}
-          {/*        <div className='system-sm-regular shrink-0 w-[200px] py-2 text-center text-text-secondary'>0</div> */}
-          {/*        <div className='flex w-[200px] shrink-0 items-center justify-center'> */}
-          {/*          <Button variant='ghost-accent' size='small' className={cn('shrink-0')} disabled={!isCurrentWorkspaceManager || isMemberFull} */}
-          {/*            onClick={() => { */}
-          {/*              setTransfer({ */}
-          {/*                mode: 'user', */}
-          {/*                row: JSON.parse(JSON.stringify(dept)), */}
-          {/*              }) */}
-          {/*              setUserModalVisible(true) */}
-          {/*            }}> */}
-          {/*            关联用户 */}
-          {/*          </Button> */}
-          {/*          <Button variant='ghost-accent' size='small' className={cn('shrink-0')} disabled={!isCurrentWorkspaceManager || isMemberFull} */}
-          {/*            onClick={() => { */}
-          {/*              setTransfer({ */}
-          {/*                mode: 'edit', */}
-          {/*                row: JSON.parse(JSON.stringify(dept)), */}
-          {/*              }) */}
-          {/*              setDetailModalVisible(true) */}
-          {/*            }}> */}
-          {/*            编辑 */}
-          {/*          </Button> */}
-          {/*          <Button variant='ghost' size='small' className={cn('shrink-0 text-red-600')} disabled={!isCurrentWorkspaceManager || isMemberFull} onClick={() => { */}
-          {/*            setRow(dept) */}
-          {/*            setShowConfirmDelete(true) */}
-          {/*          }}> */}
-          {/*            刪除 */}
-          {/*          </Button> */}
-          {/*        </div> */}
-          {/*      </div> */}
-          {/*    )) */}
-          {/*  } */}
-          {/* </div> */}
         </div>
       </div>
       {
@@ -215,7 +171,7 @@ const DeptsPage = () => {
       {showConfirmDelete && (
         <Confirm
           title="删除确认"
-          content={`请确认是否删除${row.name}?`}
+          content={`请确认是否删除${row.dept_name}?`}
           isShow={showConfirmDelete}
           onConfirm={handleDel}
           onCancel={() => setShowConfirmDelete(false)}

+ 92 - 120
web/app/components/header/account-setting/dept-page/user-modal.tsx

@@ -1,103 +1,72 @@
 'use client'
-import React, { useCallback, useEffect, useState } from 'react'
-import { RiAddLine, RiCloseLine, RiRefreshLine, RiSearchLine } from '@remixicon/react'
+import React, { useEffect, useState } from 'react'
+import { RiAddLine, RiCloseLine } from '@remixicon/react'
 import Modal from '@/app/components/base/modal'
 import Button from '@/app/components/base/button'
-import { delCorpus, fetchIntentType, fetchTypes } from '@/service/common'
+import { deptAddUsers, deptDelUsers, fetchIntent, fetchNoDeptUsers } from '@/service/common'
 import 'react-multi-email/dist/style.css'
-import Input from '@/app/components/base/input'
-import useSWR from 'swr'
 import cn from '@/utils/classnames'
 import Confirm from '@/app/components/base/confirm'
-import Pagination from '@/app/components/base/pagination'
-import { SimpleSelect } from '@/app/components/base/select'
+import { Select as AntdSelect } from 'antd'
 
-const TypeModal = ({
+const UserModal = ({
   onCancel,
   onSend,
+  transfer,
 }: any) => {
-  const [page, setPage] = React.useState<number>(0)
-  const [limit, setLimit] = useState<number>(10)
-  const [name, setName] = useState('')
-  const [query, setQuery] = useState<any>({})
-  const { data, mutate }: any = useSWR(
-    {
-      url: '/xxx',
-      params: {
-        page: page + 1,
-        limit,
-        ...query,
-      },
-    },
-    fetchIntentType,
-  )
-  const list: any = data?.data || []
-  const total = data?.total || 0
-  const handleSearch = (reset = false) => {
-    if (reset)
-      setIntentType('')
-
-    const params: any = {}
-    if (intentType)
-      params.intentType = intentType
-    setQuery(params)
-    setPage(0)
+  const [list, setList] = useState<any>([])
+  const [total, setTotal] = useState(0)
+  const handlePage = () => {
+    fetchIntent({
+      url: `/dept/dept-accounts/${transfer.row.dept_id}`,
+      params: {},
+    }).then((res: any) => {
+      setList(res.data)
+      setTotal(res.data.length)
+    })
   }
   useEffect(() => {
-    mutate()
-  }, [page, limit])
+    handlePage()
+  }, [])
   const [showConfirmDelete, setShowConfirmDelete] = useState(false)
   const [row, setRow] = useState<any>({})
   const handleDel = async () => {
     try {
-      await delCorpus({
-        url: `/tags/${row.id}`,
-        body: {},
+      const { result }: any = await deptDelUsers({
+        url: '/dept/dept-accounts',
+        body: { dept_id: transfer.row.dept_id, account_ids: [{ account_id: row.account_id }] },
       })
-      setShowConfirmDelete(false)
+      if (result === 'success') {
+        setShowConfirmDelete(false)
+        handlePage()
+      }
     }
     catch (e) { }
   }
   const [showDetail, setShowDetail] = useState(false)
-  const [mode, setMode] = useState<any>('add')
-  const [editIntentType, setEditIntentType] = useState('')
-  const [selectUser, setSelectUser] = useState<any>('')
+  const [selectUser, setSelectUser] = useState<any>([])
   const [userOptions, setUserOptions] = useState<any>([])
   useEffect(() => {
-    fetchTypes({
-      url: '/tags/page',
-      params: {
-        page: 1,
-        limit: 99999,
-        tag_type: 'knowledge_category',
-      },
+    fetchNoDeptUsers({
+      url: '/account/nodept',
+      params: {},
     }).then((res: any) => {
-      setUserOptions(res.data.map((v: any) => ({ name: v.name, value: v.id })) || [])
+      setUserOptions(res.data.map((v: any) => ({ label: v.email, value: v.account_id })) || [])
     })
   }, [])
-  const handleSave = useCallback(async () => {
-    // try {
-    //   let res
-    //   if (transfer.mode === 'add') {
-    //     res = await addCorpus({
-    //       url: '/xxx',
-    //       body: { name, type: 'knowledge_category' },
-    //     })
-    //   }
-    //   else {
-    //     res = await editCorpus({
-    //       url: '/xxx',
-    //       body: { name },
-    //     })
-    //   }
-    //   const { id }: any = res
-    //   if (id) {
-    //     onCancel()
-    //     onSend()
-    //   }
-    // }
-    // catch (e) { }
-  }, [mode, editIntentType, onCancel, onSend])
+  const handleSave = async () => {
+    try {
+      const { result }: any = await deptAddUsers({
+        url: '/dept/dept-accounts',
+        body: { dept_id: transfer.row.dept_id, account_ids: selectUser.map((v: any) => ({ account_id: v })) },
+      })
+      if (result === 'success') {
+        setShowDetail(false)
+        handlePage()
+      }
+    }
+    catch (e) { }
+  }
   return (
     <div>
       <Modal overflowVisible isShow onClose={() => { }} className="p-[24px 32px] w-[800px] max-w-[800px]">
@@ -106,36 +75,34 @@ const TypeModal = ({
           <RiCloseLine className='h-4 w-4 cursor-pointer text-text-tertiary' onClick={onCancel} />
         </div>
         <div className='flex h-[600px] flex-col'>
-          <div className="flex items-center gap-2">
-            <div className="flex shrink-0 items-center text-gray-500">
-              用户名称
-              <Input
-                className="ml-2"
-                showClearIcon
-                wrapperClassName='!w-[200px]'
-                value={name}
-                onChange={e => setName(e.target.value)}
-                onClear={() => setName('')}
-              />
-            </div>
-            <Button variant='primary' className={cn('ml-auto shrink-0')} onClick={() => {
-              handleSearch(false)
-            }}>
-              <RiSearchLine className='mr-1 h-4 w-4' />
-              搜索
-            </Button>
-            <Button variant='primary' className={cn('shrink-0')} onClick={() => {
-              handleSearch(true)
-            }}>
-              <RiRefreshLine className='mr-1 h-4 w-4' />
-              重置
-            </Button>
-          </div>
+          {/* <div className="flex items-center gap-2"> */}
+          {/*  <div className="flex shrink-0 items-center text-gray-500"> */}
+          {/*    用户名称 */}
+          {/*    <Input */}
+          {/*      className="ml-2" */}
+          {/*      showClearIcon */}
+          {/*      wrapperClassName='!w-[200px]' */}
+          {/*      value={name} */}
+          {/*      onChange={e => setName(e.target.value)} */}
+          {/*      onClear={() => setName('')} */}
+          {/*    /> */}
+          {/*  </div> */}
+          {/*  <Button variant='primary' className={cn('ml-auto shrink-0')} onClick={() => { */}
+          {/*    handleSearch(false) */}
+          {/*  }}> */}
+          {/*    <RiSearchLine className='mr-1 h-4 w-4' /> */}
+          {/*    搜索 */}
+          {/*  </Button> */}
+          {/*  <Button variant='primary' className={cn('shrink-0')} onClick={() => { */}
+          {/*    handleSearch(true) */}
+          {/*  }}> */}
+          {/*    <RiRefreshLine className='mr-1 h-4 w-4' /> */}
+          {/*    重置 */}
+          {/*  </Button> */}
+          {/* </div> */}
           <div className="mt-2">
             <Button variant='primary' className={cn('shrink-0')}
               onClick={() => {
-                setMode('add')
-                setEditIntentType('')
                 setShowDetail(true)
               }}>
               <RiAddLine className='mr-1 h-4 w-4' />
@@ -149,6 +116,7 @@ const TypeModal = ({
                   <thead className="h-8 border-b border-divider-subtle text-xs font-medium uppercase leading-8 text-text-tertiary">
                     <tr>
                       <td>用户名称</td>
+                      <td>用户账号</td>
                       <td className="w-[120px] text-center">操作</td>
                     </tr>
                   </thead>
@@ -159,6 +127,7 @@ const TypeModal = ({
                         className={'h-8 border-b border-divider-subtle hover:bg-background-default-hover'}
                       >
                         <td>{item.name}</td>
+                        <td>{item.email}</td>
                         <td className="flex justify-center gap-2">
                           <Button variant='ghost' size='small' className={cn('shrink-0 text-red-600')} onClick={() => {
                             setRow(item)
@@ -173,24 +142,24 @@ const TypeModal = ({
                 </table>
               </div>
               {/* Show Pagination only if the total is more than the limit */}
-              {total && (
-                <Pagination
-                  total={total}
-                  limit={limit}
-                  onLimitChange={setLimit}
-                  current={page}
-                  onChange={setPage}
-                  className='w-full shrink-0 px-0 pb-0'
-                />
-              )}
+              {/* {total && ( */}
+              {/*  <Pagination */}
+              {/*    total={total} */}
+              {/*    limit={limit} */}
+              {/*    onLimitChange={setLimit} */}
+              {/*    current={page} */}
+              {/*    onChange={setPage} */}
+              {/*    className='w-full shrink-0 px-0 pb-0' */}
+              {/*  /> */}
+              {/* )} */}
             </div>
           </div>
         </div>
       </Modal>
       {showConfirmDelete && (
         <Confirm
-          title="删除确认"
-          content={`请确认是否删除${row.name}?`}
+          title="取消确认"
+          content={`请确认是否取消关联${row.name}?`}
           isShow={showConfirmDelete}
           onConfirm={handleDel}
           onCancel={() => setShowConfirmDelete(false)}
@@ -209,11 +178,14 @@ const TypeModal = ({
                   选择用户
                 </div>
                 <div className='w-full'>
-                  <SimpleSelect
-                    defaultValue={selectUser}
-                    onSelect={(i) => { setSelectUser(i.value) }}
-                    items={userOptions}
-                    allowSearch={false}
+                  <AntdSelect
+                    className="w-full"
+                    mode="multiple"
+                    showSearch
+                    placeholder="请选择用户"
+                    optionFilterProp="label"
+                    onChange={v => setSelectUser(v)}
+                    options={userOptions}
                   />
                 </div>
               </div>
@@ -221,7 +193,7 @@ const TypeModal = ({
                 tabIndex={0}
                 className='w-full'
                 onClick={handleSave}
-                disabled={!editIntentType.length}
+                disabled={!selectUser.length}
                 variant='primary'
               >
                 保存
@@ -234,4 +206,4 @@ const TypeModal = ({
   )
 }
 
-export default TypeModal
+export default UserModal

+ 1 - 0
web/app/components/header/account-setting/members-page/index.tsx

@@ -33,6 +33,7 @@ const MembersPage = () => {
     editor: t('common.members.editor'),
     dataset_operator: t('common.members.datasetOperator'),
     normal: t('common.members.normal'),
+    leader: t('common.members.leader'),
   }
   const { locale } = useContext(I18n)
 

+ 3 - 2
web/app/components/header/account-setting/members-page/operation/index.tsx

@@ -29,17 +29,18 @@ const Operation = ({
     editor: t('common.members.editor'),
     normal: t('common.members.normal'),
     dataset_operator: t('common.members.datasetOperator'),
+    leader: t('common.members.leader'),
   }
   const roleList = useMemo(() => {
     if (operatorRole === 'owner') {
       return [
-        ...['admin', 'editor', 'normal'],
+        ...['admin', 'leader', 'editor', 'normal'],
         ...(datasetOperatorEnabled ? ['dataset_operator'] : []),
       ]
     }
     if (operatorRole === 'admin') {
       return [
-        ...['editor', 'normal'],
+        ...['leader', 'editor', 'normal'],
         ...(datasetOperatorEnabled ? ['dataset_operator'] : []),
       ]
     }

+ 32 - 10
web/app/components/header/index.tsx

@@ -1,5 +1,5 @@
 'use client'
-import { useCallback, useEffect } from 'react'
+import { useCallback, useEffect, useState } from 'react'
 import Link from 'next/link'
 import { useBoolean } from 'ahooks'
 import { useSelectedLayoutSegment } from 'next/navigation'
@@ -11,10 +11,8 @@ import EnvNav from './env-nav'
 import PluginsNav from './plugins-nav'
 import ExploreNav from './explore-nav'
 import ToolsNav from './tools-nav'
-import { WorkspaceProvider } from '@/context/workspace-context'
 import { useAppContext } from '@/context/app-context'
 import LogoSite from '@/app/components/base/logo/logo-site'
-import WorkplaceSelector from '@/app/components/header/account-dropdown/workplace-selector'
 import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
 import { useProviderContext } from '@/context/provider-context'
 import { useModalContext } from '@/context/modal-context'
@@ -22,6 +20,7 @@ import PlanBadge from './plan-badge'
 import LicenseNav from './license-env'
 import { Plan } from '../billing/type'
 import SkillNav from './skill-nav'
+import { fetchDepts } from '@/service/common'
 
 const navClassName = `
   flex items-center relative mr-0 sm:mr-3 px-3 h-8 rounded-xl
@@ -30,7 +29,7 @@ const navClassName = `
 `
 
 const Header = () => {
-  const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator } = useAppContext()
+  const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator, userProfile } = useAppContext()
   const selectedSegment = useSelectedLayoutSegment()
   const media = useBreakpoints()
   const isMobile = media === MediaType.mobile
@@ -49,6 +48,28 @@ const Header = () => {
     hideNavMenu()
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [selectedSegment])
+  const [deptMap, setDeptMap] = useState<any>(new Map())
+  const addDeptMap = (key: any, value: any) => {
+    setDeptMap((prevMap: any) => {
+      const newMap = new Map(prevMap)
+      newMap.set(key, value)
+      return newMap
+    })
+  }
+  const formatDept = (depts: any) => {
+    depts.forEach((v: any) => {
+      addDeptMap(v.dept_id, v.dept_name)
+      if (v.children?.length > 0)
+        formatDept(v.children)
+    })
+  }
+  useEffect(() => {
+    fetchDepts({
+      url: '/depts',
+    }).then((res: any) => {
+      formatDept(res.data || [])
+    })
+  }, [])
   return (
     <div className='flex flex-1 items-center justify-between bg-background-body px-4'>
       <div className='flex items-center'>
@@ -65,12 +86,13 @@ const Header = () => {
               <LogoSite className='object-contain' />
             </Link>
             <div className='font-light text-divider-deep'>/</div>
-            <div className='flex items-center gap-0.5'>
-              <WorkspaceProvider>
-                <WorkplaceSelector />
-              </WorkspaceProvider>
-              {enableBilling ? <PlanBadge allowHover sandboxAsUpgrade plan={plan.type} onClick={handlePlanClick} /> : <LicenseNav />}
-            </div>
+            {/* <div className='flex items-center gap-0.5'> */}
+            {/*  <WorkspaceProvider> */}
+            {/*    <WorkplaceSelector /> */}
+            {/*  </WorkspaceProvider> */}
+            {/*  {enableBilling ? <PlanBadge allowHover sandboxAsUpgrade plan={plan.type} onClick={handlePlanClick} /> : <LicenseNav />} */}
+            {/* </div> */}
+            <div className="text-gray-500">{deptMap.get(userProfile.dept_id) || userProfile.dept_id}</div>
           </div>
         }
       </div >

+ 2 - 0
web/i18n/zh-Hans/common.ts

@@ -230,6 +230,8 @@ const translation = {
     owner: '所有者',
     admin: '管理员',
     adminTip: '能够建立应用程序和管理团队设置',
+    leader: '部门领导',
+    leaderTip: '能够对部门内数据进行管理',
     normal: '成员',
     normalTip: '只能使用应用程序,不能建立应用程序',
     editor: '编辑',

+ 1 - 0
web/models/common.ts

@@ -31,6 +31,7 @@ export type UserProfileResponse = {
   last_active_at?: string
   last_login_ip?: string
   created_at?: string
+  dept_id?: string
 }
 
 export type UserProfileOriginResponse = {

+ 22 - 33
web/service/common.ts

@@ -588,39 +588,28 @@ export const editDept = ({ url, body }: any) => {
   console.log('编辑部门', url, body)
   return post(url, { body })
 }
+
+export const delDept = ({ url, body }: any) => {
+  console.log('删除部门', url, body)
+  return del(url, { body })
+}
+
 export const fetchDeptUsers = ({ url, params }: any) => {
   console.log('查询部门用户列表', params, url)
-  // return get(url, { params })
-  return new Promise((resolve) => {
-    setTimeout(() => {
-      const arr: any = []
-      for (let i = 1; i < 3; i++) {
-        const dept1: any = {
-          id: `${i}`,
-          name: `部门_${i}`,
-          children: [],
-        }
-        for (let j = 1; j < 4; j++) {
-          const dept2: any = {
-            id: `${i}_${j}`,
-            name: `部门_${i}-${j}`,
-            children: [],
-          }
-          for (let k = 1; k < 5; k++) {
-            const dept3: any = {
-              id: `${i}_${j}_${k}`,
-              name: `用户_${i}-${j}-${k}`,
-              relation: k % 2,
-            }
-            dept2.children.push(dept3)
-          }
-          dept1.children.push(dept2)
-        }
-        arr.push(dept1)
-      }
-      resolve({
-        data: arr,
-      })
-    }, 1000)
-  })
+  return get(url, { params })
+}
+
+export const fetchNoDeptUsers = ({ url, params }: any) => {
+  console.log('查询未绑定部门用户列表', params, url)
+  return get(url, { params })
+}
+
+export const deptAddUsers = ({ url, body }: any) => {
+  console.log('部门关联用户', url, body)
+  return post(url, { body })
+}
+
+export const deptDelUsers = ({ url, body }: any) => {
+  console.log('部门删除用户', url, body)
+  return del(url, { body })
 }