WGShare.Client.Electron/src/components/SharedFilesModel/index.tsx

396 lines
24 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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