很早以前就大概看过一点angualrjs,但是没有项目,一直没有进行下去,就是干巴巴的看着,过了一段时间发现什么也不记得了。

来yulebaby我的第一个后台管理是用easyui做的,做完那个以后发现有很多局限,因为easyui里面都是内嵌了iframe,当时在iframe中操作js的时候我真的是头疼想死呀。然后我就想着还是用angualr来弄吧,这也是现在前后台分离的方向,然后就有了接下来那些有趣的事情。

Angularjs虽然很强大,但是你要是掌握了其中这几大块其实也是那么回事,双向数据绑定,作用域,指令,控制器,服务,路由,过滤器,我这次项目中也就用到了这几块的内容,不过接触的也不复杂,都是些基本的。

首先我大致说一下我们这个后台管理的原型和需求。

我们的后台管理分3种角色,不过目前我们只做了2种,设备助理和财务,设备助理主要是用来添加设备,生成设备销售单的,还有就是设备销售单管理和设备销售单退单管理;财务主要用来管理设备库的,财务也有设备销售单管理和设备销售单退单管理的权限,只是有些是可看不可操作的,具体的不同的角色有不同的权限这个就不细说了......

而且我们在做权限控制这块还用到了监听路由改变,然后将没有权限的url进行拦截,这个主要是因为,我们的后台是java,他们用了一个古老的框架,由于后台框架的限制,我们的angualr项目不能放到他们的webinfor下面,单独拿出来以后,权限什么的就不受他们控制了,所以当时我们在没有办法的情况下就用了一个比较笨的方法来控制权限了,具体如下:

  1. app.run(function ($rootScope, $state) {
  2. $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams, options){
  3. function getCookie(name){
  4. var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
  5. if(arr=document.cookie.match(reg)){
  6. return (arr[2]);
  7. }
  8. else{
  9. return null;
  10. }
  11. }
  12. var roleId = getCookie('roleId');
  13. var caiwu = ['error', 'router', 'index', 'equipSaleManageAllCw','equipSaleManageAllCwdefult','equipSaleManageDetailCw','equipReturnAllCw','equipReturnDetailCw','equipListCw','equipPackageCw','equipClassCw','equipDetailsCw','addEquipmentCw','equipPackageDetailsCw','equipClassDetailsCw','equipNewClassCw'];
  14. var sbzli = ['error', 'router', 'index', 'equipAdd','equipSaleManageAll','equipSaleManageAlldefult','equipSaleManageDetail','equipSaleManagethDetail','equipReturnAll','equipReturnDetail'];
  15. if(roleId == 23){
  16. if(caiwu.indexOf(toState.name) < 0){
  17. event.preventDefault();
  18. $state.go('error');
  19. }
  20. }
  21. if(roleId == 27){
  22. if(sbzli.indexOf(toState.name) < 0){
  23. event.preventDefault();
  24. $state.go('error');
  25. }
  26. }
  27. })
  28. })

 然后这个项目中有个比较麻烦的就是分页和图片上传了,首先说一下分页,我们的分页是自己分装了一个指令,

  1. <div class="bby-page-box" ng-show="page.count > 1">
  2. <a href="javascript: void(0);" ng-show="page.pageNo!==1" ng-click="queryData(page.pageNo - 1)">上一页</a><!--
  3. --><a href="javascript: void(0);" ng-show="page.pageNo - 4 > 0 && page.count > 7" ng-click="queryData(1)">1</a><!--
  4. --><a href="javascript: void(0);" ng-show="page.pageNo - 4 > 0 && page.count > 7" class="bby-page-ellipsis">…</a><!--
  5. --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 6)" ng-show="page.pageNo - 6 > 0 && page.count <= 7">{{page.pageNo - 6}}</a><!--
  6. --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 5)" ng-show="page.pageNo - 5 > 0 && page.count <= 7">{{page.pageNo - 5}}</a><!--
  7. --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 4)" ng-show="page.pageNo - 4 > 0 && page.count <= 7">{{page.pageNo - 4}}</a><!--
  8. --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 3)" ng-show="page.pageNo - 3 > 0">{{page.pageNo - 3}}</a><!--
  9. --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 2)" ng-show="page.pageNo - 2 > 0">{{page.pageNo - 2}}</a><!--
  10. --><a href="javascript: void(0);" ng-click="queryData(page.pageNo - 1)" ng-show="page.pageNo - 1 > 0">{{page.pageNo - 1}}</a><!--
  11. --><a href="javascript: void(0);" class="active">{{page.pageNo}}</a><!--
  12. --><a href="javascript: void(0);" ng-click="queryData(page.pageNo + 1)" ng-show="page.pageNo + 1 <= page.count">{{page.pageNo + 1}}</a><!--
  13. --><a href="javascript: void(0);" ng-click="queryData(page.pageNo + 2)" ng-show="page.pageNo + 2 <= page.count">{{page.pageNo + 2}}</a><!--
  14. --><a href="javascript: void(0);" ng-click="queryData(page.pageNo + 3)" ng-show="page.pageNo + 3 <= page.count">{{page.pageNo + 3}}</a><!--
  15. --><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><!--
  16. --><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><!--
  17. --><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><!--
  18. --><a href="javascript: void(0);" ng-show="page.count >= page.pageNo + 4 && page.count > 7" class="bby-page-ellipsis">…</a><!--
  19. --><a href="javascript: void(0);" ng-show="page.count >= page.pageNo + 4 && page.count > 7" ng-click="queryData(page.count)">{{page.count}}</a><!--
  20. --><a href="javascript: void(0);" ng-show="page.pageNo !== page.count" ng-click="queryData(page.pageNo + 1)">下一页</a><!--
  21. --><span>
  22. 到第<!--
  23. --><input type="text" ng-model="gonum" placeholder="1" ng-change="ongonum()"><!--
  24. --><!--
  25. --><a href="javascript: void(0);" ng-click="queryData(gonum)">确定</a>
  26. </span><!--
  27.  
  28. --><select ng-model="pageNumber" ng-options="pageNumber.text for pageNumber in pageNumList" ng-init="pageNumber = pageNumList[0]">
  29. </select>
  30. <span>共{{page.count}}页{{page.pageCount}}条</span>
  31. </div>
  1. app.directive('pagination', function(){
  2. return {
  3. controller: function($scope, $element, $attrs, $transclude, $http) {
  4. /* 每页显示条数 */
  5. $scope.pageNumList = [{value: 10, text: 10},{value: 20, text: 20},{value: 30, text: 30},{value: 50, text: 50},{value: 100, text: 100}];
  6. /* 监听每页显示条数 */
  7. $scope.$watch('pageNumber', function (n, o) {
  8. if(n.value !== o.value){$scope.queryData(1);}
  9. })
  10. $scope.queryData = function (pegeNo, query) {
  11. $scope.gonum = '';//点击确认调转页数以后清空输入框
  12. $scope.queryCriteria = query !== undefined ? query : $scope.queryCriteria;
  13. $scope.pageNo = pegeNo !== undefined ? pegeNo : 1;
  14. try{
  15. $scope.param = $scope.pageNumber.value ? $scope.pageNumber.value : 10;
  16. }catch (e) {
  17. $scope.param = 10;
  18. }
  19. $scope.pageNo = pegeNo ? pegeNo : 1;
  20. var params = {
  21. pageNo: $scope.pageNo,
  22. pageSize: $scope.param
  23. };
  24. if($scope.queryCriteria){
  25. for(var v in $scope.queryCriteria){
  26. params[v] = $scope.queryCriteria[v];
  27. }
  28. }
  29. $scope.$emit('loading', {});
  30. $scope.loading = true;
  31. $http({
  32. url: $scope.URL,
  33. method: 'get',
  34. params: params
  35. }).then(function (res) {
  36. $scope.page = res.data;
  37. $scope.page.count = Math.ceil(res.data.pageCount/res.data.pageSize);
  38. $scope.$emit('items', res.data);
  39. },function (e) {
  40. $scope.loading = false;
  41. $scope.$emit('items', {code: 1, message: "网络异常,请刷新页面"});
  42. })
  43. }
  44. $scope.queryData(1,$scope.defult);
  45. $scope.$on('query', function (e, d) {
  46. $scope.queryData(1, d);
  47. })
  48. $scope.$emit('onload', {});
  49. },
  50. restrict: 'EA',
  51. templateUrl: 'script/directives/directiveView/pagination.html',
  52. replace: true,
  53. link: function (scope, ele, attrs){
  54. scope.ongonum = function () {
  55. if(!scope.gonum){return;}
  56. var vue = parseInt(scope.gonum.replace(/[^\d]/g,''));
  57. if(!vue){scope.gonum = '1';return;}
  58. if(vue > scope.page.count){
  59. scope.gonum = scope.page.count;
  60. }else if(vue < 1){
  61. scope.gonum = 1;
  62. }else{
  63. scope.gonum = vue;
  64. }
  65. }
  66. }
  67. };
  68. });

分页指令封装好了,然后在html页面调用就直接写上<pagination></pagination>这个就好了,指令调用的方式有4种,EACM,元素,属性,类名,注释。

然后在控制器中使用直接接收指令传输过来的数据:

  1. $scope.$on('items', function (e, data) {
  2. $scope.loading = false;
  3. if(data.code == 1000){
  4. if(data.data){
  5. $scope.items = data.data;
  6. }else{
  7. $scope.items = [];
  8. }
  9. }else{
  10. $scope.items = [];
  11. $scope.promptBlen = true;
  12. $scope.promptText = data.message;
  13. }
  14. $scope.init=function(){
  15. angular.forEach($scope.items, function(data){
  16. if(data.status == 7){
  17. data.returnRule=true; //把returnRule绑定到每个对象显示退货按钮
  18. }else{
  19. data.returnRule=false;
  20. }
  21. });
  22. }
  23. $scope.init();
  24. $scope.flag=true;
  25. });

这里要直接注意下,指令与控制器之间的通信方式,还有控制器用控制器直接的通信方式,反正我就是记住一点,通信用$on来接收数据,如果是父控制器向子控制器传播数据就是广播,$broadcast,如果是子控制器向父控制器传送数据就是$emit,向上传递数据。这个很重要,如果记起来比较困难的,再去百度下就好了。

分页的成品如下:

然后还有就是图片上传:

我们的图片上传采用的是可以单张上传,也可以多张上传的,但是不能超过6张,最开始准备在网上找个angualr图片上传的插件,但是后来还是用jquery来写了,js具体如下:

  1. app.factory('$preview', function () {
  2. // getUrlFn(window.location.href)
  3. var getUrlFn = function(str){
  4. var oaPosition = str.indexOf('oa');
  5. return str.substring(0,oaPosition+2);
  6. }
  7. return {
  8. upfile: function (id, status, see){
  9. window.delParent = '';
  10. var imgContainer = $("#photoItemsBox"); //存放图片的父亲元素
  11. var data = {};
  12. var numUp;
  13. if(status == 0){
  14. data.equOrderNo = id
  15. }else{
  16. data.orderReturnNo = id;
  17. }
  18. if(see){
  19. $('.z_file').hide();
  20. }
  21. $.ajax({
  22. url: getUrlFn(window.location.href) + '/equipment/equImgUpload/queryImgs.do',
  23. type: 'get',
  24. data: data,
  25. dataType: 'json',
  26. success: function (data) {
  27. if(data.code == 1000){
  28. if(data.data!=undefined && data.data!=null && data.data.length>0){
  29. for(var i = 0; i < data.data.length; i++){
  30. (function (){
  31. var box = $('<div class="up-section"></div>');
  32. var closeBg = $('<a href="javascript: void(0);" class="close-upimg">×</a>');
  33.  
  34. var imgThis = $('<img class="up-img" src="'+ data.data[i].imgUrl +'" />');
  35. box.append(imgThis);
  36. var input = $('<input id="imgIds" name="imgIds" value="'+ data.data[i].id +'" type="hidden"/>');
  37.  
  38. if(!see){
  39. box.append(closeBg);
  40. box.append(input);
  41. }
  42. imgContainer.append(box);
  43. })()
  44. }
  45. }
  46. numUp = $('.up-section').length;
  47. if(numUp < 6 && !see){
  48. $(".z_file").show();
  49. }else{
  50. $(".z_file").hide();
  51. }
  52. }
  53. }
  54. })
  55.  
  56. var defaults = {
  57. fileType : ["jpg","png","gif","jpeg"], // 上传文件的类型
  58. fileSize : 1024 * 1024 * 5
  59. };
  60. /*点击图片的文本框*/
  61. $("#file").change(function(){
  62. var idFile = $(this).attr("id");
  63. var file = document.getElementById(idFile);
  64. var fileList = file.files; //获取的图片文件
  65. var imgArr = [];
  66. //遍历得到的图片文件
  67. var numUp = imgContainer.find(".up-section").length;
  68. var totalNum = numUp + fileList.length;
  69. if(fileList.length > 6 || totalNum > 6 ){
  70. alert("图片超出6张,请删除多余图片后再上传");
  71. }else if(numUp < 6){
  72. fileList = validateUp(fileList);
  73. var formData = new FormData();
  74. for(v in data){
  75. formData.append(v, data[v]);
  76. }
  77. for(var i = 0; i < fileList.length; i++){
  78. var imgUrl = window.URL.createObjectURL(fileList[i]);
  79. imgArr.push(imgUrl);
  80.  
  81. var OrderImg = 'OrderImg'+(i+1);
  82. var OrderImgName = 'OrderImgName'+(i+1);
  83.  
  84. formData.append(OrderImg, fileList[i]);
  85. formData.append(OrderImgName, fileList[i].name);
  86.  
  87. (function (){
  88. var box = $('<div class="up-section"></div>');
  89. var loading = $('<div class="line-scale"><div></div><div></div><div></div><div></div><div></div></div>');
  90. box.append(loading);
  91. var closeBg = $('<a href="javascript: void(0);" class="close-upimg">×</a>');
  92. box.append(closeBg);
  93. var imgThis = $('<img class="up-img" src="'+ imgArr[i] +'" />');
  94. box.append(imgThis);
  95. var input = $('<input id="imgIds" name="imgIds" type="hidden"/>');
  96. box.append(input);
  97. imgContainer.append(box);
  98. })()
  99. }
  100. $.ajax({
  101. url: getUrlFn(window.location.href) + "/equipment/equImgUpload/addImgs.do",
  102. type: 'POST',
  103. cache: false,
  104. data: formData,
  105. processData: false,
  106. contentType: false,
  107. success: function(data) {
  108. if(data.code == 1000){
  109. $('.line-scale').hide();
  110. for(var i = 0; i < data.data.length; i++){
  111. imgContainer.children('div').eq(i).find('.up-img').attr('src', data.data[i].imgUrl);
  112. imgContainer.children('div').eq(i).find('input').val(data.data[i].id);
  113. }
  114. }
  115. console.log("成功");
  116. },
  117. error: function(e) {
  118. console.log('失败')
  119. }
  120. });
  121. }
  122. numUp = imgContainer.find(".up-section").length;
  123. if(numUp >= 6){
  124. $(this).parent().hide();
  125. }
  126.  
  127. //input内容清空
  128. $(this).val("");
  129. });
  130.  
  131. $("body").on("click",'.close-upimg',function(){
  132. event.preventDefault();
  133. event.stopPropagation();
  134. $(".works-mask").show();
  135. window.delParent = $(this).parent();
  136. deleteId = $(this).siblings('input').val();
  137. });
  138.  
  139. $(".wsdel-ok").click(function(){
  140. $(".works-mask").hide();
  141. var dataD = data;
  142. dataD.imgIds1 = deleteId
  143. $.ajax({
  144. url: getUrlFn(window.location.href) + '/equipment/equImgUpload/delete.do',
  145. type: 'get',
  146. data: dataD,
  147. dataType: 'json',
  148. success: function (data) {
  149. if(data.code == 1000){
  150. var numUp = window.delParent.siblings().length;
  151. if(numUp < 7){
  152. $(".z_file").show();
  153. }
  154. window.delParent.remove();
  155. }else{
  156. alert(data.message);
  157. }
  158. },
  159. error: function (e) {
  160. console.log('请求失败');
  161. }
  162. })
  163.  
  164. });
  165.  
  166. $(".wsdel-no").click(function(){
  167. $(".works-mask").hide();
  168. });
  169.  
  170. function validateUp(files){
  171. var arrFiles = [];//替换的文件数组
  172. for(var i = 0, file; file = files[i]; i++){
  173. //获取文件上传的后缀名
  174. var newStr = file.name.split("").reverse().join("");
  175. if(newStr.split(".")[0] != null){
  176. var type = newStr.split(".")[0].split("").reverse().join("");
  177. if(jQuery.inArray(type, defaults.fileType) > -1){
  178. // 类型符合,可以上传
  179. if (file.size >= defaults.fileSize) {
  180. alert('您这个"'+ file.name + '-----' + file.size +'"文件大小过大');
  181. } else {
  182. // 在这里需要判断当前所有文件中
  183. arrFiles.push(file);
  184. }
  185. }else{
  186. alert('您这个"'+ file.name +'"上传类型不符合');
  187. }
  188. }else{
  189. alert('您这个"'+ file.name +'"没有类型, 无法识别');
  190. }
  191. }
  192. return arrFiles;
  193. }
  194. }
  195. }
  196. })

我们是封装了一个服务,然后在页面引入html

  1. <!--上传图片 -->
  2. <div class="bby-form-item" ng-show="statu!=1" class="upPhoto">
  3. <label for="" class="bby-form-label">交款凭证图:</label>
  4. <div class="bby-input-block">
  5. <div class="z_photo" id="photoItemsBox"></div>
  6. <div class="z_file">
  7. <label for="file" class="add-img">点击上传图片</label>
  8. <input type="file" name="file" id="file" accept="image/jpg,image/jpeg,image/png,image/gif" multiple />
  9. </div>
  10. <div class="mask works-mask">
  11. <div class="mask-content">
  12. <p class="del-p">确定要删除该图片吗?</p>
  13. <p class="check-p"><span class="del-com wsdel-ok">确定</span><span class="wsdel-no">取消</span></p>
  14. </div>
  15. </div>
  16. </div>
  17. </div>

  然后在控制器依赖注入这个服务,直接调用就好了

上传图片成品如下:(包括显示图片,上传图片,点击查看大图,删除图片)

这里,我们的图片服务器出来点问题,所以图片失效了,线上的是没有问题的。

反正做这个项目的难点和思路大概也就这么些,第一次用angualr,还有很多东西做的很粗糙,今天写的博客也稀里糊涂的,思路不太清晰,就是随便写写,记录下自己的成长,未来的路还很长,慢慢来.......

第一次用angularJS做后台管理点滴的更多相关文章

  1. MVC + LigerUI 做后台管理还真是清爽

    LigerUI是基于Jquery,轻量级UI框架.具体可以看官方演示 http://www.ligerui.com/ 我的简单后台 模拟Winodw桌面效果,挺不错呢.最喜欢的还是他的,下拉列表绑定G ...

  2. 换个思维,boot结合vue做后台管理

    可以添加,可以删除.动态的添加数据. 不用操作dom,只要操作json数据即可. <form class="form-horizontal addForm" id=" ...

  3. 使用layui 做后台管理界面,在Tab中的链接点击后添加一个新TAB的解决方法

    给链接或按钮  添加 onclick="self.parent.addTab('百度','http://www.baidu.com','icon-add')" 如: <a h ...

  4. MVC5 网站开发实践 2、后台管理

    目录 MVC5 网站开发实践 概述 MVC5 网站开发实践 1.建立项目   从这一部分开始做后台管理,首先是基本框架的 一.Data项目 1.项目添加EntityFramework引用 在Data项 ...

  5. python3.6环境中django2.0与xadmin0.6结合的后台管理

    1.xadmin简介 django的admin管理后台页面很简洁,对个人来说做后台管理非常简单:xadmin的比较admin优化界面,看着也舒服. xadmin界面效果如下: 2.xadmin安装 从 ...

  6. docloud后台管理项目(开篇)

    最近朋友做app需要web做后台管理,所以花了一周时间做了这个项目. 废话不多说,开发环境是nginx+php5.3,使用thinkphp框架.是一个医疗器械数据统计的后台,业务功能很简单就是查看用户 ...

  7. 后台管理UI的选择

    最近要做一个企业的OA系统,以前一直使用EasyUI,一切都好,但感觉有点土了,想换成现在流行的Bootstrap为基础的后台UI风格,想满足的条件应该达到如下几个: 1.美观.大方.简洁 2.兼容I ...

  8. 后台管理UI皮肤的选择

    后台管理UI的选择 目录 一.EasyUI 二.DWZ JUI 三.HUI 四.BUI 五.Ace Admin 六.Metronic 七.H+ UI 八.Admin LTE 九.INSPINIA 十. ...

  9. 后台管理UI推荐

    目录 一.EasyUI 二.DWZ JUI 三.HUI 四.BUI 五.Ace Admin 六.Metronic 七.H+ UI 八.其它UI 九.总结 最近要做一个企业的OA系统,以前一直使用Eas ...

随机推荐

  1. Kubernetes tutorial - K8S 官方入门教程

    tutorials 教程 kubectl 的命令手册 1 Creating a Cluster 1.1 Using Minikube to Create a Cluster Kubernetes Cl ...

  2. 编程语言-Python2-问题整理

    InsecureRequestWarning: Unverified HTTPS request is being made. import urllib3 urllib3.disable_warni ...

  3. 排序,其他的运用 os fork

    while True: str_num = input("Enter number:") flag = True dotCount = 0 if str_num[0] == '-' ...

  4. c#Cache的用法

    public class Cache { /// <summary> /// 获取数据缓存 /// </summary> /// <param name="ca ...

  5. 诊断:MRP0: Background Media Recovery process shutdown with error ORA-19909

    oracle12c data guard,从库无法应用日志,检查alert日至发现 2019-10-21T14:55:40.087819+08:00 MRP0: Background Media Re ...

  6. spring-第十四篇之资源访问Resource接口

    1.Resource接口提供的主要方法 1>getInputStream():定位并打开资源,返回资源对应的输入流.每次调用都返回新的输入流.调用者必须负责关闭输入流. 2>isOpen( ...

  7. 用vuex写了一个购物车H5页面的示例代码

    用vuex写了一个购物车H5页面的示例代码:https://www.jb51.net/article/152008.htm 通过购物车的一个案列,把vuex学习了一篇. vuex概念浅谈 Vuex 是 ...

  8. luoguP3391[模板]文艺平衡树(Splay) 题解

    链接一下题目:luoguP3391[模板]文艺平衡树(Splay) 平衡树解析 这里的Splay维护的显然不再是权值排序 现在按照的是序列中的编号排序(不过在这道题目里面就是权值诶...) 那么,继续 ...

  9. poj2385 Apple Catching (线性dp)

    题目传送门 Apple Catching Apple Catching Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 154 ...

  10. [转]java web 文件上传

    实现WEB开发中的文件上传功能,需完成如下二步操作: 在WEB页面中添加上传输入项,<input type=“life” name=“”>,使用时注意: 1.          必须要设置 ...