material.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. import React, { forwardRef, Ref, useContext, useEffect, useImperativeHandle, useRef, useState } from "react"
  2. import style from './index.less'
  3. import { Breadcrumb, Button, Card, Checkbox, Dropdown, Pagination, Radio, Spin, Typography } from "antd"
  4. import { DispatchCloudNew } from "."
  5. import { getFolderListApi } from "@/services/adqV3/cloudNew"
  6. import { useAjax } from "@/Hook/useAjax"
  7. import { useSize } from "ahooks"
  8. import './global.less'
  9. import { useModel } from "umi"
  10. import { CheckboxValueType } from "antd/lib/checkbox/Group"
  11. import MoveFile from "./moveFile"
  12. import { ItemType } from "antd/lib/menu/hooks/useItems"
  13. import UploadFile from "./uploadFile"
  14. const { Text } = Typography;
  15. interface Props {
  16. /** 新增文件夹 */
  17. onAddFolder?: () => void
  18. onUpdateFolder?: (data: any) => void
  19. onDelFolder?: (id: number, name: string) => void
  20. }
  21. interface MaterialRef {
  22. folderRefresh: () => void
  23. }
  24. /**
  25. * 素材列表
  26. * @returns
  27. */
  28. const Material = forwardRef(({ onAddFolder, onUpdateFolder, onDelFolder }: Props, ref1: Ref<MaterialRef>) => {
  29. /********************************/
  30. const { initialState } = useModel('@@initialState');
  31. const { breadcrumdData, setSelectedKeys, setBreadcrumdData, selectedKeys, treeData, folderCreateBy, findParentKeys, loadedKeys, handleUpdateFolder, batchFolderVisible, setBatchFolderVisible, handleType, setHandleType } = useContext(DispatchCloudNew)!;
  32. const ref = useRef<HTMLDivElement>(null);
  33. const size = useSize(ref);
  34. const [folderList, setFolderList] = useState<{ id: number, folderName: string, createBy: number, description?: string }[]>([])
  35. const [rowNum, setRowNum] = useState<number>(0)
  36. const [checkedFolderList, setCheckedFolderList] = useState<CheckboxValueType[]>([])
  37. const [checkFolderAll, setCheckFolderAll] = useState<boolean>(false);
  38. const [indeterminateFolder, setIndeterminateFolder] = useState<boolean>(false);
  39. const [moveVisible, setMoveVisible] = useState<boolean>(false)
  40. const [moveType, setMoveType] = useState<'folder' | 'file'>('folder')
  41. const [checkedList, setCheckedList] = useState<CheckboxValueType[]>([])
  42. const [uploadVisible, setUploadVisible] = useState<boolean>(false)
  43. const getFolderList = useAjax((params) => getFolderListApi(params))
  44. /********************************/
  45. useImperativeHandle(ref1, () => ({
  46. // 刷新文件夹
  47. folderRefresh() {
  48. getFolder()
  49. }
  50. }));
  51. // 根据内容宽度计算列数
  52. useEffect(() => {
  53. if (size?.width) {
  54. let rowNum = Math.floor((size?.width - 26) / 200)
  55. setRowNum(rowNum || 1)
  56. }
  57. }, [size?.width])
  58. useEffect(() => {
  59. if (isShowFolder()) {
  60. // 文件夹
  61. getFolder()
  62. } else {
  63. // 文件
  64. }
  65. }, [selectedKeys, handleType])
  66. /** 获取下级文件夹 */
  67. const getFolder = () => {
  68. let parentId: number | undefined;
  69. if (selectedKeys?.length) {
  70. const parentIdArr = (selectedKeys[0] as string).split('-')
  71. const parentIdArrLength = parentIdArr.length
  72. parentId = Number(parentIdArr[parentIdArrLength - 1])
  73. }
  74. getFolderList.run({ parentId }).then(res => {
  75. setFolderList(() => res || [])
  76. })
  77. }
  78. // 文件夹选择
  79. const onCheckboxChange = (checkedValues: CheckboxValueType[]) => {
  80. setCheckedFolderList(checkedValues)
  81. setIndeterminateFolder(!!checkedValues.length && checkedValues.length < folderList.length);
  82. setCheckFolderAll(checkedValues.length === folderList.length);
  83. };
  84. // 取消选择
  85. const cancelSelect = () => {
  86. setCheckFolderAll(false)
  87. setCheckedFolderList([])
  88. setIndeterminateFolder(false)
  89. setCheckedList([])
  90. }
  91. // 是否管理员
  92. const isAdmin = () => {
  93. return ['999'].includes(initialState?.currentUser?.powerLevel?.toString() || '')
  94. }
  95. // 是否有权限
  96. const isPermission = (createBy: any) => {
  97. return initialState?.currentUser?.userId?.toString() === createBy.toString()
  98. }
  99. const getItems = (item: any) => {
  100. let data: ItemType[] = []
  101. if (isPermission(item.createBy)) {
  102. data.push({ label: '编辑', style: { fontSize: 12 }, key: 'edit', onClick: () => onUpdateFolder?.(item) })
  103. if (!!selectedKeys?.[0]) {
  104. data.push({
  105. label: '移动', style: { fontSize: 12 }, key: 'move', onClick: () => {
  106. setCheckedList([item.id])
  107. setMoveType('folder')
  108. setMoveVisible(true)
  109. }
  110. })
  111. } else if (isAdmin()) {
  112. data.push({
  113. label: '修改文件夹所属人', style: { fontSize: 12 }, key: 'createBy', onClick: () => {
  114. }
  115. })
  116. }
  117. data.push({ label: <span style={{ color: 'red', fontSize: 12 }}>删除</span>, key: 'del', onClick: () => onDelFolder?.(item.id, item?.folderName) })
  118. } else {
  119. if (isAdmin() && !selectedKeys?.[0]) {
  120. data.push({
  121. label: '修改文件夹所属人', style: { fontSize: 12 }, key: 'createBy', onClick: () => {
  122. }
  123. })
  124. }
  125. }
  126. return data
  127. }
  128. // 是否展示文件夹
  129. const isShowFolder = () => {
  130. return !selectedKeys?.[0] || handleType === 'folder'
  131. }
  132. return <div className={style.material}>
  133. <div className={style.operates}>
  134. <div className={style.left_bts}>
  135. {!!selectedKeys?.[0] && <Checkbox
  136. onChange={(e) => {
  137. setHandleType(e.target.checked ? 'folder' : 'file')
  138. }}
  139. checked={handleType === 'folder'}
  140. ><span style={{ fontSize: 12 }}>是否操作文件夹</span></Checkbox>}
  141. {(!selectedKeys?.[0] || handleType === 'folder') && <Button onClick={() => onAddFolder?.()} disabled={folderCreateBy ? !isPermission(folderCreateBy) : false}>新建文件夹</Button>}
  142. {handleType === 'folder' ? <>
  143. {!!selectedKeys?.[0] && <Button onClick={() => setBatchFolderVisible(true)} disabled={folderCreateBy ? !isPermission(folderCreateBy) : false}>批量操作文件夹</Button>}
  144. </> : <>
  145. {!!selectedKeys?.[0] && <Button type="primary" disabled={folderCreateBy ? !isPermission(folderCreateBy) : false} onClick={() => setUploadVisible(true)}>上传素材</Button>}
  146. </>}
  147. </div>
  148. </div>
  149. {batchFolderVisible ? <div className={style.operates}>
  150. <div className={style.left_bts}>
  151. <Checkbox onChange={(e) => {
  152. setCheckedFolderList(e.target.checked ? folderList.map(item => item.id) : [])
  153. setIndeterminateFolder(false)
  154. setCheckFolderAll(e.target.checked)
  155. }} indeterminate={indeterminateFolder} checked={checkFolderAll}>全选</Checkbox>
  156. <span style={{ color: '#1890FF' }}>已选{checkedFolderList?.length || 0}个文件夹</span>
  157. </div>
  158. <div className={style.left_bts}>
  159. <Button disabled={checkedFolderList?.length === 0} onClick={() => {
  160. setCheckedList(checkedFolderList)
  161. setMoveVisible(true)
  162. setMoveType('folder')
  163. }}>移动文件夹</Button>
  164. <Button type="primary" onClick={() => {
  165. setBatchFolderVisible(false)
  166. }}>完成</Button>
  167. </div>
  168. </div> : <div className={style.operates}>
  169. <Breadcrumb>
  170. {breadcrumdData.map((item, index) => <Breadcrumb.Item key={item.key}>
  171. {breadcrumdData.length !== index + 1 ? <a
  172. style={{ color: '#1890ff' }}
  173. onClick={() => {
  174. setBreadcrumdData(data => data.splice(0, index + 1))
  175. setSelectedKeys(item.currentKey === '0' ? [] : [item.currentKey])
  176. }}
  177. >{item.label}</a> : item.label}
  178. </Breadcrumb.Item>)}
  179. </Breadcrumb>
  180. </div>}
  181. <div className={`${style.content} content_global`}>
  182. <Spin spinning={getFolderList.loading}>
  183. <div className={style.content_scroll} ref={ref}>
  184. <Checkbox.Group value={checkedFolderList} style={{ width: '100%' }} onChange={onCheckboxChange}>
  185. <div className={style.content_scroll_div}>
  186. {isShowFolder() ? folderList.map((item, index) => <div key={index} className={style.content_row} style={{ width: rowNum ? (1 / rowNum * 100) + '%' : 200 }}>
  187. <Card
  188. hoverable
  189. bodyStyle={{ padding: 0 }}
  190. className={`${style.content_col}`}
  191. cover={<div style={{ height: 120 }} className={style.content_cover}>
  192. {batchFolderVisible && <div className={style.checkbox}><Checkbox value={item.id} /></div>}
  193. <img src={require('../../../../../public/file.png')} height={'100%'} alt="" />
  194. </div>}
  195. onDoubleClick={() => {
  196. if (!batchFolderVisible) {
  197. let newExpandedKeys = '0-' + item.id
  198. if (selectedKeys?.[0]) {
  199. newExpandedKeys = selectedKeys[0] + '-' + item.id
  200. }
  201. findParentKeys(newExpandedKeys, treeData)
  202. setSelectedKeys([newExpandedKeys])
  203. // 判断是否加载了下级文件 加载了 就不更新
  204. if (!loadedKeys.includes(newExpandedKeys))
  205. handleUpdateFolder(newExpandedKeys)
  206. }
  207. }}
  208. >
  209. <div className={style.body}>
  210. <Text ellipsis>{item?.folderName}</Text>
  211. </div>
  212. <div className={style.actions}>
  213. <div style={{ height: 22 }}></div>
  214. {isPermission(item.createBy) || (!selectedKeys?.[0] && isAdmin()) ? <Dropdown menu={{
  215. items: getItems(item)
  216. }}>
  217. <a onClick={e => e.preventDefault()} style={{ fontSize: 11 }}>更多</a>
  218. </Dropdown> : <a style={{ fontSize: 11 }}>无权限操作</a>}
  219. </div>
  220. </Card>
  221. </div>) : <>
  222. 素材
  223. </>}
  224. </div>
  225. </Checkbox.Group>
  226. </div>
  227. </Spin>
  228. </div>
  229. {handleType === 'file' && <div className={style.fotter}>
  230. <Pagination size="small" total={50} showSizeChanger showQuickJumper />
  231. </div>}
  232. {/* 移动文件 */}
  233. {moveVisible && <MoveFile
  234. moveType={moveType}
  235. checkedList={checkedList}
  236. userId={initialState?.currentUser?.userId?.toString() || ''}
  237. visible={moveVisible}
  238. onClose={() => {
  239. setMoveVisible(false)
  240. cancelSelect()
  241. }}
  242. onChange={(selectedKey: string) => {
  243. getFolder()
  244. setMoveVisible(false)
  245. cancelSelect()
  246. handleUpdateFolder(selectedKeys[0] as string)
  247. if (loadedKeys.includes(selectedKey)) {
  248. handleUpdateFolder(selectedKey)
  249. }
  250. setBatchFolderVisible(false)
  251. }}
  252. />}
  253. {/* 上传文件 */}
  254. {uploadVisible && <UploadFile
  255. visible={uploadVisible}
  256. onChange={() => {
  257. }}
  258. onClose={() => {
  259. setUploadVisible(false)
  260. }}
  261. />}
  262. </div>
  263. })
  264. export default React.memo(Material)