很早以前就大概看过一点angualrjs,但是没有项目,一直没有进行下去,就是干巴巴的看着,过了一段时间发现什么也不记得了。
来yulebaby我的第一个后台管理是用easyui做的,做完那个以后发现有很多局限,因为easyui里面都是内嵌了iframe,当时在iframe中操作js的时候我真的是头疼想死呀。然后我就想着还是用angualr来弄吧,这也是现在前后台分离的方向,然后就有了接下来那些有趣的事情。
Angularjs虽然很强大,但是你要是掌握了其中这几大块其实也是那么回事,双向数据绑定,作用域,指令,控制器,服务,路由,过滤器,我这次项目中也就用到了这几块的内容,不过接触的也不复杂,都是些基本的。
首先我大致说一下我们这个后台管理的原型和需求。
我们的后台管理分3种角色,不过目前我们只做了2种,设备助理和财务,设备助理主要是用来添加设备,生成设备销售单的,还有就是设备销售单管理和设备销售单退单管理;财务主要用来管理设备库的,财务也有设备销售单管理和设备销售单退单管理的权限,只是有些是可看不可操作的,具体的不同的角色有不同的权限这个就不细说了......
而且我们在做权限控制这块还用到了监听路由改变,然后将没有权限的url进行拦截,这个主要是因为,我们的后台是java,他们用了一个古老的框架,由于后台框架的限制,我们的angualr项目不能放到他们的webinfor下面,单独拿出来以后,权限什么的就不受他们控制了,所以当时我们在没有办法的情况下就用了一个比较笨的方法来控制权限了,具体如下:
app.run(function ($rootScope, $state) { $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams, options){ function getCookie(name){ var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)"); if(arr=document.cookie.match(reg)){ return (arr[2]); } else{ return null; } } var roleId = getCookie('roleId'); var caiwu = ['error', 'router', 'index', 'equipSaleManageAllCw','equipSaleManageAllCwdefult','equipSaleManageDetailCw','equipReturnAllCw','equipReturnDetailCw','equipListCw','equipPackageCw','equipClassCw','equipDetailsCw','addEquipmentCw','equipPackageDetailsCw','equipClassDetailsCw','equipNewClassCw']; var sbzli = ['error', 'router', 'index', 'equipAdd','equipSaleManageAll','equipSaleManageAlldefult','equipSaleManageDetail','equipSaleManagethDetail','equipReturnAll','equipReturnDetail']; if(roleId == 23){ if(caiwu.indexOf(toState.name) < 0){ event.preventDefault(); $state.go('error'); } } if(roleId == 27){ if(sbzli.indexOf(toState.name) < 0){ event.preventDefault(); $state.go('error'); } } }) })
然后这个项目中有个比较麻烦的就是分页和图片上传了,首先说一下分页,我们的分页是自己分装了一个指令,
<div class="bby-page-box" ng-show="page.count > 1"> <a href="javascript: void(0);" ng-show="page.pageNo!==1" ng-click="queryData(page.pageNo - 1)">上一页</a><!-- --><a href="javascript: void(0);" ng-show="page.pageNo - 4 > 0 && page.count > 7" ng-click="queryData(1)">1</a><!-- --><a href="javascript: void(0);" ng-show="page.pageNo - 4 > 0 && page.count > 7" class="bby-page-ellipsis">…</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 6)" ng-show="page.pageNo - 6 > 0 && page.count <= 7">{{page.pageNo - 6}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 5)" ng-show="page.pageNo - 5 > 0 && page.count <= 7">{{page.pageNo - 5}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 4)" ng-show="page.pageNo - 4 > 0 && page.count <= 7">{{page.pageNo - 4}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 3)" ng-show="page.pageNo - 3 > 0">{{page.pageNo - 3}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 2)" ng-show="page.pageNo - 2 > 0">{{page.pageNo - 2}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 1)" ng-show="page.pageNo - 1 > 0">{{page.pageNo - 1}}</a><!-- --><a href="javascript: void(0);" class="active">{{page.pageNo}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo + 1)" ng-show="page.pageNo + 1 <= page.count">{{page.pageNo + 1}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo + 2)" ng-show="page.pageNo + 2 <= page.count">{{page.pageNo + 2}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo + 3)" ng-show="page.pageNo + 3 <= page.count">{{page.pageNo + 3}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo + 4)" ng-show="page.pageNo + 4 <= page.count && page.pageNo + 4 < 8">{{page.pageNo + 4}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo + 5)" ng-show="page.pageNo + 5 <= page.count && page.pageNo + 5 < 8">{{page.pageNo + 5}}</a><!-- --><a href="javascript: void(0);" ng-click="queryData(page.pageNo + 6)" ng-show="page.pageNo + 6 <= page.count && page.pageNo + 6 < 8">{{page.pageNo + 6}}</a><!-- --><a href="javascript: void(0);" ng-show="page.count >= page.pageNo + 4 && page.count > 7" class="bby-page-ellipsis">…</a><!-- --><a href="javascript: void(0);" ng-show="page.count >= page.pageNo + 4 && page.count > 7" ng-click="queryData(page.count)">{{page.count}}</a><!-- --><a href="javascript: void(0);" ng-show="page.pageNo !== page.count" ng-click="queryData(page.pageNo + 1)">下一页</a><!-- --><span> 到第<!-- --><input type="text" ng-model="gonum" placeholder="1" ng-change="ongonum()"><!-- -->页<!-- --><a href="javascript: void(0);" ng-click="queryData(gonum)">确定</a> </span><!-- --><select ng-model="pageNumber" ng-options="pageNumber.text for pageNumber in pageNumList" ng-init="pageNumber = pageNumList[0]"> </select> <span>共{{page.count}}页{{page.pageCount}}条</span> </div>
app.directive('pagination', function(){ return { controller: function($scope, $element, $attrs, $transclude, $http) { /* 每页显示条数 */ $scope.pageNumList = [{value: 10, text: 10},{value: 20, text: 20},{value: 30, text: 30},{value: 50, text: 50},{value: 100, text: 100}]; /* 监听每页显示条数 */ $scope.$watch('pageNumber', function (n, o) { if(n.value !== o.value){$scope.queryData(1);} }) $scope.queryData = function (pegeNo, query) { $scope.gonum = '';//点击确认调转页数以后清空输入框 $scope.queryCriteria = query !== undefined ? query : $scope.queryCriteria; $scope.pageNo = pegeNo !== undefined ? pegeNo : 1; try{ $scope.param = $scope.pageNumber.value ? $scope.pageNumber.value : 10; }catch (e) { $scope.param = 10; } $scope.pageNo = pegeNo ? pegeNo : 1; var params = { pageNo: $scope.pageNo, pageSize: $scope.param }; if($scope.queryCriteria){ for(var v in $scope.queryCriteria){ params[v] = $scope.queryCriteria[v]; } } $scope.$emit('loading', {}); $scope.loading = true; $http({ url: $scope.URL, method: 'get', params: params }).then(function (res) { $scope.page = res.data; $scope.page.count = Math.ceil(res.data.pageCount/res.data.pageSize); $scope.$emit('items', res.data); },function (e) { $scope.loading = false; $scope.$emit('items', {code: 1, message: "网络异常,请刷新页面"}); }) } $scope.queryData(1,$scope.defult); $scope.$on('query', function (e, d) { $scope.queryData(1, d); }) $scope.$emit('onload', {}); }, restrict: 'EA', templateUrl: 'script/directives/directiveView/pagination.html', replace: true, link: function (scope, ele, attrs){ scope.ongonum = function () { if(!scope.gonum){return;} var vue = parseInt(scope.gonum.replace(/[^d]/g,'')); if(!vue){scope.gonum = '1';return;} if(vue > scope.page.count){ scope.gonum = scope.page.count; }else if(vue < 1){ scope.gonum = 1; }else{ scope.gonum = vue; } } } }; });
分页指令封装好了,然后在html页面调用就直接写上<pagination></pagination>这个就好了,指令调用的方式有4种,EACM,元素,属性,类名,注释。
然后在控制器中使用直接接收指令传输过来的数据:
$scope.$on('items', function (e, data) { $scope.loading = false; if(data.code == 1000){ if(data.data){ $scope.items = data.data; }else{ $scope.items = []; } }else{ $scope.items = []; $scope.promptBlen = true; $scope.promptText = data.message; } $scope.init=function(){ angular.forEach($scope.items, function(data){ if(data.status == 7){ data.returnRule=true; //把returnRule绑定到每个对象显示退货按钮 }else{ data.returnRule=false; } }); } $scope.init(); $scope.flag=true; });
这里要直接注意下,指令与控制器之间的通信方式,还有控制器用控制器直接的通信方式,反正我就是记住一点,通信用$on来接收数据,如果是父控制器向子控制器传播数据就是广播,$broadcast,如果是子控制器向父控制器传送数据就是$emit,向上传递数据。这个很重要,如果记起来比较困难的,再去百度下就好了。
分页的成品如下:
然后还有就是图片上传:
我们的图片上传采用的是可以单张上传,也可以多张上传的,但是不能超过6张,最开始准备在网上找个angualr图片上传的插件,但是后来还是用jquery来写了,js具体如下:
app.factory('$preview', function () { // getUrlFn(window.location.href) var getUrlFn = function(str){ var oaPosition = str.indexOf('oa'); return str.substring(0,oaPosition+2); } return { upfile: function (id, status, see){ window.delParent = ''; var imgContainer = $("#photoItemsBox"); //存放图片的父亲元素 var data = {}; var numUp; if(status == 0){ data.equOrderNo = id }else{ data.orderReturnNo = id; } if(see){ $('.z_file').hide(); } $.ajax({ url: getUrlFn(window.location.href) + '/equipment/equImgUpload/queryImgs.do', type: 'get', data: data, dataType: 'json', success: function (data) { if(data.code == 1000){ if(data.data!=undefined && data.data!=null && data.data.length>0){ for(var i = 0; i < data.data.length; i++){ (function (){ var box = $('<div class="up-section"></div>'); var closeBg = $('<a href="javascript: void(0);" class="close-upimg">×</a>'); var imgThis = $('<img class="up-img" src="'+ data.data[i].imgUrl +'" />'); box.append(imgThis); var input = $('<input id="imgIds" name="imgIds" value="'+ data.data[i].id +'" type="hidden"/>'); if(!see){ box.append(closeBg); box.append(input); } imgContainer.append(box); })() } } numUp = $('.up-section').length; if(numUp < 6 && !see){ $(".z_file").show(); }else{ $(".z_file").hide(); } } } }) var defaults = { fileType : ["jpg","png","gif","jpeg"], // 上传文件的类型 fileSize : 1024 * 1024 * 5 }; /*点击图片的文本框*/ $("#file").change(function(){ var idFile = $(this).attr("id"); var file = document.getElementById(idFile); var fileList = file.files; //获取的图片文件 var imgArr = []; //遍历得到的图片文件 var numUp = imgContainer.find(".up-section").length; var totalNum = numUp + fileList.length; if(fileList.length > 6 || totalNum > 6 ){ alert("图片超出6张,请删除多余图片后再上传"); }else if(numUp < 6){ fileList = validateUp(fileList); var formData = new FormData(); for(v in data){ formData.append(v, data[v]); } for(var i = 0; i < fileList.length; i++){ var imgUrl = window.URL.createObjectURL(fileList[i]); imgArr.push(imgUrl); var OrderImg = 'OrderImg'+(i+1); var OrderImgName = 'OrderImgName'+(i+1); formData.append(OrderImg, fileList[i]); formData.append(OrderImgName, fileList[i].name); (function (){ var box = $('<div class="up-section"></div>'); var loading = $('<div class="line-scale"><div></div><div></div><div></div><div></div><div></div></div>'); box.append(loading); var closeBg = $('<a href="javascript: void(0);" class="close-upimg">×</a>'); box.append(closeBg); var imgThis = $('<img class="up-img" src="'+ imgArr[i] +'" />'); box.append(imgThis); var input = $('<input id="imgIds" name="imgIds" type="hidden"/>'); box.append(input); imgContainer.append(box); })() } $.ajax({ url: getUrlFn(window.location.href) + "/equipment/equImgUpload/addImgs.do", type: 'POST', cache: false, data: formData, processData: false, contentType: false, success: function(data) { if(data.code == 1000){ $('.line-scale').hide(); for(var i = 0; i < data.data.length; i++){ imgContainer.children('div').eq(i).find('.up-img').attr('src', data.data[i].imgUrl); imgContainer.children('div').eq(i).find('input').val(data.data[i].id); } } console.log("成功"); }, error: function(e) { console.log('失败') } }); } numUp = imgContainer.find(".up-section").length; if(numUp >= 6){ $(this).parent().hide(); } //input内容清空 $(this).val(""); }); $("body").on("click",'.close-upimg',function(){ event.preventDefault(); event.stopPropagation(); $(".works-mask").show(); window.delParent = $(this).parent(); deleteId = $(this).siblings('input').val(); }); $(".wsdel-ok").click(function(){ $(".works-mask").hide(); var dataD = data; dataD.imgIds1 = deleteId $.ajax({ url: getUrlFn(window.location.href) + '/equipment/equImgUpload/delete.do', type: 'get', data: dataD, dataType: 'json', success: function (data) { if(data.code == 1000){ var numUp = window.delParent.siblings().length; if(numUp < 7){ $(".z_file").show(); } window.delParent.remove(); }else{ alert(data.message); } }, error: function (e) { console.log('请求失败'); } }) }); $(".wsdel-no").click(function(){ $(".works-mask").hide(); }); function validateUp(files){ var arrFiles = [];//替换的文件数组 for(var i = 0, file; file = files[i]; i++){ //获取文件上传的后缀名 var newStr = file.name.split("").reverse().join(""); if(newStr.split(".")[0] != null){ var type = newStr.split(".")[0].split("").reverse().join(""); if(jQuery.inArray(type, defaults.fileType) > -1){ // 类型符合,可以上传 if (file.size >= defaults.fileSize) { alert('您这个"'+ file.name + '-----' + file.size +'"文件大小过大'); } else { // 在这里需要判断当前所有文件中 arrFiles.push(file); } }else{ alert('您这个"'+ file.name +'"上传类型不符合'); } }else{ alert('您这个"'+ file.name +'"没有类型, 无法识别'); } } return arrFiles; } } } })
我们是封装了一个服务,然后在页面引入html
<!--上传图片 --> <div class="bby-form-item" ng-show="statu!=1" class="upPhoto"> <label for="" class="bby-form-label">交款凭证图:</label> <div class="bby-input-block"> <div class="z_photo" id="photoItemsBox"></div> <div class="z_file"> <label for="file" class="add-img">点击上传图片</label> <input type="file" name="file" id="file" accept="image/jpg,image/jpeg,image/png,image/gif" multiple /> </div> <div class="mask works-mask"> <div class="mask-content"> <p class="del-p">确定要删除该图片吗?</p> <p class="check-p"><span class="del-com wsdel-ok">确定</span><span class="wsdel-no">取消</span></p> </div> </div> </div> </div>
然后在控制器依赖注入这个服务,直接调用就好了
上传图片成品如下:(包括显示图片,上传图片,点击查看大图,删除图片)
这里,我们的图片服务器出来点问题,所以图片失效了,线上的是没有问题的。
反正做这个项目的难点和思路大概也就这么些,第一次用angualr,还有很多东西做的很粗糙,今天写的博客也稀里糊涂的,思路不太清晰,就是随便写写,记录下自己的成长,未来的路还很长,慢慢来.......