wjx 2 tuần trước cách đây
mục cha
commit
ef4ff035ff

+ 96 - 0
src/pages/weComTask/API/groupManage/index.ts

@@ -0,0 +1,96 @@
+import request from "@/utils/request";
+const { api } = process.env.CONFIG;
+
+export interface GetProjectGroupsListProps {
+    pageNum: number,
+    pageSize: number,
+    createTimeEnd?: string,
+    createTimeStart?: string,
+    name?: string
+}
+
+/**
+ * 项目组列表
+ * @param data 
+ * @returns 
+ */
+export function getProjectGroupsListApi(data: GetProjectGroupsListProps) {
+    return request({
+        url: api + `/corpOperation/projectGroups/list`,
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 全部项目组列表
+ * @returns 
+ */
+export function getProjectGroupsAllListApi() {
+    return request({
+        url: api + `/corpOperation/projectGroups/listAll`,
+        method: 'POST'
+    })
+}
+
+export interface AddProjectGroupsProps {
+    name: string,
+    description?: string
+    groupId?: number
+}
+
+/**
+ * 新增项目组
+ * @param data 
+ * @returns 
+ */
+export function addProjectGroupsApi(data: AddProjectGroupsProps) {
+    return request({
+        url: api + `/corpOperation/projectGroups/create`,
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 修改项目组
+ * @param param0 
+ * @returns 
+ */
+export function editProjectGroupsApi({ groupId, ...data }: AddProjectGroupsProps) {
+    return request({
+        url: api + `/corpOperation/projectGroups/edit/${groupId}`,
+        method: 'POST',
+        data
+    })
+}
+
+
+/**
+ * 删除项目组
+ * @param param0 
+ * @returns 
+ */
+export function delProjectGroupsApi(groupId: number) {
+    return request({
+        url: api + `/corpOperation/projectGroups/deleteGroup/${groupId}`,
+        method: 'DELETE'
+    })
+}
+
+export interface UpdateMembersProps {
+    groupId: number,
+    userIds: number[]
+}
+/**
+ * 更新成员
+ * @param param0 
+ * @returns 
+ */
+export function updateMembersApi({ groupId, userIds }: UpdateMembersProps) {
+    return request({
+        url: api + `/corpOperation/projectGroups/updateMembers/${groupId}`,
+        method: 'POST',
+        data: userIds
+    })
+}

+ 5 - 5
src/pages/weComTask/page/businessPlan/create/index.tsx

@@ -60,7 +60,7 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
                 setProjectId(id)
             }
             getCreateDetails.run(id).then(res => {
-                // sessionStorage.removeItem('OFFICIALTASKID')
+                sessionStorage.removeItem('OFFICIALTASKID')
                 if (res?.data) {
                     const { corpUsers, bizType, platform, templateProductId, welcomeMsgTemplateDTO, groupSendTaskAddDTO, externalUserTransferTasksDTO } = res.data
                     let newSettings: TASK_CREATE.SettingsProps = {
@@ -69,8 +69,8 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
                         templateProductId,
                         corpUserGroups: corpUsers.map(item => {
                             return {
-                                corpUsers: item.corpUserList.map(({ corpUserId, name, corpId, mpAccountId, mpAccountInfo }) => {
-                                    return { corpUserId, name, corpName: item.corpName, corpId, mpAccountId, mpAccountName: mpAccountInfo?.name }
+                                corpUsers: item.corpUserList.map(({ corpUserId, name, corpId, mpAccountId, mpAccountInfo, id }) => {
+                                    return { id: id || (corpId + '_' + corpUserId), corpUserId, name, corpName: item.corpName, corpId, mpAccountId, mpAccountName: mpAccountInfo?.name }
                                 })
                             }
                         }),
@@ -582,8 +582,8 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
                                     ...settings, corpUserGroups: corpUserGroups.map(item => {
                                         return {
                                             ...item, corpUsers: item.corpUsers.map((item: any) => {
-                                                const { corpUserId, name, corpName, corpId, mpAccountId, mpAccountInfo } = item
-                                                return { corpUserId, name, corpName, corpId, mpAccountId, mpAccountName: mpAccountInfo?.name }
+                                                const { corpUserId, name, corpName, corpId, mpAccountId, mpAccountInfo, id } = item
+                                                return { corpUserId, name, corpName, corpId, mpAccountId, mpAccountName: mpAccountInfo?.name, id }
                                             })
                                         }
                                     })

+ 24 - 2
src/pages/weComTask/page/businessPlan/create/submitModal.tsx

@@ -1,7 +1,9 @@
-import { Form, Input, message, Modal } from "antd"
-import React from "react"
+import { Form, Input, message, Modal, Select } from "antd"
+import React, { useEffect, useState } from "react"
 import dayjs from "dayjs"
 import { randomString } from "@/utils/utils"
+import { useAjax } from "@/Hook/useAjax"
+import { getProjectGroupsAllListApi } from "@/pages/weComTask/API/groupManage"
 
 /**
  * 设置名称
@@ -19,8 +21,17 @@ const SubmitModal: React.FC<Props> = (props) => {
     /********************/
     const { visible, onClose, onChange, loading, projectName } = props
     const [form] = Form.useForm()
+    const [groupList, setGroupList] = useState<{ label: string, value: number }[]>([])
+
+    const getProjectGroupsAllList = useAjax(() => getProjectGroupsAllListApi())
     /********************/
 
+    useEffect(() => {
+        getProjectGroupsAllList.run().then(res => {
+            setGroupList(res?.data?.map(item => ({ label: item.name, value: item.id })) || [])
+        })
+    }, [])
+
     const handleOk = () => {
         form.validateFields().then((values) => {
             const params = JSON.parse(JSON.stringify(values))
@@ -60,6 +71,17 @@ const SubmitModal: React.FC<Props> = (props) => {
             <Form.Item label={<strong>任务名称</strong>} name="projectName" rules={[{ required: true, message: '请输入任务名称!' }]}>
                 <Input placeholder="请输入任务名称" />
             </Form.Item>
+            <Form.Item label={<strong>项目组</strong>} name="projectGroupId">
+                <Select
+                    placeholder='请选择项目组'
+                    allowClear
+                    options={groupList}
+                    showSearch
+                    filterOption={(input, option) =>
+                        (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
+                    }
+                />
+            </Form.Item>
         </Form>
     </Modal>
 }

+ 1 - 1
src/pages/weComTask/page/businessPlan/create/typings.d.ts

@@ -71,7 +71,7 @@ declare namespace TASK_CREATE {
         friendsTagContent?: any[],
         friendsMsgContent?: any[],
     }
-    type CorpUserProps = { corpUserId: string, name: string, corpName: string, corpId: string, mpAccountId?: number, mpAccountName?: string }
+    type CorpUserProps = { corpUserId: string, name: string, corpName: string, corpId: string, id: string, mpAccountId?: number, mpAccountName?: string }
     type CorpUserGroupProps = { 
         corpUsers: CorpUserProps[],
         welcomeMsgContent?: any[],

+ 11 - 11
src/pages/weComTask/page/corpUserManage/selectCorpUserGroupModal.tsx

@@ -191,7 +191,7 @@ const SelectCorpUserGroupModal: React.FC<Props> = ({ visible, onClose, value, on
                     dataSource={getCorpUser?.data?.data?.records}
                     size='small'
                     scroll={{ y: 300 }}
-                    rowKey={'corpUserId'}
+                    rowKey={'id'}
                     loading={getCorpUser.loading}
                     pagination={{
                         current: getCorpUser?.data?.data?.current || 1,
@@ -202,23 +202,23 @@ const SelectCorpUserGroupModal: React.FC<Props> = ({ visible, onClose, value, on
                     }}
                     rowSelection={{
                         type: 'checkbox',
-                        selectedRowKeys: data?.[selectAdz - 1]?.corpUsers?.map(item => item.corpUserId),
+                        selectedRowKeys: data?.[selectAdz - 1]?.corpUsers?.map(item => item.id),
                         getCheckboxProps: (record: any) => ({
-                            disabled: data.filter((_, i) => i !== selectAdz - 1)?.map(item => item.corpUsers).flat(1)?.map(item => item.corpUserId).includes(record.corpUserId) ||
+                            disabled: data.filter((_, i) => i !== selectAdz - 1)?.map(item => item.corpUsers).flat(1)?.map(item => item.id).includes(record.id) ||
                                 (data?.[selectAdz - 1]?.corpUsers?.length > 0 ? data?.[selectAdz - 1]?.corpUsers?.[0]?.corpId !== record.corpId || (data?.[selectAdz - 1]?.corpUsers?.[0]?.mpAccountId ? data?.[selectAdz - 1]?.corpUsers?.[0]?.mpAccountId !== record.mpAccountId : record.mpAccountId) : false)
                         }),
-                        onSelect: (record: { corpUserId: string }, selected: boolean) => {
+                        onSelect: (record: { id: string }, selected: boolean) => {
                             const newData = JSON.parse(JSON.stringify(data))
                             let dataIten = newData[selectAdz - 1]?.corpUsers || []
                             if (selected) {
                                 dataIten.push({ ...record })
                             } else {
-                                dataIten = dataIten.filter((item: { corpUserId: string }) => item.corpUserId !== record.corpUserId)
+                                dataIten = dataIten.filter((item: { id: string }) => item.id !== record.id)
                             }
                             newData[selectAdz - 1].corpUsers = dataIten
                             setData(newData)
                         },
-                        onSelectAll: (selected: boolean, _, changeRows: { corpUserId: string, corpId: string, mpAccountId?: string }[]) => {
+                        onSelectAll: (selected: boolean, _, changeRows: { id: string, corpId: string, mpAccountId?: string }[]) => {
                             const newData = JSON.parse(JSON.stringify(data))
                             const dataIten = newData[selectAdz - 1]?.corpUsers || []
                             if (selected) {
@@ -227,9 +227,9 @@ const SelectCorpUserGroupModal: React.FC<Props> = ({ visible, onClose, value, on
                                     const { mpAccountId, corpId } = changeRows[0]
                                     changeRows = changeRows.filter(item => item.corpId === corpId && item?.mpAccountId === mpAccountId)
                                 }
-                                changeRows.forEach((item: { corpUserId: string }) => {
-                                    const index = newSelectAccData.findIndex((ite: { corpUserId: string }) => {
-                                        return ite.corpUserId === item.corpUserId
+                                changeRows.forEach((item: { id: string }) => {
+                                    const index = newSelectAccData.findIndex((ite: { id: string }) => {
+                                        return ite.id === item.id
                                     })
                                     if (index === -1) {
                                         const data: any = { ...item }
@@ -238,8 +238,8 @@ const SelectCorpUserGroupModal: React.FC<Props> = ({ visible, onClose, value, on
                                 })
                                 newData[selectAdz - 1].corpUsers = newSelectAccData
                             } else {
-                                const newSelectAccData = dataIten.filter((item: { corpUserId: string }) => {
-                                    const index = changeRows.findIndex((ite: { corpUserId: string }) => ite.corpUserId === item.corpUserId)
+                                const newSelectAccData = dataIten.filter((item: { id: string }) => {
+                                    const index = changeRows.findIndex((ite: { id: string }) => ite.id === item.id)
                                     if (index !== -1) {
                                         return false
                                     } else {

+ 2 - 0
src/pages/weComTask/page/groupChat/create/index.tsx

@@ -222,6 +222,7 @@ const GroupChatCreate: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREAT
         const { bizType, platform, templateProductId, corpUsers, corpUserChat, robotCorpUsers, strategyDTO } = settings
         console.log('--->', values)
         const params: { [x: string]: any } = {
+            ...values,
             taskName: values.projectName,
             bizType,
             platform,
@@ -264,6 +265,7 @@ const GroupChatCreate: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREAT
                 }
             })
         }
+        delete params?.projectName
         console.log('提交参数--->', params)
         if (projectId) {
             params.projectId = projectId

+ 1 - 1
src/pages/weComTask/page/groupChatSend/official/create/index.tsx

@@ -333,7 +333,7 @@ const OfficialCreate: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE
                     groupChatMsgContent[strategyIndex][sendIndex][contentIndex] = previewContent?.[id] || {};
                 })
                 return {
-                    mpAccountId: item?.mpAccount.value,
+                    mpAccountId: item?.mpAccount?.value,
                     corpIds: item.corp?.map(c => c.value) || [],
                     groupChatMsgContent
                 }

+ 1 - 1
src/pages/weComTask/page/groupLeaderManage/index.tsx

@@ -57,7 +57,7 @@ const GroupLeaderManage: React.FC = () => {
     }
 
     return <Card
-        styles={{ body: { padding: 0, display: 'flex', flexDirection: 'column', height: 'calc(100vh - 74px)', overflow: 'hidden' } }}
+        styles={{ body: { padding: 0, display: 'flex', flexDirection: 'column', height: 'calc(100vh - 88px)', overflow: 'hidden' } }}
     >
         <div>
             <SearchBox

+ 0 - 2
src/pages/weComTask/page/groupLeaderManage/tableConfig.tsx

@@ -1,6 +1,4 @@
-import { copy } from "@/utils/utils"
 import { ColumnsType } from "antd/es/table"
-import { Button, Flex, Popconfirm, Popover, Tag } from "antd"
 import BindDetails from "./bindDetails"
 import { STATUSENUM } from "."
 

+ 81 - 0
src/pages/weComTask/page/groupManage/groupModal.tsx

@@ -0,0 +1,81 @@
+import { App, Form, Input, Modal } from 'antd';
+import React from 'react';
+import { useAjax } from '@/Hook/useAjax';
+import { addProjectGroupsApi, editProjectGroupsApi } from '../../API/groupManage';
+
+interface GroupModalProps {
+    initialValues?: any
+    visible?: boolean
+    onChange?: () => void
+    onClose?: () => void
+}
+
+
+const GroupModal: React.FC<GroupModalProps> = ({ initialValues, visible, onChange, onClose }) => {
+
+    /****************************************/
+    const { message } = App.useApp()
+    const [form] = Form.useForm();
+    const addProjectGroups = useAjax((params) => addProjectGroupsApi(params))
+    const editProjectGroups = useAjax((params) => editProjectGroupsApi(params))
+    /****************************************/
+
+    const handleOk = () => {
+        form.validateFields().then((values) => {
+            if (initialValues?.id) {
+                editProjectGroups.run({ ...values, groupId: initialValues.id }).then((res) => {
+                    if (res?.data) {
+                        message.success('修改成功')
+                        onChange?.()
+                    }
+                })
+            } else {
+                addProjectGroups.run(values).then((res) => {
+                    if (res?.data) {
+                        message.success('添加成功')
+                        onChange?.()
+                    }
+                })
+            }
+
+        }).catch((err) => {
+            console.log('err', err)
+            form.submit()
+        });
+    }
+
+    return <Modal
+        title={<strong>{initialValues?.id ? '修改' : '新增'}新增项目组</strong>}
+        open={visible}
+        onCancel={onClose}
+        width={500}
+        onOk={handleOk}
+        confirmLoading={addProjectGroups.loading}
+    >
+        <Form
+            form={form}
+            name="newGRoup"
+            labelAlign='left'
+            labelCol={{ span: 5 }}
+            colon={false}
+            scrollToFirstError={{
+                behavior: 'smooth',
+                block: 'center'
+            }}
+            onFinishFailed={({ errorFields }) => {
+                message.error(errorFields?.[0]?.errors?.[0])
+            }}
+            preserve={true}
+            initialValues={initialValues}
+        >
+            <Form.Item label={<strong>项目组名称</strong>} name="name" rules={[{ required: true, message: '请输入项目组名称!' }]}>
+                <Input placeholder='请输入项目组名称' allowClear />
+            </Form.Item>
+            <Form.Item label={<strong>描述</strong>} name="description">
+                <Input.TextArea placeholder='请输入项目组描述' allowClear />
+            </Form.Item>
+        </Form>
+    </Modal>
+};
+
+export default React.memo(GroupModal);

+ 130 - 0
src/pages/weComTask/page/groupManage/index.tsx

@@ -0,0 +1,130 @@
+import { useSize } from 'ahooks';
+import { App, Button, Card, DatePicker, Input, Pagination, Table } from 'antd';
+import React, { useEffect, useRef, useState } from 'react';
+import SearchBox from '../../components/searchBox';
+import { SearchOutlined, PlusOutlined } from '@ant-design/icons';
+import { delProjectGroupsApi, getProjectGroupsListApi, GetProjectGroupsListProps } from '../../API/groupManage';
+import { useAjax } from '@/Hook/useAjax';
+import GroupModal from './groupModal';
+import style from '../bookLink/index.less'
+import { GroupTableConfig } from './tableConfig';
+import UpdateUser from './updateUser';
+
+const GroupManage: React.FC = () => {
+
+    /*******************************************/
+    const { message } = App.useApp();
+    const ref = useRef<HTMLDivElement>(null)
+    const size = useSize(ref)
+
+    const [queryParams, setQueryParams] = useState<GetProjectGroupsListProps>({ pageNum: 1, pageSize: 20 })
+    const [queryParamsNew, setQueryParamsNew] = useState<GetProjectGroupsListProps>({ pageNum: 1, pageSize: 20 })
+    const [visible, setVisible] = useState<boolean>(false)
+    const [initialValues, setInitialValues] = useState<any>()
+    const [userData, setUserData] = useState<{ data: any, visible: boolean }>({ data: undefined, visible: false })
+
+    const getProjectGroupsList = useAjax((params) => getProjectGroupsListApi(params))
+    const delProjectGroups = useAjax((params) => delProjectGroupsApi(params))
+    /*******************************************/
+
+    useEffect(() => {
+        getProjectGroupsList.run(queryParamsNew)
+    }, [queryParamsNew])
+
+    const handleUser = (data: any) => {
+        setUserData({ data, visible: true })
+    }
+
+    const handleEdit = (data: any) => {
+        setInitialValues(data)
+        setVisible(true)
+    }
+
+    const handleDel = (groupId: number) => {
+        delProjectGroups.run(groupId).then(res => {
+            getProjectGroupsList.refresh()
+            message.success('删除成功')
+        })
+    }
+
+    return <Card
+        styles={{ body: { padding: 0, display: 'flex', flexDirection: 'column', height: 'calc(100vh - 88px)', overflow: 'hidden' } }}
+    >
+        <div>
+            <SearchBox
+                bodyPadding={`10px 16px 4px`}
+                buttons={<>
+                    <Button type="primary" onClick={() => {
+                        setQueryParamsNew({ ...queryParams, pageNum: 1 })
+                    }} loading={getProjectGroupsList.loading} icon={<SearchOutlined />}>搜索</Button>
+                    <Button type="primary" icon={<PlusOutlined />} onClick={() => setVisible(true)}>新增项目组</Button>
+                </>}
+            >
+                <>
+                    <Input onChange={(e) => setQueryParams({ ...queryParams, name: e.target.value as any })} value={queryParams?.name} placeholder="项目组名称" allowClear />
+                    <DatePicker.RangePicker placeholder={['开始时间创建', '结束时间创建']} onChange={(date, dateString) => setQueryParams({ ...queryParams, createTimeStart: dateString[0], createTimeEnd: dateString[1] })} />
+                </>
+            </SearchBox>
+        </div>
+
+        <div className={style.bookLinkTable} ref={ref}>
+            <Table
+                dataSource={getProjectGroupsList?.data?.data?.records}
+                columns={GroupTableConfig(handleUser, handleEdit, handleDel)}
+                bordered
+                className='resetTable'
+                pagination={false}
+                rowKey={'id'}
+                size='small'
+                loading={getProjectGroupsList?.loading}
+                scroll={{ y: size?.height && ref.current ? size?.height - ref.current.querySelector('.ant-table-thead').clientHeight : 300 }}
+            />
+        </div>
+        <div className={style.bookLinkPagination}>
+            <Pagination
+                size="small"
+                total={getProjectGroupsList?.data?.data?.total || 0}
+                showSizeChanger
+                showQuickJumper
+                pageSize={getProjectGroupsList?.data?.data?.size || 20}
+                current={getProjectGroupsList?.data?.data?.current || 1}
+                onChange={(page: number, pageSize: number) => {
+                    setTimeout(() => {
+                        setQueryParams({ ...queryParams, pageNum: page, pageSize })
+                        setQueryParamsNew({ ...queryParamsNew, pageNum: page, pageSize })
+                    }, 50)
+                }}
+                showTotal={(total: number) => <span style={{ fontSize: 12 }}>共 {total} 条</span>}
+            />
+        </div>
+
+        {/* 新增项目组 */}
+        {visible && <GroupModal
+            visible={visible}
+            initialValues={initialValues}
+            onChange={() => {
+                setVisible(false)
+                setInitialValues(undefined)
+                getProjectGroupsList.refresh()
+            }}
+            onClose={() => {
+                setInitialValues(undefined)
+                setVisible(false)
+            }}
+        />}
+
+        {/* 修改用户 */}
+        {userData?.visible && <UpdateUser
+            {...userData}
+            onClose={() => {
+                setUserData({ data: undefined, visible: false })
+            }}
+            onChange={() => {
+                setUserData({ data: undefined, visible: false })
+                getProjectGroupsList.refresh()
+            }}
+        />}
+    </Card>
+};
+
+export default GroupManage;

+ 77 - 0
src/pages/weComTask/page/groupManage/tableConfig.tsx

@@ -0,0 +1,77 @@
+import { Popconfirm, Space } from "antd"
+import { ColumnsType } from "antd/es/table"
+
+
+export function GroupTableConfig(handleUser: (data: any) => void, handleEdit: (data: any) => void, handleDel: (id: number) => void): ColumnsType<any> {
+
+    const arr: ColumnsType<any> = [
+        {
+            title: '项目组名称',
+            dataIndex: 'name',
+            key: 'name',
+            width: 150,
+            ellipsis: true,
+            fixed: 'left'
+        },
+        {
+            title: '项目组成员',
+            dataIndex: 'userList',
+            key: 'userList',
+            width: 400,
+            ellipsis: true,
+            render(value) {
+                return value?.length > 0 ? value.map((item: any) => item.nickname).join(',') : '--'
+            }
+        },
+        {
+            title: '描述',
+            dataIndex: 'description',
+            key: 'description',
+            width: 220,
+            ellipsis: true,
+            render(value) {
+                return value || '--'
+            },
+        },
+        {
+            title: '创建人',
+            dataIndex: 'createByInfo',
+            key: 'createByInfo',
+            width: 100,
+            ellipsis: true,
+            align: 'center',
+            render(value) {
+                return value?.nickname || '--'
+            },
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            key: 'createTime',
+            width: 135,
+            ellipsis: true,
+            align: 'center'
+        },
+        {
+            title: '操作',
+            dataIndex: 'cz',
+            key: 'cz',
+            align: 'center',
+            width: 130,
+            fixed: 'right',
+            render(_, record) {
+                return <Space>
+                    <a onClick={() => handleUser(record)}>成员更新</a>
+                    <a onClick={() => handleEdit(record)}>修改</a>
+                    <Popconfirm
+                        title="确认删除?"
+                        onConfirm={() => handleDel(record.id)}
+                    >
+                        <a style={{ color: 'red' }}>删除</a>
+                    </Popconfirm>
+                </Space>
+            },
+        }
+    ]
+    return arr
+}

+ 94 - 0
src/pages/weComTask/page/groupManage/updateUser.tsx

@@ -0,0 +1,94 @@
+import { App, Form, Modal, Transfer } from 'antd';
+import React, { useEffect, useState } from 'react';
+import { useAjax } from '@/Hook/useAjax';
+import { updateMembersApi } from '../../API/groupManage';
+import { getUserAllListApi } from '@/pages/login/API';
+import { TransferItem } from 'antd/es/transfer';
+
+interface UpdateUserProps {
+    data: any
+    visible?: boolean
+    onChange?: () => void
+    onClose?: () => void
+}
+
+
+const UpdateUser: React.FC<UpdateUserProps> = ({ data, visible, onChange, onClose }) => {
+
+    /****************************************/
+    const { message } = App.useApp()
+    const [form] = Form.useForm();
+    const [userList, setUserList] = useState<TransferItem[]>([])
+
+    const updateMembers = useAjax((params) => updateMembersApi(params))
+    const getUserAllList = useAjax(() => getUserAllListApi())
+    /****************************************/
+
+    useEffect(() => {
+        getUserAllList.run().then(res => {
+            if (res?.data) {
+                setUserList(res.data.map(item => {
+                    return {
+                        key: item.userId,
+                        title: item.nickname
+                    }
+                }))
+            }
+        })
+    }, [visible])
+
+    const handleOk = () => {
+        form.validateFields().then((values) => {
+            updateMembers.run({ ...values, groupId: data.id }).then((res) => {
+                if (res?.data) {
+                    message.success('更新成功')
+                    onChange?.()
+                }
+            })
+        }).catch((err) => {
+            console.log('err', err)
+            form.submit()
+        });
+    }
+
+    return <Modal
+        title={<strong>{data?.name} 项目组成员更新</strong>}
+        open={visible}
+        onCancel={onClose}
+        width={500}
+        onOk={handleOk}
+        confirmLoading={updateMembers.loading}
+    >
+        <Form
+            form={form}
+            name="updateGRoup"
+            layout='vertical'
+            colon={false}
+            scrollToFirstError={{
+                behavior: 'smooth',
+                block: 'center'
+            }}
+            onFinishFailed={({ errorFields }) => {
+                message.error(errorFields?.[0]?.errors?.[0])
+            }}
+            preserve={true}
+            initialValues={{ userIds: data?.userList?.map(item => item.userId) || [] }}
+        >
+            <Form.Item label={<strong>成员</strong>} name="userIds" rules={[{ required: true, message: '请选择成员!' }]} valuePropName='targetKeys'>
+                <Transfer
+                    dataSource={userList}
+                    titles={['未选', '已选']}
+                    showSearch
+                    render={(item) => item.title}
+                    oneWay
+                    listStyle={{
+                        width: 'calc(50% - 8px)', // 减去间距
+                        height: 360,
+                    }}
+                />
+            </Form.Item>
+        </Form>
+    </Modal>
+};
+
+export default React.memo(UpdateUser);