4343<a href= " #" onclick= " createNewFile()" >{{t " nFile" }}</a>
4444<a href= " #" onclick= " createNewDir()" >{{t " nDir" }}</a>
4545<h3>{{t " cUpFile" }}</h3>
46- <form id= " uploadForm" action = " /do/upload/{{.path}} " method = " post " enctype= " multipart/form-data" >
46+ <form id= " uploadForm" enctype= " multipart/form-data" >
4747 <input type= " file" name= " file" id= " fileInput" >
4848</form>
49+ <div id= " upload-progress" style= " display:none;margin-top:10px;" >
50+ <div style= " font-size:13px;margin-bottom:4px;" id= " upload-filename" ></div>
51+ <div style= " background:#ddd;border-radius:4px;height:16px;width:100%;overflow:hidden;" >
52+ <div id= " upload-bar" style= " background:#337ab7;height:16px;width:0%;transition:width 0.15s;" ></div>
53+ </div>
54+ <div style= " font-size:12px;margin-top:4px;color:#555;" id= " upload-percent" >0%</div>
55+ </div>
4956<script src= " https://s3.pstatp.com/cdn/expire-1-M/jquery/3.2.1/jquery.min.js" ></script>
5057<script>
51- //拖放上传文件 start
52- // 获取 body 元素
53- const body = document.querySelector ('body');
58+ var CHUNK_SIZE = 2 * 1024 * 1024; // 2MB per chunk
5459
55- // 监听文件拖放事件
56- body.addEventListener ('drop', (event) = > {
57- event.preventDefault ();
58- event.stopPropagation ();
60+ function getFileId(file) {
61+ return file.name + '_' + file.size + '_' + file.lastModified ;
62+ }
63+
64+ function showProgress(filename) {
65+ document.getElementById ('upload-progress').style.display = 'block ';
66+ document.getElementById ('upload-filename').textContent = filename;
67+ updateProgress(0);
68+ }
69+
70+ function updateProgress(percent) {
71+ var p = Math.min (100, Math.round (percent));
72+ document.getElementById ('upload-bar').style.width = p + '%';
73+ document.getElementById ('upload-percent').textContent = p + '%';
74+ }
75+
76+ function hideProgress() {
77+ document.getElementById ('upload-progress').style.display = 'none';
78+ }
79+
80+ function checkChunks(fileId, totalChunks) {
81+ return fetch('/do/chunk/check', {
82+ method: 'POST',
83+ headers: {'Content-Type': 'application/x-www-form-urlencoded'},
84+ body: 'fileId= ' + encodeURIComponent(fileId) + '&totalChunks= ' + totalChunks
85+ }).then (function(r) { return r.json (); })
86+ .then (function(d) { return d.uploaded || []; })
87+ .catch (function() { return []; });
88+ }
5989
60- // 获取拖放的文件
61- const file = event.dataTransfer.files [0];
90+ function uploadChunk(fileId, chunkIndex, totalChunks, chunk, onProgress) {
91+ return new Promise(function(resolve, reject) {
92+ var formData = new FormData();
93+ formData.append ('fileId', fileId);
94+ formData.append ('chunkIndex', chunkIndex);
95+ formData.append ('totalChunks', totalChunks);
96+ formData.append ('file', chunk);
97+ var xhr = new XMLHttpRequest();
98+ xhr.upload.addEventListener ('progress', function(e) {
99+ if (e.lengthComputable ) onProgress(e.loaded / e.total );
100+ });
101+ xhr.onload = function() {
102+ try {
103+ var data = JSON.parse (xhr.responseText );
104+ data.stat ? resolve() : reject(new Error('chunk upload failed'));
105+ } catch(e) { reject(e); }
106+ };
107+ xhr.onerror = function() { reject(new Error('network error')); };
108+ xhr.open ('POST', '/do/chunk/upload');
109+ xhr.send (formData);
110+ });
111+ }
112+
113+ function mergeChunks(fileId, totalChunks, fileName, path) {
114+ return fetch('/do/chunk/merge', {
115+ method: 'POST',
116+ headers: {'Content-Type': 'application/x-www-form-urlencoded'},
117+ body: 'fileId= ' + encodeURIComponent(fileId) +
118+ '&totalChunks= ' + totalChunks +
119+ '&fileName= ' + encodeURIComponent(fileName) +
120+ '&path= ' + encodeURIComponent(path)
121+ }).then (function(r) { return r.json (); })
122+ .then (function(d) { return d.stat ; });
123+ }
62124
63- // 判断拖放的元素是否为文件,如果是,则模拟表单提交
64- if (file) {
65- // 创建 form 元素
66- const form = document.createElement ('form');
67- form.setAttribute ('method', 'post');
68- form.setAttribute ('enctype', 'multipart/form-data');
69- form.setAttribute ('action', '/do/upload/{{.path }}');
125+ async function uploadFile(file, uploadPath) {
126+ var fileId = getFileId(file);
127+ var totalChunks = Math.ceil (file.size / CHUNK_SIZE) || 1;
128+ showProgress(file.name );
70129
71- // 创建 file input 元素
72- const fileInput = document.createElement ('input');
73- fileInput.setAttribute ('type', 'file');
74- fileInput.setAttribute ('name', 'file');
75- fileInput.files = event.dataTransfer.files ;
130+ var uploadedList = await checkChunks(fileId, totalChunks);
131+ var uploadedSet = new Set(uploadedList);
132+ var completedChunks = uploadedList.length ;
76133
77- // 创建 submit input 元素
78- const submitInput = document.createElement ('input');
79- submitInput.setAttribute ('type', 'submit');
80- submitInput.setAttribute ('value', '{{t " submit" }}');
81- // 添加元素到 form 中
82- form.appendChild (fileInput);
83- form.appendChild (submitInput);
84- // 添加 form 到 body 中
85- body.appendChild (form);
86- // 提交表单
87- form.submit ();
134+ for (var i = 0; i < totalChunks; i++) {
135+ if (uploadedSet.has (i)) {
136+ updateProgress(completedChunks / totalChunks * 100);
137+ continue;
138+ }
139+ var chunk = file.slice (i * CHUNK_SIZE, Math.min ((i + 1) * CHUNK_SIZE, file.size ));
140+ var capturedI = i;
141+ try {
142+ await uploadChunk(fileId, capturedI, totalChunks, chunk, function(chunkProg) {
143+ updateProgress((completedChunks + chunkProg) / totalChunks * 100);
144+ });
145+ completedChunks++;
146+ updateProgress(completedChunks / totalChunks * 100);
147+ } catch(e) {
148+ hideProgress();
149+ alert('上传失败:' + e.message );
150+ return;
151+ }
88152 }
89- });
90153
91- // 防止浏览器默认行为
92- body.addEventListener ('dragover', (event) = > {
154+ updateProgress(100);
155+ try {
156+ var ok = await mergeChunks(fileId, totalChunks, file.name , uploadPath);
157+ hideProgress();
158+ if (ok) {
159+ if (confirm('上传成功,点击确认刷新')) location.reload ();
160+ } else {
161+ alert('文件合并失败');
162+ }
163+ } catch(e) {
164+ hideProgress();
165+ alert('合并请求失败');
166+ }
167+ }
168+
169+ // 拖放上传
170+ var body = document.querySelector ('body');
171+ body.addEventListener ('drop', function(event) {
172+ event.preventDefault ();
173+ event.stopPropagation ();
174+ var file = event.dataTransfer.files [0];
175+ if (file) uploadFile(file, '{{.path }}');
176+ });
177+ body.addEventListener ('dragover', function(event) {
93178 event.preventDefault ();
94179 event.stopPropagation ();
95180 });
96- //拖放上传文件 end
181+
182+ // 文件选择上传
183+ document.getElementById ('fileInput').addEventListener ('change', function() {
184+ if (this.files.length > 0) uploadFile(this.files [0], '{{.path }}');
185+ });
186+
97187 function createNewDir() {
98- const dirName = window.prompt (" 请输入文件夹名:" );
188+ var dirName = window.prompt (" 请输入文件夹名:" );
99189 if (dirName !== null) {
100190 $ .post (" /do/newdir" ,{path:{{.path }},dirname:dirName},function(data,status){
101191 if (status == " success" ){
112202 }
113203 }
114204 function createNewFile() {
115- const fileName = window.prompt (" 请输入文件名:" );
205+ var fileName = window.prompt (" 请输入文件名:" );
116206 if (fileName !== null) {
117207 $ .post (" /do/newfile" ,{path:{{.path }},filename:fileName},function(data,status){
118208 if (status == " success" ){
161251 }
162252 }
163253 function edite(path) {
164- var temp = document.createElement (" form" ); //创建form表单
254+ var temp = document.createElement (" form" );
165255 temp.action = " /edite" ;
166256 temp.method = " post" ;
167- temp.target = " _blank"
168- temp.style.display = " none" ;//表单样式为隐藏
169- var opt = document.createElement (" input" ); //添加input标签
170- opt.type = " text" ; //类型为text
171- opt.name = " path" ; //设置name属性
172- opt.value = path; //设置value属性
257+ temp.target = " _blank" ;
258+ temp.style.display = " none" ;
259+ var opt = document.createElement (" input" );
260+ opt.type = " text" ;
261+ opt.name = " path" ;
262+ opt.value = path;
173263 temp.appendChild (opt);
174264 document.body.appendChild (temp);
175265 temp.submit ();
176266 return temp;
177267 }
178- document.getElementById ('fileInput').addEventListener ('change', function() {
179- if (this.files.length > 0) {
180- // 创建一个FormData对象
181- var formData = new FormData();
182- formData.append ('file', this.files [0]);
183-
184- // 创建一个XMLHttpRequest对象
185- var xhr = new XMLHttpRequest();
186-
187- // 设置请求方法和上传文件的URL
188- xhr.open ('POST', '/do/upload/{{.path }}', true);
189-
190- // 设置请求完成的处理函数
191- xhr.onload = function () {
192- if (xhr.status === 200) {
193- alert('文件上传成功');
194- location.reload (); // 或者其他的逻辑,比如显示上传的文件
195- } else {
196- alert('文件上传失败');
197- }
198- };
199-
200- // 发送FormData对象
201- xhr.send (formData);
202- }
203- });
204-
205268</script>
206269{{ end }}
207270</body>
208- </html >
271+ </html >
0 commit comments