UPload.js 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. /*
  2. 上传下载处理类
  3. */
  4. Namespace.register("U.UF.UP");
  5. //上传总函数
  6. /*
  7. * @param {array} 所有需要上传的input
  8. * @param {function} 上传成功回调函数
  9. * @param {array} 回调参数
  10. * @param {string} 上传后响应的处理文件地址 http://disk.1473.cn/upload.ashx
  11. * 上下文(上一个函数与下一个函数的联系):
  12. r.context 回调函数的参数。上下文之间的传参,同第四个参数。
  13. 返回值说明:
  14. 由开发者定义:例如:可以定义为数组,格式如下:
  15. array [文件在服务器的路径, 缩略图的路径, 文件id, 文件大小, 文件对应群, 文件目录id]
  16. */
  17. U.UF.UP.upload = function (inputarr, url, cb, params) {
  18. //如果是html5,走html5
  19. //如果有flash,则走flash。此处难做,暂时不做。
  20. //如果html,走html..不能断点续传,不能解析md5.
  21. }
  22. //#region input上传
  23. /**
  24. * html input上传
  25. *
  26. * @param {array} 所有需要上传的input
  27. * @param {string} 上传后响应的处理文件地址 http://disk.1473.cn/upload.ashx
  28. * @param {function} 上传成功回调函数
  29. * @param {array} 回调参数
  30. */
  31. U.UF.UP.inputUpload = function (inputarr, url, cb, params) { //生成传输的iframe
  32. U.UF.UP.uploading(inputarr, cb, params, url);
  33. }
  34. /**
  35. * html input上传
  36. *
  37. * @param {array} 所有需要上传的input
  38. * @param {function} 上传成功回调函数
  39. * @param {array} 回调参数
  40. * @param {string} 上传后响应的处理文件地址 http://disk.1473.cn/upload.ashx
  41. */
  42. U.UF.UP.uploading = function (inputarr, cb, params, url) { //生成传输的iframe
  43. var _iframe, //iframe变量
  44. _body = document.body, //body
  45. _name = Guid.guidNoDash() //用于刷新的iframe的id
  46. ;
  47. //创建一个接收上传回值的iframe,创建这个iframe主要的作用是做无刷上传,让上传的input不在页面上刷新而是在iframe里面刷新(为什么要创建iframe,因为form上传页面是会刷的,需要通过)
  48. _iframe = $$("iframe", { "id": _name, "name": _name, "width": 0, "height": 0, "style": { "display": "none" }, "frameBorder": 0 }, _body);
  49. //创建一个iframe用于做无刷上传 因为form上传的时候会刷新页面但是如果form的action属性指向的是一个iframe就不会刷新页面,这里为什么要创建跨域的iframe的因为我们项目通常不是一个域名是多个域名,等input上传结束后需要通过iframe去取值,那么下面的创建就显得非常重要
  50. U.UF.C.iframeSameDomain(_iframe, "", function () {
  51. //提交input上传
  52. U.UF.UP.inputUpload.submit(_iframe, inputarr, cb, params, url, _name);
  53. });
  54. }
  55. /**
  56. * html input上传提交区域
  57. *
  58. * @param {element} 用于刷新页面的iframe数组
  59. * @param {array} 所有需要上传的input
  60. * @param {function} 上传成功回调函数
  61. * @param {array} 回调参数
  62. * @param {string} 回调调用地址 允许带参数
  63. * @param {string} 刷新iframe的name
  64. */
  65. U.UF.UP.inputUpload.submit = function (iframe, inputarr, cb, params, url, name) {
  66. //input上传处理,首先创建一个form表单,然后把需要上传的input循环的放入form中,上传到服务器中
  67. var i, _form, _cloneinput, _changefun, _isfile;
  68. //跨域页面必须设置name,由于在ie8-的系列在创建元素的过程中无法设置name会出现问题,所以在这里加成成功后才能设置
  69. iframe.contentWindow.name = name;
  70. //创建一个form表单进行上传
  71. _form = $$("form", { "action": url, "target": name, "encoding": "multipart/form-data", "enctype": "multipart/form-data", "method": "post", "name": "loading", "style": { "display": "none"} }, document.body);
  72. //循环把input放在form表单里面
  73. for (i = 0; i < inputarr.length; i++) {
  74. //给上传的input设置id,如果不设置的话后台就无法获取上传的文件
  75. inputarr[i].name = inputarr[i].name || inputarr[i].id || Guid.newGuid();
  76. //由于要把input追加到上面创建的form表单里面,所以要克隆一个input
  77. _cloneinput = inputarr[i].cloneNode();
  78. //由于克隆的元素的value值还存在 也说明文件还存在,那么会导致上传同一个文件onchange事件无法触发,下面就是清理value值的兼容
  79. //清空input内容处理,在之前测试是用无数次的情况下会出现异常错误,所以加了try catch
  80. try {
  81. //ie清理value值的方法,比较麻烦,ie input file设置value = ""无效 所以没办法
  82. if (document.selection) {
  83. _cloneinput.select();
  84. document.selection.clear();
  85. }
  86. else {
  87. _cloneinput.value = "";
  88. }
  89. }
  90. catch (e) { }
  91. //把创建好的input代替现在要上传的input
  92. if (inputarr[i].parentNode) {
  93. inputarr[i].parentNode.replaceChild(_cloneinput, inputarr[i]); //由于要把上传的元素放在form里面进行上传处理,所以这里要克隆一个元素,否则元素就会丢失。
  94. }
  95. //form表单里面添加
  96. _form.appendChild(inputarr[i]); //把input添加到form表单里
  97. //判断上传的文件是否是file,如果不是file那么就不用multipart/form-data这种格式提交,因为只是正常的上传input里面只有文字的会产生乱码,这种乱码在java下是没有办法看的
  98. if (inputarr[i].type == "file") {
  99. _isfile = true;
  100. }
  101. }
  102. //如果不是文件上传 只是传输input,那么改成文本上传
  103. if (_isfile !== true) {
  104. _form.encoding = _form.enctype = "application/x-www-form-urlencoded";
  105. }
  106. //上传异步处理
  107. U.UF.DL.iframeLoad(iframe, function () {
  108. U.selectEl(_form).remove(); //元素移除
  109. U.UF.UP.inputUpload.asyn(iframe, inputarr, cb, params); //上传结束异步
  110. });
  111. //开始上传处理
  112. _form.submit();
  113. //拼接传参的链接,在上传的过程中添加上传用户的id,此处需要删除.因为disk.1473.cn的上传是需要做用户识别的,所以这里设置了用户id,但是这种方式是错误的,应该直接去后台获取用户id
  114. // if (US && US.userInfo && US.userInfo.userid) {
  115. // url = url + (url.indexOf("?") > -1 ? "&" : "?") + "UserId=" + (US.userInfo.userid || US.userInfo.userid);
  116. // }
  117. }
  118. /**
  119. * 上传结束异步
  120. *
  121. * @param {element} 用于刷新页面的iframe
  122. * @param {array} 所有需要上传的input
  123. * @param {function} 上传成功回调函数
  124. * @param {object} 回调参数
  125. */
  126. U.UF.UP.inputUpload.asyn = function (iframe, inputarr, cb, params) {
  127. //跨域上传的时候,服务器返回值,在ie下已经可以直接获取到值,其他浏览器不行,这里给iframe修改src让src指向"about:blank"
  128. if (!(U.UF.CI.getBrowser().browser == "msie")) {
  129. iframe.src = "about:blank";
  130. //由于src重新赋值
  131. setTimeout(function () {
  132. U.UF.UP.inputUpload.callback(iframe, inputarr, cb, params); //执行回调处理
  133. }, 0);
  134. }
  135. //如果是ie浏览器的情况,那么直接回调,已经经过测试
  136. else {
  137. U.UF.UP.inputUpload.callback(iframe, inputarr, cb, params); //执行回调处理
  138. }
  139. }
  140. /**
  141. * 上传回调处理
  142. *
  143. * @param {element} 用于刷新页面的iframe
  144. * @param {array} 所有需要上传的input
  145. * @param {function} 上传成功回调函数
  146. * @param {object} 回调参数
  147. */
  148. U.UF.UP.inputUpload.callback = function (iframe, inputarr, cb, params) {
  149. var _value = U.UF.UP.inputUpload.getData(iframe); //获取服务器返回的值
  150. //上传成功后删除iframe
  151. U.selectEl(iframe).remove();
  152. //回调处理
  153. if (U.UF.C.isFunction(cb)) { //判断是否为函数的处理
  154. //调用回调的处理
  155. cb({
  156. "value": _value, //服务器返回的数组,类似[文件在服务器的路径, 缩略图的路径, 文件id, 文件大小, 文件对应群, 文件目录id]
  157. "context": params, //
  158. "inputs": inputarr
  159. });
  160. }
  161. }
  162. /**
  163. * 获取上传成功后后台返回的值
  164. * @param {element} 用于刷新页面的iframe
  165. *
  166. */
  167. U.UF.UP.inputUpload.getData = function (iframe) {
  168. var _value = null; //获取返回值的变量
  169. //通过iframe.contentWindow找到执行域到执行域里面获取innerHTML的方式获取值
  170. try {
  171. _value = iframe.contentWindow.document.body.innerHTML;
  172. }
  173. catch (e) { }
  174. //如果上面获取值的方式没有成功,就使用下面的方法获取
  175. if (!_value) {
  176. try {
  177. _value = iframe.contentWindow.name != iframe.id ? iframe.contentWindow.name : ""; //因为跨域上传后iframe的src的地址已经是跨域的地址,这个时候要通过Window.name方式获取跨域的值
  178. }
  179. catch (e) {
  180. }
  181. }
  182. //上传失败
  183. if (_value == null) {
  184. U.alert("服务器处理繁忙,上传失败");
  185. }
  186. else {
  187. //获取值转化成json对象
  188. _value = U.UF.C.toJson(_value);
  189. }
  190. return _value;
  191. }
  192. //#endregion
  193. //#region html5上传
  194. /*
  195. * @param {element} 所有需要上传的input
  196. * @param {function} 上传成功回调函数
  197. * @param {object} 失败的回调
  198. {
  199. * "error": "U.UF.UP.error", //错误处理
  200. * "select": "U.UF.UP.select", //选择文件处理
  201. * "getHashCallBack": "U.UF.UP.getHashCallBack", //上传解析文件的处理
  202. * "progress": "U.UF.UP.progress", //解析文件md5值,和上传文件的时候的进度条处理
  203. * "uploadComplete": "U.UF.UP.uploadComplete", //上传结束的处理,这个时候还没有返回值
  204. * "getData": "U.UF.UP.getData", //上传结束后服务器返回的值
  205. * "endUpload": "U.UF.UP.endUpload", //上传结束处理
  206. }
  207. */
  208. U.UF.UP.html5Upload = function (fileinfo, succallback, callback) { //生成传输的iframe
  209. //进行文件加密 回调参数(进度,完成,文件hash)
  210. U.UF.UP.html5Upload.fileMd5(fileinfo, function (progress, finish, filehash) {
  211. if (finish) {//判断是否解析完成
  212. //获取hash后的回调处理
  213. if (U.UF.C.isFunction(callback.getHashCallBack)) {
  214. callback.getHashCallBack(filehash, fileinfo, succallback, callback.error);
  215. }
  216. }
  217. });
  218. }
  219. /*
  220. * @param {element} 所有需要上传的input
  221. * @param {function} 解析回调函数
  222. */
  223. U.UF.UP.html5Upload.fileMd5 = function (file, callback) {//生成文件hash
  224. var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice, //分割文件的方法
  225. chunkSize = 2097152, // Read in chunks of 2MB
  226. chunks = Math.ceil(file.size / chunkSize), //分割的次数
  227. currentChunk = 0,
  228. spark = new U.UF.EC.SparkMD5.ArrayBuffer(),
  229. fileReader = new FileReader()
  230. ;
  231. file.fileReader = fileReader;
  232. //解析监听
  233. fileReader.onload = function (e) {
  234. spark.append(e.target.result);
  235. currentChunk++;
  236. //判断是否解析成功
  237. if (currentChunk < chunks) {
  238. loadNext();
  239. callback({ 'Loaded': currentChunk, 'Total': chunks }) // 参数:进度
  240. }
  241. else {
  242. callback({ 'Loaded': 100, 'Total': 100 }, true, spark.end()) // 参数:进度、 是否完成、 文件hash
  243. }
  244. };
  245. //解析失败监听
  246. fileReader.onerror = function () {
  247. callback(null, 'oops, something went wrong.') // 参数:进度
  248. };
  249. //解析下一步处理
  250. var loadNext = function () {
  251. var start = currentChunk * chunkSize,
  252. end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
  253. fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
  254. }
  255. loadNext();
  256. }
  257. /*
  258. * 判断上传的文件是否在服务器中
  259. * @param {file} 所有需要上传的input
  260. * @param {string} 上传文件的hash值
  261. * @param {function} 解析回调函数
  262. */
  263. U.UF.UP.html5Upload.select = function (file, filehash, callback) {
  264. U.A.Request("http://upload.1473.cn/select", [file.name, filehash, file.size], function (r) {
  265. callback(r.value.fileServerName, r.value.filesize);
  266. });
  267. }
  268. /*
  269. * 断点续传函数
  270. * @param {file} 文件
  271. * @param {int} 文件总大小
  272. * @param {int} 文件每次上传
  273. * @param {string} 文件服务器名
  274. * @param {int} 服务器文件大小
  275. * @param {fun} 成功回调函数
  276. * @param {fun} 失败回调函数
  277. * @param {int} 第几次上传次数
  278. * @param {int} 总上传次顺
  279. * @param {string} 文件hash
  280. */
  281. U.UF.UP.html5Upload.loop = function (file, filehash, fileservername, filesize, callback) {
  282. var _xhr, _fd, _thunkto, _islast, // 切割末端
  283. _totalsize = file.size, // 总大小
  284. _eachsize = 1024 * 500, // 每次上传大小 这里是500kb
  285. _thunkfrom = filesize // 切割起始端
  286. ;
  287. //判断是否是最后一次上传
  288. if (_eachsize + filesize >= _totalsize) {
  289. _thunkto = _totalsize; //设置上传结束为止的大小
  290. _islast = true; //设置本次上传为最后一次上传
  291. }
  292. //非最后一次上传,这是每次上传为500kb
  293. else {
  294. _thunkto = _eachsize + filesize;
  295. }
  296. //创建form表单发送数据
  297. _fd = new FormData();
  298. _fd.append('theFile', file.slice(_thunkfrom, _thunkto)); // 分好段的文件
  299. _fd.append('filehash', filehash);
  300. _fd.append('fileChunk', 0); // 大小
  301. _fd.append('isLastChunk', _islast); // 是否最后一次上传 count === counts - 1
  302. _fd.append('fileServerName', fileservername); //文件名
  303. //调用ajax请求发送form数据
  304. _xhr = new XMLHttpRequest();
  305. file.xhr = _xhr;
  306. _xhr.open("post", "http://upload.1473.cn/upload", true);
  307. _xhr.onreadystatechange = function () {
  308. if (_xhr.readyState == 4 && _xhr.status == 200) {
  309. var _rs = JSON.parse(_xhr.responseText); //获取后台返回的值
  310. if (_rs.status == 200) {
  311. callback({ 'Loaded': _thunkto, 'Total': _totalsize }); //进度条处理
  312. //判断是否继续上传
  313. if (!_rs.isLastChunk) {
  314. //继续上传
  315. U.UF.UP.html5Upload.loop(file, filehash, fileservername, _thunkto, callback)
  316. }
  317. else {
  318. callback(true);
  319. }
  320. }
  321. }
  322. };
  323. _xhr.send(_fd);
  324. }
  325. /**
  326. * 删除指定上传文件
  327. *
  328. */
  329. U.UF.UP.html5Upload.deleteUploadFile = function (file) {
  330. if (file.fileReader) {
  331. file.fileReader.abort(); //停止解析
  332. }
  333. if (file.xhr) {
  334. file.xhr.abort(); //停止上传
  335. }
  336. }
  337. /**
  338. * 删除所有的文件
  339. *
  340. */
  341. U.UF.UP.html5Upload.deleteUploadAllFile = function () {
  342. }
  343. Namespace.register("U.UF.UP.HTML5");
  344. /**
  345. * html5上传文件函数
  346. * 可另外写一个函数封装为其他开发者也能上传的函数,需要多加2个参数,服务器文件名,已经上传大小
  347. *
  348. * @param url 必填! 上传地址
  349. * @param file 必填! 上传文件对象,非input,是input里面的问题件
  350. * @param callback 必填! 上传成功回调,其值为文件对象file。里面有
  351. * 返回值为文件对象,其值在file.fileServerName中。
  352. * 形如:fileHash: "8a4e8d737b1514414e84c3428fceaffc"
  353. fileReader: FileReader {readyState: 2, result: ArrayBuffer(57), error: null, onloadstart: null, onprogress: null, …}
  354. fileServerName: "0c66a100-568e-11ec-bd9b-a7f8f2b18a24.txt"
  355. lastModified: 1599451644496
  356. lastModifiedDate: Mon Sep 07 2020 12:07:24 GMT+0800 (中国标准时间) {}
  357. name: "文件.txt"
  358. size: 57
  359. type: "text/plain"
  360. uploadedSize: 0
  361. url: "http://upload.1473.cn/upload"
  362. * @param md5callback 非必填项!
  363. * md5验证进度条回调,上传大文件做md5验证进度条, 分片大小为2M
  364. * 其取值如下:{ 'Loaded': currentChunk, 'Total': chunks } 共有多少分片,当前解析到哪一个分片
  365. * { 'Loaded': "success", 'Total': 100 } 全部完成
  366. * { 'Loaded': "error", 'Total': 'oops, something went wrong.' } 如果Loaded为error,表示发生错误,错误信息放置在Total中。
  367. * @param upprogresscallback 非必填项!
  368. * 上传进度条回调,上传大文件做文件上传进度条用。 分片大小为500kb
  369. * 否则,progress为进度条{ 'Loaded': currentChunk, 'Total': chunks }
  370. * 上传成功后的返回值为{ 'Loaded': "success", 'Total': chunks }。
  371. */
  372. U.UF.UP.HTML5.upload = function (url, file, callback, md5callback, upprogresscallback) {
  373. //文件md5验证,并生成进度条
  374. U.UF.UP.HTML5.fileMd5(file, function (progress, filehash) {
  375. //错误处理
  376. if (progress.Loaded == "error") {
  377. console.log("上传错误:" + progress.Total);
  378. }
  379. //解析完成
  380. if (progress.Loaded == "success") {
  381. ////根据filehash去数据库判断是否以前已经上传过,已经上传,则不用再上传,否则,执行上传
  382. //写自己的代码的地方
  383. file.url = url;
  384. file.fileHash = filehash;
  385. //执行上传。去upload选取上传数据,此数据库没有做记录,是否已经上传,是采用文件覆盖的方式执行上传。
  386. U.A.Request("http://upload.1473.cn/select", [file.name, file.fileHash, file.size], function (r) {
  387. if (r.value) {
  388. //获取服务器返回值,包含了文件服务器名称,文件大小。
  389. var _result = r.value;
  390. //此处生成上传文件的服务器名称,即guid名称。
  391. file.fileServerName = _result.fileServerName;
  392. //_result.filesize为已经上传的文件大小
  393. file.uploadedSize = _result.filesize;
  394. //上传文件,并生成进度条。
  395. U.UF.UP.HTML5.loop(file.url, file, file.fileHash, file.fileServerName, file.uploadedSize,
  396. //回调函数,参数一为进度条
  397. function (progress) {
  398. //上传进度条。
  399. if (progress.Loaded == "success") {
  400. //上传成,回调。
  401. callback(file);
  402. }
  403. //上传中的处理
  404. else {
  405. //上传中的进度条
  406. upprogresscallback(progress);
  407. }
  408. }
  409. );
  410. }
  411. else {
  412. U.alert("上传异常,服务器未响应,此处需要做处理!");
  413. }
  414. });
  415. }
  416. //未解析完毕进度条处理
  417. else {
  418. //生成md5验证进度条
  419. md5callback(progress);
  420. }
  421. });
  422. }
  423. /**
  424. * 给使用uform框架的其他开发者封装的函数,未做验证
  425. * html5上传文件函数,
  426. * 可另外写一个函数封装为其他开发者也能上传的函数,需要多加2个参数,服务器文件名,已经上传大小
  427. *
  428. * @param url 必填! 上传地址
  429. * @param file 必填! 上传文件对象,非input,是input里面的问题件
  430. * @param fileservername 必填! 文件服务器名称
  431. * @param uploadedsize 必填! 文件已经上传的大小,未上传填写0.
  432. * @param callback 必填! 上传成功回调,其值为文件对象file。里面有
  433. * 返回值为文件对象,其值在file.fileServerName中。
  434. * 形如:fileHash: "8a4e8d737b1514414e84c3428fceaffc"
  435. fileReader: FileReader {readyState: 2, result: ArrayBuffer(57), error: null, onloadstart: null, onprogress: null, …}
  436. fileServerName: "0c66a100-568e-11ec-bd9b-a7f8f2b18a24.txt"
  437. lastModified: 1599451644496
  438. lastModifiedDate: Mon Sep 07 2020 12:07:24 GMT+0800 (中国标准时间) {}
  439. name: "文件.txt"
  440. size: 57
  441. type: "text/plain"
  442. uploadedSize: 0
  443. url: "http://upload.1473.cn/upload"
  444. * @param md5callback 非必填项!
  445. * md5验证进度条回调,上传大文件做md5验证进度条, 分片大小为2M
  446. * 其取值如下:{ 'Loaded': currentChunk, 'Total': chunks } 共有多少分片,当前解析到哪一个分片
  447. * { 'Loaded': "success", 'Total': 100 } 全部完成
  448. * { 'Loaded': "error", 'Total': 'oops, something went wrong.' } 如果Loaded为error,表示发生错误,错误信息放置在Total中。
  449. * @param upprogresscallback 非必填项!
  450. * 上传进度条回调,上传大文件做文件上传进度条用。 分片大小为500kb
  451. * 否则,progress为进度条{ 'Loaded': currentChunk, 'Total': chunks }
  452. * 上传成功后的返回值为{ 'Loaded': "success", 'Total': chunks }。
  453. */
  454. U.UF.UP.HTML5.upload.Api = function (url, file, fileservername, uploadedsize, callback, md5callback, upprogresscallback) {
  455. //文件md5验证,并生成进度条
  456. U.UF.UP.HTML5.fileMd5(file, function (progress, filehash) {
  457. //错误处理
  458. if (progress.Loaded == "error") {
  459. console.log("上传错误:" + progress.Total);
  460. }
  461. //解析完成
  462. if (progress.Loaded == "success") {
  463. ////根据filehash去数据库判断是否以前已经上传过,已经上传,则不用再上传,否则,执行上传
  464. //写自己的代码的地方
  465. file.url = url;
  466. file.fileHash = filehash;
  467. //此处生成上传文件的服务器名称,即guid名称。
  468. file.fileServerName = fileservername;
  469. //_result.filesize为已经上传的文件大小
  470. file.uploadedSize = uploadedsize;
  471. //上传文件,并生成进度条。
  472. U.UF.UP.HTML5.loop(file.url, file, file.fileHash, file.fileServerName, file.uploadedSize,
  473. //回调函数,参数一为进度条
  474. function (progress) {
  475. //上传进度条。
  476. if (progress.Loaded == "success") {
  477. //上传成,回调。
  478. callback(file);
  479. }
  480. //上传中的处理
  481. else {
  482. //上传中的进度条
  483. upprogresscallback(progress);
  484. }
  485. }
  486. );
  487. }
  488. //未解析完毕进度条处理
  489. else {
  490. //生成md5验证进度条
  491. md5callback(progress);
  492. }
  493. });
  494. }
  495. /*
  496. * @param {element} 所需要上传的文件,
  497. * @param {function} 解析回调函数,此回调函数传递参数不一致。
  498. */
  499. U.UF.UP.HTML5.fileMd5 = function (file, callback) {//生成文件hash
  500. var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice, //分割文件的方法
  501. chunkSize = 2097152, // Read in chunks of 2MB
  502. chunks = Math.ceil(file.size / chunkSize), //分割的次数
  503. currentChunk = 0,//当前第一个分割从0开始
  504. spark = new U.UF.EC.SparkMD5.ArrayBuffer(),//得到md5编码
  505. fileReader = new FileReader()
  506. ;
  507. file.fileReader = fileReader;
  508. //解析监听
  509. fileReader.onload = function (e) {
  510. spark.append(e.target.result);
  511. currentChunk++;
  512. //判断md5是否解析成功
  513. if (currentChunk < chunks) {
  514. //未完成,则继续
  515. loadNext();
  516. //并且给出进度条
  517. callback({ 'Loaded': currentChunk, 'Total': chunks }) // 参数:进度
  518. }
  519. else {
  520. //获取md5完成,则执行回调函数
  521. callback({ 'Loaded': "success", 'Total': 100 }, spark.end()) // 参数:进度、 文件hash
  522. }
  523. };
  524. //解析失败监听
  525. fileReader.onerror = function () {
  526. callback({ 'Loaded': "error", 'Total': 'oops, something went wrong.' }) // 参数:进度
  527. };
  528. //解析下一步处理
  529. var loadNext = function () {
  530. var start = currentChunk * chunkSize,
  531. end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
  532. fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
  533. }
  534. loadNext();
  535. }
  536. /*
  537. * 判断上传的文件是否在服务器中,此函数未使用
  538. * @param {file} 需要上传的input
  539. * @param {string} 上传文件的hash值
  540. * @param {function} 解析回调函数
  541. */
  542. U.UF.UP.HTML5.selectFromDB = function (file, filehash, callback) {
  543. //由于历史原因,有mysql数据库和sqlserver数据库保存了上传数据,两个数据库需要合一。此任务列为下学期任务。
  544. //首先去sqlserver数据库去找,为何是此三个参数?
  545. U.A.Request(US.DISK, ["GetFileByHash", filehash, file.size, file.name.getExtendName()], function (r) {
  546. //如果找到,则返回
  547. if (r.value) {
  548. }
  549. else {
  550. //如果没找到,继续去mysql中查找。
  551. //从html5上传接口去查询,此数据库为mysql数据库,由余中豪所做。
  552. U.A.Request("http://upload.1473.cn/select", [file.name, filehash, file.size], function (r) {
  553. //如果有怎么处理?如果没有怎么处理?
  554. if(r.value){
  555. }
  556. else {
  557. //都没找到,回调回去上传
  558. callback(r.value.fileServerName, r.value.filesize);
  559. }
  560. });
  561. }
  562. });
  563. }
  564. /*
  565. * 断点续传函数,此处为html5的上传功能实现,参考upload.1473.cn下面的split-upload.js文件。
  566. * @param {file} 文件对象
  567. * @param {string} 文件hash
  568. * @param {string} 文件服务器名,后端的guid名。由后端返回,同时需要向后端传递。以利于服务器定位文件。
  569. * 每上传完一个片段需要返回一次,用于在服务器查找文件,此处多次返回。
  570. * @param {int} 文件大小。每次增量大小。由后台返回,每上传完一个片段需要返回一次。
  571. * @param {fun} 回调函数,如为上传完毕,回调函数处理进度条,否则,回调函数处理完成事宜。
  572. */
  573. U.UF.UP.HTML5.loop = function (url,file, filehash, fileservername, filesize, callback) {
  574. var _xhr,//ajax请求
  575. _fd,//formdata的实例。
  576. _thunkto,//
  577. _islast=false, // 假定非最后一次上传
  578. _totalsize = file.size, // 总大小
  579. _eachsize = 1024 * 500, // 每次上传大小 这里是500kb
  580. _count = filesize / _eachsize,//上传次数
  581. _thunkfrom = filesize // 切割起始端
  582. ;
  583. //判断是否是最后一次上传
  584. if (filesize >= _totalsize) {
  585. _thunkto = _totalsize; //设置上传结束为止的大小
  586. _islast = true; //设置本次上传为最后一次上传
  587. }
  588. //非最后一次上传,这是每次上传为500kb
  589. else {
  590. _thunkto = _eachsize + filesize;
  591. }
  592. //创建form表单发送数据
  593. _fd = new FormData();
  594. _fd.append('theFile', file.slice(_thunkfrom, _thunkto)); // 分好段的文件
  595. _fd.append('filehash', filehash);
  596. _fd.append('fileChunk', _count); // 上传次数
  597. _fd.append('isFirstChunk', _count); // 是否第一次上传
  598. _fd.append('isLastChunk', _islast); // 是否最后一次上传 count === counts - 1
  599. _fd.append('fileServerName', fileservername); //文件名
  600. //调用ajax请求发送form数据
  601. _xhr = new XMLHttpRequest();
  602. file.xhr = _xhr;
  603. _xhr.open("post", url, true);
  604. //_xhr.open("post", "http://upload.1473.cn/upload", true);
  605. _xhr.onreadystatechange = function () {
  606. if (_xhr.readyState == 4 && _xhr.status == 200) {
  607. var _rs = JSON.parse(_xhr.responseText); //获取后台返回的值
  608. if (_rs.status == 200) {
  609. callback({ 'Loaded': _thunkto, 'Total': _totalsize }); //进度条处理
  610. //判断是否继续上传
  611. if (_rs.isLastChunk) {
  612. //上传完毕,返回success。
  613. callback({ 'Loaded': "success", 'Total': _totalsize });
  614. return;
  615. }
  616. //继续上传,必须放在这里。
  617. U.UF.UP.HTML5.loop(url, file, filehash, fileservername, _thunkto, callback)
  618. }
  619. else {
  620. U.alert("上传服务器出错!");
  621. }
  622. }
  623. };
  624. _xhr.send(_fd);
  625. }
  626. /**
  627. * 停止指定上传文件
  628. *
  629. */
  630. U.UF.UP.HTML5.stopUploadFile = function (file) {
  631. if (file.fileReader) {
  632. file.fileReader.abort(); //停止解析
  633. }
  634. if (file.xhr) {
  635. file.xhr.abort(); //停止上传
  636. }
  637. }
  638. /**
  639. * 删除所有的文件
  640. *
  641. */
  642. U.UF.UP.HTML5.deleteUploadAllFile = function () {
  643. }
  644. //#endregion
  645. //#region flash上传处理
  646. /**
  647. *flash上传按钮的数组,把所有加载的flash按钮放在这里,这样的话在多个地方加载flash按钮就可以在加载成功后触发事件后统一设置flash上传按钮的样式和回调事件
  648. *{ flashbottom:flashobject, uploadtype:"*", style:{"width":"100", "height":"100"} callback:{
  649. * "error": "U.UF.UP.error", //错误处理
  650. * "select": "U.UF.UP.select", //选择文件处理
  651. * "getHashCallBack": "U.UF.UP.getHashCallBack", //上传解析文件的处理
  652. * "progress": "U.UF.UP.progress", //解析文件md5值,和上传文件的时候的进度条处理
  653. * "uploadComplete": "U.UF.UP.uploadComplete", //上传结束的处理,这个时候还没有返回值
  654. * "getData": "U.UF.UP.getData", //上传结束后服务器返回的值
  655. * "endUpload": "U.UF.UP.endUpload", //上传结束处理
  656. *} }
  657. */
  658. U.UF.UP.flashbottom = {}; //flash上传按钮的处理
  659. /**
  660. * flash按钮初始化得到
  661. *
  662. * @param {element} flash对象要放置的地方
  663. * @param {string} flash对象名字
  664. * @param {object} flash按钮的样式 {"width":"100", "height":"100"}
  665. * @param {object} flash按钮上传的回调函数的处理 {
  666. * "error": "U.UF.UP.error", //错误处理
  667. * "select": "U.UF.UP.select", //选择文件处理
  668. * "getHashCallBack": "U.UF.UP.getHashCallBack", //上传解析文件的处理
  669. * "progress": "U.UF.UP.progress", //解析文件md5值,和上传文件的时候的进度条处理
  670. * "uploadComplete": "U.UF.UP.uploadComplete", //上传结束的处理,这个时候还没有返回值
  671. * "getData": "U.UF.UP.getData", //上传结束后服务器返回的值
  672. * "endUpload": "U.UF.UP.endUpload", //上传结束处理
  673. *} }
  674. */
  675. U.UF.UP.addFlashUploadBottom = function (el, name, style, callback, uploadtype) {
  676. var _divel,
  677. _width = style._width,
  678. _height = style._height,
  679. _uploadbootom = U.selectEl("object", el)[0]; //获取flash按钮
  680. _name = name || Guid.newGuid(); //随机生成的name
  681. //如果flash上传按钮,添加,这里做了ie低版本的兼容
  682. if (!_uploadbootom) {
  683. _divel = $$("div", {
  684. "innerHTML": "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' class='U_MD_D_filePrew' _width='" + style._width + "' _height='" + style._height + "' id='" + _name + "' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0'>" +
  685. "<param name='movie' value='/img/upload.swf' />" +
  686. "<param name='menu' value='false' />" +
  687. "<param name='wmode' value='Opaque' />" +
  688. "<param name='quality' value='high' />" +
  689. "<param name='bgcolor' value='ffffff' />" +
  690. "<param name='allowScriptAccess' value='always' />" +
  691. "<embed src='/img/upload.swf' quality='high' bgcolor='ffffff' _width='" + style._width + "' _height='" + style._height + "' name='" + _name + "' align='middle' play='true' wmode='transparent' loop='false' quality='high' style='z-index: 0;' allowScriptAccess='always' type='application/x-shockwave-flash' pluginspage='http://www.adobe.com/go/getflashplayer'>" +
  692. "</embed>" +
  693. "</object>"
  694. });
  695. _uploadbootom = _divel.firstChild; //用上面的div去加载了object和embed标签后这里去获取
  696. el.insertBefore(_uploadbootom, el.firstChild); //insertBefore() 在指定子节点前插入
  697. }
  698. //把上传文件设置到flash集合中
  699. U.UF.UP.flashbottom[name] = {
  700. uploadtype: uploadtype || "*", //上传的格式
  701. flashbottom: U.selectEl("*" + name, el)[0], //flash上传按钮
  702. style: style || {}, //flash按钮的样式
  703. callback: callback || {} //flash按钮的回调函数,定义有注释
  704. };
  705. return _uploadbootom;
  706. }
  707. /**
  708. * flash按钮加载成功的处理
  709. *
  710. */
  711. U.UF.UP.flashLoad = function () {
  712. var i,
  713. _obj = U.UF.UP.flashbottom;
  714. //循环给flash按钮设置处理
  715. for (i in _obj) {
  716. //调用设置
  717. if (_obj[i].flashbottom.setUploadStyle) {
  718. _obj[i].flashbottom.setUploadStyle(i, _obj[i].style, {}, _obj[i].uploadtype); //加载插件初始化
  719. }
  720. }
  721. }
  722. /**
  723. * 错误处理
  724. *
  725. */
  726. U.UF.UP.error = function (e) {
  727. U.alert(e); //错误提醒
  728. }
  729. /**
  730. * 选择文件处理
  731. * @param {string} flash按钮的唯一识别id
  732. * @param {array} 选择上传的文件数组
  733. *
  734. */
  735. U.UF.UP.select = function (bottomid, filesarr) {
  736. var _obj = U.UF.UP.flashbottom[bottomid]; //获取点击弹出选择文件上传的按钮对象
  737. _obj.callback.select(filesarr); //执行flash的回调
  738. }
  739. /**
  740. * 选择文件处理
  741. * @param {element} 选择文件上传的flash按钮
  742. * @param {number} 获取FileReferenceList第几个需要解析的文件
  743. * @param {number} 在FileReferenceList数组里的第几个,默认是0,前端可以不传递,这里会出现一个这样的情况,用户点击上传框选择了文件,这个时候产生了一个FileReferenceList,在未上传完成的过程中又点击选择了文件,又产生了一个FileReferenceList,那么这里会出现多个FileReferenceList同时处理
  744. *
  745. */
  746. U.UF.UP.generateFileHash = function (flashbottom, fileid, i, j) {
  747. flashbottom.generateFileHash(fileid, 0, 0); //执行flash的回调
  748. }
  749. /**
  750. * 上传解析文件的处理
  751. * @param {string} 解析的文件md5值
  752. * @param {string} flash上传按钮的id
  753. *
  754. */
  755. U.UF.UP.getHashCallBack = function (md5value, uploadid, fileid) {
  756. var _obj = U.UF.UP.flashbottom[uploadid]; //获取点击弹出选择文件上传的按钮对象
  757. _obj.callback.getHashCallBack(md5value, fileid); //执行flash的回调
  758. }
  759. /**
  760. * 解析文件md5值,和上传文件的时候的进度条处理
  761. * @param {string} 解析的文件md5值
  762. * @param {string} flash上传按钮的id
  763. * @param {string} 进度的提醒,包括 解析中,上传中,成功
  764. *
  765. */
  766. U.UF.UP.progress = function (speedobj, uploadid, fileid, str) {
  767. var _obj = U.UF.UP.flashbottom[uploadid]; //获取点击弹出选择文件上传的按钮对象
  768. _obj.callback.progress(speedobj, fileid, str); //执行flash的回调
  769. }
  770. /**
  771. * 解析文件md5值,和上传文件的时候的进度条处理
  772. * @param {element} 选择文件上传的flash按钮
  773. * @param {string} 上传文件到哪个链接下处理
  774. * @param {number} 获取FileReferenceList第几个需要解析的文件
  775. * @param {number} 在FileReferenceList数组里的第几个,默认是0,前端可以不传递,这里会出现一个这样的情况,用户点击上传框选择了文件,这个时候产生了一个FileReferenceList,在未上传完成的过程中又点击选择了文件,又产生了一个FileReferenceList,那么这里会出现多个FileReferenceList同时处理
  776. *
  777. */
  778. U.UF.UP.flashUpload = function (flashbottom, fileid, url, i, j) {
  779. flashbottom.upload(url, fileid, i, j); //flash上传调用
  780. }
  781. /**
  782. * 上传结束的处理,这个时候还没有返回值
  783. * @param {object} 上传成功后返回的提示值
  784. * @param {string} flash上传按钮的id
  785. */
  786. U.UF.UP.uploadComplete = function (e, uploadid, fileid) {
  787. var _obj = U.UF.UP.flashbottom[uploadid]; //获取点击弹出选择文件上传的按钮对象
  788. _obj.callback.uploadComplete(e, fileid); //执行flash的回调
  789. }
  790. /**
  791. * 上传结束后服务器返回的值
  792. * @param {object} 服务器响应等到的request结果,request中的data是返回的值
  793. * @param {string} flash上传按钮的id
  794. */
  795. U.UF.UP.getData = function (request, uploadid, fileid) {
  796. var _obj = U.UF.UP.flashbottom[uploadid]; //获取点击弹出选择文件上传的按钮对象
  797. _obj.callback.getData(request, fileid); //执行flash的回调
  798. }
  799. /**
  800. * 上传结束处理
  801. * @param {string} flash上传按钮的id
  802. */
  803. U.UF.UP.endUpload = function (uploadid) {
  804. var _obj = U.UF.UP.flashbottom[uploadid]; //获取点击弹出选择文件上传的按钮对象
  805. _obj.callback.endUpload(); //执行flash的回调
  806. }
  807. /**
  808. * 移除正在上传的文件,当我们在上传的过程中,取消上传,或者是文件已经上传成功了的处理
  809. * @param {element} 选择文件上传的flash按钮
  810. * @param {int} 获取FileReferenceList第几个需要解析的文件
  811. * @param {int} 在FileReferenceList数组里的第几个,默认是0,前端可以不传递,这里会出现一个这样的情况,用户点击上传框选择了文件,这个时候产生了一个FileReferenceList,在未上传完成的过程中又点击选择了文件,又产生了一个FileReferenceList,那么这里会出现多个FileReferenceList同时处理
  812. *
  813. */
  814. U.UF.UP.deleteUploadFile = function (flashbottom, i, j) {
  815. flashbottom.deleteUploadFile(i, j); //flash上传调用
  816. }
  817. /**
  818. * 删除单个选择文件弹框下所有的文件
  819. * @param {int} 在FileReferenceList数组里的第几个,默认是0,前端可以不传递,这里会出现一个这样的情况,用户点击上传框选择了文件,这个时候产生了一个FileReferenceList,在未上传完成的过程中又点击选择了文件,又产生了一个FileReferenceList,那么这里会出现多个FileReferenceList同时处理
  820. *
  821. */
  822. U.UF.UP.deleteReferenceFile = function (flashbottom, i) {
  823. flashbottom.deleteReferenceFile(i); //flash上传调用
  824. }
  825. /**
  826. * 删除所有的文件
  827. *
  828. */
  829. U.UF.UP.deleteUploadAllFile = function (flashbottom) {
  830. flashbottom.deleteUploadAllFile(); //flash上传调用
  831. }
  832. //#endregion
  833. //#region 下载
  834. /**
  835. * 文件下载区域
  836. *
  837. * @param {string} 文件下载的名字 名字.jgp
  838. * @param {string} 下载文件的路径 fa.1473.cn/aa.jpg
  839. * @param {string} 下载文件的处理类的地址 http://disk.1473.cn/USUpfile.ashx typename=" + (fun || "UploadFile"
  840. */
  841. U.UF.UP.download = function (filename, filepath, url) {
  842. var _filenameinput = $$("input", { "type": "text", "value": encodeURIComponent(filename), "name": "filename" }), //下载下来的文件名
  843. _filepathinput = $$("input", { "type": "text", "value": filepath, "name": "filepath" }); //下载的文件在服务器的路径
  844. //调用上传的接口进行下载,实际上传接口的作用是把input上传到服务器进行响应
  845. U.UF.UP.inputUpload([_filenameinput, _filepathinput], url);
  846. }
  847. //#endregion
  848. //#region 帮助处理
  849. /**
  850. * 获取上传的名字和类型
  851. *
  852. * @param {string} 文件名+类型
  853. * @return {array}
  854. ----------[0] 文件名
  855. ----------[1] 文件类型
  856. */
  857. U.UF.UP.getFileNameAndExtension = function (filename) {
  858. filename = filename.toLocaleLowerCase(); //把文字转成消息 如 gg.JPG 转成 gg.jpg 这样下面判断容易
  859. var _num = filename.lastIndexOf("."), //文件后缀.所在的位置
  860. _index = filename.lastIndexOf("\\"),
  861. _xindex = filename.lastIndexOf("/"),
  862. _name = filename.substr((_index > _xindex ? _index : _xindex) + 1, _num), //名字
  863. _extension = filename.substr(_num + 1) //后缀
  864. ;
  865. return [_name, _extension]; //文件名和后缀数组
  866. }
  867. /**
  868. * 判断是否为图片类型,fun为文件名,比如"aaaa.jpg"
  869. *
  870. * @param {string} 文件名
  871. * @param {boolean} 是否为图片
  872. */
  873. U.UF.UP.isImg = function (name) {
  874. var _extension = U.UF.UP.getFileNameAndExtension(name.toLowerCase())[1]; //获取文件的后缀
  875. return ["jpg", "gif", "png", "bmp", "jpeg"].indexOf(_extension) > -1; //根据后缀判断文件是否为图片
  876. }
  877. /**
  878. * 文件由小转大
  879. *
  880. * @param {string} 文件
  881. */
  882. U.UF.UP.minUnitToMaxUnit = function (filesize) {
  883. var _unitarr = ["B", "KB", "M", "G", "TB"], //指定的文件类型
  884. _unit = (filesize + "").replace(U.UF.S.Num, ""), //获取单位
  885. i = _unitarr.indexOf(_unit) < 0 ? 0 : _unitarr.indexOf(_unit); //现在单位对应下标
  886. filesize = parseFloat(filesize); //获取文件大小
  887. //判断文件大小
  888. while (filesize > 1024) {
  889. filesize /= 1024; //每次除以1024,往下一个单位去变化
  890. i++; //单位
  891. }
  892. return parseInt(filesize.toFixed(2)) + _unitarr[i]; //文件大小加单位
  893. }
  894. /**
  895. * 获取最小单位的大小
  896. *
  897. * @param {string} 文件大小 如 10000B 10240KB 等等
  898. */
  899. U.UF.UP.maxUnitToByte = function (filesize) {
  900. var _unitarr = ["B", "KB", "M", "G", "TB"], //指定的文件类型
  901. _unit = (filesize + "").replace(U.UF.S.Num, ""), //获取单位
  902. i = _unitarr.indexOf(_unit); //看看单位对应的大小
  903. i = i < 0 ? 0 : i; //看看转成最小单位需要*i个1024个次方
  904. return parseFloat(filesize) * Math.pow(1024, i); //获取最大单位
  905. }
  906. //#endregion