addGroupObject.tsx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. import { App, Button, Card, Empty, Form, Input, InputNumber, Modal, Popover, Radio, Select, Space, Table, Typography } from 'antd';
  2. import React, { useEffect, useState } from 'react';
  3. import { PlusOutlined, QuestionCircleFilled } from '@ant-design/icons';
  4. import FilterUser from '@/pages/weComTask/components/filterUser';
  5. import MindTags from '@/pages/weComTask/components/mindTags';
  6. import { getAllWxListApi } from '@/pages/weComTask/API/corpUserAssign';
  7. import { useAjax } from '@/Hook/useAjax';
  8. import FilterUserTooltip from '@/pages/weComTask/components/filterUser/filterUserTooltip';
  9. import { businessPlanData } from '@/pages/weComTask/page/businessPlan/create/const';
  10. import { ColumnsType } from 'antd/es/table';
  11. const { Text, Paragraph } = Typography;
  12. /**
  13. * 进群对象新建组件
  14. * @param param0
  15. * @returns
  16. */
  17. const AddGroupObject: React.FC<GROUP_CHAT_CREATE.AddGroupObjectProps> = ({ value = [], onChange, bookPlatForm, bookList }) => {
  18. /******************************************/
  19. const [visible, setVisible] = useState<boolean>(false)
  20. const [initialValues, setInitialValues] = useState<any>(undefined)
  21. /******************************************/
  22. return <>
  23. {value?.length > 0 ? <ShowGroupUserTable
  24. value={value}
  25. bookList={bookList}
  26. bookPlatForm={bookPlatForm}
  27. handleDelete={(id) => {
  28. onChange?.(value.filter((_, index) => index + 1 !== id))
  29. }}
  30. handleEdit={(record) => {
  31. setInitialValues(record)
  32. setVisible(true)
  33. }}
  34. /> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description='暂无群配置' />}
  35. <Button type="dashed" style={{ width: '100%' }} block icon={<PlusOutlined />} onClick={() => setVisible(true)}>新建群配置</Button>
  36. {visible && <AddGroupObjectModal
  37. visible={visible}
  38. initialValues={initialValues}
  39. onChange={(values) => {
  40. const newValue = JSON.parse(JSON.stringify(value))
  41. if (initialValues?.id) {
  42. newValue[initialValues.id - 1] = values
  43. } else {
  44. newValue.push(values)
  45. }
  46. onChange?.(newValue)
  47. setVisible(false)
  48. setInitialValues(undefined)
  49. }}
  50. onClose={() => {
  51. setVisible(false)
  52. setInitialValues(undefined)
  53. }}
  54. />}
  55. </>
  56. };
  57. export const ShowGroupUserTable: React.FC<GROUP_CHAT_CREATE.ShowGroupUserTableProps> = React.memo(({ bookList, bookPlatForm, value, handleEdit, handleDelete, isPreview }) => {
  58. const columns: ColumnsType<any> = [
  59. {
  60. title: '群配置名称',
  61. dataIndex: 'groupObjectName',
  62. key: 'groupObjectName',
  63. width: 120,
  64. ellipsis: true,
  65. fixed: 'left'
  66. },
  67. {
  68. title: '进群对象',
  69. dataIndex: 'externalUserFilter',
  70. key: 'externalUserFilter',
  71. width: 90,
  72. align: 'center',
  73. render(value) {
  74. return value ? <div style={{ display: 'flex', alignItems: 'center' }}>
  75. <div style={{ flex: '1 0', overflow: 'hidden' }}>
  76. <Text ellipsis>指定</Text>
  77. </div>
  78. <Popover
  79. placement="right"
  80. styles={{ body: { maxWidth: 350, maxHeight: 350, overflow: 'hidden', overflowY: 'auto' } }}
  81. mouseEnterDelay={0.5}
  82. content={<FilterUserTooltip
  83. bookCityList={bookPlatForm?.map(item => ({ label: item.platformName, value: item.platformKey }))}
  84. configName={value?.configName}
  85. data={value?.configContent}
  86. />}
  87. >
  88. <a style={{ color: '#000' }}><QuestionCircleFilled /></a>
  89. </Popover>
  90. </div> : '全部'
  91. },
  92. },
  93. {
  94. title: '群递增起始编号',
  95. dataIndex: 'groupIndex',
  96. key: 'groupIndex',
  97. width: 60,
  98. align: 'center'
  99. },
  100. {
  101. title: '群固定人数',
  102. dataIndex: 'groupUserCount',
  103. key: 'groupUserCount',
  104. width: 50,
  105. align: 'center'
  106. },
  107. {
  108. title: '邀请客户进群完毕后客服号是否退群',
  109. dataIndex: 'autoOutGroup',
  110. key: 'autoOutGroup',
  111. width: 85,
  112. align: 'center',
  113. render(value) {
  114. return value ? <span style={{ color: '#1890ff' }}>是</span> : <span style={{ color: 'red' }}>否</span>
  115. },
  116. },
  117. {
  118. title: '是否排除已在群的客户',
  119. dataIndex: 'excludeInGroup',
  120. key: 'excludeInGroup',
  121. width: 60,
  122. align: 'center',
  123. render(value) {
  124. return value ? <span style={{ color: '#1890ff' }}>是</span> : <span style={{ color: 'red' }}>否</span>
  125. },
  126. },
  127. {
  128. title: '拉群完成后自动删除拉群标签',
  129. dataIndex: 'excludeInGroup',
  130. key: 'excludeInGroup',
  131. width: 70,
  132. align: 'center',
  133. render(value) {
  134. return value ? <span style={{ color: '#1890ff' }}>是</span> : <span style={{ color: 'red' }}>否</span>
  135. },
  136. },
  137. {
  138. title: '群聊关联公众号',
  139. dataIndex: 'weChatAppid',
  140. key: 'weChatAppid',
  141. width: 100,
  142. align: 'center',
  143. ellipsis: true,
  144. render(value) {
  145. return value || '--'
  146. },
  147. },
  148. {
  149. title: '拉群完成后群聊备注',
  150. dataIndex: 'remark',
  151. key: 'remark',
  152. width: 140,
  153. ellipsis: true,
  154. render(value) {
  155. return value || '--'
  156. },
  157. },
  158. {
  159. title: '拉群完成后群聊智能标签',
  160. dataIndex: 'tagDTO',
  161. key: 'tagDTO',
  162. width: 200,
  163. ellipsis: true,
  164. render(value) {
  165. return value && Object.keys(value)?.length > 0 ?
  166. <Paragraph ellipsis style={{ margin: 0 }}>{Object.keys(value).map(key => {
  167. if (key === 'business' && value[key]) {
  168. return `业务(来源渠道):${businessPlanData.find(i => i.value === value.business)?.label || '<空>'}`
  169. } else if (key === 'bookCity' && value[key]) {
  170. return `书城(来源渠道):${bookPlatForm.find(i => i.id === value.bookCity)?.platformName || '<空>'}`
  171. } else if (key === 'product' && value[key]) {
  172. return `产品(来源渠道):${bookList.find(i => i.id === value.product)?.bookName || '<空>'}`
  173. }
  174. return ''
  175. }).join('、')}</Paragraph> : '--'
  176. },
  177. },
  178. {
  179. title: '建群成功发送内容',
  180. dataIndex: 'groupSendMsg',
  181. key: 'groupSendMsg',
  182. width: 140,
  183. ellipsis: true
  184. },
  185. {
  186. title: '操作',
  187. dataIndex: 'cz',
  188. key: 'cz',
  189. width: 75,
  190. fixed: 'right',
  191. align: 'center',
  192. render(_, record) {
  193. return <Space>
  194. <a onClick={() => {
  195. handleEdit?.(record)
  196. }}>修改</a>
  197. <a style={{ color: 'red' }} onClick={() => {
  198. handleDelete?.(record.id)
  199. }}>删除</a>
  200. </Space>
  201. },
  202. }
  203. ]
  204. if (isPreview) {
  205. columns.pop()
  206. }
  207. return <Table
  208. size='small'
  209. bordered
  210. rowKey={'id'}
  211. dataSource={value?.map((item, index) => ({ ...item, id: index + 1 }))}
  212. scroll={{ y: 1000 }}
  213. columns={columns}
  214. />
  215. })
  216. const AddGroupObjectModal: React.FC<GROUP_CHAT_CREATE.AddGroupObjectModalProps> = React.memo(({ visible, onChange, onClose, initialValues }) => {
  217. /******************************************/
  218. const { message } = App.useApp();
  219. const [form] = Form.useForm();
  220. const externalUserType = Form.useWatch('externalUserType', form);
  221. const getAccountList = useAjax(() => getAllWxListApi())
  222. /******************************************/
  223. useEffect(() => {
  224. getAccountList.run()
  225. }, [])
  226. const handleOk = () => {
  227. form.validateFields().then((values) => {
  228. console.log(values)
  229. onChange?.(values)
  230. }).catch(() => {
  231. form.submit()
  232. });
  233. }
  234. return <Modal
  235. title={<strong>{(initialValues && Object.keys(initialValues).length > 0) ? '修改' : '新建'}群配置</strong>}
  236. open={visible}
  237. onCancel={onClose}
  238. width={600}
  239. onOk={handleOk}
  240. styles={{ body: { maxHeight: 550, overflowY: 'auto' } }}
  241. >
  242. <Form
  243. form={form}
  244. name="addGroupUser"
  245. labelAlign='left'
  246. labelCol={{ span: 6 }}
  247. colon={false}
  248. labelWrap
  249. scrollToFirstError={{
  250. behavior: 'smooth',
  251. block: 'center'
  252. }}
  253. onFinishFailed={({ errorFields }) => {
  254. message.error(errorFields?.[0]?.errors?.[0])
  255. }}
  256. onFinish={handleOk}
  257. initialValues={(initialValues && Object.keys(initialValues).length > 0) ? initialValues : { externalUserType: 'all', groupIndex: 1, groupUserCount: 37, autoOutGroup: false, excludeInGroup: true, deleteGroupTag: true }}
  258. preserve={true}
  259. >
  260. <Form.Item
  261. name={'groupObjectName'}
  262. label={<strong>群配置名称</strong>}
  263. rules={[{ required: true, message: '请输入群配置名称!' }]}
  264. >
  265. <Input placeholder='请输入群配置名称' allowClear />
  266. </Form.Item>
  267. <Form.Item
  268. label={<strong>进群对象配置</strong>}
  269. required
  270. >
  271. <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
  272. <Form.Item
  273. name={'externalUserType'}
  274. rules={[{ required: true, message: '请选择转移对象!' }]}
  275. noStyle
  276. >
  277. <Radio.Group options={[{ label: '全部', value: 'all' }, { label: '指定', value: 'specify' }]} />
  278. </Form.Item>
  279. {externalUserType === 'specify' && <div style={{ marginTop: 8, width: '100%' }}>
  280. <Form.Item
  281. name={'externalUserFilter'}
  282. rules={[{ required: true, message: '请选择人群包!' }]}
  283. noStyle
  284. >
  285. <FilterUser configType={'USER_GROUP'} />
  286. </Form.Item>
  287. </div>}
  288. </div>
  289. </Form.Item>
  290. <Form.Item
  291. name={'groupIndex'}
  292. tooltip={{ title: `例如:起始编号为'1'群名为'测试群',再建群后群名为'测试群1'超出群人数的用户将分配到'测试群2'依次递增`, placement: 'top' }}
  293. label={<strong>群递增起始编号</strong>}
  294. rules={[{ required: true, message: '请输入群递增起始编号!' }]}
  295. >
  296. <InputNumber placeholder='请输入群递增起始编号' min={1} style={{ width: '100%' }} />
  297. </Form.Item>
  298. <Form.Item
  299. name={'groupUserCount'}
  300. tooltip={{ title: `不包括建群人和固定企微号,最大上限数量38`, placement: 'top' }}
  301. label={<strong>群固定人数</strong>}
  302. rules={[{ required: true, message: '请输入群固定人数!' }]}
  303. >
  304. <InputNumber placeholder='请输入群固定人数' max={38} min={1} style={{ width: '100%' }} />
  305. </Form.Item>
  306. <Form.Item
  307. name={'autoOutGroup'}
  308. label={<strong>邀请客户进群完毕后客服号是否退群</strong>}
  309. rules={[{ required: true, message: '请选择是否退群!' }]}
  310. >
  311. <Radio.Group>
  312. <Radio value={true}>是</Radio>
  313. <Radio value={false}>否</Radio>
  314. </Radio.Group>
  315. </Form.Item>
  316. <Form.Item
  317. name={'excludeInGroup'}
  318. label={<strong>是否排除已在群的客户</strong>}
  319. rules={[{ required: true, message: '请选择是否排除已在群的客户!' }]}
  320. >
  321. <Radio.Group>
  322. <Radio value={true}>是</Radio>
  323. </Radio.Group>
  324. </Form.Item>
  325. <Form.Item
  326. name={'deleteGroupTag'}
  327. label={<strong>拉群完成后自动删除拉群标签</strong>}
  328. rules={[{ required: true, message: '请选择拉群完成后自动删除拉群标签!' }]}
  329. >
  330. <Radio.Group>
  331. <Radio value={true}>是</Radio>
  332. </Radio.Group>
  333. </Form.Item>
  334. <Form.Item
  335. name={'weChatAppid'}
  336. label={<strong>群聊关联公众号</strong>}
  337. >
  338. <Select
  339. showSearch
  340. allowClear
  341. placeholder="选择公众号"
  342. filterOption={(input, option) =>
  343. (option?.label as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
  344. }
  345. options={getAccountList?.data?.data?.map(item => ({ label: item.name, value: item.name + '_' + item.appId }))}
  346. />
  347. </Form.Item>
  348. <Form.Item
  349. name={'remark'}
  350. label={<strong>拉群完成后群聊备注</strong>}
  351. >
  352. <Input.TextArea placeholder="请输入群聊备注" />
  353. </Form.Item>
  354. <Card title={<strong>拉群完成后群聊智能标签</strong>} style={{ background: '#fff', marginBottom: 10 }} styles={{ body: { padding: '6px 0 6px 16px' } }}>
  355. <Form.Item
  356. name={'tagDTO'}
  357. style={{ marginBottom: 0 }}
  358. >
  359. <MindTags />
  360. </Form.Item>
  361. </Card>
  362. <Form.Item
  363. name={'groupSendMsg'}
  364. label={<strong>建群成功发送内容</strong>}
  365. rules={[{ required: true, message: '请输入建群成功发送内容!' }]}
  366. >
  367. <Input.TextArea placeholder="请输入建群成功发送内容" />
  368. </Form.Item>
  369. </Form>
  370. </Modal>
  371. })
  372. export default React.memo(AddGroupObject);