From baf2d8c5d354fb9ea0db88e3f4d83f1d32fa4100 Mon Sep 17 00:00:00 2001 From: yombo Date: Wed, 1 Mar 2023 17:51:23 +0800 Subject: [PATCH] U: #589 --- spug_web/src/pages/ssh/FileManager.js | 187 ++++++++++++++++---------- 1 file changed, 119 insertions(+), 68 deletions(-) diff --git a/spug_web/src/pages/ssh/FileManager.js b/spug_web/src/pages/ssh/FileManager.js index eec26fc..4b1a964 100644 --- a/spug_web/src/pages/ssh/FileManager.js +++ b/spug_web/src/pages/ssh/FileManager.js @@ -26,6 +26,7 @@ class FileManager extends React.Component { super(props); this.input = null; this.input2 = null + this.pwdHistoryCaches = new Map() this.state = { fetching: false, showDot: false, @@ -100,12 +101,18 @@ class FileManager extends React.Component { fetchFiles = (pwd) => { this.setState({ fetching: true }); - pwd = pwd || this.state.pwd; + pwd = pwd || (this.pwdHistoryCaches.get(this.props.id) || []); + if (this.pwdHistoryCaches.has(this.props.id)) { + let pwdCache = this.pwdHistoryCaches.get(this.props.id) + pwdCache.push(pwd.length > 0 ? pwd.splice(-1) : null) + pwd = pwdCache.filter(x => !!x) + } const path = '/' + pwd.join('/'); return http.get('/api/file/', { params: { id: this.props.id, path } }) .then(res => { const objects = lds.orderBy(res, [this._kindSort, 'name'], ['desc', 'asc']); this.setState({ objects, pwd }) + this.pwdHistoryCaches.set(this.props.id, pwd) this.state.inputPath !== null && this.setState({ inputPath: path }) }) .finally(() => this.setState({ fetching: false })) @@ -118,122 +125,154 @@ class FileManager extends React.Component { this.setState({ inputPath: null }) } else if (action === '2') { const index = pwd.indexOf(name); - pwd = pwd.splice(0, index + 1) + pwd = pwd.splice(0, index + 1); } else { - pwd = [] + pwd = []; } - this.fetchFiles(pwd) + this.fetchFiles(pwd); }; handleInputEnter = () => { if (this.state.inputPath === null) { if (this.state.pwd.length > 0) { - this.setState({ inputPath: `/${this.state.pwd.join('/')}/` }) + this.setState({ inputPath: `/${this.state.pwd.join("/")}/` }); } else { - this.setState({ inputPath: '/' }) + this.setState({ inputPath: "/" }); } - setTimeout(() => this.input2.focus(), 100) + setTimeout(() => this.input2.focus(), 100); } else { - let pwdStr = this.state.inputPath.replace(/^\/+/, '') - pwdStr = pwdStr.replace(/\/+$/, '') - this.fetchFiles(pwdStr.split('/')) - .then(() => this.setState({ inputPath: null })) + let pwdStr = this.state.inputPath.replace(/^\/+/, ""); + pwdStr = pwdStr.replace(/\/+$/, ""); + this.fetchFiles(pwdStr.split("/")).then(() => + this.setState({ inputPath: null }) + ); } - } + }; handleUpload = () => { this.input.click(); - this.input.onchange = e => { - this.setState({ uploading: true, uploadStatus: 'active', percent: 0 }); - const file = e.target['files'][0]; + this.input.onchange = (e) => { + this.setState({ uploading: true, uploadStatus: "active", percent: 0 }); + const file = e.target["files"][0]; const formData = new FormData(); const token = uniqueId(); this._updatePercent(token); - formData.append('file', file); - formData.append('id', this.props.id); - formData.append('token', token); - formData.append('path', '/' + this.state.pwd.join('/')); - this.input.value = ''; - http.post('/api/file/object/', formData, { timeout: 600000, onUploadProgress: this._updateLocal }) - .then(() => { - this.setState({ uploadStatus: 'success' }); - this.fetchFiles() - }, () => this.setState({ uploadStatus: 'exception' })) - .finally(() => setTimeout(() => this.setState({ uploading: false }), 2000)) - } + formData.append("file", file); + formData.append("id", this.props.id); + formData.append("token", token); + formData.append("path", "/" + this.state.pwd.join("/")); + this.input.value = ""; + http + .post("/api/file/object/", formData, { + timeout: 600000, + onUploadProgress: this._updateLocal, + }) + .then( + () => { + this.setState({ uploadStatus: "success" }); + this.fetchFiles(); + }, + () => this.setState({ uploadStatus: "exception" }) + ) + .finally(() => + setTimeout(() => this.setState({ uploading: false }), 2000) + ); + }; }; _updateLocal = (e) => { - const percent = e.loaded / e.total * 100 / 2 - this.setState({ percent: Number(percent.toFixed(1)) }) - } + const percent = ((e.loaded / e.total) * 100) / 2; + this.setState({ percent: Number(percent.toFixed(1)) }); + }; - _updatePercent = token => { - const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; - this.socket = new WebSocket(`${protocol}//${window.location.host}/api/ws/subscribe/${token}/?x-token=${X_TOKEN}`); - this.socket.onopen = () => this.socket.send('ok'); - this.socket.onmessage = e => { - if (e.data === 'pong') { - this.socket.send('ping') + _updatePercent = (token) => { + const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; + this.socket = new WebSocket( + `${protocol}//${window.location.host}/api/ws/subscribe/${token}/?x-token=${X_TOKEN}` + ); + this.socket.onopen = () => this.socket.send("ok"); + this.socket.onmessage = (e) => { + if (e.data === "pong") { + this.socket.send("ping"); } else { const percent = this.state.percent + Number(e.data) / 2; - if (percent > this.state.percent) this.setState({ percent: Number(percent.toFixed(1)) }); + if (percent > this.state.percent) + this.setState({ percent: Number(percent.toFixed(1)) }); if (percent === 100) { - this.socket.close() + this.socket.close(); } } - } + }; }; handleDownload = (name) => { - const file = `/${this.state.pwd.join('/')}/${name}`; - const link = document.createElement('a'); + const file = `/${this.state.pwd.join("/")}/${name}`; + const link = document.createElement("a"); link.download = name; link.href = `/api/file/object/?id=${this.props.id}&file=${file}&x-token=${X_TOKEN}`; document.body.appendChild(link); link.click(); document.body.removeChild(link); - message.warning('即将开始下载,请勿重复点击。') + message.warning("即将开始下载,请勿重复点击。"); }; handleDelete = (name) => { - const file = `/${this.state.pwd.join('/')}/${name}`; + const file = `/${this.state.pwd.join("/")}/${name}`; Modal.confirm({ - title: '删除文件确认', + title: "删除文件确认", content: `确认删除文件:${file} ?`, onOk: () => { - return http.delete('/api/file/object/', { params: { id: this.props.id, file } }) + return http + .delete("/api/file/object/", { params: { id: this.props.id, file } }) .then(() => { - message.success('删除成功'); - this.fetchFiles() - }) - } - }) + message.success("删除成功"); + this.fetchFiles(); + }); + }, + }); }; render() { let objects = this.state.objects; if (!this.state.showDot) { - objects = objects.filter(x => !x.name.startsWith('.')) + objects = objects.filter((x) => !x.name.startsWith(".")); } const scrollY = document.body.clientHeight - 168; return ( - this.input = ref} /> + (this.input = ref)} + />
{this.state.inputPath !== null ? ( - this.input2 = ref} size="small" className={styles.input} - suffix={
回车确认
} - value={this.state.inputPath} onChange={e => this.setState({ inputPath: e.target.value })} + (this.input2 = ref)} + size="small" + className={styles.input} + suffix={ +
回车确认
+ } + value={this.state.inputPath} + onChange={(e) => this.setState({ inputPath: e.target.value })} onBlur={this.handleInputEnter} - onPressEnter={this.handleInputEnter} /> + onPressEnter={this.handleInputEnter} + /> ) : ( - this.handleChdir('', '0')}> + this.handleChdir("", "0")} + > - {this.state.pwd.map(item => ( - this.handleChdir(item, '2')}> + {this.state.pwd.map((item) => ( + this.handleChdir(item, "2")} + > {item} ))} @@ -249,10 +288,15 @@ class FileManager extends React.Component { checked={this.state.showDot} checkedChildren="开启" unCheckedChildren="关闭" - onChange={v => this.setState({ showDot: v })} /> + onChange={(v) => this.setState({ showDot: v })} + /> {this.state.uploading ? ( - + ) : ( } - onClick={this.handleUpload}>上传文件 + onClick={this.handleUpload} + > + 上传文件 + )}
@@ -271,11 +318,15 @@ class FileManager extends React.Component { pagination={false} columns={this.columns} scroll={{ y: scrollY }} - style={{ fontFamily: 'Source Code Pro, Courier New, Courier, Monaco, monospace, PingFang SC, Microsoft YaHei' }} - dataSource={objects} /> + style={{ + fontFamily: + "Source Code Pro, Courier New, Courier, Monaco, monospace, PingFang SC, Microsoft YaHei", + }} + dataSource={objects} + />
- ) + ); } } -export default FileManager \ No newline at end of file +export default FileManager;