index.tsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. import React, { useCallback, useEffect, useRef, useState } from 'react';
  2. import style from '../../corpUserManage/index.less'
  3. import { App, Button, Card, DatePicker, Drawer, Input, Pagination, Popconfirm, Select, Space, Table, Tabs, Tag, Typography } from 'antd';
  4. import { MenuUnfoldOutlined, MenuFoldOutlined, SearchOutlined } from '@ant-design/icons';
  5. import { useAjax } from '@/Hook/useAjax';
  6. import { api_corpUser_allOfUser, getAdAccountAllOfMember } from '@/API/global';
  7. import TeamMembers from '@/components/Team/teamMembers';
  8. import SearchBox from '@/pages/weComTask/components/searchBox';
  9. import { ApiParamsChatListProps, disbandChatApi, getGroupChatCountApi, getGroupChatListApi } from '@/pages/weComTask/API/global';
  10. import { useSize } from 'ahooks';
  11. import { TableConfig } from './tableConfig';
  12. import UserContent from './userContent';
  13. import RemarkSet from './remarkSet';
  14. import DisbandChatLog from './disbandChatLog';
  15. import ZpMp from './zpMp';
  16. import ChatLog from './chatLog';
  17. import { getBindMpListApi } from '@/pages/weComTask/API/corpUserAssign';
  18. const { Title } = Typography;
  19. const WeAssociationList: React.FC = () => {
  20. /************************************/
  21. const { message } = App.useApp()
  22. const ref = useRef<HTMLDivElement>(null)
  23. const size = useSize(ref)
  24. const [activeKey, setActiveKey] = useState<string>('1')
  25. const [showLeft, setShowLeft] = useState<boolean>(false)
  26. const userIdStr = sessionStorage.getItem('userId');
  27. const [userId, setUserId] = useState<number>(userIdStr ? Number(userIdStr) : undefined);
  28. const [listData, setListData] = useState<ApiParamsChatListProps>({
  29. pageNum: 1,
  30. pageSize: 20
  31. })
  32. const [userQuerys, setUserQuerys] = useState<{
  33. numArr: Array<number | undefined>,
  34. value: number | null,
  35. options: { value: number, label: string }[]
  36. }>({
  37. numArr: [0, 100],
  38. value: null,
  39. options: []
  40. })
  41. const [open, setOpen] = useState(false)
  42. const [activeCorp, setActiveCorp] = useState<any>()
  43. const [editSelectedRow, setEditSelectedRow] = useState<any[]>([])
  44. const [userData, setUserData] = useState<any>()
  45. const [remarkVisible, setRemarkVisible] = useState<boolean>(false)
  46. const [zpVisible, setZpVisible] = useState<boolean>(false)
  47. const [chatLogData, setChatLogData] = useState<{ visible: boolean, chatData: any }>();
  48. const corpUser_allOfUser = useAjax((params) => api_corpUser_allOfUser(params))
  49. const getGroupChatList = useAjax((params) => getGroupChatListApi(params))
  50. const getGroupChatCount = useAjax((params) => getGroupChatCountApi(params))
  51. const allOfMember = useAjax(() => getAdAccountAllOfMember())
  52. const disbandChat = useAjax((params) => disbandChatApi(params))
  53. const getBindMpList = useAjax(() => getBindMpListApi())
  54. /************************************/
  55. useEffect(() => {
  56. allOfMember.run()
  57. getBindMpList.run()
  58. }, [])
  59. useEffect(() => {
  60. if (userId) {
  61. corpUser_allOfUser.run(userId).then(res => {
  62. setActiveCorp(res?.data?.[0])
  63. setListData({ ...listData, corpId: res?.data?.[0]?.t1?.corpId, pageNum: 1 })
  64. })
  65. }
  66. }, [userId])
  67. // 初始请求
  68. useEffect(() => {
  69. if (listData.corpId) {
  70. getList()
  71. } else if (getGroupChatList?.data) {
  72. getGroupChatList.mutate({ data: { records: [], size: 20, total: 0, pages: 0, current: 1 } })
  73. getGroupChatCount.mutate({ data: {} })
  74. }
  75. }, [listData])
  76. //搜索事件
  77. const getList = () => {
  78. getGroupChatList.run({ ...listData })
  79. getGroupChatCount.run({ ...listData })
  80. }
  81. // 人数输入确定
  82. const setNum = useCallback(() => {
  83. let options = [
  84. { value: 1, label: `最小${userQuerys.numArr[0]}人` + '~' + `最大${userQuerys.numArr[1]}人` }
  85. ]
  86. setUserQuerys({
  87. ...userQuerys,
  88. value: 1,
  89. options
  90. })
  91. setListData({ ...listData, userCountMin: userQuerys.numArr[0], userCountMax: userQuerys.numArr[1], })
  92. setOpen(false)
  93. }, [userQuerys, listData])
  94. //查看客户
  95. const lockUsers = (data: any) => {
  96. setUserData(data)
  97. }
  98. // 解散群聊
  99. const disbandChatHandle = () => {
  100. disbandChat.run({ chatIdList: editSelectedRow.map(item => item.chatId), corpId: listData.corpId }).then(res => {
  101. if (res?.data) {
  102. message.success('任务提交成功')
  103. getGroupChatList.refresh()
  104. }
  105. })
  106. }
  107. const handleChatLog = (d: any) => {
  108. setChatLogData({ visible: true, chatData: d });
  109. }
  110. return <div className={style.corpUserManage}>
  111. <Tabs
  112. tabBarStyle={{ marginBottom: 1 }}
  113. activeKey={activeKey}
  114. type="card"
  115. onChange={(activeKey) => {
  116. if (activeKey !== 'contract') {
  117. if (activeKey === '1') {
  118. setUserId(Number(userIdStr));
  119. }
  120. setActiveKey(activeKey)
  121. } else {
  122. setShowLeft(!showLeft)
  123. }
  124. }}
  125. items={[{ label: '我的', key: '1' }, { label: '组员', key: '2' }, { label: showLeft ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />, key: 'contract' }]}
  126. />
  127. <div className={style.corpUserManage_bottom}>
  128. {!showLeft && activeKey === '2' && <TeamMembers
  129. allOfMember={allOfMember}
  130. onChange={(putUserId) => {
  131. setUserId(putUserId);
  132. }}
  133. value={userId}
  134. />}
  135. <Card className={style.corpUserList} styles={{ body: { padding: 0, display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' } }}>
  136. <SearchBox
  137. bodyPadding={`16px 16px 12px`}
  138. buttons={<>
  139. <Button type="primary" onClick={() => getList()} icon={<SearchOutlined />}>搜索</Button>
  140. <Button onClick={() => setRemarkVisible(true)} disabled={editSelectedRow.length === 0} type="primary">添加备注</Button>
  141. <Popconfirm
  142. title="确定解散群聊?"
  143. onConfirm={disbandChatHandle}
  144. disabled={editSelectedRow.length === 0}
  145. >
  146. <Button disabled={editSelectedRow.length === 0} loading={disbandChat.loading} danger type="primary">解散群聊</Button>
  147. </Popconfirm>
  148. <DisbandChatLog corpId={listData.corpId} />
  149. <Button onClick={() => setZpVisible(true)} disabled={editSelectedRow.length === 0} type="primary">指派公众号</Button>
  150. </>}
  151. >
  152. <>
  153. <Select
  154. style={{ width: 180 }}
  155. placeholder="选择企业"
  156. value={listData?.corpId}
  157. showSearch
  158. maxTagCount={1}
  159. onChange={(e, option: any) => {
  160. setListData({ ...listData, corpId: e, pageNum: 1 })
  161. setActiveCorp(option?.data)
  162. }}
  163. filterOption={(input: string, option?: { label: string; value: string }) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
  164. options={corpUser_allOfUser?.data?.data?.map((item: { t1: any }) => ({ label: item.t1?.corpName, value: item.t1?.corpId, data: item }))}
  165. />
  166. <Input placeholder="群名称"
  167. allowClear
  168. style={{ maxWidth: 150 }}
  169. onChange={(e) => {
  170. let v = e.target.value
  171. setListData({ ...listData, chatName: v })
  172. }}
  173. />
  174. <Select
  175. style={{ minWidth: 150 }}
  176. placeholder="选择群主"
  177. value={listData?.corpUserId}
  178. showSearch
  179. allowClear
  180. mode="multiple"
  181. maxTagCount={1}
  182. onChange={(e) => {
  183. setListData({ ...listData, corpUserId: e, pageNum: 1 })
  184. }}
  185. filterOption={(input: string, option?: { label: string; value: string }) =>
  186. (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
  187. options={activeCorp?.t2?.map((item: { name: any; corpUserId: any }) => ({ label: item.name, value: item.corpUserId }))}
  188. />
  189. <DatePicker.RangePicker placeholder={['建群开始日期', '建群结束日期']} allowClear onChange={(dates, dateStrings) => {
  190. console.log(dateStrings)
  191. setListData({ ...listData, createTimeStart: dateStrings[0], createTimeEnd: dateStrings[1] })
  192. }} />
  193. <Select
  194. style={{ width: 200 }}
  195. placeholder='群人数'
  196. value={userQuerys.value}
  197. options={userQuerys.options}
  198. allowClear
  199. onChange={(value) => {
  200. if (!value) {
  201. setUserQuerys({
  202. numArr: [0, 100],
  203. value: null,
  204. options: []
  205. })
  206. let { userCountMin, userCountMax, ...newObj } = listData
  207. setListData(newObj)
  208. }
  209. console.log(value)
  210. }}
  211. open={open}
  212. onDropdownVisibleChange={(open) => {
  213. setOpen(open)
  214. }}
  215. dropdownRender={() => {
  216. return <div >
  217. <div style={{ display: 'flex', flexFlow: 'row', alignItems: 'center' }}>
  218. <Input placeholder="最小人数" allowClear value={userQuerys.numArr[0]} onChange={(e) => {
  219. let value = e.target.value
  220. if (!isNaN(Number(value)) && !value.includes('.')) {
  221. console.log(11111)
  222. let newArr = userQuerys.numArr
  223. newArr[0] = Number(value)
  224. setUserQuerys({ ...userQuerys, numArr: newArr })
  225. }
  226. }} />~<Input placeholder="最大人数" allowClear value={userQuerys.numArr[1]} onChange={(e) => {
  227. let value = e.target.value
  228. if (!isNaN(Number(value)) && !value.includes('.')) {
  229. let newArr = userQuerys.numArr
  230. newArr[1] = Number(value)
  231. setUserQuerys({ ...userQuerys, numArr: newArr })
  232. }
  233. }} />
  234. </div>
  235. <Button style={{ width: '100%', marginTop: 5 }} type='primary' onClick={setNum}>确定</Button>
  236. </div>
  237. }}
  238. />
  239. <Input placeholder="群备注"
  240. allowClear
  241. style={{ maxWidth: 150 }}
  242. onChange={(e) => {
  243. let v = e.target.value
  244. setListData({ ...listData, remark: v })
  245. }}
  246. />
  247. <Select
  248. style={{ width: 180 }}
  249. placeholder="公众号绑定状态查询"
  250. value={listData?.mpAccountIdIsNull}
  251. showSearch
  252. allowClear
  253. disabled={!!listData?.mpAccountId}
  254. onChange={(e) => {
  255. setListData({ ...listData, mpAccountIdIsNull: e, mpAccountId: undefined, pageNum: 1 })
  256. }}
  257. filterOption={(input: string, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
  258. options={[{ label: '查询所有群聊', value: false }, { label: '查询没有绑定公众号群聊', value: true }]}
  259. />
  260. <Select
  261. style={{ width: 180 }}
  262. placeholder="公众号"
  263. value={listData?.mpAccountId}
  264. showSearch
  265. allowClear
  266. disabled={(listData?.mpAccountIdIsNull === false || listData?.mpAccountIdIsNull === true)}
  267. onChange={(e) => {
  268. setListData({ ...listData, mpAccountId: e, mpAccountIdIsNull: undefined, pageNum: 1 })
  269. }}
  270. filterOption={(input: string, option: any) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
  271. options={getBindMpList?.data?.data?.map((item: any) => ({ label: item.name, value: item.id }))}
  272. />
  273. <Select
  274. style={{ width: 200 }}
  275. placeholder="是否新企微运营系统创建的群聊"
  276. value={listData?.newCorpGroupChat}
  277. showSearch
  278. allowClear
  279. onChange={(e) => {
  280. setListData({ ...listData, newCorpGroupChat: e, pageNum: 1 })
  281. }}
  282. filterOption={(input: string, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
  283. options={[{ label: '否', value: false }, { label: '是', value: true }]}
  284. />
  285. </>
  286. </SearchBox>
  287. <div className={style.corpUserList_table} ref={ref}>
  288. <Table
  289. style={{ marginBottom: 1 }}
  290. dataSource={getGroupChatList?.data?.data?.records}
  291. loading={getGroupChatList?.loading}
  292. columns={TableConfig(lockUsers, handleChatLog)}
  293. scroll={{ y: size?.height && ref.current ? size?.height - ref.current.querySelector('.ant-table-thead').clientHeight : 300 }}
  294. rowKey={'id'}
  295. bordered
  296. pagination={false}
  297. size='small'
  298. rowSelection={{
  299. type: 'checkbox',
  300. selectedRowKeys: editSelectedRow?.map(item => item.id),
  301. getCheckboxProps: (record: any) => ({
  302. name: record.name,
  303. }),
  304. onSelect: (record, selected) => {
  305. if (selected) {
  306. setEditSelectedRow([...editSelectedRow, record])
  307. } else {
  308. setEditSelectedRow(editSelectedRow?.filter(item => item.id !== record.id))
  309. }
  310. },
  311. onSelectAll: (selected, rows, changeRows) => {
  312. if (selected) {
  313. setEditSelectedRow([...editSelectedRow, ...changeRows])
  314. } else {
  315. let newArr = editSelectedRow?.filter(item => changeRows.every(i => i?.id !== item?.id))
  316. setEditSelectedRow(newArr)
  317. }
  318. }
  319. }}
  320. />
  321. </div>
  322. <div className={style.corpUserList_footer}>
  323. <Space size={40}>
  324. <Title level={4} style={{ margin: 0 }}>群总数:{getGroupChatCount.data?.data?.groupChatCount || 0}</Title>
  325. <Title level={4} style={{ margin: 0 }}>群成员总数:{getGroupChatCount.data?.data?.groupChatUserCount || 0}</Title>
  326. </Space>
  327. </div>
  328. <div className={style.corpUserList_footer}>
  329. <Pagination
  330. size="small"
  331. total={getGroupChatList?.data?.data?.total || 0}
  332. showSizeChanger
  333. showQuickJumper
  334. pageSize={getGroupChatList?.data?.data?.size || 20}
  335. current={getGroupChatList?.data?.data?.current || 1}
  336. onChange={(page: number, pageSize: number) => {
  337. ref.current?.scrollTo({ top: 0 })
  338. setListData({ ...listData, pageNum: page, pageSize })
  339. }}
  340. showTotal={(total: number) => <span style={{ fontSize: 12 }}>共 {total} 条</span>}
  341. />
  342. </div>
  343. </Card>
  344. </div>
  345. {/* 设置备注弹窗 */}
  346. {remarkVisible && <RemarkSet
  347. corpId={listData.corpId}
  348. listData={listData}
  349. editSelectedRow={editSelectedRow}
  350. visible={remarkVisible}
  351. onClose={() => {
  352. setRemarkVisible(false)
  353. }}
  354. onChange={() => {
  355. setEditSelectedRow([])
  356. setRemarkVisible(false)
  357. getGroupChatList.refresh()
  358. }}
  359. />}
  360. {/* 客户列表弹窗 */}
  361. <Drawer
  362. title={userData?.chatName + '--成员列表'}
  363. placement="right"
  364. width='80%'
  365. onClose={() => { setUserData(null) }}
  366. open={userData}
  367. >
  368. <UserContent userData={userData} />
  369. </Drawer>
  370. {/* 指派公众号 */}
  371. {zpVisible && <ZpMp
  372. corpId={listData.corpId}
  373. visible={zpVisible}
  374. onClose={() => setZpVisible(false)}
  375. editSelectedRow={editSelectedRow}
  376. onChange={() => {
  377. setEditSelectedRow([])
  378. setZpVisible(false)
  379. getGroupChatList.refresh()
  380. }}
  381. />}
  382. {/* 变更记录 */}
  383. {chatLogData?.visible && <ChatLog
  384. {...chatLogData}
  385. corpId={listData.corpId}
  386. onClose={() => setChatLogData(undefined)}
  387. />}
  388. </div>;
  389. };
  390. export default WeAssociationList;