396 lines
24 KiB
TypeScript
396 lines
24 KiB
TypeScript
import styles from '@/components/SharedFilesModel/index.module.scss'
|
||
import {
|
||
DeleteOutlined,
|
||
ProfileOutlined,
|
||
ReloadOutlined,
|
||
SearchOutlined,
|
||
VerticalAlignBottomOutlined
|
||
} from '@ant-design/icons';
|
||
import { Button, Input, message, Modal, Pagination, Popconfirm, Progress, Table } from 'antd';
|
||
import { forwardRef, useEffect, useImperativeHandle, useState, useRef } from "react";
|
||
import { DeleteRoomFile, GetRoomFile, GetRoomFileDwUrl, GetRoomUpFileurl, GetRoomUserItem, PostRoomFile } from '@/api/Meeting';
|
||
import axios from 'axios';
|
||
import { useLocation } from 'react-router-dom';
|
||
import { storage } from '@/utils';
|
||
import StupWizard from '../StupWizard';
|
||
import { role } from '@/config/role';
|
||
const fs = require('fs').promises;
|
||
const { exec } = require('child_process');
|
||
const { Column } = Table
|
||
|
||
const SharedFilesModel = forwardRef((props: any, ref: any) => {
|
||
useImperativeHandle(ref, () => ({
|
||
getData: () => {
|
||
setIsSharedFilesModel(true)
|
||
GetRoomUserItem(state.channelId, user.uid).then((res: any) => {
|
||
if (res.code === 200) {
|
||
setRoomUserItem(res.data)
|
||
}
|
||
})
|
||
getRoomFile()
|
||
}
|
||
}))
|
||
const stupWizardRef = useRef<any>();
|
||
const { state } = useLocation();
|
||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||
const [roomUserItem, setRoomUserItem] = useState<any>({})
|
||
const [showRowSelection, setShowRowSelection] = useState(false);
|
||
const [isUpFile, setIsUpFile] = useState(false);
|
||
const [isSharedFilesModel, setIsSharedFilesModel] = useState(false);
|
||
const [user, setUser] = useState<any>({});
|
||
const [fileList, setFileList] = useState({
|
||
data: [],
|
||
keyword: '',
|
||
total: 0,
|
||
pageIndex: 1,
|
||
pageSize: 10,
|
||
})
|
||
const [uploadProgress, setUploadProgress] = useState(0);
|
||
useEffect(() => {
|
||
let userInfo = JSON.parse(storage.getItem('user') as string)
|
||
setUser(userInfo)
|
||
getRoomFile()
|
||
}, [fileList.pageIndex, fileList.keyword]);
|
||
// 获取共享文件列表
|
||
const getRoomFile = async (): Promise<void> => {
|
||
await GetRoomFile({
|
||
pageIndex: fileList.pageIndex,
|
||
pageSize: fileList.pageSize,
|
||
keyword: fileList.keyword,
|
||
roomId: state.roomId
|
||
}).then(res => {
|
||
if (res.code === 200) {
|
||
setFileList({
|
||
...fileList,
|
||
data: res.data.items.map((item: any) => {
|
||
return {
|
||
...item,
|
||
key: item.id,
|
||
}
|
||
}),
|
||
total: res.data.total
|
||
})
|
||
}
|
||
})
|
||
}
|
||
return (
|
||
<>
|
||
<Modal
|
||
title="共享文件"
|
||
open={isSharedFilesModel}
|
||
footer={null}
|
||
centered
|
||
width={'800px'}
|
||
onCancel={() => setIsSharedFilesModel(false)}
|
||
>
|
||
<div>
|
||
<div className={styles.sharedFilesModel}>
|
||
<div>
|
||
<div>
|
||
<span>
|
||
共{fileList.total}个文件
|
||
</span>
|
||
{isUpFile ? <div>
|
||
<span>上传进度:</span>
|
||
{/* <span>{uploadProgress === 100 ? '上传完成' : '上传中'} </span> */}
|
||
<Progress percent={uploadProgress} trailColor={'#e8e8e8'}
|
||
percentPosition={{ align: 'center', type: 'inner' }}
|
||
size={{ width: 100, height: 20 }} />
|
||
</div> : null}
|
||
</div>
|
||
<div style={{ color: 'white' }}>
|
||
<Input
|
||
placeholder="请输入文件名"
|
||
style={{ width: '200px' }}
|
||
prefix={<SearchOutlined style={{ color: 'white' }} />}
|
||
onPressEnter={(e: any) => {
|
||
if (fileList.pageIndex === 1) {
|
||
setFileList({
|
||
...fileList,
|
||
keyword: e.target.value,
|
||
})
|
||
} else {
|
||
setFileList({
|
||
...fileList,
|
||
keyword: e.target.value,
|
||
pageIndex: 1
|
||
})
|
||
}
|
||
}}
|
||
onBlur={(e) => {
|
||
if (fileList.pageIndex === 1) {
|
||
setFileList({
|
||
...fileList,
|
||
keyword: e.target.value,
|
||
})
|
||
} else {
|
||
setFileList({
|
||
...fileList,
|
||
keyword: e.target.value,
|
||
pageIndex: 1
|
||
})
|
||
}
|
||
}}
|
||
suffix={
|
||
<span
|
||
style={{ color: '#47D3D0', cursor: 'pointer' }}
|
||
onClick={() => {
|
||
getRoomFile()
|
||
}}
|
||
>搜索
|
||
</span>
|
||
}
|
||
/>
|
||
<ReloadOutlined title='刷新' onClick={() => {
|
||
if (fileList.pageIndex === 1) {
|
||
getRoomFile()
|
||
} else {
|
||
setFileList({
|
||
...fileList,
|
||
pageIndex: 1
|
||
})
|
||
}
|
||
}} />
|
||
{roomUserItem && (role.ID.includes(roomUserItem.roleId) || roomUserItem.isRoomManager) && fileList.data.length ? <ProfileOutlined title={showRowSelection ? '取消框选' : '显示框选'} onClick={() => {
|
||
setShowRowSelection(!showRowSelection)
|
||
}} style={{ color: showRowSelection ? '#5575F2' : 'white' }} /> : null}
|
||
{showRowSelection && fileList.data.length && selectedRowKeys.length ?
|
||
<Popconfirm
|
||
title="提示"
|
||
description="确认删除吗?"
|
||
onConfirm={() => {
|
||
if (selectedRowKeys.length) {
|
||
DeleteRoomFile(selectedRowKeys).then(res => {
|
||
if (res.code === 200) {
|
||
message.success('删除成功!')
|
||
if (fileList.pageIndex === 1) {
|
||
getRoomFile()
|
||
} else {
|
||
setFileList({
|
||
...fileList,
|
||
pageIndex: 1
|
||
})
|
||
}
|
||
}
|
||
})
|
||
} else {
|
||
message.error('请选择文件!')
|
||
}
|
||
}}
|
||
onCancel={() => {
|
||
|
||
}}
|
||
okText="确认"
|
||
cancelText="取消"
|
||
>
|
||
<DeleteOutlined title='删除' />
|
||
</Popconfirm> : null}
|
||
{roomUserItem && role.ID.includes(roomUserItem.roleId) || roomUserItem.isRoomManager ? <Button type="primary" style={{ backgroundColor: '#31353A' }}
|
||
onClick={() => {
|
||
if (isUpFile) {
|
||
message.error('文件上传中,请稍后上传。')
|
||
return
|
||
}
|
||
const file = document.createElement("input") as any;
|
||
file.type = "file";
|
||
file.onchange = async () => {
|
||
const fileInfo = file.files[0];
|
||
const maxSize = 100 * 1024 * 1024; // 100MB in bytes
|
||
if (fileInfo.size > maxSize) {
|
||
message.error('文件太大!请上传小于100MB的文件。')
|
||
// 清除文件输入框的值,以便用户可以选择其他文件
|
||
return
|
||
}
|
||
const fileType = fileInfo.name.split('.');
|
||
const fileTypeName = fileType[fileType.length - 1];
|
||
setIsUpFile(true)
|
||
setUploadProgress(0)
|
||
await GetRoomUpFileurl(state.channelId, fileTypeName).then(async res => {
|
||
const formData = new FormData();
|
||
formData.append("name", fileInfo.name);
|
||
formData.append("OSSAccessKeyId", res.data.ossAccessKeyId);
|
||
formData.append("key", res.data.key);
|
||
formData.append("policy", res.data.policy);
|
||
formData.append("signature", res.data.signature);
|
||
formData.append("success_action_status", res.data.success_action_status);
|
||
formData.append("file", fileInfo);
|
||
await axios.post(res.data.host, formData, {
|
||
headers: {
|
||
"Content-Type": "multipart/form-data",
|
||
"Authorization": `Bearer ${user.token}`
|
||
},
|
||
withCredentials: false,
|
||
onUploadProgress: (progressEvent: any) => {
|
||
// 获取上传进度
|
||
const { loaded, total } = progressEvent;
|
||
const progress = Math.round((loaded * 100) / total);
|
||
setUploadProgress(progress)
|
||
}
|
||
}).then(_response => {
|
||
setIsUpFile(false)
|
||
setUploadProgress(100)
|
||
message.success('上传成功')
|
||
}).catch(_error => {
|
||
setIsUpFile(false)
|
||
message.error('上传失败')
|
||
});
|
||
await PostRoomFile({
|
||
fileUrl: res.data.key,
|
||
size: fileInfo.size,
|
||
fileName: fileInfo.name,
|
||
roomId: state.roomId
|
||
})
|
||
getRoomFile()
|
||
})
|
||
};
|
||
file.click();
|
||
}}
|
||
>上传</Button> : null}
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<Table
|
||
size={'small'}
|
||
rowSelection={showRowSelection ? {
|
||
selectedRowKeys,
|
||
onChange: (newSelectedRowKeys: React.Key[]) => {
|
||
setSelectedRowKeys(newSelectedRowKeys);
|
||
}
|
||
} : undefined}
|
||
dataSource={fileList.data}
|
||
pagination={false}
|
||
scroll={{ y: '40vh' }}
|
||
style={{ width: '100%' }}
|
||
>
|
||
<Column title="文件" width={140}
|
||
render={(item) => (
|
||
<>
|
||
<div>
|
||
<span>{item.fileName}</span>
|
||
<span>
|
||
{item.showPercentComplete ? <Progress percent={item.percentComplete} trailColor={'#e8e8e8'}
|
||
percentPosition={{ align: 'center', type: 'inner' }}
|
||
size={{ width: 40, height: 10 }} /> : null}
|
||
</span>
|
||
</div>
|
||
</>
|
||
)}
|
||
/>
|
||
<Column title="更新时间" dataIndex="modifyTime" key="modifyTime" width={200} />
|
||
<Column title="大小" render={(item) => (
|
||
<>
|
||
<span>{item.size / 1024 > 1000 ? (item.size / (1024 * 1024)).toFixed(2) + 'MB' : (item.size / 1024).toFixed(2) + 'KB'}</span>
|
||
</>
|
||
)} />
|
||
<Column title="上传者" dataIndex="userName" key="userName" />
|
||
<Column title="下载次数"
|
||
render={(item) => (
|
||
<>
|
||
<span>{item.downloadCount}次</span>
|
||
</>
|
||
)}
|
||
/>
|
||
<Column title="操作" render={(item) => (
|
||
<>
|
||
{!item.showPercentComplete ? <VerticalAlignBottomOutlined title='下载'
|
||
style={{ color: '#5575F2', cursor: 'pointer' }}
|
||
onClick={async () => {
|
||
storage.setItem('loading', true)
|
||
GetRoomFileDwUrl(item.fileUrl, item.id).then(res => {
|
||
if (res.code === 200) {
|
||
axios({
|
||
url: res.data,
|
||
method: 'GET',
|
||
onDownloadProgress: (progressEvent: any) => {
|
||
const totalLength = item.size;
|
||
if (totalLength !== null) {
|
||
const percentComplete = (progressEvent.loaded / totalLength * 100).toFixed(2);
|
||
const fileIndex = fileList.data.findIndex((row: any) => row.id === item.id);
|
||
let fileItem = [...fileList.data] as any;
|
||
fileItem[fileIndex].percentComplete = percentComplete
|
||
fileItem[fileIndex].showPercentComplete = true
|
||
setFileList({
|
||
...fileList,
|
||
data: fileItem,
|
||
})
|
||
}
|
||
}
|
||
}).then(async () => {
|
||
const fileIndex = fileList.data.findIndex((row: any) => row.id === item.id);
|
||
let fileItem = [...fileList.data] as any;
|
||
fileItem[fileIndex].percentComplete = 100
|
||
setTimeout(() => {
|
||
fileItem[fileIndex].showPercentComplete = false
|
||
}, 1000)
|
||
setFileList({
|
||
...fileList,
|
||
data: fileItem,
|
||
})
|
||
const setting = await JSON.parse(storage.getItem('setting') as string)
|
||
if (setting.isShareSavePath) {
|
||
window.electron.selectFilePath({
|
||
fileName: fileItem[fileIndex].fileName,
|
||
filePath: res.data
|
||
})
|
||
} else {
|
||
try {
|
||
await fs.access(setting.shareFilesPath, fs.constants.F_OK)
|
||
const response = await fetch(res.data);
|
||
const arrayBuffer = await response.arrayBuffer();
|
||
const buffer = Buffer.from(arrayBuffer);
|
||
fs.writeFile(`${setting.shareFilesPath}${fileItem[fileIndex].fileName}`, buffer, {});
|
||
message.success(`下载成功!文件已保存至:${setting.shareFilesPath}`)
|
||
await fs.access(setting.shareFilesPath, fs.constants.F_OK);
|
||
if (process.platform === 'win32') {
|
||
exec(`explorer "${setting.shareFilesPath}"`);
|
||
} else if (process.platform === 'darwin') {
|
||
exec(`open "${setting.shareFilesPath}"`);
|
||
}
|
||
} catch (error: any) {
|
||
if (error.code === 'ENOENT') {
|
||
message.error({
|
||
content: <div>文件夹不存在 <span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
|
||
stupWizardRef.current.changeModal(4)
|
||
}}>前往设置</span></div>,
|
||
})
|
||
return
|
||
} else {
|
||
message.error(error)
|
||
}
|
||
}
|
||
}
|
||
setTimeout(() => {
|
||
getRoomFile()
|
||
}, 2000)
|
||
})
|
||
}
|
||
}).finally(() => {
|
||
storage.setItem('loading', false)
|
||
})
|
||
}} /> : null}
|
||
{/* <FolderOutlined title='文件' style={{ color: '#FFA000', cursor: 'pointer', marginLeft: '10px' }} /> */}
|
||
</>
|
||
)} />
|
||
</Table>
|
||
<div style={{ display: 'flex', justifyContent: 'center', marginTop: '10px' }}>
|
||
<Pagination size="small" total={fileList.total} onChange={(e) => {
|
||
setFileList({
|
||
...fileList,
|
||
pageIndex: e
|
||
})
|
||
}} pageSize={fileList.pageSize} current={fileList.pageIndex} hideOnSinglePage={true} showSizeChanger={false} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
|
||
|
||
</div>
|
||
</div>
|
||
</Modal>
|
||
<StupWizard ref={stupWizardRef} />
|
||
</>
|
||
)
|
||
})
|
||
|
||
export default SharedFilesModel
|