wjx 1 month ago
parent
commit
b4b5db47a0

+ 13 - 0
src/pages/weComTask/API/businessPlan/create.ts

@@ -14,6 +14,19 @@ export async function addTaskApi(data: BUSINES_SPLAN_API.AddTaskProps) {
     });
 }
 
+/**
+ * 修改
+ * @param data 
+ * @returns 
+ */
+export async function updateTaskApi({ projectId, ...data }: BUSINES_SPLAN_API.AddTaskProps) {
+    return request({
+        url: api + `/corpOperation/corp/create/project/task/edit/${projectId}`,
+        method: 'POST',
+        data
+    });
+}
+
 /**
  * 计划列表
  * @param data 

+ 1 - 0
src/pages/weComTask/API/businessPlan/typings.d.ts

@@ -22,6 +22,7 @@ declare namespace BUSINES_SPLAN_API {
         welcomeMsgTemplateDTO?: { [x: string]: any }
         groupSendTaskAddDTO?: { [x: string]: any }
         externalUserTransferTasksDTO?: { [x: string]: any }
+        projectId?: number
     }
 
     interface GetProjectListProps {

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

@@ -10,7 +10,7 @@ import { SearchOutlined, PlusOutlined, RedoOutlined, SaveOutlined, CheckOutlined
 import { getGroupData, getHighGroupData, getUserInDataData, restoreGroupData, restoreUserInheritData } from './const';
 import { friendsColumns, highMassSendingColumns, massSendingColumns, userInheritColumns, welcomeColumns } from './tableConfig';
 import SubmitModal from './submitModal';
-import { addTaskApi, getCreateDetailsApi, getProjectDetailsApi } from '@/pages/weComTask/API/businessPlan/create';
+import { addTaskApi, getCreateDetailsApi, getProjectDetailsApi, updateTaskApi } from '@/pages/weComTask/API/businessPlan/create';
 import { useNavigate } from 'react-router-dom';
 import SelectExternalAccount from '@/pages/weComTask/components/selectExternalAccount';
 import Welcome from './components/welcome';
@@ -34,6 +34,7 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
     const navigate = useNavigate();
     const { bookList, bookPlatForm } = toJS(weComTaskStore.data)
     const [settings, setSettings] = useState<TASK_CREATE.SettingsProps>();
+    const [projectId, setProjectId] = useState<number>()
     const { message, modal } = App.useApp()
     const [msgJobTypeList, setMsgJobTypeList] = useState<{ value: string, label: string }[]>([])
     const [previewData, setPreviewData] = useState<TASK_CREATE.previewDataProps>({})
@@ -47,15 +48,20 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
     const welcomeMsgJobType = useAjax(() => welcomeMsgJobTypeApi())//获取欢迎语类型
 
     const addTask = useAjax((params) => addTaskApi(params))
+    const updateTask = useAjax((params) => updateTaskApi(params))
     const getCreateDetails = useAjax((params) => getCreateDetailsApi(params))
     const getBindMpList = useAjax(() => getBindMpListApi())
     /***********************************************/
     console.log('settings--->', settings, previewContent)
 
     useEffect(() => {
-        const projectId = sessionStorage.getItem('OFFICIALTASKID')
-        if (projectId) {
-            getCreateDetails.run(projectId).then(res => {
+        const project = sessionStorage.getItem('OFFICIALTASKID')
+        if (project) {
+            const { id, isCopy } = JSON.parse(project)
+            if (!isCopy) {
+                setProjectId(id)
+            }
+            getCreateDetails.run(id).then(res => {
                 sessionStorage.removeItem('OFFICIALTASKID')
                 if (res?.data) {
                     const { corpUsers, bizType, platform, templateProductId, welcomeMsgTemplateDTO, groupSendTaskAddDTO, externalUserTransferTasksDTO } = res.data
@@ -762,24 +768,37 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
         //         })
         //     }
         // }
-        addTask.run(params).then(res => {
-            console.log(res)
-            if (res?.data) {
-                modal.success({
-                    content: '任务提交成功',
-                    styles: { body: { fontWeight: 700 } },
-                    okText: '跳转任务列表',
-                    closable: true,
-                    onOk: () => {
-                        sessionStorage.setItem('CAMPCORP', values?.projectName)
-                        navigate('/weComTask/businessPlan/taskList')
-                    },
-                    onCancel: () => {
-                        setSubVisible(false)
-                    }
-                })
-            }
-        })
+        if (projectId) {
+            params.projectId = projectId
+            updateTask.run(params).then(res => {
+                console.log(res)
+                if (res?.data) {
+                    message.success('修改提交成功')
+                    setProjectId(undefined)
+                    sessionStorage.setItem('CAMPCORP', values?.projectName)
+                    navigate('/weComTask/businessPlan/taskList')
+                }
+            })
+        } else {
+            addTask.run(params).then(res => {
+                console.log(res)
+                if (res?.data) {
+                    modal.success({
+                        content: '任务提交成功',
+                        styles: { body: { fontWeight: 700 } },
+                        okText: '跳转任务列表',
+                        closable: true,
+                        onOk: () => {
+                            sessionStorage.setItem('CAMPCORP', values?.projectName)
+                            navigate('/weComTask/businessPlan/taskList')
+                        },
+                        onCancel: () => {
+                            setSubVisible(false)
+                        }
+                    })
+                }
+            })
+        }
     }
 
     // 重置表格
@@ -850,7 +869,7 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
 
     return <div className={style.create}>
         <Spin spinning={getCreateDetails.loading}>
-            <Card title={<strong>配置区</strong>} className={`${style.card} ${style.config}`}>
+            <Card title={<strong>{projectId ? getCreateDetails?.data?.data?.projectName + '任务编辑' : ''}配置区</strong>} className={`${style.card} ${style.config}`}>
                 <Space wrap>
                     <Space.Compact>
                         <Button>客服组</Button>
@@ -1111,7 +1130,8 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
         {/* 提交配置 */}
         {subVisible && <SubmitModal
             visible={subVisible}
-            ajax={addTask}
+            loading={addTask.loading || updateTask.loading}
+            projectName={projectId ? getCreateDetails?.data?.data?.projectName : undefined}
             onChange={(values) => {
                 onSubmit(values)
             }}

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

@@ -11,12 +11,13 @@ interface Props {
     visible?: boolean,
     onClose?: () => void,
     onChange?: (data: any) => void
-    ajax?: any
+    loading?: boolean
+    projectName?: string
 }
 const SubmitModal: React.FC<Props> = (props) => {
 
     /********************/
-    const { visible, onClose, onChange, ajax } = props
+    const { visible, onClose, onChange, loading, projectName } = props
     const [form] = Form.useForm()
     /********************/
 
@@ -31,9 +32,9 @@ const SubmitModal: React.FC<Props> = (props) => {
 
 
     return <Modal
-        title={<strong style={{ fontSize: 20 }}>提交</strong>}
+        title={<strong style={{ fontSize: 20 }}>{projectName ? projectName + '任务修改' : ''}提交</strong>}
         open={visible}
-        confirmLoading={ajax?.loading}
+        confirmLoading={loading}
         onCancel={onClose}
         maskClosable={false}
         onOk={handleOk}
@@ -53,7 +54,7 @@ const SubmitModal: React.FC<Props> = (props) => {
             colon={false}
             labelAlign="left"
             initialValues={{
-                projectName: '任务' + dayjs().format('MMDDHHmmss') + '_' + randomString(true, 3, 5)
+                projectName: projectName || '任务' + dayjs().format('MMDDHHmmss') + '_' + randomString(true, 3, 5)
             }}
         >
             <Form.Item label={<strong>任务名称</strong>} name="projectName" rules={[{ required: true, message: '请输入任务名称!' }]}>

+ 2 - 2
src/pages/weComTask/page/businessPlan/taskList/index.tsx

@@ -45,8 +45,8 @@ const TaskList: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookL
     }
 
     // 复制
-    const handleCopy = (data: any) => {
-        sessionStorage.setItem('OFFICIALTASKID', data.id)
+    const handleCopy = (data: any, isCopy: boolean) => {
+        sessionStorage.setItem('OFFICIALTASKID', JSON.stringify({ id: data.id, isCopy }))
         sessionStorage.setItem('oldPath', '/weComTask/businessPlan/create')
         window.location.href = '/weComTask#/weComTask/businessPlan/create'
     }

+ 4 - 3
src/pages/weComTask/page/businessPlan/taskList/tableConfig.tsx

@@ -16,7 +16,7 @@ const taskListColumns = (
     bookPlatForm: any[],
     bookList: any[],
     handleLog: (data: any) => void,
-    handleCopy: (data: any) => void,
+    handleCopy: (data: any, isCopy: boolean) => void,
     handleDel: (data: any, type: 'del' | 'cancel') => void,
 ): ColumnsType<AnyObject> => {
 
@@ -25,7 +25,7 @@ const taskListColumns = (
             title: '操作',
             dataIndex: 'cz',
             key: 'cz',
-            width: 150,
+            width: 160,
             render(_, record) {
                 return <Space>
                     <Popconfirm
@@ -34,7 +34,8 @@ const taskListColumns = (
                     >
                         <a style={{ color: 'orange' }}>取消任务</a>
                     </Popconfirm>
-                    <a onClick={() => handleCopy(record)}>复制</a>
+                    <a onClick={() => handleCopy(record, true)}>复制</a>
+                    <a onClick={() => handleCopy(record, false)}>编辑</a>
                     <a onClick={() => handleLog(record)}>详情</a>
                     <Popconfirm
                         title="确定删除?"

+ 361 - 13
src/pages/weComTask/page/groupChat/create/components/groupUser/addGroupObject.tsx

@@ -1,38 +1,386 @@
-import { Button, Modal } from 'antd';
-import React, { useState } from 'react';
-import { PlusOutlined } from '@ant-design/icons';
+import { App, Button, Card, Empty, Form, Input, InputNumber, Modal, Popover, Radio, Select, Space, Table, Typography } from 'antd';
+import React, { useEffect, useState } from 'react';
+import { PlusOutlined, QuestionCircleFilled } from '@ant-design/icons';
+import FilterUser from '@/pages/weComTask/components/filterUser';
+import MindTags from '@/pages/weComTask/components/mindTags';
+import { getAllWxListApi } from '@/pages/weComTask/API/corpUserAssign';
+import { useAjax } from '@/Hook/useAjax';
+import FilterUserTooltip from '@/pages/weComTask/components/filterUser/filterUserTooltip';
+import { businessPlanData } from '@/pages/weComTask/page/businessPlan/create/const';
+import { ColumnsType } from 'antd/es/table';
+const { Text, Paragraph } = Typography;
 
 /**
  * 进群对象新建组件
  * @param param0 
  * @returns 
  */
-const AddGroupObject: React.FC<GROUP_CHAT_CREATE.AddGroupObjectProps> = ({ value, onChange }) => {
+const AddGroupObject: React.FC<GROUP_CHAT_CREATE.AddGroupObjectProps> = ({ value = [], onChange, bookPlatForm, bookList }) => {
 
     /******************************************/
     const [visible, setVisible] = useState<boolean>(false)
+    const [initialValues, setInitialValues] = useState<any>(undefined)
     /******************************************/
 
     return <>
-        <Button type="dashed" style={{ width: '100%' }} block icon={<PlusOutlined />} onClick={() => setVisible(true)}>新建进群对象</Button>
+
+        {value?.length > 0 ? <ShowGroupUserTable
+            value={value}
+            bookList={bookList}
+            bookPlatForm={bookPlatForm}
+            handleDelete={(id) => {
+                onChange?.(value.filter((_, index) => index + 1 !== id))
+            }}
+            handleEdit={(record) => {
+                setInitialValues(record)
+                setVisible(true)
+            }}
+        /> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description='暂无群配置' />}
+        <Button type="dashed" style={{ width: '100%' }} block icon={<PlusOutlined />} onClick={() => setVisible(true)}>新建群配置</Button>
+        {visible && <AddGroupObjectModal
+            visible={visible}
+            initialValues={initialValues}
+            onChange={(values) => {
+                const newValue = JSON.parse(JSON.stringify(value))
+                if (initialValues?.id) {
+                    newValue[initialValues.id - 1] = values
+                } else {
+                    newValue.push(values)
+                }
+                onChange?.(newValue)
+                setVisible(false)
+                setInitialValues(undefined)
+            }}
+            onClose={() => {
+                setVisible(false)
+                setInitialValues(undefined)
+            }}
+        />}
     </>
 };
 
-const AddGroupObjectModal: React.FC<GROUP_CHAT_CREATE.AddGroupObjectModalProps> = React.memo(({visible, onChange, onClose, value}) => {
-    
+export const ShowGroupUserTable: React.FC<GROUP_CHAT_CREATE.ShowGroupUserTableProps> = React.memo(({ bookList, bookPlatForm, value, handleEdit, handleDelete, isPreview }) => {
+
+    const columns: ColumnsType<any> = [
+        {
+            title: '群配置名称',
+            dataIndex: 'groupObjectName',
+            key: 'groupObjectName',
+            width: 120,
+            ellipsis: true,
+            fixed: 'left'
+        },
+        {
+            title: '进群对象',
+            dataIndex: 'externalUserFilter',
+            key: 'externalUserFilter',
+            width: 90,
+            align: 'center',
+            render(value) {
+                return value ? <div style={{ display: 'flex', alignItems: 'center' }}>
+                    <div style={{ flex: '1 0', overflow: 'hidden' }}>
+                        <Text ellipsis>指定</Text>
+                    </div>
+                    <Popover
+                        placement="right"
+                        styles={{ body: { maxWidth: 350, maxHeight: 350, overflow: 'hidden', overflowY: 'auto' } }}
+                        mouseEnterDelay={0.5}
+                        content={<FilterUserTooltip
+                            bookCityList={bookPlatForm?.map(item => ({ label: item.platformName, value: item.platformKey }))}
+                            configName={value?.configName}
+                            data={value?.configContent}
+                        />}
+                    >
+                        <a style={{ color: '#000' }}><QuestionCircleFilled /></a>
+                    </Popover>
+                </div> : '全部'
+            },
+        },
+        {
+            title: '群递增起始编号',
+            dataIndex: 'groupIndex',
+            key: 'groupIndex',
+            width: 60,
+            align: 'center'
+        },
+        {
+            title: '群固定人数',
+            dataIndex: 'groupUserCount',
+            key: 'groupUserCount',
+            width: 50,
+            align: 'center'
+        },
+        {
+            title: '邀请客户进群完毕后客服号是否退群',
+            dataIndex: 'autoOutGroup',
+            key: 'autoOutGroup',
+            width: 85,
+            align: 'center',
+            render(value) {
+                return value ? <span style={{ color: '#1890ff' }}>是</span> : <span style={{ color: 'red' }}>否</span>
+            },
+        },
+        {
+            title: '是否排除已在群的客户',
+            dataIndex: 'excludeInGroup',
+            key: 'excludeInGroup',
+            width: 60,
+            align: 'center',
+            render(value) {
+                return value ? <span style={{ color: '#1890ff' }}>是</span> : <span style={{ color: 'red' }}>否</span>
+            },
+        },
+        {
+            title: '拉群完成后自动删除拉群标签',
+            dataIndex: 'excludeInGroup',
+            key: 'excludeInGroup',
+            width: 70,
+            align: 'center',
+            render(value) {
+                return value ? <span style={{ color: '#1890ff' }}>是</span> : <span style={{ color: 'red' }}>否</span>
+            },
+        },
+        {
+            title: '群聊关联公众号',
+            dataIndex: 'weChatAppid',
+            key: 'weChatAppid',
+            width: 100,
+            align: 'center',
+            ellipsis: true,
+            render(value) {
+                return value || '--'
+            },
+        },
+        {
+            title: '拉群完成后群聊备注',
+            dataIndex: 'remark',
+            key: 'remark',
+            width: 140,
+            ellipsis: true,
+            render(value) {
+                return value || '--'
+            },
+        },
+        {
+            title: '拉群完成后群聊智能标签',
+            dataIndex: 'tagDTO',
+            key: 'tagDTO',
+            width: 200,
+            ellipsis: true,
+            render(value) {
+                return value && Object.keys(value)?.length > 0 ?
+                    <Paragraph ellipsis style={{ margin: 0 }}>{Object.keys(value).map(key => {
+                        if (key === 'business' && value[key]) {
+                            return `业务(来源渠道):${businessPlanData.find(i => i.value === value.business)?.label || '<空>'}`
+                        } else if (key === 'bookCity' && value[key]) {
+                            return `书城(来源渠道):${bookPlatForm.find(i => i.id === value.bookCity)?.platformName || '<空>'}`
+                        } else if (key === 'product' && value[key]) {
+                            return `产品(来源渠道):${bookList.find(i => i.id === value.product)?.bookName || '<空>'}`
+                        }
+                        return ''
+                    }).join('、')}</Paragraph> : '--'
+            },
+        },
+        {
+            title: '建群成功发送内容',
+            dataIndex: 'groupSendMsg',
+            key: 'groupSendMsg',
+            width: 140,
+            ellipsis: true
+        },
+        {
+            title: '操作',
+            dataIndex: 'cz',
+            key: 'cz',
+            width: 75,
+            fixed: 'right',
+            align: 'center',
+            render(_, record) {
+                return <Space>
+                    <a onClick={() => {
+                        handleEdit?.(record)
+                    }}>修改</a>
+                    <a style={{ color: 'red' }} onClick={() => {
+                        handleDelete?.(record.id)
+                    }}>删除</a>
+                </Space>
+            },
+        }
+    ]
+    if (isPreview) {
+        columns.pop()
+    }
+
+    return <Table
+        size='small'
+        bordered
+        rowKey={'id'}
+        dataSource={value?.map((item, index) => ({ ...item, id: index + 1 }))}
+        scroll={{ y: 1000 }}
+        columns={columns}
+    />
+})
+
+const AddGroupObjectModal: React.FC<GROUP_CHAT_CREATE.AddGroupObjectModalProps> = React.memo(({ visible, onChange, onClose, initialValues }) => {
+
+    /******************************************/
+    const { message } = App.useApp();
+    const [form] = Form.useForm();
+    const externalUserType = Form.useWatch('externalUserType', form);
+
+    const getAccountList = useAjax(() => getAllWxListApi())
+    /******************************************/
+
+    useEffect(() => {
+        getAccountList.run()
+    }, [])
 
     const handleOk = () => {
-        
+        form.validateFields().then((values) => {
+            console.log(values)
+            onChange?.(values)
+        }).catch(() => {
+            form.submit()
+        });
     }
 
-    return <Modal 
-        title={<strong>新建进群对象</strong>} 
-        open={visible} 
+    return <Modal
+        title={<strong>{(initialValues && Object.keys(initialValues).length > 0) ? '修改' : '新建'}群配置</strong>}
+        open={visible}
         onCancel={onClose}
-        width={660}
+        width={600}
         onOk={handleOk}
-    > 
+        styles={{ body: { maxHeight: 550, overflowY: 'auto' } }}
+    >
+        <Form
+            form={form}
+            name="addGroupUser"
+            labelAlign='left'
+            labelCol={{ span: 6 }}
+            colon={false}
+            labelWrap
+            scrollToFirstError={{
+                behavior: 'smooth',
+                block: 'center'
+            }}
+            onFinishFailed={({ errorFields }) => {
+                message.error(errorFields?.[0]?.errors?.[0])
+            }}
+            onFinish={handleOk}
+            initialValues={(initialValues && Object.keys(initialValues).length > 0) ? initialValues : { externalUserType: 'all', groupIndex: 1, groupUserCount: 37, autoOutGroup: false, excludeInGroup: true, deleteGroupTag: true }}
+            preserve={true}
+        >
+            <Form.Item
+                name={'groupObjectName'}
+                label={<strong>群配置名称</strong>}
+                rules={[{ required: true, message: '请输入群配置名称!' }]}
+            >
+                <Input placeholder='请输入群配置名称' allowClear />
+            </Form.Item>
+            <Form.Item
+                label={<strong>进群对象配置</strong>}
+                required
+            >
+                <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
+                    <Form.Item
+                        name={'externalUserType'}
+                        rules={[{ required: true, message: '请选择转移对象!' }]}
+                        noStyle
+                    >
+                        <Radio.Group options={[{ label: '全部', value: 'all' }, { label: '指定', value: 'specify' }]} />
+                    </Form.Item>
+                    {externalUserType === 'specify' && <div style={{ marginTop: 8, width: '100%' }}>
+                        <Form.Item
+                            name={'externalUserFilter'}
+                            rules={[{ required: true, message: '请选择人群包!' }]}
+                            noStyle
+                        >
+                            <FilterUser configType={'USER_GROUP'} />
+                        </Form.Item>
+                    </div>}
+                </div>
+            </Form.Item>
+            <Form.Item
+                name={'groupIndex'}
+                tooltip={{ title: `例如:起始编号为'1'群名为'测试群',再建群后群名为'测试群1'超出群人数的用户将分配到'测试群2'依次递增`, placement: 'top' }}
+                label={<strong>群递增起始编号</strong>}
+                rules={[{ required: true, message: '请输入群递增起始编号!' }]}
+            >
+                <InputNumber placeholder='请输入群递增起始编号' min={1} style={{ width: '100%' }} />
+            </Form.Item>
+            <Form.Item
+                name={'groupUserCount'}
+                tooltip={{ title: `不包括建群人和固定企微号,最大上限数量38`, placement: 'top' }}
+                label={<strong>群固定人数</strong>}
+                rules={[{ required: true, message: '请输入群固定人数!' }]}
+            >
+                <InputNumber placeholder='请输入群固定人数' max={38} min={1} style={{ width: '100%' }} />
+            </Form.Item>
+            <Form.Item
+                name={'autoOutGroup'}
+                label={<strong>邀请客户进群完毕后客服号是否退群</strong>}
+                rules={[{ required: true, message: '请选择是否退群!' }]}
+            >
+                <Radio.Group>
+                    <Radio value={true}>是</Radio>
+                    <Radio value={false}>否</Radio>
+                </Radio.Group>
+            </Form.Item>
+            <Form.Item
+                name={'excludeInGroup'}
+                label={<strong>是否排除已在群的客户</strong>}
+                rules={[{ required: true, message: '请选择是否排除已在群的客户!' }]}
+            >
+                <Radio.Group>
+                    <Radio value={true}>是</Radio>
+                </Radio.Group>
+            </Form.Item>
+            <Form.Item
+                name={'deleteGroupTag'}
+                label={<strong>拉群完成后自动删除拉群标签</strong>}
+                rules={[{ required: true, message: '请选择拉群完成后自动删除拉群标签!' }]}
+            >
+                <Radio.Group>
+                    <Radio value={true}>是</Radio>
+                </Radio.Group>
+            </Form.Item>
+            <Form.Item
+                name={'weChatAppid'}
+                label={<strong>群聊关联公众号</strong>}
+            >
+                <Select
+                    showSearch
+                    allowClear
+                    placeholder="选择公众号"
+                    filterOption={(input, option) =>
+                        (option?.label as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    }
+                    options={getAccountList?.data?.data?.map(item => ({ label: item.name, value: item.name + '_' + item.appId }))}
+                />
+            </Form.Item>
+            <Form.Item
+                name={'remark'}
+                label={<strong>拉群完成后群聊备注</strong>}
+            >
+                <Input.TextArea placeholder="请输入群聊备注" />
+            </Form.Item>
 
+            <Card title={<strong>拉群完成后群聊智能标签</strong>} style={{ background: '#fff', marginBottom: 10 }} styles={{ body: { padding: '6px 0 6px 16px' } }}>
+                <Form.Item
+                    name={'tagDTO'}
+                    style={{ marginBottom: 0 }}
+                >
+                    <MindTags />
+                </Form.Item>
+            </Card>
+            <Form.Item
+                name={'groupSendMsg'}
+                label={<strong>建群成功发送内容</strong>}
+                rules={[{ required: true, message: '请输入建群成功发送内容!' }]}
+            >
+                <Input.TextArea placeholder="请输入建群成功发送内容" />
+            </Form.Item>
+        </Form>
     </Modal>
 })
 

+ 38 - 16
src/pages/weComTask/page/groupChat/create/components/groupUser/index.tsx

@@ -4,6 +4,7 @@ import useNewToken from '@/Hook/useNewToken';
 import { App, Button, Empty } from 'antd';
 import { DispatchGroupChatCreate } from '../..';
 import SettingsGroupUser from './settingsGroupUser';
+import PreviewGroupUser from './previewGroupUser';
 
 
 /**
@@ -15,42 +16,63 @@ const GroupUser: React.FC = () => {
     /*********************************/
     const { message } = App.useApp()
     const { token } = useNewToken()
-    const { setSettings, settings, onPreviewReset } = useContext(DispatchGroupChatCreate)!;
+    const { setSettings, settings, onPreviewReset, bookPlatForm, bookList } = useContext(DispatchGroupChatCreate)!;
     const [newVisible, setNewVisible] = useState<boolean>(false);
     /*********************************/
 
 
     return <>
-        <div className={`${style.settingsBody_content_row}`} style={{width: '50%'}}>
+        <div className={`${style.settingsBody_content_row}`} style={{ width: '65%' }}>
             <div className={`${style.settingsBody_content_col}`} style={{ width: '100%' }}>
                 <div className={style.title}>
-                    <span>群聊创建进群对象</span>
+                    <span>群</span>
+                    {settings?.strategyDTO?.strategyList?.every(item => item?.groupObjectList?.length > 0) && <a
+                        style={{ color: 'red' }}
+                        onClick={() => {
+                            setSettings({
+                                ...settings,
+                                strategyDTO: {
+                                    ...settings.strategyDTO,
+                                    strategyList: settings.strategyDTO.strategyList.map(item => ({
+                                        ...item,
+                                        groupObjectList: []
+                                    }))
+                                }
+                            });
+                        }}
+                    >清空</a>}
                 </div>
                 <div className={style.detail}>
-                    <div className={style.detail_title}>群聊创建进群对象配置</div>
+                    <div className={style.detail_title}>群配置</div>
                     <div className={style.detail_body}>
-                        {settings?.groupUsersDTO && Object.keys(settings?.groupUsersDTO).length > 0 ? <>
-                            
-                        </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
+                        {settings?.strategyDTO && Object.keys(settings?.strategyDTO).length > 0 ? <PreviewGroupUser
+                            strategyList={settings?.strategyDTO?.strategyList || []}
+                            bookList={bookList}
+                            bookPlatForm={bookPlatForm}
+                        /> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
                     </div>
                 </div>
                 <div className={style.detail_footer}>
-                    {settings?.strategyDTO && Object.keys(settings?.strategyDTO).length > 0 ? 
-                        <Button type="link" style={{ padding: 0, fontSize: 12, color: token.colorPrimary }} size="small" onClick={() => setNewVisible(true)}>编辑</Button> : 
+                    {settings?.strategyDTO && Object.keys(settings?.strategyDTO).length > 0 ?
+                        <Button type="link" style={{ padding: 0, fontSize: 12, color: token.colorPrimary }} size="small" onClick={() => setNewVisible(true)}>编辑</Button> :
                         <Button type="link" style={{ padding: 0, fontSize: 12, color: token.colorPrimary }} size="small" onClick={() => message.error('请先编辑群聊创建策略')}>编辑</Button>}
                 </div>
             </div>
         </div>
-        
+
         {/* 配置群聊创建进群对象 */}
-        {newVisible && <SettingsGroupUser 
-            visible={newVisible} 
-            onClose={() => setNewVisible(false)} 
+        {newVisible && <SettingsGroupUser
+            visible={newVisible}
+            onClose={() => setNewVisible(false)}
             onChange={(values) => {
-                setNewVisible(false)
+                setSettings({
+                    ...settings,
+                    strategyDTO: values
+                });
+                onPreviewReset();
+                setNewVisible(false);
             }}
-            value={settings?.groupUsersDTO}
-            strategyDTO={settings?.strategyDTO}
+            value={settings?.strategyDTO}
         />}
     </>
 };

+ 48 - 0
src/pages/weComTask/page/groupChat/create/components/groupUser/previewGroupUser.tsx

@@ -0,0 +1,48 @@
+import { Tabs, Typography } from 'antd';
+import React, { useState } from 'react';
+import { ShowGroupUserTable } from './addGroupObject';
+const { Text } = Typography;
+
+interface PreviewGroupUserProps {
+    strategyList: { [x: string]: any }[];
+    bookPlatForm: TASK_CREATE.BookPlatFormProps[]
+    bookList: TASK_CREATE.BookListProps[]
+}
+
+/**
+ * 群配置预览
+ * @param param0 
+ * @returns 
+ */
+const PreviewGroupUser: React.FC<PreviewGroupUserProps> = ({ strategyList, bookList, bookPlatForm }) => {
+
+    /****************************************/
+    const [activeKey, setActiveKey] = useState<string>('1')
+    /****************************************/
+
+    return <Tabs
+        activeKey={activeKey}
+        tabPosition='left'
+        style={{
+            height: '100%',
+            width: '100%'
+        }}
+        onChange={(key) => { setActiveKey(key) }}
+        items={strategyList.map((item, index) => {
+            return {
+                label: <div style={{ maxWidth: 100 }}><Text>{item.strategyName}</Text></div>,
+                key: `${index + 1}`,
+                children: <div style={{ width: '100%', height: 282, overflow: 'hidden', overflowY: 'auto' }}>
+                    <ShowGroupUserTable
+                        value={item.groupObjectList}
+                        bookList={bookList}
+                        bookPlatForm={bookPlatForm}
+                        isPreview={true}
+                    />
+                </div>
+            }
+        })}
+    />;
+};
+
+export default PreviewGroupUser;

+ 58 - 222
src/pages/weComTask/page/groupChat/create/components/groupUser/settingsGroupUser.tsx

@@ -1,34 +1,31 @@
-import { App, Button, Card, Form, Input, InputNumber, Modal, Popover, Radio, Select, Space } from "antd";
-import React, { useEffect, useState } from "react";
+import { App, Card, Form, Modal, Popover, Space } from "antd";
+import React, { useContext, useEffect, useRef, useState } from "react";
 import '../../../../businessPlan/create/global.less'
-import { PlusOutlined, MinusCircleOutlined, QuestionCircleFilled, RightOutlined, DownOutlined, VerticalLeftOutlined } from '@ant-design/icons';
+import { QuestionCircleFilled, RightOutlined, DownOutlined } from '@ant-design/icons';
 import PreviewTime from "@/pages/weComTask/components/previewTime";
-import FilterUser from "@/pages/weComTask/components/filterUser";
 import { getAllWxListApi } from "@/pages/weComTask/API/corpUserAssign";
 import { useAjax } from "@/Hook/useAjax";
-import MindTags from "@/pages/weComTask/components/mindTags";
-
-interface Props extends GROUP_CHAT_CREATE.FoundationProps<any> {
-    strategyDTO: { [x: string]: any }
-}
-
-// 默认进群对象
-const defaultGroupObject = { externalUserType: 'all', groupIndex: 1, groupUserCount: 37, autoOutGroup: false, excludeInGroup: true, deleteGroupTag: true }
+import AddGroupObject from "./addGroupObject";
+import { DispatchGroupChatCreate } from "../..";
+import NewSteps from "@/pages/weComTask/components/newSteps";
 
 /**
  * 群聊创建进群对象配置
  * @param param0 
  * @returns 
  */
-const SettingsGroupUser: React.FC<Props> = ({ strategyDTO, visible, onClose, value, onChange }) => {
+const SettingsGroupUser: React.FC<GROUP_CHAT_CREATE.FoundationProps<any>> = ({ visible, onClose, value, onChange }) => {
 
 
     /***************************************/
+    const { bookPlatForm, bookList } = useContext(DispatchGroupChatCreate)!;
+    const ref1 = useRef<HTMLDivElement>(null)
+
     const { message } = App.useApp();
     const [form] = Form.useForm();
     const strategyList = Form.useWatch('strategyList', form)
     const [activeKey, setActiveKey] = useState<number[]>([])
-    const [groupObjectActiveKey, setGroupObjectActiveKey] = useState<string[]>([])
+    const [stepsList, setStepsList] = useState<any>([])
 
     const getAccountList = useAjax(() => getAllWxListApi())
     /***************************************/
@@ -38,37 +35,53 @@ const SettingsGroupUser: React.FC<Props> = ({ strategyDTO, visible, onClose, val
     }, [])
 
     useEffect(() => {
+        const strategyList = value?.strategyList?.map(item => {
+            return {
+                ...item,
+                groupObjectList: item?.groupObjectList || []
+            }
+        })
         form.setFieldsValue({
-            strategyList: strategyDTO?.strategyList?.map(item => {
-                return {
-                    ...item,
-                    groupObjectList: item?.groupObjectList || [defaultGroupObject]
-                }
-            })
+            strategyList
         })
-    }, [strategyDTO])
+        filedUpdateChange({ strategyList })
+    }, [value])
 
     const handleOk = () => {
         form.validateFields().then((values) => {
             console.log(values)
-            // onChange(data)
+            onChange?.(values)
         }).catch(() => {
             form.submit()
         });
     };
 
+    const filedUpdateChange = ({ strategyList }: any) => {
+        const stepsData = strategyList?.map((item, index) => {
+            const { strategyName } = item
+            return { title: `策略${index + 1}: ${strategyName}`, description: `进群对象名称、进群对象配置、群递增起始编号、群固定人数...`, id: `strategy_${index + 1}`, checked: item?.groupObjectList?.length > 0 }
+        })
+        setStepsList(stepsData)
+    }
+
     return <Modal
-        title={<strong>群聊创建进群对象配置</strong>}
+        title={<strong>群聊创建群配置</strong>}
         open={visible}
         onCancel={onClose}
-        width={850}
+        width={1000}
         onOk={handleOk}
         className={`settingsModal`}
     >
         <div className={`body_steps`}>
-
+            <NewSteps
+                items={stepsList}
+                onChange={(e) => {
+                    if (e?.id)
+                        ref1.current?.querySelector('#' + e?.id)?.scrollIntoView({ behavior: 'smooth' })
+                }}
+            />
         </div>
-        <div className={`body_content`}>
+        <div className={`body_content`} ref={ref1}>
             <Form
                 form={form}
                 name="newGroupUser"
@@ -83,7 +96,6 @@ const SettingsGroupUser: React.FC<Props> = ({ strategyDTO, visible, onClose, val
                 onFinishFailed={({ errorFields }) => {
                     console.log('errorFields--->', errorFields)
                     setActiveKey(data => data?.filter(item => item != errorFields?.[0]?.name?.[1]))
-                    setGroupObjectActiveKey(data => data?.filter(item => item != (errorFields?.[0]?.name?.[1] + '_' + errorFields?.[0]?.name?.[3])))
                     message.error(errorFields?.[0]?.errors?.[0])
                 }}
                 onFinish={handleOk}
@@ -91,19 +103,19 @@ const SettingsGroupUser: React.FC<Props> = ({ strategyDTO, visible, onClose, val
                     // strategyList: [{ id: Date.now() }]
                 }}
                 onFieldsChange={() => {
-                    // filedUpdateChange(form.getFieldsValue())
+                    filedUpdateChange(form.getFieldsValue())
                 }}
                 preserve={true}
             >
                 <Form.List name="strategyList">
                     {(fields) => (
                         <>
-                            {fields.map(({ key, name }, index) => {
+                            {fields.map(({ key, name, ...restField }, index) => {
                                 const strategyItem = strategyList[index]
                                 return <Card
                                     key={key}
                                     title={<Space>
-                                        <strong>策略{index + 1} {strategyItem?.strategyName}</strong>
+                                        <strong>{strategyItem?.strategyName}</strong>
                                         <Popover
                                             placement="right"
                                             content={<div>
@@ -119,26 +131,15 @@ const SettingsGroupUser: React.FC<Props> = ({ strategyDTO, visible, onClose, val
                                     style={{ background: '#fff', marginBottom: 10 }}
                                     hoverable
                                     id={`strategy_${index + 1}`}
-                                    extra={<Space>
-                                        <a
-                                            style={{ padding: 2 }}
-                                            onClick={() => {
-                                                const allKey = strategyItem?.groupObjectList?.map((_, i) => `${index}_${i}`)
-                                                setGroupObjectActiveKey(data => [...new Set([...data, ...allKey])])
-                                            }}
-                                        >
-                                            <VerticalLeftOutlined />
-                                        </a>
-                                        <a
-                                            style={{ padding: 2 }}
-                                            onClick={() => setActiveKey(data => {
-                                                if (data.includes(index)) {
-                                                    return data.filter(item => item !== index)
-                                                }
-                                                return [...new Set([...data, index])]
-                                            })}
-                                        >{activeKey.includes(index) ? <RightOutlined /> : <DownOutlined />}</a>
-                                    </Space>}
+                                    extra={<a
+                                        style={{ padding: 2 }}
+                                        onClick={() => setActiveKey(data => {
+                                            if (data.includes(index)) {
+                                                return data.filter(item => item !== index)
+                                            }
+                                            return [...new Set([...data, index])]
+                                        })}
+                                    >{activeKey.includes(index) ? <RightOutlined /> : <DownOutlined />}</a>}
                                     styles={{
                                         body: {
                                             transition: 'height 0.3s ease-in-out',
@@ -148,178 +149,13 @@ const SettingsGroupUser: React.FC<Props> = ({ strategyDTO, visible, onClose, val
                                         }
                                     }}
                                 >
-                                    <Form.List name={[name, 'groupObjectList']}>
-                                        {(fields, { add, remove }) => (
-                                            <>
-                                                {fields.map(({ key, name, ...restField }, index1) => {
-                                                    const groupObjectItem = strategyItem?.groupObjectList?.[index1]
-
-                                                    return <Card
-                                                        key={key}
-                                                        title={<strong>进群对象{index1 + 1} 配置</strong>}
-                                                        style={{ background: '#fff', marginBottom: 10 }}
-                                                        id={`strategy_${index + 1}_groupObject_${index1 + 1}`}
-                                                        extra={<Space>
-                                                            {strategyItem?.groupObjectList?.length > 1 && <div
-                                                                style={{ color: 'red', cursor: 'pointer', padding: 2 }}
-                                                                onClick={() => {
-                                                                    remove(name)
-                                                                }}
-                                                            >
-                                                                <MinusCircleOutlined />
-                                                            </div>}
-                                                            <a
-                                                                style={{ padding: 2 }}
-                                                                onClick={() => setGroupObjectActiveKey(data => {
-                                                                    if (data.includes(index + '_' + index1)) {
-                                                                        return data.filter(item => item !== (index + '_' + index1))
-                                                                    }
-                                                                    return [...new Set([...data, index + '_' + index1])]
-                                                                })}
-                                                            >{groupObjectActiveKey.includes(index + '_' + index1) ? <RightOutlined /> : <DownOutlined />}</a>
-                                                        </Space>}
-                                                        styles={{
-                                                            body: {
-                                                                transition: 'height 0.3s ease-in-out',
-                                                                overflow: 'hidden',
-                                                                height: !groupObjectActiveKey.includes(index + '_' + index1) ? 'auto' : 0,
-                                                                padding: !groupObjectActiveKey.includes(index + '_' + index1) ? '16px' : 0
-                                                            }
-                                                        }}
-                                                    >
-                                                        <Form.Item
-                                                            {...restField}
-                                                            name={[name, 'groupObjectName']}
-                                                            label={<strong>进群对象名称</strong>}
-                                                            rules={[{ required: true, message: '请输入进群对象名称!' }]}
-                                                        >
-                                                            <Input placeholder='请输入进群对象名称' allowClear style={{ width: 358 }} />
-                                                        </Form.Item>
-                                                        <Form.Item
-                                                            label={<strong>进群对象配置</strong>}
-                                                            required
-                                                        >
-                                                            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
-                                                                <Form.Item
-                                                                    {...restField}
-                                                                    name={[name, 'externalUserType']}
-                                                                    rules={[{ required: true, message: '请选择转移对象!' }]}
-                                                                    noStyle
-                                                                >
-                                                                    <Radio.Group options={[{ label: '全部', value: 'all' }, { label: '指定', value: 'specify' }]} />
-                                                                </Form.Item>
-                                                                {groupObjectItem?.externalUserType === 'specify' && <div style={{ marginTop: 8, width: '100%' }}>
-                                                                    <Form.Item
-                                                                        {...restField}
-                                                                        name={[name, 'externalUserFilter']}
-                                                                        rules={[{ required: true, message: '请选择人群包!' }]}
-                                                                        noStyle
-                                                                    >
-                                                                        <FilterUser configType={'USER_GROUP'} />
-                                                                    </Form.Item>
-                                                                </div>}
-                                                            </div>
-                                                        </Form.Item>
-                                                        <Form.Item
-                                                            {...restField}
-                                                            name={[name, 'groupIndex']}
-                                                            tooltip={{ title: `例如:起始编号为'1'群名为'测试群',再建群后群名为'测试群1'超出群人数的用户将分配到'测试群2'依次递增`, placement: 'top' }}
-                                                            label={<strong>群递增起始编号</strong>}
-                                                            rules={[{ required: true, message: '请输入群递增起始编号!' }]}
-                                                        >
-                                                            <InputNumber placeholder='请输入群递增起始编号' min={1} style={{ width: 358 }} />
-                                                        </Form.Item>
-                                                        <Form.Item
-                                                            {...restField}
-                                                            name={[name, 'groupUserCount']}
-                                                            tooltip={{ title: `不包括建群人和固定企微号,最大上限数量38`, placement: 'top' }}
-                                                            label={<strong>群固定人数</strong>}
-                                                            rules={[{ required: true, message: '请输入群固定人数!' }]}
-                                                        >
-                                                            <InputNumber placeholder='请输入群固定人数' max={38} min={1} style={{ width: 358 }} />
-                                                        </Form.Item>
-                                                        <Form.Item
-                                                            {...restField}
-                                                            name={[name, 'autoOutGroup']}
-                                                            label={<strong>邀请客户进群完毕后客服号是否退群</strong>}
-                                                            rules={[{ required: true, message: '请选择是否退群!' }]}
-                                                        >
-                                                            <Radio.Group>
-                                                                <Radio value={true}>是</Radio>
-                                                                <Radio value={false}>否</Radio>
-                                                            </Radio.Group>
-                                                        </Form.Item>
-                                                        <Form.Item
-                                                            {...restField}
-                                                            name={[name, 'excludeInGroup']}
-                                                            label={<strong>是否排除已在群的客户</strong>}
-                                                            rules={[{ required: true, message: '请选择是否排除已在群的客户!' }]}
-                                                        >
-                                                            <Radio.Group>
-                                                                <Radio value={true}>是</Radio>
-                                                            </Radio.Group>
-                                                        </Form.Item>
-                                                        <Form.Item
-                                                            {...restField}
-                                                            name={[name, 'deleteGroupTag']}
-                                                            label={<strong>拉群完成后自动删除拉群标签</strong>}
-                                                            rules={[{ required: true, message: '请选择拉群完成后自动删除拉群标签!' }]}
-                                                        >
-                                                            <Radio.Group>
-                                                                <Radio value={true}>是</Radio>
-                                                            </Radio.Group>
-                                                        </Form.Item>
-                                                        <Form.Item
-                                                            {...restField}
-                                                            name={[name, 'weChatAppid']}
-                                                            label={<strong>群聊关联公众号</strong>}
-                                                        >
-                                                            <Select
-                                                                showSearch
-                                                                style={{ width: 358 }}
-                                                                allowClear
-                                                                placeholder="选择公众号"
-                                                                filterOption={(input, option) =>
-                                                                    (option?.label as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
-                                                                }
-                                                                options={getAccountList?.data?.data?.map(item => ({ label: item.name, value: item.appId }))}
-                                                            />
-                                                        </Form.Item>
-                                                        <Form.Item
-                                                            {...restField}
-                                                            name={[name, 'remark']}
-                                                            label={<strong>拉群完成后群聊备注</strong>}
-                                                        >
-                                                            <Input.TextArea placeholder="请输入群聊备注" style={{ width: 358 }} />
-                                                        </Form.Item>
-
-                                                        <Card title={<strong>拉群完成后群聊智能标签</strong>} style={{ background: '#fff', marginBottom: 10 }} styles={{ body: { padding: '6px 0 6px 16px' } }}>
-                                                            <Form.Item
-                                                                {...restField}
-                                                                name={[name, 'tagDTO']}
-                                                                style={{ marginBottom: 0 }}
-                                                            >
-                                                                <MindTags />
-                                                            </Form.Item>
-                                                        </Card>
-                                                        <Form.Item
-                                                            {...restField}
-                                                            name={[name, 'groupSendMsg']}
-                                                            label={<strong>建群成功发送内容</strong>}
-                                                            rules={[{ required: true, message: '请输入建群成功发送内容!' }]}
-                                                        >
-                                                            <Input.TextArea placeholder="请输入建群成功发送内容" style={{ width: 358 }} />
-                                                        </Form.Item>
-                                                    </Card>
-                                                })}
-                                                <Form.Item>
-                                                    <Button type="dashed" onClick={() => add(defaultGroupObject)} block icon={<PlusOutlined />}>
-                                                        新增进群对象
-                                                    </Button>
-                                                </Form.Item>
-                                            </>
-                                        )}
-                                    </Form.List>
+                                    <Form.Item
+                                        {...restField}
+                                        name={[name, 'groupObjectList']}
+                                        rules={[{ required: true, message: '请新增群配置!' }]}
+                                    >
+                                        <AddGroupObject bookPlatForm={bookPlatForm} bookList={bookList} />
+                                    </Form.Item>
                                 </Card>
                             })}
                         </>

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

@@ -19,10 +19,10 @@ const Strategy: React.FC = () => {
 
 
     return <>
-        <div className={`${style.settingsBody_content_row}`} style={{ width: '50%' }}>
+        <div className={`${style.settingsBody_content_row}`} style={{ width: '35%' }}>
             <div className={`${style.settingsBody_content_col}`} style={{ width: '100%' }}>
                 <div className={style.title}>
-                    <span>群聊创建策略</span>
+                    <span>策略</span>
                 </div>
                 <div className={style.detail}>
                     <div className={style.detail_title}>群聊创建策略配置</div>

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

@@ -142,7 +142,8 @@ const GroupChatCreate: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREAT
                         <DispatchGroupChatCreate.Provider
                             value={{
                                 settings, setSettings,
-                                onPreviewReset
+                                onPreviewReset,
+                                bookPlatForm, bookList
                             }}
                         >
                             {/* 策略配置 */}

+ 16 - 5
src/pages/weComTask/page/groupChat/create/typings.d.ts

@@ -12,23 +12,34 @@ declare namespace GROUP_CHAT_CREATE {
         channel?: string;   // 渠道
         templateProductId?: string; // 适用产品
         strategyDTO?: { [x: string]: any };
-        groupUsersDTO?: { [x: string]: any };
     }
     interface DispatchGroupChatCreate {
         settings: SettingsProps
         setSettings: React.Dispatch<React.SetStateAction<SettingsProps>>
         onPreviewReset: () => void
+        bookPlatForm: TASK_CREATE.BookPlatFormProps[]
+        bookList: TASK_CREATE.BookListProps[]
     }
     interface FoundationProps<T> extends TASK_CREATE.DefaultProps, TASK_CREATE.DefaultChangeProps<T> {
         value?: { [x: string]: any };
     }
     interface AddGroupObjectProps {
-        value?: { [x: string]: any };
-        onChange?: (value: any) => void;
+        bookPlatForm: TASK_CREATE.BookPlatFormProps[]
+        bookList: TASK_CREATE.BookListProps[]
+        value?: { [x: string]: any }[];
+        onChange?: (value: { [x: string]: any }[]) => void;
+    }
+    interface ShowGroupUserTableProps {
+        bookPlatForm: TASK_CREATE.BookPlatFormProps[]
+        bookList: TASK_CREATE.BookListProps[]
+        value: { [x: string]: any }[];
+        handleEdit?: (data: { [x: string]: any }) => void
+        handleDelete?: (id: number) => void
+        isPreview?: boolean
     }
     interface AddGroupObjectModalProps {
-        value?: { [x: string]: any };
-        onChange?: (value: any) => void;
+        initialValues?: any;
+        onChange?: (value: { [x: string]: any }[]) => void;
         visible?: boolean;
         onClose?: () => void;
     }