123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- import React, { forwardRef, Ref, useContext, useEffect, useImperativeHandle, useRef, useState } from "react"
- import style from './index.less'
- import { Breadcrumb, Button, Card, Checkbox, Dropdown, Empty, message, Modal, Pagination, Popconfirm, Radio, Spin, Typography } from "antd"
- import { DispatchCloudNew } from "."
- import { deleteBatchApi, delMaterialApi, getFolderListApi, getMaterialListApi } from "@/services/adqV3/cloudNew"
- import { useAjax } from "@/Hook/useAjax"
- import { useSize } from "ahooks"
- import './global.less'
- import { useModel } from "umi"
- import { CheckboxValueType } from "antd/lib/checkbox/Group"
- import MoveFile from "./moveFile"
- import { ItemType } from "antd/lib/menu/hooks/useItems"
- import UploadFile from "./uploadFile"
- import UpdateCreate from "./updateCreate"
- import { formatSecondsToTime, getVideoImgUrl } from "@/utils/utils"
- import { ExclamationCircleOutlined } from "@ant-design/icons"
- import UpdateFile from "./updateFile"
- import Details from "./details"
- import useFileDrop from "@/Hook/useFileDrop"
- import UploadsTable from "./uploadsTable"
- const { Text } = Typography;
- interface Props {
- /** 新增文件夹 */
- onAddFolder?: () => void
- onUpdateFolder?: (data: any) => void
- onDelFolder?: (id: number, name: string) => void
- }
- interface MaterialRef {
- folderRefresh: () => void
- search: (value: {
- searchType: "file" | "folder";
- keyword?: string;
- }) => void
- }
- /**
- * 素材列表
- * @returns
- */
- const Material = forwardRef(({ onAddFolder, onUpdateFolder, onDelFolder }: Props, ref1: Ref<MaterialRef>) => {
- /********************************/
- const { initialState } = useModel('@@initialState');
- const { breadcrumdData, setSelectedKeys, setBreadcrumdData, setMaterialParams, materialParams, selectedKeys, treeData, folderCreateBy, findParentKeys, loadedKeys, handleUpdateFolder, batchFolderVisible, setBatchFolderVisible, handleType, setHandleType } = useContext(DispatchCloudNew)!;
- const ref = useRef<HTMLDivElement>(null);
- const size = useSize(ref);
- const [folderList, setFolderList] = useState<{ id: number, folderName: string, createBy: number, description?: string }[]>([])
- const [rowNum, setRowNum] = useState<number>(0)
- const [checkedFolderList, setCheckedFolderList] = useState<CheckboxValueType[]>([])
- const [checkFolderAll, setCheckFolderAll] = useState<boolean>(false);
- const [indeterminateFolder, setIndeterminateFolder] = useState<boolean>(false);
- const [moveVisible, setMoveVisible] = useState<boolean>(false)
- const [moveType, setMoveType] = useState<'folder' | 'file'>('folder')
- const [batchType, setBatchType] = useState<'folder' | 'file'>()
- const [checkedList, setCheckedList] = useState<CheckboxValueType[]>([])
- const [uploadVisible, setUploadVisible] = useState<boolean>(false)
- const [updateOwnerData, setUpdateOwnerData] = useState<{ visible?: boolean, folderId: number }>({ folderId: 0 })
- const [updateFileData, setUpdateFileData] = useState<{ visible?: boolean, initialValues: any }>({ visible: false, initialValues: {} })
- const [detailsData, setDetailsData] = useState<{ visible?: boolean, data: any }>({ visible: false, data: {} })
- const getFolderList = useAjax((params) => getFolderListApi(params))
- const delMaterial = useAjax((params) => delMaterialApi(params))
- const deleteBatch = useAjax((params) => deleteBatchApi(params))
- const getMaterialList = useAjax((params) => getMaterialListApi(params))
- /********************************/
- useImperativeHandle(ref1, () => ({
- // 刷新文件夹
- folderRefresh() {
- getFolder()
- },
- search(value) {
- setHandleType('file')
- setMaterialParams(data => ({ ...data, ...value, pageNum: 1 }))
- }
- }));
- // 根据内容宽度计算列数
- useEffect(() => {
- if (size?.width) {
- let rowNum = Math.floor((size?.width - 26) / 200)
- setRowNum(rowNum || 1)
- }
- }, [size?.width])
- useEffect(() => {
- cancelSelect()
- if (isShowFolder()) {
- // 文件夹
- getFolder()
- } else {
- // 文件
- getFile()
- }
- }, [selectedKeys, handleType, materialParams])
- /** 获取下级文件夹 */
- const getFolder = () => {
- let parentId: number | undefined;
- if (selectedKeys?.length) {
- const parentIdArr = (selectedKeys[0] as string).split('-')
- const parentIdArrLength = parentIdArr.length
- parentId = Number(parentIdArr[parentIdArrLength - 1])
- }
- getFolderList.run({ parentId }).then(res => {
- setFolderList(() => res || [])
- })
- }
- // 搜索素材
- const getFile = () => {
- let parentId: number | undefined;
- if (selectedKeys?.length) {
- const parentIdArr = (selectedKeys[0] as string).split('-')
- const parentIdArrLength = parentIdArr.length
- parentId = Number(parentIdArr[parentIdArrLength - 1])
- }
- let params = JSON.parse(JSON.stringify(materialParams))
- if (params?.width || params?.height) {
- params.sizeQueries = [{ width: params?.width, height: params?.height, relation: '=' }]
- delete params?.width
- delete params?.height
- } else {
- delete params?.sizeQueries
- }
- getMaterialList.run({ ...params, folderId: parentId })
- }
- // 文件夹选择
- const onCheckboxChange = (checkedValues: CheckboxValueType[]) => {
- let data: any[] = []
- if (batchType === 'folder') {
- data = folderList
- } else {
- data = getMaterialList?.data?.records || []
- }
- setCheckedFolderList(checkedValues)
- setIndeterminateFolder(!!checkedValues.length && checkedValues.length < data.length);
- setCheckFolderAll(checkedValues.length === data.length);
- };
- // 取消选择
- const cancelSelect = () => {
- setCheckFolderAll(false)
- setCheckedFolderList([])
- setIndeterminateFolder(false)
- setCheckedList([])
- }
- // 是否管理员
- const isAdmin = () => {
- return ['999'].includes(initialState?.currentUser?.powerLevel?.toString() || '')
- }
- // 是否有权限
- const isPermission = (createBy: any) => {
- return initialState?.currentUser?.userId?.toString() === createBy.toString()
- }
- // 文件夹更多
- const getItems = (item: any) => {
- let data: ItemType[] = []
- if (isPermission(item.createBy)) {
- data.push({ label: '编辑', style: { fontSize: 12 }, key: 'edit', onClick: () => onUpdateFolder?.(item) })
- if (!!selectedKeys?.[0]) {
- data.push({
- label: '移动', style: { fontSize: 12 }, key: 'move', onClick: () => {
- setCheckedList([item.id])
- setMoveType('folder')
- setMoveVisible(true)
- }
- })
- } else if (isAdmin()) {
- data.push({
- label: '修改文件夹所属人', style: { fontSize: 12 }, key: 'createBy', onClick: () => {
- setUpdateOwnerData({ visible: true, folderId: item.id })
- }
- })
- }
- data.push({ label: <span style={{ color: 'red', fontSize: 12 }}>删除</span>, key: 'del', onClick: () => onDelFolder?.(item.id, item?.folderName) })
- } else {
- if (isAdmin() && !selectedKeys?.[0]) {
- data.push({
- label: '修改文件夹所属人', style: { fontSize: 12 }, key: 'createBy', onClick: () => {
- setUpdateOwnerData({ visible: true, folderId: item.id })
- }
- })
- }
- }
- return data
- }
- // 删除素材
- const delFile = (id: number, name: string) => {
- Modal.confirm({
- title: <strong>{`删除素材“${name}”`}</strong>,
- icon: <ExclamationCircleOutlined />,
- content: '是否确定删除该素材',
- okText: '确认',
- cancelText: '取消',
- className: 'modalResetCss',
- onOk: () => {
- return new Promise((resolve: (value: unknown) => void) => {
- delMaterial.run(id).then(res => {
- if (res) {
- message.success('删除成功');
- getMaterialList.refresh()
- resolve('')
- }
- })
- })
- }
- });
- }
- // 操作素材 更多
- const getItemsFile = (item: any) => {
- let data: ItemType[] = []
- if (isPermission(item.createBy)) {
- data.push({
- label: <div onClick={(e) => {
- e.stopPropagation()
- e.preventDefault()
- setUpdateFileData({ visible: true, initialValues: item })
- }}>编辑</div>, style: { fontSize: 12 }, key: 'edit'
- })
- if (!!selectedKeys?.[0]) {
- data.push({
- label: <div onClick={(e) => {
- e.stopPropagation()
- e.preventDefault()
- setCheckedList([item.id])
- setMoveType('file')
- setMoveVisible(true)
- }}>移动</div>, style: { fontSize: 12 }, key: 'move'
- })
- }
- data.push({
- label: <div style={{ color: 'red', fontSize: 12 }} onClick={(e) => {
- e.stopPropagation()
- e.preventDefault()
- delFile(item.id, item?.materialName)
- }}>删除</div>, key: 'del'
- })
- }
- return data
- }
- // 是否展示文件夹
- const isShowFolder = () => {
- return handleType === 'folder'
- }
- // 获取拖拽的文件
- const [fileList, setFileList] = useState<FileList>()
- const [uploadsVisible, setUploadsVisible] = useState<boolean>(false)
- const { isDragOver, dropAreaProps } = useFileDrop((fileList) => {
- console.log('fileList--->', fileList)
- setFileList(fileList)
- setUploadsVisible(true)
- });
- return <div className={style.material}>
- <div className={style.operates}>
- <div className={style.left_bts}>
- <Checkbox
- onChange={(e) => {
- setHandleType(e.target.checked ? 'folder' : 'file')
- setMaterialParams({ pageNum: 1, pageSize: 30 })
- setBatchFolderVisible(false)
- cancelSelect()
- }}
- checked={handleType === 'folder'}
- ><span style={{ fontSize: 12 }}>是否操作文件夹</span></Checkbox>
- {handleType === 'folder' && <Button onClick={() => onAddFolder?.()} disabled={folderCreateBy ? !isPermission(folderCreateBy) : false}>新建文件夹</Button>}
- {(!selectedKeys?.[0] && handleType === 'folder') && <>
- <Button type="primary" disabled={folderCreateBy ? !isPermission(folderCreateBy) : false} onClick={() => setUploadVisible(true)}>上传素材</Button>
- </>}
- {handleType === 'folder' ? <>
- {!!selectedKeys?.[0] && <Button onClick={() => { setBatchFolderVisible(true); setBatchType('folder') }} disabled={folderCreateBy ? !isPermission(folderCreateBy) : false}>批量操作文件夹</Button>}
- </> : <>
- <Button type="primary" disabled={folderCreateBy ? !isPermission(folderCreateBy) : false} onClick={() => setUploadVisible(true)}>上传素材</Button>
- <Button onClick={() => { setBatchFolderVisible(true); setBatchType('file') }} disabled={folderCreateBy ? !isPermission(folderCreateBy) : false}>批量操作素材</Button>
- </>}
- </div>
- <div className={style.left_bts}>
- <Button type="link" loading={getMaterialList.loading} onClick={() => {
- getMaterialList.refresh()
- }}>刷新</Button>
- </div>
- </div>
- {batchFolderVisible ? <div className={style.operates}>
- <div className={style.left_bts}>
- <Checkbox
- onChange={(e) => {
- setCheckedFolderList(
- e.target.checked ? batchType === 'folder' ?
- folderList.map(item => item.id) :
- getMaterialList?.data?.records?.filter((item: { createBy: any }) => isPermission(item.createBy)).map((item: { id: any }) => item.id) :
- []
- )
- setIndeterminateFolder(false)
- setCheckFolderAll(e.target.checked)
- }}
- disabled={batchType === 'folder' ? folderList?.length ? false : true : !getMaterialList?.data?.records?.some((item: { createBy: any }) => isPermission(item.createBy))}
- indeterminate={indeterminateFolder}
- checked={checkFolderAll}
- >全选</Checkbox>
- <span style={{ color: '#1890FF' }}>已选{checkedFolderList?.length || 0}个{batchType === 'file' ? '素材' : '文件夹'}</span>
- </div>
- <div className={style.left_bts}>
- <Button disabled={checkedFolderList?.length === 0} onClick={() => {
- setCheckedList(checkedFolderList)
- setMoveVisible(true)
- setMoveType(batchType as any)
- }}>{batchType === 'folder' ? '移动文件夹' : '移动素材'}</Button>
- {batchType === 'file' && <Popconfirm
- title="确定删除?"
- onConfirm={() => {
- const hide = message.loading('正在删除...', 0, () => {});
- deleteBatch.run(checkedFolderList).then(res => {
- hide()
- if (res) {
- getMaterialList.refresh()
- message.success('删除成功')
- }
- }).catch(() => hide())
- }}
- >
- <Button danger disabled={checkedFolderList?.length === 0} loading={deleteBatch.loading}>删除</Button>
- </Popconfirm>}
- <Button type="primary" onClick={() => {
- setBatchFolderVisible(false)
- }}>完成</Button>
- </div>
- </div> : (materialParams?.materialName || materialParams?.materialType || (materialParams?.designerIds && materialParams?.designerIds?.length > 0) || materialParams?.width || materialParams?.height) ? <div className={style.operates}>
- <span>搜索「素材」
- {materialParams?.materialName && <span style={{ fontSize: 12 }}>关键词【{materialParams.materialName}】</span>}
- {(materialParams?.designerIds && materialParams?.designerIds?.length > 0) && <span style={{ fontSize: 12 }}>设计师ID【{materialParams.designerIds.join(',')}】</span>}
- {materialParams?.materialType && <span style={{ fontSize: 12 }}>素材类型【{materialParams.materialType === 'video' ? '视频' : '图片'}】</span>}
- {materialParams?.width && <span style={{ fontSize: 12 }}>素材宽【{materialParams.width}】</span>}
- {materialParams?.height && <span style={{ fontSize: 12 }}>素材高【{materialParams.height}】</span>}
- </span>
- </div> : <div className={style.operates}>
- <Breadcrumb>
- {breadcrumdData.map((item, index) => <Breadcrumb.Item key={item.key}>
- {breadcrumdData.length !== index + 1 ? <a
- style={{ color: '#1890ff' }}
- onClick={() => {
- setBreadcrumdData(data => data.splice(0, index + 1))
- setSelectedKeys(item.currentKey === '0' ? [] : [item.currentKey])
- }}
- >{item.label}</a> : item.label}
- </Breadcrumb.Item>)}
- </Breadcrumb>
- </div>}
- <div className={`${style.content} content_global`}>
- <Spin spinning={getFolderList.loading || getMaterialList.loading}>
- <div className={style.content_scroll} ref={ref} {...dropAreaProps}>
- {isDragOver && <div className={`${style.placeholder} ${isDragOver ? style.dragOver : ''}`}><span>拖动文件到这里</span></div>}
- {(isShowFolder() && folderList.length > 0) || (!isShowFolder() && getMaterialList?.data?.records?.length > 0) ? <Checkbox.Group value={checkedFolderList} style={{ width: '100%' }} onChange={onCheckboxChange}>
- <div className={style.content_scroll_div}>
- {isShowFolder() ? folderList.map((item) => <div key={item.id} className={style.content_row} style={{ width: rowNum ? (1 / rowNum * 100) + '%' : 200 }}>
- <Card
- hoverable
- bodyStyle={{ padding: 0 }}
- className={`${style.content_col}`}
- cover={<div className={style.content_cover} style={{ height: 120 }}>
- {batchFolderVisible && <div className={style.checkbox}><Checkbox value={item.id} disabled={!isPermission(item.createBy)} /></div>}
- <img src={require('../../../../../public/file.png')} height={'100%'} alt="" />
- </div>}
- onDoubleClick={() => {
- if (!batchFolderVisible) {
- let newExpandedKeys = '0-' + item.id
- if (selectedKeys?.[0]) {
- newExpandedKeys = selectedKeys[0] + '-' + item.id
- }
- findParentKeys(newExpandedKeys, treeData)
- setSelectedKeys([newExpandedKeys])
- // 判断是否加载了下级文件 加载了 就不更新
- if (!loadedKeys.includes(newExpandedKeys))
- handleUpdateFolder(newExpandedKeys)
- }
- }}
- >
- <div className={style.body}>
- <Text ellipsis>{item?.folderName}</Text>
- </div>
- <div className={style.actions}>
- <div style={{ height: 22 }}></div>
- {isPermission(item.createBy) || (!selectedKeys?.[0] && isAdmin()) ? <Dropdown menu={{
- items: getItems(item)
- }}>
- <a onClick={e => e.preventDefault()} style={{ fontSize: 11 }}>更多</a>
- </Dropdown> : <a style={{ fontSize: 11 }}>无权限操作</a>}
- </div>
- </Card>
- </div>) : getMaterialList?.data?.records.map((item: any) => <div key={item.id} className={style.content_row} style={{ width: rowNum ? (1 / rowNum * 100) + '%' : 200 }}>
- <Card
- hoverable
- bodyStyle={{ padding: 0 }}
- className={`${style.content_col}`}
- cover={<div style={{ height: 120, padding: 0 }} className={style.content_cover}>
- {batchFolderVisible && <div className={style.checkbox} onClick={(e) => { e.stopPropagation(); }}><Checkbox value={item.id} disabled={!isPermission(item.createBy)} /></div>}
- {item.materialType === 'video' && <div className={style.playr}>
- <img src={require('../../../../../public/image/play.png')} alt="" />
- </div>}
- <div className={style.file_info}>
- <div>{item.width}*{item.height}</div>
- {item.materialType === 'video' && <div>{formatSecondsToTime(Math.floor(item.videoDuration))}</div>}
- </div>
- <img src={item.materialType === 'image' ? item.ossUrl : getVideoImgUrl(item.ossUrl)} className={style.coverImg} alt="" />
- </div>}
- onClick={() => { setDetailsData({ visible: true, data: item }) }}
- >
- <div className={style.body}>
- <div className={style.title}><Text ellipsis>{item?.materialName}</Text></div>
- <a className={style.detailBt}>详情</a>
- </div>
- <div className={style.actions}>
- <div style={{ height: 22 }}></div>
- {isPermission(item.createBy) ? <Dropdown
- menu={{
- items: getItemsFile(item)
- }}
- >
- <a onClick={e => { e.preventDefault(); e.stopPropagation() }} style={{ fontSize: 11 }}>更多</a>
- </Dropdown> : <a style={{ fontSize: 11 }}>无权限操作</a>}
- </div>
- </Card>
- </div>)}
- </div>
- </Checkbox.Group> : <div style={{ height: '100%', width: '100%', alignContent: 'center' }}><Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /></div>}
- </div>
- </Spin>
- </div>
- {handleType === 'file' && <div className={style.fotter}>
- <Pagination
- size="small"
- total={getMaterialList?.data?.totalRow || 0}
- showSizeChanger
- showQuickJumper
- pageSize={getMaterialList?.data?.pageSize || 30}
- current={getMaterialList?.data?.pageNumber || 1}
- onChange={(page: number, pageSize: number) => {
- setMaterialParams({ ...materialParams, pageNum: page, pageSize })
- }}
- />
- </div>}
- {/* 移动文件 素材 */}
- {moveVisible && <MoveFile
- moveType={moveType}
- checkedList={checkedList}
- userId={initialState?.currentUser?.userId?.toString() || ''}
- visible={moveVisible}
- onClose={() => {
- setMoveVisible(false)
- cancelSelect()
- }}
- onChange={(selectedKey: string) => {
- getFolder()
- setMoveVisible(false)
- if (moveType === 'folder') {
- handleUpdateFolder(selectedKeys[0] as string)
- if (loadedKeys.includes(selectedKey)) {
- handleUpdateFolder(selectedKey)
- }
- } else {
- getMaterialList.refresh()
- }
- cancelSelect()
- setBatchFolderVisible(false)
- }}
- />}
- {/* 上传文件 */}
- {uploadVisible && <UploadFile
- folderId={breadcrumdData[breadcrumdData.length - 1].key}
- userId={(initialState?.currentUser?.userId || 0) as number}
- visible={uploadVisible}
- onChange={() => {
- setUploadVisible(false)
- getMaterialList.refresh()
- }}
- onClose={() => {
- setUploadVisible(false)
- }}
- />}
- {/* 修改所属人 */}
- {updateOwnerData.visible && <UpdateCreate
- {...updateOwnerData}
- onClose={() => {
- setUpdateOwnerData({ visible: false, folderId: 0 })
- }}
- onChange={() => {
- getFolder()
- setUpdateOwnerData({ visible: false, folderId: 0 })
- }}
- />}
- {/* 修改素材 */}
- {updateFileData?.visible && <UpdateFile
- {...updateFileData}
- onClose={() => {
- setUpdateFileData({ visible: false, initialValues: {} })
- }}
- onChange={() => {
- getMaterialList.refresh()
- setUpdateFileData({ visible: false, initialValues: {} })
- }}
- />}
- {/* 素材详情 */}
- {detailsData?.visible && <Details
- {...detailsData}
- onClose={() => {
- setDetailsData({ visible: false, data: {} })
- }}
- onChange={() => {
- getMaterialList.refresh()
- }}
- />}
- {/* 拖动上传 */}
- {uploadsVisible && <UploadsTable
- folderId={breadcrumdData[breadcrumdData.length - 1].key}
- userId={(initialState?.currentUser?.userId || 0) as number}
- visible={uploadsVisible}
- fileList={fileList}
- isPermission={!!(folderCreateBy && isPermission(folderCreateBy))}
- onClose={() => {
- setUploadsVisible(false)
- setFileList(undefined)
- }}
- onChange={() => {
- setUploadsVisible(false)
- setFileList(undefined)
- getMaterialList.refresh()
- }}
- />}
- </div>
- })
- export default React.memo(Material)
|