UNPKG

ng-request-cache

Version:

AngularJS HTTP request cache for IndexeDB and $cacheFactory

507 lines 19.3 kB
/** * # ng-unit unitFactory for web PC 工具类自定义服务 * * 需要在`index.html`入口页面引入的CSS文件 ```html <link href="https://cdn.bootcss.com/toastr.js/latest/css/toastr.min.css" rel="stylesheet"> <link href="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.css" rel="stylesheet"> ``` * * 需要在`index.html`入口页面引入的JS文件 ```html <script type="text/javascript" src="https://cdn.bootcss.com/underscore.js/1.8.3/underscore-min.js"></script> <script type="text/javascript" src="https://cdn.bootcss.com/spin.js/2.3.2/spin.min.js"></script> <script type="text/javascript" src="https://cdn.bootcss.com/toastr.js/latest/js/toastr.min.js"></script> <script type="text/javascript" src="https://cdn.bootcss.com/sweetalert/1.1.3/sweetalert.min.js"></script> <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.6.9/angular.js"></script> <script type="text/javascript" src="https://cdn.bootcss.com/angular-filter/0.5.17/angular-filter.js"></script> <script type="text/javascript" src="https://cdn.bootcss.com/oclazyload/1.1.0/ocLazyLoad.min.js"></script> <script type="text/javascript" src="node_modules/angular-indexedDB/angular-indexed-db.min.js"></script> <script type="text/javascript" src="node_modules/ng-request-cache/ng-unit-webpc.js"></script> <script type="text/javascript" src="node_modules/ng-request-cache/ng-request-cache.js"></script> ``` * * 加载到你的模块, 并进行的配置. ```javascript var app = angular.module('myApp', ['oc.lazyLoad', 'angular.filter', 'xc.indexedDB', 'ng-unit', 'ng-request-cache']); app.constant('app_config', { db_name: 'myIndexedDB', swal: { allowOutsideClick: false, // 如果设置为“true”,用户可以通过点击警告框以外的区域关闭警告框。 confirmButtonColor: "#DD6B55", // 该参数用来改变确认按钮的背景颜色(必须是一个HEX值)。 confirmButtonText: "确定", // 该参数用来改变确认按钮上的文字。如果设置为"true",那么确认按钮将自动将"Confirm"替换为"OK"type: 'info', // 窗口的类型。有4种类型的图标动画:"warning", "error", "success""info".可以将它放在"type"数组或通过第三个参数传递。 title: null, // 窗口的名称。可以通过对象的"title"属性或第一个参数进行传递。 text: null, // 窗口的描述。可以通过对象的"text"属性或第二个参数进行传递。 showCancelButton: false, // 如果设置为“true”,“cancel”按钮将显示,点击可以关闭警告框。 showConfirmButton: true, // 如果设置为“false”,“Confirm”按钮将不显示。 cancelButtonText: '取消', // 该参数用来改变取消按钮的文字。 closeOnConfirm: true, // 如果希望以后点击了确认按钮后模态窗口仍然保留就设置为"false"。该参数在其他SweetAlert触发确认按钮事件时十分有用。 timer: null // 警告框自动关闭的时间。单位是ms。 }, spin: { type: 'spinner', opts: { lines: 13, // The number of lines to draw length: 38, // The length of each line width: 22, // The line thickness radius: 49, // The radius of the inner circle scale: 1, // Scales overall size of the spinner corners: 1, // Corner roundness (0..1) color: '#333333', // CSS color or array of colors fadeColor: 'transparent', // CSS color or array of colors opacity: 0.3, // Opacity of the lines rotate: 0, // The rotation offset direction: 1, // 1: clockwise, -1: counterclockwise speed: 1, // Rounds per second trail: 60, // Afterglow percentage fps: 20, // Frames per second when using setTimeout() as a fallback in IE 9 zIndex: 2e9, // The z-index (defaults to 2000000000) className: 'spinner', // The CSS class to assign to the spinner top: '50%', // Top position relative to parent left: '50%', // Left position relative to parent shadow: 'none', // Box-shadow for the lines position: 'absolute' // Element positioning } }, sendSmsWait: 60, extended_timeout: 2000, duration_timeout: 10000, hint_type: 'toastr', restful: { url: 'http://www.yoursite.com/app.php?s=/Api/angular.html', cache: false, timeout: 1000 * 15, }, cache_timeout: 5*60*1000, }); ``` */ angular.module('ng-unit', []) .factory('unitFactory', function($q, $http, $window, $injector, $ocLazyLoad, $timeout, app_config, toastr){ var getTitle = function(type, title){ if(angular.isUndefined(title) || title === null){ switch(type.toLowerCase()){ case 'success': return '操作成功!'; case 'error': return '操作失败!'; case 'warning': return '操作警告!'; case 'info': return '温馨提示!'; } }else{ return title; } } return { isEmptyObject: function(e){ if(angular.isUndefined(e) || e === null){ return true; }else{ var t; for (t in e) return !true; return !false; } }, inArray: function(search, array) { for(var i in array){ if(array[i].toString() == search) return true; } return false; }, isArray: function (value) { return value && typeof value === 'object' && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length')); }, isJson: function (str) { try { JSON.parse(str); } catch (e) { return false; } return true; }, timestamp: function(){ return parseInt(new Date().getTime()); }, datetime: function () { var date = new Date(); var year = date.getFullYear(); var month = date.getMonth()+1; var day = date.getDate(); var hour = date.getHours(); var minute = date.getMinutes(); var second = date.getSeconds(); return year+'年'+month+'月'+day+'日 '+hour+':'+minute+':'+second; }, imgToBase64: function (url, callback, outputFormat){ var canvas = document.createElement('CANVAS'), ctx = canvas.getContext('2d'), img = new Image; img.crossOrigin = 'Anonymous'; img.onload = function(){ canvas.height = img.height; canvas.width = img.width; ctx.drawImage(img,0,0); var dataURL = canvas.toDataURL(outputFormat || 'image/png'); callback.call(this, {url: url, base64: dataURL, status: 200}); canvas = null; }; img.onerror = function(){ callback.call(this, {url: url, base64: null, status:404}); } img.src = url; }, alert: function(param, callback){ var config = {} config.type = (this.isEmptyObject(param.type))?'success':param.type.toLowerCase(); config.title = getTitle(config.type, param.title); swal(angular.extend(app_config.swal, param, config), function(){ if(typeof(callback) == 'function') callback(); }); }, popup: function(param){ var type = (angular.isUndefined(param.type) || this.isEmptyObject(param.type))?'success':param.type.toLowerCase(); var config = { type: type, title: getTitle(type, param.title), showConfirmButton: false, timer: app_config.timeout.extended || 2000, } swal(angular.extend(config, param)); }, confirm: function(param, callback_ok, callback_cancel){ var config = {} config.type = (this.isEmptyObject(param.type))?'warning':param.type.toLowerCase(); config.title = getTitle(config.type, param.title); config.showCancelButton = true; swal(angular.extend(app_config.swal, param, config), function(isConfirm){ if (isConfirm) { if(typeof(callback_ok) == 'function') callback_ok(); }else{ if(typeof(callback_cancel) == 'function') callback_cancel(); } }); }, progress: function(param){ var config = { type: 'info', html: true, title: getTitle('info'), text: '<h5 style="color: #797979">正在 <span class="progressText">'+param.text+'</span> 请等待!</h5><div class = "progress progress-striped active">' + '<div class = "progress-bar progress-bar-success" role="progressbar" style="width: '+param.width+'%;"></div></div>', showLoaderOnConfirm: true, }; swal(angular.extend(app_config.swal, config)); swal.disableButtons(); }, prompt: function (param, callback) { var config ={} config.type = (this.isEmptyObject(param.type))?'input':param.type.toLowerCase(); config.showCancelButton = true; config.closeOnConfirm= false; config.disableButtonsOnConfirm = true; config.animation = "slide-from-top"; swal(angular.extend(app_config.swal, config, param), function(inputValue){ swal.close(); if(inputValue) if(typeof(callback) == 'function') callback(inputValue); }); }, loading: function(text){ app_config.duration_timeout = app_config.duration_timeout || 10000; text = text || '加载数据'; var config = { type: 'info', html: true, title: getTitle('info'), text: '<h5 style="color: #797979">正在 <span class="progressText">'+text+'</span> 请等待!</h5>', showLoaderOnConfirm: true, timer: app_config.timeout.duration || 10000 }; swal(angular.extend(app_config.swal, config)); swal.disableButtons(); }, loading_stop: function(){ swal.close(); }, spinner: function(id){ id = id || 'spinner'; var opts = { lines: app_config.spin.lines || 13, length: app_config.spin.length || 38, width: app_config.spin.width || 22, radius: app_config.spin.radius || 49, scale: app_config.spin.scale || 1, corners: app_config.spin.corners || 1, color: app_config.spin.color || '#333333', fadeColor: app_config.spin.fadeColor || 'transparent', opacity: app_config.spin.opacity || 0.3, rotate: app_config.spin.rotate || 0, direction: app_config.spin.direction || 1, speed: app_config.spin.speed || 1, trail: app_config.spin.trail || 60, fps: app_config.spin.fps || 20, zIndex: app_config.spin.zIndex || 2e9, className: app_config.spin.className || 'spinner', top: app_config.spin.top || '50%', left: app_config.spin.left || '50%', shadow: app_config.spin.shadow || 'none', position: app_config.spin.position || 'absolute' }; var _self = this; var target = document.getElementById(id); target.style.display = 'inline'; target.style.position = 'fixed'; target.style.width = '100%'; target.style.height = '100%'; target.style.top = '0'; target.style.left = '0'; target.style.background = app_config.spin.box_background || '#333'; target.style.zIndex = app_config.spin.box_zIndex || '999999'; target.style.opacity = app_config.spin.box_opacity || '0.6'; var spinner = new Spinner(opts).spin(target); $timeout(function(){ _self.spinner_stop(spinner, id); }, app_config.timeout.duration || 10000); return spinner; }, spinner_stop: function (spinner, id) { id = id || 'spinner'; var target = document.getElementById(id); target.style.display = 'none'; spinner.stop(); }, toastr: function(param, text, title) { var defer = $q.defer(); if(angular.isObject(param)){ var type = param.type; text = text || param.msg; title = title || param.title; }else{ var type = param; } toastr.onHidden = function(){ defer.resolve(); }; switch (type.toLowerCase()) { case 'success': toastr.success(text, this.isEmptyObject(title) ? '操作成功!' : title); break; case 'error': toastr.error(text, this.isEmptyObject(title) ? '操作失败!' : title); break; case 'warning': toastr.warning(text, this.isEmptyObject(title) ? '操作警告!' : title); break; case 'info': default: toastr.info(text, this.isEmptyObject(title) ? '操作提醒!' : title); } return defer.promise; }, close: function(){ swal.close(); }, enableButtons: function(){ swal.enableButtons(); }, disableButtons: function(){ swal.disableButtons(); }, /** * # 创建公私密钥 * @param keySize * @returns {{privkey: *, pubkey: *}} */ generateKey: function(keySize){ keySize = keySize || 512; var crypt = new JSEncrypt({default_key_size: keySize}); crypt.getKey(); return { privkey: crypt.getPrivateKey(), pubkey: crypt.getPublicKey(), } }, /** * # 使用公钥对数据进行加密 * @param string * @param public_key */ encrypt: function(string, public_key){ var crypt = new JSEncrypt(); crypt.setPublicKey(public_key); return crypt.encrypt(string); }, /** * # 使用私钥对加密数据进行解密 * @param string * @param private_key */ decrypt: function(string, private_key){ var crypt = new JSEncrypt(); crypt.setPrivateKey(private_key); return crypt.decrypt(string); }, /** * # HTTP 网络数据请求 * @param params * @param method * @returns {Promise} */ http: function(params, method){ app_config.timeout.extended = app_config.timeout.extended || 2000; app_config.type.hint = app_config.type.hint || 'toastr'; var config = { url: (app_config.url && app_config.url.restful)?app_config.url.restful:'http://www.yoursite.com/app.php?s=/Api/angular.html', cache: (app_config.cache && app_config.cache.restful)?app_config.cache.restful:false, timeout: (app_config.timeout && app_config.timeout.restful)?app_config.timeout.restful:1000 * 15, } var defer = $q.defer(); var _self = this; var rsa_key = $window.localStorage.getItem('rsa_key'); if(!_self.isEmptyObject(rsa_key) && params.rsa) params.router = _self.encrypt(angular.toJson(params.router), angular.fromJson(rsa_key).client_public); var after = {}; angular.forEach(params, function(obj, key){ if(!_self.isEmptyObject(obj)) this[key] = angular.isObject(obj)?angular.toJson(obj):obj; }, after); switch(method.toLowerCase()){ case 'get': case 'delete': config.method = method.toLowerCase(); config.params = after; break; case 'post': case 'put': default: config.method = method.toLowerCase(); config.data = after; } $http(config).then(function(result){ if(result.status == 200 && angular.isObject(result.data) && result.data.type.toLowerCase() == 'success'){ if(_.indexOf(['post', 'put'], method.toLowerCase()) >= 0){ if(!angular.isUndefined(app_config.type) && !angular.isUndefined(app_config.type.hint) && app_config.type.hint == 'alert'){ _self.alert({ text: result.data.msg, type: result.data.type.toLowerCase(), },function(){ defer.resolve(result.data); }); }else if(!angular.isUndefined(app_config.type) && !angular.isUndefined(app_config.type.hint) && app_config.type.hint == 'toastr'){ _self.toastr(result.data.type.toLowerCase(), result.data.msg).then(function(){ defer.resolve(result.data); }); }else{ defer.resolve(result.data); } }else{ defer.resolve(result.data); } }else{ if(app_config.debug.request) _self.debug('Request', angular.toJson(result), 'Error'); if(!angular.isUndefined(app_config.type) && !angular.isUndefined(app_config.type.hint) && app_config.type.hint == 'alert'){ _self.alert({ text: 'HTTP请求失败! ' + result.data.msg, type: 'error', closeOnConfirm: true, confirmButtonText: '确定', showCancelButton: false, },function(){ defer.reject(result); }); }else if(!angular.isUndefined(app_config.type) && !angular.isUndefined(app_config.type.hint) && app_config.type.hint == 'toastr'){ _self.toastr('error', 'HTTP请求失败! ' + result.data.msg).then(function(){ defer.reject(result); }); }else{ defer.reject(result); } } }, function(error){ if(app_config.debug.request) _self.debug('Request', angular.toJson(error), 'Error'); if(!angular.isUndefined(app_config.type) && !angular.isUndefined(app_config.type.hint) && app_config.type.hint == 'alert'){ _self.alert({ text: 'HTTP请求失败! ' + error, type: 'error', closeOnConfirm: true, confirmButtonText: '确定', showCancelButton: false, },function(){ defer.reject(error); }); }else if(!angular.isUndefined(app_config.type) && !angular.isUndefined(app_config.type.hint) && app_config.type.hint == 'toastr'){ _self.toastr('error', 'HTTP请求失败! ' + error).then(function(){ defer.reject(error); }); }else{ defer.reject(error); } }); return defer.promise; }, /** * # 文件上传 * @param files 需要上传的文件或文件数组 * @param text 上传过程中进度条的提示说明 * @param type 上传文件的类型 * @param uid 上传者的uid, 默认为0 * @param url 需要上传的服务器地址, 默认为配置中的 `url.upload` 地址 * @returns {Promise} */ upload: function(files, text, type, uid, url){ var defer = $q.defer(); var _self = this; if(!angular.isUndefined(files)){ text = text || '上传文件'; uid = uid || 0; url = url || app_config.url.upload; $ocLazyLoad.load('file_upload').then(function(){ var Upload = $injector.get('Upload'); Upload.upload({ url: url, method: 'POST', headers : { 'Content-Type': 'application/x-www-form-urlencoded' }, data: {file: files, type: type, uid: uid}, }).then(function (result) { defer.reject(result); }, function (error) { if(app_config.debug.upload) _self.debug('Upload', angular.toJson(error), 'Error'); if(app_config.hint_type == 'alert'){ _self.popup({ text: '文件上传请求失败! ' + error.status, type: 'error', }); defer.reject(error); }else if(app_config.hint_type == 'toastr'){ _self.toastr('error', '文件上传请求失败!' + error.status).then(function(){ defer.reject(error); }); }else{ defer.reject(error); } }, function (evt) { _self.progress({text: text, width: parseInt(100.0 * evt.loaded / evt.total)}); }); }); }else{ var error = { text: '没有指定上传文件! ', type: 'error', } if(app_config.debug.upload) _self.debug('Upload', angular.toJson(error), 'Error'); _self.popup(error); defer.reject(error); } return defer.promise; }, debug: function(key, msg, type){ type = type || 'Debug'; $window.sessionStorage.setItem(type + '-' + key + '-' + this.datetime(), msg); }, } });