111
沙世明
2022-11-22 928399eceec50e3d37ea08669a12789a9410a9d2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
    
    var j$ = jQuery.noConflict();
    var filesList = [];
    var Base64 = {};
    j$(document).ready(function() {
 
        //Event listener for click of Upload button
        j$("#uploadButton").click(function(){
            prepareFileUploads();
        });
        
        //Event listener to clear upload details/status bars once upload is complete
        j$("#clear").on('click',function(){
            j$(".upload").remove();
        });
    });
    
    var byteChunkArray; 
    var files;
    var currentFile;
    var $upload;
    var CHUNK_SIZE = 180000; //Must be evenly divisible by 3, if not, data corruption will occur
    var VIEW_URL = '/servlet/servlet.FileDownload?file=';
    //var parentId, you will see this variable used below but it is set in the component as this is a dynamic value passed in by component attribute
    
    //Executes when start Upload button is selected
    function prepareFileUploads(){
        //Get the file(s) from the input field
        files = document.getElementById('filesInput').files;
        
        //Only proceed if there are files selected
        if(files.length == 0){
            alert('Please select a file!');
            return; //end function
        }
        
        //Disable inputs and buttons during the upload process
        j$(".uploadBox input").attr("disabled", "disabled");
        j$(".uploadBox button").attr({
            disabled: "disabled",
            class: "btnDisabled"
        });
      
        //Build out the upload divs for each file selected
        var uploadMarkup = '';
        for(i = 0; i < files.length; i++){
            //Determine file display size
            if(files[i].size < 1000000){
                var displaySize = Math.floor(files[i].size/1000) + 'K';
            }else{
                var displaySize  = Math.round((files[i].size / 1000000)*10)/10 + 'MB';
            }
            
            //For each file being uploaded create a div to represent that file, includes file size, status bar, etc. data-Status tracks status of upload
            uploadMarkup += '<div class="upload" data-status="pending" data-index="'+i+'">'; //index used to correspond these upload boxes to records in the files array
            uploadMarkup += '<div class="fileName"><span class="name">'+ files[i].name + '</span> - '+ displaySize+ '</div>';
            uploadMarkup += '<div class="percentComplete">0%</div>'
            uploadMarkup += '<div class="clear"/>';
            uploadMarkup += '<div class="statusBar">';
            uploadMarkup += '<div class="statusBarPercent"/>';
            uploadMarkup += '</div>';
            uploadMarkup += '</div>';
        }
        
        //Add markup to the upload box
        j$('.uploadBox').append(uploadMarkup);
        
        //Once elements have been added to the page representing the uploads, start the actual upload process
        checkForUploads();
    }
    
    function checkForUploads(){
        //Get div of the first matching upload element that is 'pending', if none, all uploads are complete
        //$upload = j$(".upload:first[data-status='pending']");
        $upload = j$(".upload[data-status='pending']").first();
        if($upload.length != 0){
            //Based on index of the div, get correct file from files array
            currentFile = files[$upload.attr('data-index')];
            
            /*Build the byteChunkArray array for the current file we are processing. This array is formatted as:
            ['0-179999','180000-359999',etc] and represents the chunks of bytes that will be uploaded individually.*/
            byteChunkArray = new Array();  
            
            //First check to see if file size is less than the chunk size, if so first and only chunk is entire size of file
            if(currentFile.size <= CHUNK_SIZE){
                byteChunkArray[0] = '0-' + (currentFile.size - 1);
            }else{
                //Determine how many whole byte chunks make up the file,
                var numOfFullChunks = Math.floor(currentFile.size / CHUNK_SIZE); //i.e. 1.2MB file would be 1000000 / CHUNK_SIZE
                var remainderBytes = currentFile.size % CHUNK_SIZE; // would determine remainder of 1200000 bytes that is not a full chunk
                var startByte = 0;
                var endByte = CHUNK_SIZE - 1;
                
                //Loop through the number of full chunks and build the byteChunkArray array
                for(i = 0; i < numOfFullChunks; i++){
                    byteChunkArray[i] = startByte+'-'+endByte;
                    
                    //Set new start and stop bytes for next iteration of loop
                    startByte = endByte + 1;
                    endByte += CHUNK_SIZE;
                }
                
                //Add the last chunk of remaining bytes to the byteChunkArray
                startByte = currentFile.size - remainderBytes;
                endByte = currentFile.size;
                byteChunkArray.push(startByte+'-'+endByte);
            }
            
            //Start processing the byteChunkArray for the current file, parameter is '' because this is the first chunk being uploaded and there is no attachment Id
            processByteChunkArray('');
               
        }else{
            //All uploads completed, enable the input and buttons
            j$(".uploadBox input").removeAttr("disabled");
            j$(".uploadBox button").removeAttr("disabled").attr("class","btn");
            
            /*Remove the browse input element and replace it, this essentially removes
            the selected files and helps prevent duplicate uploads*/
            j$("#filesInput").replaceWith('<input type="file" name="file" multiple="true" id="filesInput">');
        }
    }
    
    function processByteChunkArray(){
        //Proceed if there are still values in the byteChunkArray, if none, all piece of the file have been uploaded
        console.log('byteChunkArray.length = ' + byteChunkArray.length);
        if(byteChunkArray.length > 0){
            //Determine the byte range that needs to uploaded, if byteChunkArray is like... ['0-179999','180000-359999']
            console.log('byteChunkArray[0] = ' + byteChunkArray[0]);
            var indexes = byteChunkArray[0].split('-'); //... get the first index range '0-179999' -> ['0','179999']
            var startByte = parseInt(indexes[0]); //0
            var stopByte = parseInt(indexes[1]); //179999
            
            //Slice the part of the file we want to upload, currentFile variable is set in checkForUploads() method that is called before this method
            if(currentFile.slice){
                var blobChunk = currentFile.slice(startByte , stopByte + 1);
            }else if (currentFile.mozSlice) {
                var blobChunk = currentFile.mozSlice(startByte , stopByte + 1);
            }
            
            //Create a new reader object, part of HTML5 File API
            var reader = new FileReader();
            
            //Read the blobChunk as a binary string, reader.onloadend function below is automatically called after this line
            reader.readAsDataURL(blobChunk);
            
            //Create a reader.onload function, this will execute immediately after reader.readAsBinaryString() function above;
            reader.onloadend = function(evt){ 
                if(evt.target.readyState == FileReader.DONE){ //Make sure read was successful, DONE == 2
                    //Base 64 encode the data for transmission to the server with JS remoting, window.btoa currently on support by some browsers
                    //var base64value = window.btoa(evt.target.result);
                    var base64value = evt.target.result;
                    Base64.file = base64value;
                    Base64.fileName = currentFile.name;
                    Base64.size = currentFile.size;
                    filesList.push(Base64);
                    AWSService.post(newUrl, JSON.stringify(filesList), function(result){
                        result = JSON.parse(JSON.stringify(result));
                        //Use js remoting to send the base64 encoded chunk for uploading
                        let key = result.object[0];
                        let transId = result.txId;
                        BatchFileUploadController.saveFile(currentFile.name,key,transId,parentId,function(result,event){
                            //Proceed if there were no errors with the remoting call
                            if(result.status == 'success'){
                                //执行trans方法,进行确认成功
                                trans(currentFile.name,transId,1);
                                //Update the percent of the status bar and percent, first determine percent complete
                                var percentComplete = Math.round((stopByte / currentFile.size) * 100);
                                $upload.find(".percentComplete").text(percentComplete + '%');
                                $upload.find(".statusBarPercent").css('width',percentComplete + '%');
                                
                                //Remove the index information from the byteChunkArray array for the piece just uploaded.
                                byteChunkArray.shift(); //removes 0 index
                                                    
                                //Call process byteChunkArray to upload the next piece of the file
                                processByteChunkArray();
                            }else{
                                //执行trans方法,进行确认失败
                                trans(currentFile.name,transId,0);
 
                                //If script is here something broke on the JavasSript remoting call
                                //Add classes to reflect error
                                $upload.attr('data-status','complete');
                                $upload.addClass('uploadError');
                                $upload.find(".statusPercent").addClass('statusPercentError');
                                $upload.attr('title',result.message);
                                
                                //Check and continue the next file to upload
                                checkForUploads();
                            }
                        }); 
                    }, staticResource.token);
                }else{
                    //Error handling for bad read
                    alert('Could not read file');
                }
            };
            
        }else{
            //This file has completed, all byte chunks have been uploaded, set status on the div to complete
            $upload.attr('data-status','complete');
            
            //Change name of file to link of uploaded attachment
            //$upload.find(".name").html('<a href="' + VIEW_URL + attachmentId + '" target="_blank">'+currentFile.name+'</a>');
            debugger
            //Call the checkForUploads to find the next upload div that has data-status="incomplete" and start the upload process. 
            checkForUploads();
        }
    }
 
 
    function trans(fileName,txId,isSuccess){
        let transParameters = {
            txId: txId,
            isSuccess: isSuccess
        };
        console.log('txId = ' + txId);
        AWSService.confirmTrans(staticResource.updateUrl,JSON.stringify(transParameters),function(result){
            console.log(fileName);
            console.log(JSON.stringify(result))
        },staticResource.token)
    }