diff --git a/main.js b/main.js index 664b5e8..016846c 100644 --- a/main.js +++ b/main.js @@ -1,4 +1,4 @@ -const { app, BrowserWindow, screen, Tray, nativeImage, Menu, ipcMain, clipboard } = require('electron'); +const { app, BrowserWindow, screen, Tray, nativeImage, Menu, ipcMain, clipboard, dialog } = require('electron'); const path = require('node:path') app.allowRendererProcessReuse = false; let mainWindow = null; @@ -97,7 +97,6 @@ function createWindow() { app.on('ready', () => { createWindow() createTray() - // 监听f12打开控制台 mainWindow.webContents.on('before-input-event', (event, input) => { if (input.key === 'F12') { @@ -137,6 +136,24 @@ app.on('ready', () => { break; } }); + // 下载文件并放置选择的文件夹 + ipcMain.handle('dwFile', (event, url) => { + // dialog.showOpenDialog(mainWindow, { + // properties: ['openDirectory'] + // }).then(result => { + // if (!result.canceled) { + // const selectedPath = result.filePaths[0]; + // win.webContents.on('will-download', (event, item, webContents) => { + // console.log('Selected download folder:', selectedPath); + // console.log(url); + // item.setSavePath(`${selectedPath}/${url}`); + // item.resume(); + // }); + // } + // }).catch(err => { + + // }); + }); // 导出是否全屏 ipcMain.handle('getIsMaximized', () => { return mainWindow.isMaximized(); diff --git a/preload.js b/preload.js index 2476ed4..5f0913c 100644 --- a/preload.js +++ b/preload.js @@ -27,7 +27,7 @@ let videoID = ''; let iMediaRecorder = ''; const getDom = () => { - return document.getElementById(videoID); + return document.getElementById('video-1'); } // 离开频道 const leaveChannel = () => { @@ -39,7 +39,6 @@ const leaveChannel = () => { } // 离开频道 const joinChannel = (bool) => { - console.log(option); if (bool) { rtcEngine.joinChannel(option.token, option.channelId, option.userid, { channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景 @@ -75,8 +74,8 @@ rtcEngine.registerEventHandler({ // 本地用户加入频道后,设置本地视频窗口 rtcEngine.setupLocalVideo({ renderMode: RenderModeType.RenderModeFit, - sourceType: VideoSourceType.VideoSourceScreen, - // sourceType: VideoSourceType.VideoSourceCameraPrimary, + // sourceType: VideoSourceType.VideoSourceScreen, + sourceType: VideoSourceType.VideoSourceCameraPrimary, uid: localUid, view: getDom(), setupMode: VideoViewSetupMode.VideoViewSetupAdd, @@ -178,6 +177,7 @@ contextBridge.exposeInMainWorld( option.token = data.token; option.channelId = data.channelId; option.userid = Number(data.userid); + rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {}) joinChannel(false) }, // 离开频道 @@ -311,7 +311,11 @@ contextBridge.exposeInMainWorld( // 复制文字 setWriteText: (text) => { return ipcRenderer.invoke('setWriteText', text) - } + }, + // 下载文件并放置选择的文件夹 + dwFile: (url) => { + ipcRenderer.invoke('dwFile', url) + }, } ) diff --git a/src/api/Meeting/index.ts b/src/api/Meeting/index.ts new file mode 100644 index 0000000..aed9674 --- /dev/null +++ b/src/api/Meeting/index.ts @@ -0,0 +1,34 @@ +import { request } from '@/utils' + +export const GetRoomFile = (data: any) => + request({ + url: `/room/file`, + method: 'get', + data + }) +export const DeleteRoomFile = (data: any) => + request({ + url: `/room/file`, + method: 'delete', + data + }) + +export const PostRoomFile = (data: any) => + request({ + url: `/room/file`, + method: 'post', + data + }) + +export const GetRoomUpFileurl = (roomNum: string, fileSuffix: string) => + request({ + url: `/room/up-fileurl?roomNum=${roomNum}&fileSuffix=${fileSuffix}`, + method: 'get' + }) + +export const GetRoomFileDwUrl = (fileUrl: string) => + request({ + url: `/room/file-dw-url?fileUrl=${fileUrl}`, + method: 'get' + }) + diff --git a/src/page/Home/User/index.tsx b/src/page/Home/User/index.tsx index 334bac4..6d29ed1 100644 --- a/src/page/Home/User/index.tsx +++ b/src/page/Home/User/index.tsx @@ -213,7 +213,10 @@ const User: React.FC = () => {
账号: { setAddUserFrom({ diff --git a/src/page/Meeting/index.module.scss b/src/page/Meeting/index.module.scss index 1167662..d72ffcb 100644 --- a/src/page/Meeting/index.module.scss +++ b/src/page/Meeting/index.module.scss @@ -662,4 +662,33 @@ justify-content: flex-end; margin-top: 20px; } +} + +// 共享文件 +.sharedFilesModel { + >div:nth-child(1) { + display: flex; + align-items: center; + justify-content: space-between; + + >span { + color: #EEEEEE; + font-size: 20px; + } + + >div { + display: flex; + align-items: center; + + >span { + margin-right: 20px; + cursor: pointer; + font-size: 26px; + } + } + } + + >div:nth-child(2) { + margin: 20px 0; + } } \ No newline at end of file diff --git a/src/page/Meeting/index.tsx b/src/page/Meeting/index.tsx index 7ef3781..73a4bbb 100644 --- a/src/page/Meeting/index.tsx +++ b/src/page/Meeting/index.tsx @@ -6,11 +6,14 @@ import { Swiper, SwiperSlide } from 'swiper/react'; import 'swiper/css'; import 'swiper/css/navigation'; import 'swiper/css/pagination'; -import { Button, Input, Popover, Modal, Checkbox, message, Select, Slider } from "antd"; -import { SearchOutlined } from '@ant-design/icons'; +import { Button, Input, Popover, Modal, Checkbox, message, Select, Slider, Table, Pagination as AntdPagination } from "antd"; +import { DeleteOutlined, FolderOutlined, ProfileOutlined, ReloadOutlined, SearchOutlined, VerticalAlignBottomOutlined } from '@ant-design/icons'; import { useLocation, useNavigate } from 'react-router-dom'; import { thumbImageBufferToBase64 } from '@/utils/package/base64' import { storage } from '@/utils'; +import { GetRoomFile, PostRoomFile, DeleteRoomFile, GetRoomUpFileurl, GetRoomFileDwUrl } from '@/api/Meeting'; +import axios from 'axios'; +const { Column } = Table const Meeting: React.FC = () => { const navigate = useNavigate(); const { state } = useLocation(); @@ -18,8 +21,13 @@ const Meeting: React.FC = () => { userList: false, userChatList: false, }) + const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [isSharedScreenModal, setIsSharedScreenModal] = useState(false); + const [isInit, setIsInit] = useState(true); + const [user, setUser] = useState({}); const [isStupWizard, setIsStupWizard] = useState(false); + const [showRowSelection, setShowRowSelection] = useState(false); + const [isSharedFilesModel, setIsSharedFilesModel] = useState(false); const [sharedScreenList, setSharedScreenList] = useState([]); const [sharedScreenItem, setSharedScreenItem] = useState(''); const [footerList, setFooterList] = useState([ @@ -89,6 +97,14 @@ const Meeting: React.FC = () => { currentDevice: {}, currentVolume: 0, }); + const [fileList, setFileList] = useState({ + data: [], + keyword: '', + total: 0, + pageIndex: 1, + pageSize: 10, + }) + const [stepsStatus, setStepsStatus] = useState(true); const [isVideoLoad, setIsVideoLoad] = useState(false); const [list] = useState([1, 2, 3, 4, 5, 6, 7]) @@ -96,15 +112,20 @@ const Meeting: React.FC = () => { const [videoID, setVideoID] = useState('') useEffect(() => { - const user = JSON.parse(storage.getItem('user') as string); - // window.electron.setJoinChannel({ - // channelId: state.channelId, - // userid: user.userName, - // token: state.token, - // }) - }, []); + if (isInit) { + setUser(JSON.parse(storage.getItem('user') as string)) + // window.electron.setJoinChannel({ + // channelId: state.channelId, + // userid: user.userName, + // token: state.token, + // }) + setIsInit(false) + } else { + getRoomFile() + } + }, [fileList.pageIndex]); - const changeStatusList = (row: any, itemIndex: number, rowIndex: number): void => { + const changeStatusList = async (row: any, itemIndex: number, rowIndex: number): Promise => { const footerListTemplate = [...footerList] setFooterListIndex({ itemIndex, @@ -172,6 +193,10 @@ const Meeting: React.FC = () => { setFooterList(footerListTemplate) window.electron.stopRecording() break; + case '共享文件': + await getRoomFile() + setIsSharedFilesModel(true) + break; } } @@ -222,6 +247,28 @@ const Meeting: React.FC = () => { }) } + const getRoomFile = async (): Promise => { + await GetRoomFile({ + pageIndex: fileList.pageIndex, + pageSize: fileList.pageSize, + keyword: fileList.keyword, + roomId: state.channelId + }).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 ( <>
@@ -261,10 +308,10 @@ const Meeting: React.FC = () => { }} onSlideChange={() => { }} > - {list.map((item) => + {list.map((item, index) =>
-
+
{meetingContentUser()}
@@ -519,6 +566,161 @@ const Meeting: React.FC = () => {
+ setIsSharedFilesModel(false)} + maskClosable + > +
+
+
+ 共{fileList.total}个文件 +
+ } + onChange={(e) => { + setFileList({ + ...fileList, + keyword: e.target.value + }) + }} + onBlur={() => { + if (fileList.pageIndex === 1) { + getRoomFile() + } else { + setFileList({ + ...fileList, + pageIndex: 1 + }) + } + }} + /> + { + if (fileList.pageIndex === 1) { + getRoomFile() + } else { + setFileList({ + ...fileList, + pageIndex: 1 + }) + } + }} /> + { + setShowRowSelection(!showRowSelection) + }} style={{ color: showRowSelection ? '#5575F2' : 'white' }} /> + {showRowSelection ? { + if (selectedRowKeys.length) { + DeleteRoomFile(selectedRowKeys).then(res => { + if (res.code === 200) { + message.success('删除成功!') + getRoomFile() + } + }) + } else { + message.error('请选择文件!') + } + }} /> : null} + +
+
+
+ { + setSelectedRowKeys(newSelectedRowKeys); + } + } : undefined} + dataSource={fileList.data} + pagination={false} + scroll={{ y: '40vh' }} + style={{ width: '100%' }} + > + + + ( + <> + {item.size / 1024 > 1000 ? (item.size / (1024 * 1024)).toFixed(2) + 'MB' : (item.size / 1024).toFixed(2) + 'KB'} + + )} /> + + ( + <> + {item.downloadCount}次 + + )} + /> + ( + <> + { + GetRoomFileDwUrl(item.fileUrl).then(res => { + if (res.code === 200) { + window.electron.dwFile(res.data) + } + }) + }} /> + {/* */} + + )} /> +
+
+ { + setFileList({ + ...fileList, + pageIndex: e + }) + }} pageSize={fileList.pageSize} current={fileList.pageIndex} hideOnSinglePage={true} /> +
+
+
+
+ +
+
+
) } diff --git a/src/render.d.ts b/src/render.d.ts index e6dd5ad..a9625e2 100644 --- a/src/render.d.ts +++ b/src/render.d.ts @@ -21,6 +21,7 @@ export interface IElectronAPI { muteLocalAudioStream: (mute: boolean) => void; muteLocalVideoStream: (mute: boolean) => void; setWriteText: (text: string) => void; + dwFile: (url: string) => void; } declare global { diff --git a/src/utils/styles/App.css b/src/utils/styles/App.css deleted file mode 100644 index 857c8f9..0000000 --- a/src/utils/styles/App.css +++ /dev/null @@ -1,239 +0,0 @@ -.ant-select .ant-select-selector { - background-color: #28282C !important; - border: 1px solid #404145 !important; - box-sizing: border-box; -} - -.ant-select .ant-select-selector .ant-select-selection-item { - color: white; -} - -.ant-select .ant-select-selector .ant-select-selection-placeholder { - color: #EEEEEE; -} - -.ant-select .ant-select-suffix { - color: white !important; -} - -.ant-input { - background-color: #28282C !important; - border: 1px solid #404145; - color: white !important; - box-sizing: border-box; -} - -.ant-input::placeholder { - color: #E6E6E6; -} - -.ant-input-affix-wrapper { - background-color: #28282C !important; - border: 1px solid #404145; - box-sizing: border-box; -} - -.ant-input-affix-wrapper .ant-input { - color: white !important; -} - -.ant-input-affix-wrapper .ant-input-password-icon { - color: white !important; -} - -.ant-input-affix-wrapper .ant-input-show-count-suffix { - color: white; -} - -.m-ant-btn.ant-btn { - background-color: #3F51B5; - box-shadow: none; -} - -.m-ant-btn.ant-btn:hover { - background-color: #606fc7 !important; -} - -.m-ant-btn.ant-btn:active { - background-color: #32408f !important; -} - -.m-border-ant-button.ant-btn { - border: 1px solid #5575F2 !important; - color: #5575F2 !important; - background-color: #1E1E1F !important; -} - -.ant-checkbox-wrapper { - color: #848484; -} - -.ant-checkbox-wrapper .ant-checkbox .ant-checkbox-inner { - background-color: #28282C !important; - border: 1px solid #404145; -} - -.ant-checkbox-wrapper .ant-checkbox .ant-checkbox-inner::after { - background-color: #3F51B5 !important; -} - -.ant-checkbox-wrapper .ant-checkbox-checked .ant-checkbox-inner { - background-color: #3F51B5 !important; - border: 1px solid #404145; -} - -.ant-table { - background-color: #1B1E24 !important; - border-radius: 0px !important; -} - -.ant-table .ant-table-header .ant-table-cell { - background-color: #1B1E24; - color: #808080; - box-shadow: none; - border-bottom: 1px solid transparent; -} - -.ant-table .ant-table-header .ant-table-cell::before { - visibility: hidden; -} - -.ant-table .ant-table-body .ant-table-row { - background-color: #16191e; - color: white; -} - -.ant-table .ant-table-body .ant-table-row .ant-table-cell { - border-bottom: 1px solid #292F3A; -} - -.ant-table .ant-table-body .ant-table-row-selected .ant-table-cell { - background-color: #0d0f12 !important; - color: white; -} - -.ant-table .ant-table-body .ant-table-cell-row-hover { - background-color: #0d0f12 !important; -} - -.ant-table .ant-table-body .ant-table-placeholder { - background: transparent !important; -} - -.ant-table .ant-table-body .ant-table-placeholder .ant-table-cell { - border: none; -} - -.ant-pagination { - -webkit-app-region: no-drag; -} - -.ant-pagination .ant-pagination-prev { - margin-right: 10px !important; -} - -.ant-pagination .ant-pagination-prev, -.ant-pagination .ant-pagination-next { - width: 30px !important; - height: 30px !important; - border-radius: 50%; - background: #20242C; -} - -.ant-pagination .ant-pagination-prev .anticon, -.ant-pagination .ant-pagination-next .anticon { - color: #808080; -} - -.ant-pagination .ant-pagination-item { - width: 30px !important; - height: 30px !important; - line-height: 30px !important; - border-radius: 50%; - background: #20242C !important; - margin-right: 10px !important; -} - -.ant-pagination .ant-pagination-item > a { - color: #878787 !important; -} - -.ant-pagination .ant-pagination-item:hover { - background: #5575F2 !important; - border: none; - box-shadow: 0px 0px 10px 0px #66C8FF; -} - -.ant-pagination .ant-pagination-item:hover a { - color: black !important; -} - -.ant-pagination .ant-pagination-item-active { - background: #5575F2 !important; - border: none; - box-shadow: 0px 0px 10px 0px #66C8FF; -} - -.ant-pagination .ant-pagination-item-active a { - color: black !important; -} - -.ant-popover { - -webkit-app-region: no-drag; -} - -.ant-popover:not(.ant-popconfirm) .ant-popover-arrow::before { - background-color: #07090B !important; -} - -.ant-popover:not(.ant-popconfirm) .ant-popover-content .ant-popover-inner { - background-color: #07090B; -} - -.ant-modal-mask { - background-color: rgba(0, 0, 0, 0.25) !important; -} - -.ant-modal { - -webkit-app-region: no-drag; -} - -.ant-modal .ant-modal-content { - background-color: #07090B; -} - -.ant-modal .ant-modal-content .ant-modal-header { - background-color: #07090B; -} - -.ant-modal .ant-modal-content .ant-modal-header .ant-modal-title { - text-align: center; - color: #EEEEEE; - font-weight: bold; -} - -.ant-modal .ant-modal-content .ant-modal-body { - max-height: 70vh; - overflow-y: auto; -} - -.ant-slider:hover .ant-slider-rail { - background-color: white; -} - -.ant-slider .ant-slider-rail { - background-color: #D9D9D9; -} - -.ant-slider .ant-slider-track { - background-color: #3672E9; -} - -.ant-slider .ant-slider-handle::after { - background-color: #3672E9; - box-shadow: 0 0 0 2px #3672E9; -} - -.ant-empty .ant-empty-description { - color: #808080; -} diff --git a/src/utils/styles/App.min.css b/src/utils/styles/App.min.css deleted file mode 100644 index 8f0c14c..0000000 --- a/src/utils/styles/App.min.css +++ /dev/null @@ -1 +0,0 @@ -.ant-select .ant-select-selector{background-color:#28282C !important;border:1px solid #404145 !important;box-sizing:border-box}.ant-select .ant-select-selector .ant-select-selection-item{color:white}.ant-select .ant-select-selector .ant-select-selection-placeholder{color:#EEEEEE}.ant-select .ant-select-suffix{color:white !important}.ant-input{background-color:#28282C !important;border:1px solid #404145;color:white !important;box-sizing:border-box}.ant-input::placeholder{color:#E6E6E6}.ant-input-affix-wrapper{background-color:#28282C !important;border:1px solid #404145;box-sizing:border-box}.ant-input-affix-wrapper .ant-input{color:white !important}.ant-input-affix-wrapper .ant-input-password-icon{color:white !important}.ant-input-affix-wrapper .ant-input-show-count-suffix{color:white}.m-ant-btn.ant-btn{background-color:#3F51B5;box-shadow:none}.m-ant-btn.ant-btn:hover{background-color:#606fc7 !important}.m-ant-btn.ant-btn:active{background-color:#32408f !important}.m-border-ant-button.ant-btn{border:1px solid #5575F2 !important;color:#5575F2 !important;background-color:#1E1E1F !important}.ant-checkbox-wrapper{color:#848484}.ant-checkbox-wrapper .ant-checkbox .ant-checkbox-inner{background-color:#28282C !important;border:1px solid #404145}.ant-checkbox-wrapper .ant-checkbox .ant-checkbox-inner::after{background-color:#3F51B5 !important}.ant-checkbox-wrapper .ant-checkbox-checked .ant-checkbox-inner{background-color:#3F51B5 !important;border:1px solid #404145}.ant-table{background-color:#1B1E24 !important;border-radius:0px !important}.ant-table .ant-table-header .ant-table-cell{background-color:#1B1E24;color:#808080;box-shadow:none;border-bottom:1px solid transparent}.ant-table .ant-table-header .ant-table-cell::before{visibility:hidden}.ant-table .ant-table-body .ant-table-row{background-color:#16191e;color:white}.ant-table .ant-table-body .ant-table-row .ant-table-cell{border-bottom:1px solid #292F3A}.ant-table .ant-table-body .ant-table-row-selected .ant-table-cell{background-color:#0d0f12 !important;color:white}.ant-table .ant-table-body .ant-table-cell-row-hover{background-color:#0d0f12 !important}.ant-table .ant-table-body .ant-table-placeholder{background:transparent !important}.ant-table .ant-table-body .ant-table-placeholder .ant-table-cell{border:none}.ant-pagination{-webkit-app-region:no-drag}.ant-pagination .ant-pagination-prev{margin-right:10px !important}.ant-pagination .ant-pagination-prev,.ant-pagination .ant-pagination-next{width:30px !important;height:30px !important;border-radius:50%;background:#20242C}.ant-pagination .ant-pagination-prev .anticon,.ant-pagination .ant-pagination-next .anticon{color:#808080}.ant-pagination .ant-pagination-item{width:30px !important;height:30px !important;line-height:30px !important;border-radius:50%;background:#20242C !important;margin-right:10px !important}.ant-pagination .ant-pagination-item>a{color:#878787 !important}.ant-pagination .ant-pagination-item:hover{background:#5575F2 !important;border:none;box-shadow:0px 0px 10px 0px #66C8FF}.ant-pagination .ant-pagination-item:hover a{color:black !important}.ant-pagination .ant-pagination-item-active{background:#5575F2 !important;border:none;box-shadow:0px 0px 10px 0px #66C8FF}.ant-pagination .ant-pagination-item-active a{color:black !important}.ant-popover{-webkit-app-region:no-drag}.ant-popover:not(.ant-popconfirm) .ant-popover-arrow::before{background-color:#07090B !important}.ant-popover:not(.ant-popconfirm) .ant-popover-content .ant-popover-inner{background-color:#07090B}.ant-modal-mask{background-color:rgba(0,0,0,0.25) !important}.ant-modal{-webkit-app-region:no-drag}.ant-modal .ant-modal-content{background-color:#07090B}.ant-modal .ant-modal-content .ant-modal-header{background-color:#07090B}.ant-modal .ant-modal-content .ant-modal-header .ant-modal-title{text-align:center;color:#EEEEEE;font-weight:bold}.ant-modal .ant-modal-content .ant-modal-body{max-height:70vh;overflow-y:auto}.ant-slider:hover .ant-slider-rail{background-color:#fff}.ant-slider .ant-slider-rail{background-color:#D9D9D9}.ant-slider .ant-slider-track{background-color:#3672E9}.ant-slider .ant-slider-handle::after{background-color:#3672E9;box-shadow:0 0 0 2px #3672E9}.ant-empty .ant-empty-description{color:#808080} diff --git a/src/utils/styles/App.scss b/src/utils/styles/App.scss index cef72a1..56060ed 100644 --- a/src/utils/styles/App.scss +++ b/src/utils/styles/App.scss @@ -150,6 +150,12 @@ $pagination-hover-background-color: #5575F2; } } +:where(.css-dev-only-do-not-override-98ntnt).ant-table-wrapper .ant-table-tbody>tr.ant-table-placeholder:hover>th, +:where(.css-dev-only-do-not-override-98ntnt).ant-table-wrapper .ant-table-tbody>tr.ant-table-placeholder:hover>td, +:where(.css-dev-only-do-not-override-98ntnt).ant-table-wrapper .ant-table-tbody>tr.ant-table-placeholder { + background: transparent; +} + // pagination .ant-pagination { -webkit-app-region: no-drag; @@ -231,6 +237,10 @@ $pagination-hover-background-color: #5575F2; .ant-modal { -webkit-app-region: no-drag; + .ant-modal-close-icon { + color: white; + } + .ant-modal-content { background-color: #07090B;