瀏覽代碼

初始化

zhaoyun 1 天之前
當前提交
b3b2239a58
共有 100 個文件被更改,包括 38482 次插入0 次删除
  1. 1 0
      1-install.bat
  2. 1 0
      2-run.bat
  3. 1 0
      3-build.bat
  4. 5 0
      babel.config.js
  5. 1 0
      dist/css/app.ec044f50.css
  6. 28 0
      dist/css/chunk-vendors.baab0025.css
  7. 13 0
      dist/css/swiper.min.css
  8. 二進制
      dist/favicon.ico
  9. 二進制
      dist/fonts/element-icons.535877f5.woff
  10. 二進制
      dist/fonts/element-icons.732389de.ttf
  11. 二進制
      dist/img/404.3648f234.png
  12. 二進制
      dist/img/avator.c58e4651.png
  13. 二進制
      dist/img/zhongguo.20798bfa.png
  14. 1 0
      dist/index.html
  15. 2 0
      dist/js/app.4da0695f.js
  16. 1 0
      dist/js/app.4da0695f.js.map
  17. 143 0
      dist/js/chunk-vendors.e40b7682.js
  18. 1 0
      dist/js/chunk-vendors.e40b7682.js.map
  19. 14 0
      dist/js/swiper.min.js
  20. 8405 0
      dist/lunar/lunar.js
  21. 2 0
      dist/verifys/jquery-3.4.1.min.js
  22. 744 0
      dist/verifys/verify.js
  23. 321 0
      dist/verifys/yz.js
  24. 14488 0
      package-lock.json
  25. 70 0
      package.json
  26. 13 0
      public/css/swiper.min.css
  27. 二進制
      public/favicon.ico
  28. 25 0
      public/index.html
  29. 14 0
      public/js/swiper.min.js
  30. 8405 0
      public/lunar/lunar.js
  31. 2 0
      public/verifys/jquery-3.4.1.min.js
  32. 744 0
      public/verifys/verify.js
  33. 321 0
      public/verifys/yz.js
  34. 39 0
      src/App.vue
  35. 13 0
      src/assets/css/canvas-bg-1.css
  36. 6 0
      src/assets/css/canvas-bg-2.css
  37. 5 0
      src/assets/css/canvas-bg-3.css
  38. 5 0
      src/assets/css/canvas-bg-4.css
  39. 5 0
      src/assets/css/canvas-bg-5.css
  40. 9 0
      src/assets/css/element-variables.scss
  41. 47 0
      src/assets/css/style.scss
  42. 二進制
      src/assets/img/32.png
  43. 二進制
      src/assets/img/404.png
  44. 二進制
      src/assets/img/64.png
  45. 二進制
      src/assets/img/QRcode.png
  46. 二進制
      src/assets/img/avator.png
  47. 二進制
      src/assets/img/bg.jpg
  48. 二進制
      src/assets/img/captcha.jpg
  49. 二進制
      src/assets/img/jiahao.png
  50. 二進制
      src/assets/img/login.png
  51. 二進制
      src/assets/img/logo.png
  52. 二進制
      src/assets/img/password.png
  53. 二進制
      src/assets/img/role.png
  54. 二進制
      src/assets/img/test/jianshe.png
  55. 二進制
      src/assets/img/test/jiaotong.png
  56. 二進制
      src/assets/img/test/nongye.png
  57. 二進制
      src/assets/img/test/weixin.png
  58. 二進制
      src/assets/img/test/zhifubao.png
  59. 二進制
      src/assets/img/test/zhongguo.png
  60. 二進制
      src/assets/img/username.png
  61. 85 0
      src/assets/js/canvas-bg-1.js
  62. 191 0
      src/assets/js/canvas-bg-2.js
  63. 175 0
      src/assets/js/canvas-bg-3.js
  64. 335 0
      src/assets/js/canvas-bg-4.js
  65. 154 0
      src/assets/js/canvas-bg-5.js
  66. 43 0
      src/components/SvgIcon/index.vue
  67. 91 0
      src/components/common/BreadCrumbs.vue
  68. 267 0
      src/components/common/Editor.vue
  69. 144 0
      src/components/common/ExcelFileUpload.vue
  70. 165 0
      src/components/common/FileUpload.vue
  71. 343 0
      src/components/common/img.vue
  72. 166 0
      src/components/common/timeMethod.js
  73. 315 0
      src/components/common/timeable.vue
  74. 78 0
      src/components/common/tmap.vue
  75. 1 0
      src/components/echarts/china.json
  76. 56 0
      src/components/index/IndexAside.vue
  77. 923 0
      src/components/index/IndexAsideStatic.vue
  78. 51 0
      src/components/index/IndexAsideSub.vue
  79. 419 0
      src/components/index/IndexHeader.vue
  80. 160 0
      src/components/index/IndexMain.vue
  81. 85 0
      src/components/index/TagsView/ScrollPane.vue
  82. 315 0
      src/components/index/TagsView/index.vue
  83. 9 0
      src/icons/index.js
  84. 1 0
      src/icons/svg/404.svg
  85. 1 0
      src/icons/svg/articleEdit.svg
  86. 1 0
      src/icons/svg/banner.svg
  87. 1 0
      src/icons/svg/bug.svg
  88. 1 0
      src/icons/svg/build.svg
  89. 1 0
      src/icons/svg/cfg.svg
  90. 1 0
      src/icons/svg/channel.svg
  91. 1 0
      src/icons/svg/chart.svg
  92. 1 0
      src/icons/svg/clipboard.svg
  93. 1 0
      src/icons/svg/code.svg
  94. 1 0
      src/icons/svg/component.svg
  95. 1 0
      src/icons/svg/contacts.svg
  96. 1 0
      src/icons/svg/dashboard.svg
  97. 1 0
      src/icons/svg/date.svg
  98. 1 0
      src/icons/svg/dept.svg
  99. 1 0
      src/icons/svg/dict.svg
  100. 0 0
      src/icons/svg/documentation.svg

+ 1 - 0
1-install.bat

@@ -0,0 +1 @@
+npm install

+ 1 - 0
2-run.bat

@@ -0,0 +1 @@
+npm run serve

+ 1 - 0
3-build.bat

@@ -0,0 +1 @@
+npm run build

+ 5 - 0
babel.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/cli-plugin-babel/preset'
+  ]
+}

文件差異過大導致無法顯示
+ 1 - 0
dist/css/app.ec044f50.css


文件差異過大導致無法顯示
+ 28 - 0
dist/css/chunk-vendors.baab0025.css


文件差異過大導致無法顯示
+ 13 - 0
dist/css/swiper.min.css


二進制
dist/favicon.ico


二進制
dist/fonts/element-icons.535877f5.woff


二進制
dist/fonts/element-icons.732389de.ttf


二進制
dist/img/404.3648f234.png


二進制
dist/img/avator.c58e4651.png


二進制
dist/img/zhongguo.20798bfa.png


文件差異過大導致無法顯示
+ 1 - 0
dist/index.html


文件差異過大導致無法顯示
+ 2 - 0
dist/js/app.4da0695f.js


文件差異過大導致無法顯示
+ 1 - 0
dist/js/app.4da0695f.js.map


文件差異過大導致無法顯示
+ 143 - 0
dist/js/chunk-vendors.e40b7682.js


文件差異過大導致無法顯示
+ 1 - 0
dist/js/chunk-vendors.e40b7682.js.map


文件差異過大導致無法顯示
+ 14 - 0
dist/js/swiper.min.js


文件差異過大導致無法顯示
+ 8405 - 0
dist/lunar/lunar.js


文件差異過大導致無法顯示
+ 2 - 0
dist/verifys/jquery-3.4.1.min.js


+ 744 - 0
dist/verifys/verify.js

@@ -0,0 +1,744 @@
+/*! Verify-v0.1.0 MIT License by 大熊*/
+
+
+;(function($, window, document,undefined) {
+
+	//定义Code的构造函数
+    var Code = function(ele, opt) {
+        this.$element = ele,
+        this.defaults = {
+        	type : 1,
+        	figure : 100,	//位数,仅在type=2时生效
+        	arith : 0,	//算法,支持加减乘,0为随机,仅在type=2时生效
+        	width : '200px',
+		    height : '60px',
+		    fontSize : '30px',
+        	codeLength : 6,
+        	btnId : 'check-btn',
+        	ready : function(){},
+        	success : function(){},
+            error : function(){}
+        },
+        this.options = $.extend({}, this.defaults, opt)
+    };
+
+    var _code_chars = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
+    var _code_color1 = ['#fffff0', '#f0ffff', '#f0fff0', '#fff0f0'];
+    var _code_color2 = ['#FF0033', '#006699', '#993366', '#FF9900', '#66CC66', '#FF33CC'];
+
+    //定义Code的方法
+    Code.prototype = {
+    	init : function() {
+
+			var _this = this;
+
+			this.loadDom();
+			this.setCode();
+
+			this.options.ready();
+
+			this.$element[0].onselectstart = document.body.ondrag = function(){
+				return false;
+			};
+
+			//点击验证码
+			this.$element.find('.verify-code, .verify-change-code').on('click', function() {
+				_this.setCode();
+			});
+
+			//确定的点击事件
+			this.htmlDoms.code_btn.on('click', function() {
+				_this.checkCode();
+			})
+
+    	},
+
+    	//加载页面
+    	loadDom : function() {
+    		var panelHtml = '<div class="cerify-code-panel"><div class="verify-code"></div><div class="verify-code-area"><div class="verify-input-area"><input type="text" class="varify-input-code" /></div><div class="verify-change-area"><a class="verify-change-code">换一张</a></div></div></div>';
+        	this.$element.append(panelHtml);
+
+        	this.htmlDoms = {
+        		code_btn : $('#'+this.options.btnId),
+        		code : this.$element.find('.verify-code'),
+        		code_area : this.$element.find('.verify-code-area'),
+        		code_input : this.$element.find('.varify-input-code'),
+        	};
+
+        	this.htmlDoms.code.css({'width':this.options.width, 'height':this.options.height,'line-height':this.options.height, 'font-size':this.options.fontSize});
+        	this.htmlDoms.code_area.css({'width':this.options.width});
+    	},
+
+
+    	//设置验证码
+    	setCode : function() {
+
+    		var color1Num = Math.floor(Math.random() * 3);
+    		var color2Num = Math.floor(Math.random() * 5);
+
+    		this.htmlDoms.code.css({'background-color': _code_color1[color1Num], 'color': _code_color2[color2Num]});
+    		this.htmlDoms.code_input.val('');
+
+    		var code = '';
+    		this.code_chose = '';
+
+    		if(this.options.type == 1) {		//普通验证码
+				for(var i = 0; i < this.options.codeLength; i++) {
+					var charNum = Math.floor(Math.random() * 52);
+					var tmpStyle = (charNum%2 ==0)? "font-style:italic;margin-right: 10px;":"font-weight:bolder;";
+					tmpStyle += (Math.floor(Math.random() * 2) == 1)? "font-weight:bolder;":"";
+
+					this.code_chose += _code_chars[charNum];
+					code += '<font style="'+tmpStyle+'">'+_code_chars[charNum]+'</font>';
+				}
+    		}else {		//算法验证码
+
+    			var num1 = Math.floor(Math.random() * this.options.figure);
+    			var num2 = Math.floor(Math.random() * this.options.figure);
+
+    			if(this.options.arith == 0) {
+    				var tmparith = Math.floor(Math.random() * 3);
+    			}
+
+    			switch(tmparith) {
+    				case 1 :
+    					this.code_chose = parseInt(num1) + parseInt(num2);
+    					code = num1 + ' + ' + num2 + ' = ?';
+    					break;
+    				case 2 :
+    					if(parseInt(num1) < parseInt(num2)) {
+    						var tmpnum = num1;
+    						num1 = num2;
+    						num2 = tmpnum;
+    					}
+    					this.code_chose = parseInt(num1) - parseInt(num2);
+    					code = num1 + ' - ' + num2 + ' = ?';
+    					break;
+    				default :
+    					this.code_chose = parseInt(num1) * parseInt(num2);
+    					code = num1 + ' × ' + num2 + ' = ?';
+    					break;
+    			}
+    		}
+
+    		this.htmlDoms.code.html(code);
+
+    	},
+
+    	//比对验证码
+    	checkCode : function() {
+    		if(this.options.type == 1) {		//普通验证码
+    			var own_input = this.htmlDoms.code_input.val().toUpperCase();
+    			this.code_chose = this.code_chose.toUpperCase();
+    		}else {
+    			var own_input = this.htmlDoms.code_input.val();
+    		}
+
+    		if(own_input == this.code_chose) {
+    			this.options.success();
+    		}else {
+    			this.options.error();
+    			this.setCode();
+    		}
+    	}
+    };
+
+
+    //定义Slide的构造函数
+    var Slide = function(ele, opt) {
+        this.$element = ele,
+        this.defaults = {
+
+        	type : 1,
+        	vOffset: 5,
+            vSpace : 5,
+            imgName : ['1.jpg', '2.jpg'],
+            imgSize : {
+	        	width: '400px',
+	        	height: '200px',
+	        },
+	        blockSize : {
+	        	width: '50px',
+	        	height: '50px',
+	        },
+	        barSize : {
+	        	width : '400px',
+	        	height : '40px',
+	        },
+            ready : function(){},
+        	success : function(){},
+            error : function(){}
+
+        },
+        this.options = $.extend({}, this.defaults, opt)
+    };
+
+
+    //定义Slide的方法
+    Slide.prototype = {
+
+        init: function() {
+        	var _this = this;
+
+        	//加载页面
+        	this.loadDom();
+        	this.options.ready();
+
+        	this.$element[0].onselectstart = document.body.ondrag = function(){
+				return false;
+			};
+
+        	//按下
+        	this.htmlDoms.move_block.on('touchstart', function(e) {
+        		_this.start(e);
+        	});
+
+        	this.htmlDoms.move_block.on('mousedown', function(e) {
+        		_this.start(e);
+        	});
+
+        	//拖动
+            window.addEventListener("touchmove", function(e) {
+            	_this.move(e);
+            });
+            window.addEventListener("mousemove", function(e) {
+            	_this.move(e);
+            });
+
+            //鼠标松开
+            window.addEventListener("touchend", function() {
+            	_this.end();
+            });
+            window.addEventListener("mouseup", function() {
+            	_this.end();
+            });
+
+            //刷新
+            _this.$element.find('.verify-refresh').on('click', function() {
+            	_this.refresh();
+            });
+        },
+
+        //初始化加载
+        loadDom : function() {
+        	this.img_rand = Math.floor(Math.random() * this.options.imgName.length);			//随机的背景图片
+
+        	var panelHtml = '';
+        	var tmpHtml = '';
+
+        	if(this.options.type != 1) {		//图片滑动
+        		panelHtml += '<div class="verify-img-panel"><div  class="verify-refresh"><span class="icon iconfont icon-shuaxin"></span></div><div style="position: relative;z-index: 2;border: 1px solid #fff;background: #fff;" class="verify-gap"></div></div>';
+        		tmpHtml = '<div style="position: absolute;text-align: center;z-index: 3;border: 1px solid #fff;" class="verify-sub-block"></div>';
+        	}
+
+        	panelHtml += '<div class="verify-bar-area"><span  class="verify-msg">向右滑动完成验证</span><div class="verify-left-bar"><span  class="verify-msg"></span><div  class="verify-move-block"><i class="icon iconfont verify-icon icon-jinru"></i>'+tmpHtml+'</div></div></div>';
+        	this.$element.append(panelHtml);
+
+        	this.htmlDoms = {
+        		gap : this.$element.find('.verify-gap'),
+        		sub_block : this.$element.find('.verify-sub-block'),
+        		img_panel : this.$element.find('.verify-img-panel'),
+        		bar_area : this.$element.find('.verify-bar-area'),
+        		move_block : this.$element.find('.verify-move-block'),
+        		left_bar : this.$element.find('.verify-left-bar'),
+        		msg : this.$element.find('.verify-msg'),
+        		icon : this.$element.find('.verify-icon'),
+        		refresh :this.$element.find('.verify-refresh')
+        	};
+
+        	this.status = false;	//鼠标状态
+        	this.setSize = this.resetSize(this);	//重新设置宽度高度
+
+        	this.htmlDoms.gap.css({'width': this.options.blockSize.width, 'height': this.options.blockSize.height});
+        	this.htmlDoms.sub_block.css({'width': this.options.blockSize.width, 'height': this.options.blockSize.height});
+        	this.htmlDoms.img_panel.css({'width': this.setSize.img_width, 'height': this.setSize.img_height, 'background': 'url('+this.options.imgName[this.img_rand]+')', 'background-size' : this.setSize.img_width + ' '+ this.setSize.img_height});
+        	this.htmlDoms.bar_area.css({'width': this.setSize.bar_width, 'height': this.options.barSize.height, 'line-height':this.options.barSize.height});
+        	this.htmlDoms.move_block.css({'width': this.options.barSize.height, 'height': this.options.barSize.height});
+        	this.htmlDoms.left_bar.css({'width': this.options.barSize.height, 'height': this.options.barSize.height});
+
+        	this.randSet();
+        },
+
+        //鼠标按下
+        start: function(e) {
+        	this.htmlDoms.msg.text('');
+        	this.htmlDoms.move_block.css('background-color', '#337ab7');
+          this.htmlDoms.left_bar.addClass('verify-left-bar-active');
+        	// this.htmlDoms.left_bar.css('border-color', '#337AB7');
+        	this.htmlDoms.icon.css('color', '#fff');
+        	e.stopPropagation();
+        	this.status = true;
+
+        },
+
+        //鼠标移动
+        move: function(e) {
+        	if(this.status) {
+	            if(!e.touches) {    //兼容移动端
+	                var x = e.clientX;
+	            }else {     //兼容PC端
+	                var x = e.touches[0].pageX;
+	            }
+	            var bar_area_left = Slide.prototype.getLeft(this.htmlDoms.bar_area[0]);
+	            var move_block_left = x - bar_area_left; //小方块相对于父元素的left值
+
+
+	            if(this.options.type != 1) {		//图片滑动
+	            	if(move_block_left >= this.htmlDoms.bar_area[0].offsetWidth - parseInt(parseInt(this.options.blockSize.width)/2) - 2) {
+	                	move_block_left = this.htmlDoms.bar_area[0].offsetWidth - parseInt(parseInt(this.options.blockSize.width)/2) - 2;
+	            	}
+
+
+
+
+
+	            }else {		//普通滑动
+	            	if(move_block_left >= this.htmlDoms.bar_area[0].offsetWidth - parseInt(parseInt(this.options.barSize.height)/2) + 3) {
+	            		this.$element.find('.verify-msg:eq(1)').text('松开验证');
+	                	move_block_left = this.htmlDoms.bar_area[0].offsetWidth - parseInt(parseInt(this.options.barSize.height)/2) + 3;
+	            	}else {
+	            		this.$element.find('.verify-msg:eq(1)').text('');
+	            	}
+	            }
+
+
+	            if(move_block_left <= 0) {
+            		move_block_left = parseInt(parseInt(this.options.blockSize.width)/2);
+            	}
+
+	            //拖动后小方块的left值
+	            this.htmlDoms.move_block.css('left', move_block_left-parseInt(parseInt(this.options.blockSize.width)/2) + "px");
+	            this.htmlDoms.left_bar.css('width', move_block_left-parseInt(parseInt(this.options.blockSize.width)/2) + "px");
+	        }
+        },
+
+        //鼠标松开
+        end: function() {
+
+        	var _this = this;
+
+        	//判断是否重合
+        	if(this.status) {
+
+        		if(this.options.type != 1) {		//图片滑动
+
+        			var vOffset = parseInt(this.options.vOffset);
+		            if(parseInt(this.htmlDoms.gap.css('left')) >= (parseInt(this.htmlDoms.move_block.css('left')) - vOffset) && parseInt(this.htmlDoms.gap.css('left')) <= (parseInt(this.htmlDoms.move_block.css('left')) + vOffset)) {
+		            	this.htmlDoms.move_block.css('background-color', '#5cb85c');
+                  this.htmlDoms.left_bar.addClass('verify-left-bar-success');
+		            	// this.htmlDoms.left_bar.css({'border-color': '#5cb85c', 'background-color': '#fff'});
+		            	this.htmlDoms.icon.css('color', '#fff');
+		            	this.htmlDoms.icon.removeClass('icon-jinru');
+		            	this.htmlDoms.icon.addClass('icon-dagou');
+		            	this.htmlDoms.refresh.hide();
+		            	this.htmlDoms.move_block.unbind('mousedown touchstart');
+		            	this.options.success();
+		            }else{
+		            	this.htmlDoms.move_block.css('background-color', '#d9534f');
+                  this.htmlDoms.left_bar.addClass('verify-left-bar-error');
+		            	// this.htmlDoms.left_bar.css('border-color', '#d9534f');
+		            	this.htmlDoms.icon.css('color', '#fff');
+		            	this.htmlDoms.icon.removeClass('icon-jinru');
+		            	this.htmlDoms.icon.addClass('icon-guanbi1');
+
+		            	setTimeout(function () {
+					    	_this.htmlDoms.move_block.animate({'left':'0px'}, 'fast');
+					    	_this.htmlDoms.left_bar.animate({'width': '40px'}, 'fast');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-active');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-success');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-error');
+					    	// _this.htmlDoms.left_bar.css({'border-color': '#ddd'});
+
+					    	_this.htmlDoms.move_block.css('background-color', '#fff');
+					    	_this.htmlDoms.icon.css('color', '#000');
+					    	_this.htmlDoms.icon.removeClass('icon-guanbi1');
+		            		_this.htmlDoms.icon.addClass('icon-jinru');
+		            		_this.$element.find('.verify-msg:eq(0)').text('向右滑动完成验证');
+
+					    }, 400);
+
+		            	this.options.error();
+		            }
+
+        		}else {		//普通滑动
+
+        			if(parseInt(this.htmlDoms.move_block.css('left')) >= (parseInt(this.setSize.bar_width) - parseInt(this.options.barSize.height) - parseInt(this.options.vOffset))) {
+        				this.htmlDoms.move_block.css('background-color', '#5cb85c');
+                this.htmlDoms.left_bar.addClass('verify-left-bar-success');
+        				// this.htmlDoms.left_bar.css({'color': '#4cae4c', 'border-color': '#5cb85c', 'background-color': '#fff' });
+        				this.htmlDoms.icon.css('color', '#fff');
+		            	this.htmlDoms.icon.removeClass('icon-jinru');
+		            	this.htmlDoms.icon.addClass('icon-dagou');
+		            	this.htmlDoms.refresh.hide();
+		            	this.htmlDoms.move_block.unbind('mousedown');
+		            	this.htmlDoms.move_block.unbind('touchstart');
+        				this.$element.find('.verify-msg:eq(1)').text('验证成功');
+        				this.options.success();
+        			}else {
+
+        				this.htmlDoms.move_block.css('background-color', '#d9534f');
+                this.htmlDoms.left_bar.addClass('verify-left-bar-error');
+		            	// this.htmlDoms.left_bar.css('border-color', '#d9534f');
+		            	this.htmlDoms.icon.css('color', '#fff');
+		            	this.htmlDoms.icon.removeClass('icon-jinru');
+		            	this.htmlDoms.icon.addClass('icon-guanbi1');
+
+		            	setTimeout(function () {
+					    	_this.htmlDoms.move_block.animate({'left':'0px'}, 'fast');
+					    	_this.htmlDoms.left_bar.animate({'width': '40px'}, 'fast');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-active');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-success');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-error');
+					    	// _this.htmlDoms.left_bar.css({'border-color': '#ddd'});
+
+					    	_this.htmlDoms.move_block.css('background-color', '#fff');
+					    	_this.htmlDoms.icon.css('color', '#000');
+					    	_this.htmlDoms.icon.removeClass('icon-guanbi1');
+		            		_this.htmlDoms.icon.addClass('icon-jinru');
+		            		_this.$element.find('.verify-msg:eq(0)').text('向右滑动解锁');
+
+					    }, 400);
+
+		            	this.options.error();
+        			}
+        		}
+
+	            this.status = false;
+        	}
+        },
+
+
+        resetSize : function(obj) {
+        	var img_width,img_height,bar_width,bar_height;	//图片的宽度、高度,移动条的宽度、高度
+        	var parentWidth = obj.$element.parent().width() || $(window).width();
+        	var parentHeight = obj.$element.parent().height() || $(window).height();
+
+       		if(obj.options.imgSize.width.indexOf('%')!= -1){
+        		img_width = parseInt(obj.options.imgSize.width)/100 * parentWidth + 'px';
+		  }else {
+				img_width = obj.options.imgSize.width;
+			}
+
+			if(obj.options.imgSize.height.indexOf('%')!= -1){
+        		img_height = parseInt(obj.options.imgSize.height)/100 * parentHeight + 'px';
+		  }else {
+				img_height = obj.options.imgSize.height;
+			}
+
+			if(obj.options.barSize.width.indexOf('%')!= -1){
+        		bar_width = parseInt(obj.options.barSize.width)/100 * parentWidth + 'px';
+		  }else {
+				bar_width = obj.options.barSize.width;
+			}
+
+			if(obj.options.barSize.height.indexOf('%')!= -1){
+        		bar_height = parseInt(obj.options.barSize.height)/100 * parentHeight + 'px';
+		  }else {
+				bar_height = obj.options.barSize.height;
+			}
+
+			return {img_width : img_width, img_height : img_height, bar_width : bar_width, bar_height : bar_height};
+       	},
+
+        //随机出生点位
+        randSet: function() {
+        	var rand1 = Math.floor(Math.random()*9+1);
+        	var rand2 = Math.floor(Math.random()*9+1);
+        	var top = rand1 * parseInt(this.setSize.img_height)/15 + parseInt(this.setSize.img_height) * 0.1;
+        	var left = rand2 * parseInt(this.setSize.img_width)/15 + parseInt(this.setSize.img_width) * 0.1;
+
+        	this.$element.find('.verify-img-panel').css('margin-bottom', this.options.vSpace + 'px');
+        	this.$element.find('.verify-gap').css({'top': top, 'left': left});
+          	this.$element.find('.verify-sub-block').css({'top':'-'+(parseInt(this.setSize.img_height)- top + this.options.vSpace + 1)+'px', 'background-image': 'url('+this.options.imgName[this.img_rand]+')', 'background-size': this.setSize.img_width + ' '+ this.setSize.img_height,'background-position-y': '-'+top+ 'px', 'background-position-x': '-'+left+'px'});
+        },
+
+        //刷新
+        refresh: function() {
+        	this.randSet();
+        	this.img_rand = Math.floor(Math.random() * this.options.imgName.length);			//随机的背景图片
+            this.$element.find('.verify-img-panel').css({'background': 'url('+this.options.imgName[this.img_rand]+')', 'background-size': this.setSize.img_width + ' '+ this.setSize.img_height});
+            this.$element.find('.verify-sub-block').css({'background-image': 'url('+this.options.imgName[this.img_rand]+')', 'background-size': this.setSize.img_width + ' '+ this.setSize.img_height});
+        },
+
+        //获取left值
+        getLeft: function(node) {
+			var left = $(node).offset().left;
+//          var nowPos = node.offsetParent;
+//
+//          while(nowPos != null) {  
+//              left += $(nowPos).offset().left; 
+//              nowPos = nowPos.offsetParent;  
+//          }
+            return left;
+        }
+    };
+
+
+    //定义Points的构造函数
+    var Points = function(ele, opt) {
+        this.$element = ele,
+        this.defaults = {
+        	defaultNum : 4,	//默认的文字数量
+		    checkNum : 3,	//校对的文字数量
+		    vSpace : 5,	//间隔
+        	imgName : ['1.jpg', '2.jpg'],
+        	imgSize : {
+	        	width: '400px',
+	        	height: '200px',
+	        },
+	        barSize : {
+	        	width : '400px',
+	        	height : '40px',
+	        },
+	        ready : function(){},
+        	success : function(){},
+            error : function(){}
+        },
+        this.options = $.extend({}, this.defaults, opt)
+    };
+
+    //定义Points的方法
+    Points.prototype = {
+    	init : function() {
+
+			var _this = this;
+
+			//加载页面
+        	_this.loadDom();
+
+        	_this.refresh();
+        	_this.options.ready();
+
+        	this.$element[0].onselectstart = document.body.ondrag = function(){
+				return false;
+			};
+
+		 	//点击事件比对
+        	_this.$element.find('.verify-img-panel canvas').on('click', function(e) {
+
+				_this.checkPosArr.push(_this.getMousePos(this, e));
+
+				if(_this.num == _this.options.checkNum) {
+
+					_this.num = _this.createPoint(_this.getMousePos(this, e));
+					setTimeout(function () {
+						var flag = _this.comparePos(_this.fontPos, _this.checkPosArr);
+
+						if(flag == false) {	//验证失败
+
+							_this.options.error();
+							_this.$element.find('.verify-bar-area').css({'color': '#d9534f', 'border-color': '#d9534f'});
+						    _this.$element.find('.verify-msg').text('验证失败');
+
+							setTimeout(function () {
+								_this.$element.find('.verify-bar-area').css({'color': '#000','border-color': '#ddd'});
+						    	_this.refresh();
+						    }, 400);
+
+						}else {	//验证成功
+							_this.$element.find('.verify-bar-area').css({'color': '#4cae4c', 'border-color': '#5cb85c'});
+							_this.$element.find('.verify-msg').text('验证成功');
+							_this.$element.find('.verify-refresh').hide();
+							_this.$element.find('.verify-img-panel').unbind('click');
+							_this.options.success();
+						}
+					}, 400);
+
+				}
+
+				if(_this.num < _this.options.checkNum) {
+					_this.num = _this.createPoint(_this.getMousePos(this, e));
+				}
+
+        	});
+
+        	 //刷新
+            _this.$element.find('.verify-refresh').on('click', function() {
+            	_this.refresh();
+            });
+
+    	},
+
+
+
+    	//加载页面
+    	loadDom : function() {
+
+    		this.fontPos = [];	//选中的坐标信息
+    		this.checkPosArr = [];	//用户点击的坐标
+    		this.num = 1;	//点击的记数
+    		this.img_rand = Math.floor(Math.random() * this.options.imgName.length);			//随机的背景图片
+
+        	var panelHtml = '';
+        	var tmpHtml = '';
+
+        	this.setSize = Slide.prototype.resetSize(this);	//重新设置宽度高度
+
+        	panelHtml += '<div class="verify-img-panel"><div  class="verify-refresh" style="z-index:9999"><i class="icon iconfont icon-shuaxin"></i></div><canvas width="'+this.setSize.img_width+'" height="'+this.setSize.img_height+'"></canvas></div><div class="verify-bar-area"><span  class="verify-msg"></span></div>';
+
+        	this.$element.append(panelHtml);
+
+
+        	this.htmlDoms = {
+        		img_panel : this.$element.find('.verify-img-panel'),
+        		bar_area : this.$element.find('.verify-bar-area'),
+        		msg : this.$element.find('.verify-msg'),
+        	};
+
+    		this.htmlDoms.img_panel.css({'width': this.setSize.img_width, 'height': this.setSize.img_height, 'background-size' : this.setSize.img_width + ' '+ this.setSize.img_height, 'margin-bottom': this.options.vSpace + 'px'});
+    		this.htmlDoms.bar_area.css({'width': this.options.barSize.width, 'height': this.options.barSize.height, 'line-height':this.options.barSize.height});
+
+    	},
+
+    	//绘制合成的图片
+    	drawImg : function(obj, img) {
+    		//准备canvas环境
+	       	var canvas = this.$element.find('canvas')[0];
+	      	//var canvas=document.getElementById("myCanvas");
+	       	var ctx=canvas.getContext("2d");
+
+	       	// 绘制图片
+	       	ctx.drawImage(img,0,0, parseInt(this.setSize.img_width), parseInt(this.setSize.img_height));
+
+	       	// 绘制水印
+	       	var fontSizeArr = ['italic small-caps bold 20px microsoft yahei', 'small-caps normal 25px arial', '34px microsoft yahei'];
+	       	var fontStr = '天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往秋收冬藏闰余成岁律吕调阳云腾致雨露结为霜金生丽水玉出昆冈剑号巨阙珠称夜光果珍李柰菜重芥姜海咸河淡鳞潜羽翔龙师火帝鸟官人皇始制文字乃服衣裳推位让国有虞陶唐吊民伐罪周发殷汤坐朝问道垂拱平章爱育黎首臣伏戎羌遐迩体率宾归王';	//不重复的汉字
+
+
+	       	var fontChars = [];
+
+	       	var avg = Math.floor(parseInt(this.setSize.img_width)/(parseInt(this.options.defaultNum)+1));
+	       	var tmp_index = '';
+	       	var color2Num = Math.floor(Math.random() * 5);
+
+	       	for(var i = 1; i <= this.options.defaultNum; i++) {
+
+	       		fontChars[i-1] = this.getChars(fontStr, fontChars);
+
+	       		tmp_index = Math.floor(Math.random()*3);
+	       		ctx.font = fontSizeArr[tmp_index];
+		       	ctx.fillStyle = _code_color2[color2Num];
+
+		       	if(Math.floor(Math.random() * 2) == 1) {
+		       		var tmp_y = Math.floor(parseInt(this.setSize.img_height)/2) + tmp_index*20 + 20;
+		       	}else {
+		       		var tmp_y = Math.floor(parseInt(this.setSize.img_height)/2) - tmp_index*20;
+		       	}
+
+		       	ctx.fillText(fontChars[i-1],avg * i, tmp_y);
+		       	this.fontPos[i-1] = {'char': fontChars[i-1], 'x': avg * i, 'y': tmp_y};
+
+	       	}
+
+	       	for(var i = 0; i < (this.options.defaultNum-this.options.checkNum); i++) {
+	       		this.shuffle(this.fontPos).pop();
+	       	}
+
+	       	var msgStr = '';
+	       	for(var i = 0; i < this.fontPos.length; i++) {
+	       		msgStr += this.fontPos[i].char + ',';
+	       	}
+
+	       	this.htmlDoms.msg.text('请顺序点击【' + msgStr.substring(0,msgStr.length-1) + '】');
+
+	       	return this.fontPos;
+    	},
+
+    	//获取坐标
+    	getMousePos :function(obj, event) {
+            var e = event || window.event;
+            var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
+            var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
+            var x = e.clientX - ($(obj).offset().left - $(window).scrollLeft());
+    		var y = e.clientY - ($(obj).offset().top - $(window).scrollTop());
+
+            return {'x': x, 'y': y};
+     	},
+
+     	//递归去重
+     	getChars : function(fontStr, fontChars) {
+
+     		var tmp_rand = parseInt(Math.floor(Math.random() * fontStr.length));
+     		if(tmp_rand > 0) {
+     			tmp_rand = tmp_rand - 1;
+     		}
+
+     		tmp_char = fontStr.charAt(tmp_rand);
+       		if($.inArray(tmp_char, fontChars) == -1) {
+       			return tmp_char;
+       		}else {
+       			return Points.prototype.getChars(fontStr, fontChars);
+       		}
+     	},
+
+		//洗牌数组
+       	shuffle : function(arr) {
+			var m = arr.length, i;
+			while (m) {
+				i = (Math.random() * m--) >>> 0;
+				[arr[m], arr[i]] = [arr[i], arr[m]]
+			}
+			return arr;
+		},
+
+       	//创建坐标点
+       	createPoint : function (pos) {
+       		this.htmlDoms.img_panel.append('<div class="point-area" style="background-color:#1abd6c;color:#fff;z-index:9999;width:30px;height:30px;text-align:center;line-height:30px;border-radius: 50%;position:absolute;top:'+parseInt(pos.y-10)+'px;left:'+parseInt(pos.x-10)+'px;">'+this.num+'</div>');
+       		return ++this.num;
+       	},
+
+       	//比对坐标点
+       	comparePos : function (fontPos, checkPosArr) {
+
+       		var flag = true;
+       		for(var i = 0; i < fontPos.length; i++) {
+       			if(!(parseInt(checkPosArr[i].x) + 40 > fontPos[i].x && parseInt(checkPosArr[i].x) - 40 < fontPos[i].x && parseInt(checkPosArr[i].y) + 40 > fontPos[i].y && parseInt(checkPosArr[i].y) - 40 < fontPos[i].y)) {
+       				flag = false;
+       				break;
+       			}
+       		}
+
+       		return flag;
+       	},
+
+       	//刷新
+        refresh: function() {
+        	var _this = this;
+        	this.$element.find('.point-area').remove();
+        	this.fontPos = [];
+        	this.checkPosArr = [];
+        	this.num = 1;
+
+        	this.img_rand = Math.floor(Math.random() * this.options.imgName.length);			//随机的背景图片
+        	var img = new Image();
+		    img.src = this.options.imgName[this.img_rand];
+
+
+		 	// 加载完成开始绘制
+		 	$(img).on('load', function(e) {
+        		this.fontPos = _this.drawImg(_this, this);
+        	});
+
+        },
+
+    };
+
+    //在插件中使用codeVerify对象
+    $.fn.codeVerify = function(options, callbacks) {
+        var code = new Code(this, options);
+        code.init();
+    };
+
+    //在插件中使用slideVerify对象
+    $.fn.slideVerify = function(options, callbacks) {
+        var slide = new Slide(this, options);
+        slide.init();
+    };
+
+    //在插件中使用clickVerify对象
+    $.fn.pointsVerify = function(options, callbacks) {
+        var points = new Points(this, options);
+        points.init();
+    };
+
+})(jQuery, window, document);

文件差異過大導致無法顯示
+ 321 - 0
dist/verifys/yz.js


文件差異過大導致無法顯示
+ 14488 - 0
package-lock.json


+ 70 - 0
package.json

@@ -0,0 +1,70 @@
+{
+	"name": "mas-creator-admin",
+	"version": "0.1.0",
+	"private": true,
+	"scripts": {
+		"serve": "vue-cli-service serve",
+		"build": "vue-cli-service build",
+		"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
+		"lint": "vue-cli-service lint"
+	},
+	"dependencies": {
+		"@amap/amap-jsapi-loader": "^1.0.1",
+		"axios": "^0.19.2",
+		"core-js": "^3.4.4",
+		"echarts": "^5.4.1",
+		"echarts-wordcloud": "^2.1.0",
+		"vue-echarts": "^6.2.3",
+		"element-ui": "^2.13.0",
+		"js-md5": "^0.7.3",
+		"print-js": "^1.5.0",
+		"vue": "^2.6.10",
+		"vue-quill-editor": "^3.0.6",
+		"vue-amap": "^0.5.10",
+		"vue-json-excel": "^0.3.0",
+		"vue-router": "^3.1.5",
+		"vuex": "^3.2.0",
+		"swiper": "^5.2.0",
+		"animate.css": "^4.1.1",
+		"watermark-dom": "^2.3.0",
+		"emoji-mart-vue": "^2.6.6"
+	},
+	"devDependencies": {
+		"@vue/cli-plugin-babel": "^4.1.0",
+		"@vue/cli-plugin-eslint": "^4.1.0",
+		"@vue/cli-service": "^4.1.0",
+		"babel-eslint": "^10.0.3",
+		"babel-plugin-component": "^1.1.1",
+		"eslint": "^5.16.0",
+		"eslint-plugin-vue": "^5.0.0",
+		"node-sass": "^4.13.1",
+		"sass-loader": "^8.0.2",
+		"svg-sprite-loader": "4.1.3",
+		"svgo": "1.2.2",
+		"vue-template-compiler": "^2.6.10"
+	},
+	"eslintConfig": {
+		"root": true,
+		"env": {
+			"node": true
+		},
+		"extends": [
+			"plugin:vue/essential",
+			"eslint:recommended"
+		],
+		"rules": {
+			"no-console": "off",
+			"no-unused-vars": 0,
+			"no-useless-escape": "off"
+		},
+		"parserOptions": {
+			"parser": "babel-eslint"
+		}
+	},
+	"browserslist": [
+		"> 1%",
+		"last 2 versions",
+		"not ie <= 8",
+		"Android >= 4.0"
+	]
+}

文件差異過大導致無法顯示
+ 13 - 0
public/css/swiper.min.css


二進制
public/favicon.ico


+ 25 - 0
public/index.html

@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8">
+        <meta name="referrer" content="no-referrer" />
+		<meta http-equiv="X-UA-Compatible" content="IE=edge">
+		<meta name="viewport" content="width=device-width,initial-scale=1.0">
+		<link rel="icon" href="<%= BASE_URL %>favicon.ico">
+		<link rel="stylesheet" icon="icon" href="//at.alicdn.com/t/c/font_4097802_w9071sf3dx.css">
+		<link rel="stylesheet" type="text/css" href="css/swiper.min.css" />
+		<script src="<%= BASE_URL %>lunar/lunar.js"></script>
+		<script src="js/swiper.min.js" type="text/javascript" charset="utf-8"></script>
+		<script src="<%= BASE_URL %>verifys/jquery-3.4.1.min.js"></script>
+		<script src="<%= BASE_URL %>verifys/yz.js"></script>
+		<script src="<%= BASE_URL %>verifys/verify.js"></script>
+		<title>管理端-全国降水分析可视化系统的设计与实现</title>
+	</head>
+	<body>
+		<noscript>
+			<strong>We're sorry but mas-creator-admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+		</noscript>
+		<div id="app"></div>
+		<!-- built files will be auto injected -->
+	</body>
+</html>

文件差異過大導致無法顯示
+ 14 - 0
public/js/swiper.min.js


文件差異過大導致無法顯示
+ 8405 - 0
public/lunar/lunar.js


文件差異過大導致無法顯示
+ 2 - 0
public/verifys/jquery-3.4.1.min.js


+ 744 - 0
public/verifys/verify.js

@@ -0,0 +1,744 @@
+/*! Verify-v0.1.0 MIT License by 大熊*/
+
+
+;(function($, window, document,undefined) {
+
+	//定义Code的构造函数
+    var Code = function(ele, opt) {
+        this.$element = ele,
+        this.defaults = {
+        	type : 1,
+        	figure : 100,	//位数,仅在type=2时生效
+        	arith : 0,	//算法,支持加减乘,0为随机,仅在type=2时生效
+        	width : '200px',
+		    height : '60px',
+		    fontSize : '30px',
+        	codeLength : 6,
+        	btnId : 'check-btn',
+        	ready : function(){},
+        	success : function(){},
+            error : function(){}
+        },
+        this.options = $.extend({}, this.defaults, opt)
+    };
+
+    var _code_chars = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
+    var _code_color1 = ['#fffff0', '#f0ffff', '#f0fff0', '#fff0f0'];
+    var _code_color2 = ['#FF0033', '#006699', '#993366', '#FF9900', '#66CC66', '#FF33CC'];
+
+    //定义Code的方法
+    Code.prototype = {
+    	init : function() {
+
+			var _this = this;
+
+			this.loadDom();
+			this.setCode();
+
+			this.options.ready();
+
+			this.$element[0].onselectstart = document.body.ondrag = function(){
+				return false;
+			};
+
+			//点击验证码
+			this.$element.find('.verify-code, .verify-change-code').on('click', function() {
+				_this.setCode();
+			});
+
+			//确定的点击事件
+			this.htmlDoms.code_btn.on('click', function() {
+				_this.checkCode();
+			})
+
+    	},
+
+    	//加载页面
+    	loadDom : function() {
+    		var panelHtml = '<div class="cerify-code-panel"><div class="verify-code"></div><div class="verify-code-area"><div class="verify-input-area"><input type="text" class="varify-input-code" /></div><div class="verify-change-area"><a class="verify-change-code">换一张</a></div></div></div>';
+        	this.$element.append(panelHtml);
+
+        	this.htmlDoms = {
+        		code_btn : $('#'+this.options.btnId),
+        		code : this.$element.find('.verify-code'),
+        		code_area : this.$element.find('.verify-code-area'),
+        		code_input : this.$element.find('.varify-input-code'),
+        	};
+
+        	this.htmlDoms.code.css({'width':this.options.width, 'height':this.options.height,'line-height':this.options.height, 'font-size':this.options.fontSize});
+        	this.htmlDoms.code_area.css({'width':this.options.width});
+    	},
+
+
+    	//设置验证码
+    	setCode : function() {
+
+    		var color1Num = Math.floor(Math.random() * 3);
+    		var color2Num = Math.floor(Math.random() * 5);
+
+    		this.htmlDoms.code.css({'background-color': _code_color1[color1Num], 'color': _code_color2[color2Num]});
+    		this.htmlDoms.code_input.val('');
+
+    		var code = '';
+    		this.code_chose = '';
+
+    		if(this.options.type == 1) {		//普通验证码
+				for(var i = 0; i < this.options.codeLength; i++) {
+					var charNum = Math.floor(Math.random() * 52);
+					var tmpStyle = (charNum%2 ==0)? "font-style:italic;margin-right: 10px;":"font-weight:bolder;";
+					tmpStyle += (Math.floor(Math.random() * 2) == 1)? "font-weight:bolder;":"";
+
+					this.code_chose += _code_chars[charNum];
+					code += '<font style="'+tmpStyle+'">'+_code_chars[charNum]+'</font>';
+				}
+    		}else {		//算法验证码
+
+    			var num1 = Math.floor(Math.random() * this.options.figure);
+    			var num2 = Math.floor(Math.random() * this.options.figure);
+
+    			if(this.options.arith == 0) {
+    				var tmparith = Math.floor(Math.random() * 3);
+    			}
+
+    			switch(tmparith) {
+    				case 1 :
+    					this.code_chose = parseInt(num1) + parseInt(num2);
+    					code = num1 + ' + ' + num2 + ' = ?';
+    					break;
+    				case 2 :
+    					if(parseInt(num1) < parseInt(num2)) {
+    						var tmpnum = num1;
+    						num1 = num2;
+    						num2 = tmpnum;
+    					}
+    					this.code_chose = parseInt(num1) - parseInt(num2);
+    					code = num1 + ' - ' + num2 + ' = ?';
+    					break;
+    				default :
+    					this.code_chose = parseInt(num1) * parseInt(num2);
+    					code = num1 + ' × ' + num2 + ' = ?';
+    					break;
+    			}
+    		}
+
+    		this.htmlDoms.code.html(code);
+
+    	},
+
+    	//比对验证码
+    	checkCode : function() {
+    		if(this.options.type == 1) {		//普通验证码
+    			var own_input = this.htmlDoms.code_input.val().toUpperCase();
+    			this.code_chose = this.code_chose.toUpperCase();
+    		}else {
+    			var own_input = this.htmlDoms.code_input.val();
+    		}
+
+    		if(own_input == this.code_chose) {
+    			this.options.success();
+    		}else {
+    			this.options.error();
+    			this.setCode();
+    		}
+    	}
+    };
+
+
+    //定义Slide的构造函数
+    var Slide = function(ele, opt) {
+        this.$element = ele,
+        this.defaults = {
+
+        	type : 1,
+        	vOffset: 5,
+            vSpace : 5,
+            imgName : ['1.jpg', '2.jpg'],
+            imgSize : {
+	        	width: '400px',
+	        	height: '200px',
+	        },
+	        blockSize : {
+	        	width: '50px',
+	        	height: '50px',
+	        },
+	        barSize : {
+	        	width : '400px',
+	        	height : '40px',
+	        },
+            ready : function(){},
+        	success : function(){},
+            error : function(){}
+
+        },
+        this.options = $.extend({}, this.defaults, opt)
+    };
+
+
+    //定义Slide的方法
+    Slide.prototype = {
+
+        init: function() {
+        	var _this = this;
+
+        	//加载页面
+        	this.loadDom();
+        	this.options.ready();
+
+        	this.$element[0].onselectstart = document.body.ondrag = function(){
+				return false;
+			};
+
+        	//按下
+        	this.htmlDoms.move_block.on('touchstart', function(e) {
+        		_this.start(e);
+        	});
+
+        	this.htmlDoms.move_block.on('mousedown', function(e) {
+        		_this.start(e);
+        	});
+
+        	//拖动
+            window.addEventListener("touchmove", function(e) {
+            	_this.move(e);
+            });
+            window.addEventListener("mousemove", function(e) {
+            	_this.move(e);
+            });
+
+            //鼠标松开
+            window.addEventListener("touchend", function() {
+            	_this.end();
+            });
+            window.addEventListener("mouseup", function() {
+            	_this.end();
+            });
+
+            //刷新
+            _this.$element.find('.verify-refresh').on('click', function() {
+            	_this.refresh();
+            });
+        },
+
+        //初始化加载
+        loadDom : function() {
+        	this.img_rand = Math.floor(Math.random() * this.options.imgName.length);			//随机的背景图片
+
+        	var panelHtml = '';
+        	var tmpHtml = '';
+
+        	if(this.options.type != 1) {		//图片滑动
+        		panelHtml += '<div class="verify-img-panel"><div  class="verify-refresh"><span class="icon iconfont icon-shuaxin"></span></div><div style="position: relative;z-index: 2;border: 1px solid #fff;background: #fff;" class="verify-gap"></div></div>';
+        		tmpHtml = '<div style="position: absolute;text-align: center;z-index: 3;border: 1px solid #fff;" class="verify-sub-block"></div>';
+        	}
+
+        	panelHtml += '<div class="verify-bar-area"><span  class="verify-msg">向右滑动完成验证</span><div class="verify-left-bar"><span  class="verify-msg"></span><div  class="verify-move-block"><i class="icon iconfont verify-icon icon-jinru"></i>'+tmpHtml+'</div></div></div>';
+        	this.$element.append(panelHtml);
+
+        	this.htmlDoms = {
+        		gap : this.$element.find('.verify-gap'),
+        		sub_block : this.$element.find('.verify-sub-block'),
+        		img_panel : this.$element.find('.verify-img-panel'),
+        		bar_area : this.$element.find('.verify-bar-area'),
+        		move_block : this.$element.find('.verify-move-block'),
+        		left_bar : this.$element.find('.verify-left-bar'),
+        		msg : this.$element.find('.verify-msg'),
+        		icon : this.$element.find('.verify-icon'),
+        		refresh :this.$element.find('.verify-refresh')
+        	};
+
+        	this.status = false;	//鼠标状态
+        	this.setSize = this.resetSize(this);	//重新设置宽度高度
+
+        	this.htmlDoms.gap.css({'width': this.options.blockSize.width, 'height': this.options.blockSize.height});
+        	this.htmlDoms.sub_block.css({'width': this.options.blockSize.width, 'height': this.options.blockSize.height});
+        	this.htmlDoms.img_panel.css({'width': this.setSize.img_width, 'height': this.setSize.img_height, 'background': 'url('+this.options.imgName[this.img_rand]+')', 'background-size' : this.setSize.img_width + ' '+ this.setSize.img_height});
+        	this.htmlDoms.bar_area.css({'width': this.setSize.bar_width, 'height': this.options.barSize.height, 'line-height':this.options.barSize.height});
+        	this.htmlDoms.move_block.css({'width': this.options.barSize.height, 'height': this.options.barSize.height});
+        	this.htmlDoms.left_bar.css({'width': this.options.barSize.height, 'height': this.options.barSize.height});
+
+        	this.randSet();
+        },
+
+        //鼠标按下
+        start: function(e) {
+        	this.htmlDoms.msg.text('');
+        	this.htmlDoms.move_block.css('background-color', '#337ab7');
+          this.htmlDoms.left_bar.addClass('verify-left-bar-active');
+        	// this.htmlDoms.left_bar.css('border-color', '#337AB7');
+        	this.htmlDoms.icon.css('color', '#fff');
+        	e.stopPropagation();
+        	this.status = true;
+
+        },
+
+        //鼠标移动
+        move: function(e) {
+        	if(this.status) {
+	            if(!e.touches) {    //兼容移动端
+	                var x = e.clientX;
+	            }else {     //兼容PC端
+	                var x = e.touches[0].pageX;
+	            }
+	            var bar_area_left = Slide.prototype.getLeft(this.htmlDoms.bar_area[0]);
+	            var move_block_left = x - bar_area_left; //小方块相对于父元素的left值
+
+
+	            if(this.options.type != 1) {		//图片滑动
+	            	if(move_block_left >= this.htmlDoms.bar_area[0].offsetWidth - parseInt(parseInt(this.options.blockSize.width)/2) - 2) {
+	                	move_block_left = this.htmlDoms.bar_area[0].offsetWidth - parseInt(parseInt(this.options.blockSize.width)/2) - 2;
+	            	}
+
+
+
+
+
+	            }else {		//普通滑动
+	            	if(move_block_left >= this.htmlDoms.bar_area[0].offsetWidth - parseInt(parseInt(this.options.barSize.height)/2) + 3) {
+	            		this.$element.find('.verify-msg:eq(1)').text('松开验证');
+	                	move_block_left = this.htmlDoms.bar_area[0].offsetWidth - parseInt(parseInt(this.options.barSize.height)/2) + 3;
+	            	}else {
+	            		this.$element.find('.verify-msg:eq(1)').text('');
+	            	}
+	            }
+
+
+	            if(move_block_left <= 0) {
+            		move_block_left = parseInt(parseInt(this.options.blockSize.width)/2);
+            	}
+
+	            //拖动后小方块的left值
+	            this.htmlDoms.move_block.css('left', move_block_left-parseInt(parseInt(this.options.blockSize.width)/2) + "px");
+	            this.htmlDoms.left_bar.css('width', move_block_left-parseInt(parseInt(this.options.blockSize.width)/2) + "px");
+	        }
+        },
+
+        //鼠标松开
+        end: function() {
+
+        	var _this = this;
+
+        	//判断是否重合
+        	if(this.status) {
+
+        		if(this.options.type != 1) {		//图片滑动
+
+        			var vOffset = parseInt(this.options.vOffset);
+		            if(parseInt(this.htmlDoms.gap.css('left')) >= (parseInt(this.htmlDoms.move_block.css('left')) - vOffset) && parseInt(this.htmlDoms.gap.css('left')) <= (parseInt(this.htmlDoms.move_block.css('left')) + vOffset)) {
+		            	this.htmlDoms.move_block.css('background-color', '#5cb85c');
+                  this.htmlDoms.left_bar.addClass('verify-left-bar-success');
+		            	// this.htmlDoms.left_bar.css({'border-color': '#5cb85c', 'background-color': '#fff'});
+		            	this.htmlDoms.icon.css('color', '#fff');
+		            	this.htmlDoms.icon.removeClass('icon-jinru');
+		            	this.htmlDoms.icon.addClass('icon-dagou');
+		            	this.htmlDoms.refresh.hide();
+		            	this.htmlDoms.move_block.unbind('mousedown touchstart');
+		            	this.options.success();
+		            }else{
+		            	this.htmlDoms.move_block.css('background-color', '#d9534f');
+                  this.htmlDoms.left_bar.addClass('verify-left-bar-error');
+		            	// this.htmlDoms.left_bar.css('border-color', '#d9534f');
+		            	this.htmlDoms.icon.css('color', '#fff');
+		            	this.htmlDoms.icon.removeClass('icon-jinru');
+		            	this.htmlDoms.icon.addClass('icon-guanbi1');
+
+		            	setTimeout(function () {
+					    	_this.htmlDoms.move_block.animate({'left':'0px'}, 'fast');
+					    	_this.htmlDoms.left_bar.animate({'width': '40px'}, 'fast');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-active');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-success');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-error');
+					    	// _this.htmlDoms.left_bar.css({'border-color': '#ddd'});
+
+					    	_this.htmlDoms.move_block.css('background-color', '#fff');
+					    	_this.htmlDoms.icon.css('color', '#000');
+					    	_this.htmlDoms.icon.removeClass('icon-guanbi1');
+		            		_this.htmlDoms.icon.addClass('icon-jinru');
+		            		_this.$element.find('.verify-msg:eq(0)').text('向右滑动完成验证');
+
+					    }, 400);
+
+		            	this.options.error();
+		            }
+
+        		}else {		//普通滑动
+
+        			if(parseInt(this.htmlDoms.move_block.css('left')) >= (parseInt(this.setSize.bar_width) - parseInt(this.options.barSize.height) - parseInt(this.options.vOffset))) {
+        				this.htmlDoms.move_block.css('background-color', '#5cb85c');
+                this.htmlDoms.left_bar.addClass('verify-left-bar-success');
+        				// this.htmlDoms.left_bar.css({'color': '#4cae4c', 'border-color': '#5cb85c', 'background-color': '#fff' });
+        				this.htmlDoms.icon.css('color', '#fff');
+		            	this.htmlDoms.icon.removeClass('icon-jinru');
+		            	this.htmlDoms.icon.addClass('icon-dagou');
+		            	this.htmlDoms.refresh.hide();
+		            	this.htmlDoms.move_block.unbind('mousedown');
+		            	this.htmlDoms.move_block.unbind('touchstart');
+        				this.$element.find('.verify-msg:eq(1)').text('验证成功');
+        				this.options.success();
+        			}else {
+
+        				this.htmlDoms.move_block.css('background-color', '#d9534f');
+                this.htmlDoms.left_bar.addClass('verify-left-bar-error');
+		            	// this.htmlDoms.left_bar.css('border-color', '#d9534f');
+		            	this.htmlDoms.icon.css('color', '#fff');
+		            	this.htmlDoms.icon.removeClass('icon-jinru');
+		            	this.htmlDoms.icon.addClass('icon-guanbi1');
+
+		            	setTimeout(function () {
+					    	_this.htmlDoms.move_block.animate({'left':'0px'}, 'fast');
+					    	_this.htmlDoms.left_bar.animate({'width': '40px'}, 'fast');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-active');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-success');
+                _this.htmlDoms.left_bar.removeClass('verify-left-bar-error');
+					    	// _this.htmlDoms.left_bar.css({'border-color': '#ddd'});
+
+					    	_this.htmlDoms.move_block.css('background-color', '#fff');
+					    	_this.htmlDoms.icon.css('color', '#000');
+					    	_this.htmlDoms.icon.removeClass('icon-guanbi1');
+		            		_this.htmlDoms.icon.addClass('icon-jinru');
+		            		_this.$element.find('.verify-msg:eq(0)').text('向右滑动解锁');
+
+					    }, 400);
+
+		            	this.options.error();
+        			}
+        		}
+
+	            this.status = false;
+        	}
+        },
+
+
+        resetSize : function(obj) {
+        	var img_width,img_height,bar_width,bar_height;	//图片的宽度、高度,移动条的宽度、高度
+        	var parentWidth = obj.$element.parent().width() || $(window).width();
+        	var parentHeight = obj.$element.parent().height() || $(window).height();
+
+       		if(obj.options.imgSize.width.indexOf('%')!= -1){
+        		img_width = parseInt(obj.options.imgSize.width)/100 * parentWidth + 'px';
+		  }else {
+				img_width = obj.options.imgSize.width;
+			}
+
+			if(obj.options.imgSize.height.indexOf('%')!= -1){
+        		img_height = parseInt(obj.options.imgSize.height)/100 * parentHeight + 'px';
+		  }else {
+				img_height = obj.options.imgSize.height;
+			}
+
+			if(obj.options.barSize.width.indexOf('%')!= -1){
+        		bar_width = parseInt(obj.options.barSize.width)/100 * parentWidth + 'px';
+		  }else {
+				bar_width = obj.options.barSize.width;
+			}
+
+			if(obj.options.barSize.height.indexOf('%')!= -1){
+        		bar_height = parseInt(obj.options.barSize.height)/100 * parentHeight + 'px';
+		  }else {
+				bar_height = obj.options.barSize.height;
+			}
+
+			return {img_width : img_width, img_height : img_height, bar_width : bar_width, bar_height : bar_height};
+       	},
+
+        //随机出生点位
+        randSet: function() {
+        	var rand1 = Math.floor(Math.random()*9+1);
+        	var rand2 = Math.floor(Math.random()*9+1);
+        	var top = rand1 * parseInt(this.setSize.img_height)/15 + parseInt(this.setSize.img_height) * 0.1;
+        	var left = rand2 * parseInt(this.setSize.img_width)/15 + parseInt(this.setSize.img_width) * 0.1;
+
+        	this.$element.find('.verify-img-panel').css('margin-bottom', this.options.vSpace + 'px');
+        	this.$element.find('.verify-gap').css({'top': top, 'left': left});
+          	this.$element.find('.verify-sub-block').css({'top':'-'+(parseInt(this.setSize.img_height)- top + this.options.vSpace + 1)+'px', 'background-image': 'url('+this.options.imgName[this.img_rand]+')', 'background-size': this.setSize.img_width + ' '+ this.setSize.img_height,'background-position-y': '-'+top+ 'px', 'background-position-x': '-'+left+'px'});
+        },
+
+        //刷新
+        refresh: function() {
+        	this.randSet();
+        	this.img_rand = Math.floor(Math.random() * this.options.imgName.length);			//随机的背景图片
+            this.$element.find('.verify-img-panel').css({'background': 'url('+this.options.imgName[this.img_rand]+')', 'background-size': this.setSize.img_width + ' '+ this.setSize.img_height});
+            this.$element.find('.verify-sub-block').css({'background-image': 'url('+this.options.imgName[this.img_rand]+')', 'background-size': this.setSize.img_width + ' '+ this.setSize.img_height});
+        },
+
+        //获取left值
+        getLeft: function(node) {
+			var left = $(node).offset().left;
+//          var nowPos = node.offsetParent;
+//
+//          while(nowPos != null) {  
+//              left += $(nowPos).offset().left; 
+//              nowPos = nowPos.offsetParent;  
+//          }
+            return left;
+        }
+    };
+
+
+    //定义Points的构造函数
+    var Points = function(ele, opt) {
+        this.$element = ele,
+        this.defaults = {
+        	defaultNum : 4,	//默认的文字数量
+		    checkNum : 3,	//校对的文字数量
+		    vSpace : 5,	//间隔
+        	imgName : ['1.jpg', '2.jpg'],
+        	imgSize : {
+	        	width: '400px',
+	        	height: '200px',
+	        },
+	        barSize : {
+	        	width : '400px',
+	        	height : '40px',
+	        },
+	        ready : function(){},
+        	success : function(){},
+            error : function(){}
+        },
+        this.options = $.extend({}, this.defaults, opt)
+    };
+
+    //定义Points的方法
+    Points.prototype = {
+    	init : function() {
+
+			var _this = this;
+
+			//加载页面
+        	_this.loadDom();
+
+        	_this.refresh();
+        	_this.options.ready();
+
+        	this.$element[0].onselectstart = document.body.ondrag = function(){
+				return false;
+			};
+
+		 	//点击事件比对
+        	_this.$element.find('.verify-img-panel canvas').on('click', function(e) {
+
+				_this.checkPosArr.push(_this.getMousePos(this, e));
+
+				if(_this.num == _this.options.checkNum) {
+
+					_this.num = _this.createPoint(_this.getMousePos(this, e));
+					setTimeout(function () {
+						var flag = _this.comparePos(_this.fontPos, _this.checkPosArr);
+
+						if(flag == false) {	//验证失败
+
+							_this.options.error();
+							_this.$element.find('.verify-bar-area').css({'color': '#d9534f', 'border-color': '#d9534f'});
+						    _this.$element.find('.verify-msg').text('验证失败');
+
+							setTimeout(function () {
+								_this.$element.find('.verify-bar-area').css({'color': '#000','border-color': '#ddd'});
+						    	_this.refresh();
+						    }, 400);
+
+						}else {	//验证成功
+							_this.$element.find('.verify-bar-area').css({'color': '#4cae4c', 'border-color': '#5cb85c'});
+							_this.$element.find('.verify-msg').text('验证成功');
+							_this.$element.find('.verify-refresh').hide();
+							_this.$element.find('.verify-img-panel').unbind('click');
+							_this.options.success();
+						}
+					}, 400);
+
+				}
+
+				if(_this.num < _this.options.checkNum) {
+					_this.num = _this.createPoint(_this.getMousePos(this, e));
+				}
+
+        	});
+
+        	 //刷新
+            _this.$element.find('.verify-refresh').on('click', function() {
+            	_this.refresh();
+            });
+
+    	},
+
+
+
+    	//加载页面
+    	loadDom : function() {
+
+    		this.fontPos = [];	//选中的坐标信息
+    		this.checkPosArr = [];	//用户点击的坐标
+    		this.num = 1;	//点击的记数
+    		this.img_rand = Math.floor(Math.random() * this.options.imgName.length);			//随机的背景图片
+
+        	var panelHtml = '';
+        	var tmpHtml = '';
+
+        	this.setSize = Slide.prototype.resetSize(this);	//重新设置宽度高度
+
+        	panelHtml += '<div class="verify-img-panel"><div  class="verify-refresh" style="z-index:9999"><i class="icon iconfont icon-shuaxin"></i></div><canvas width="'+this.setSize.img_width+'" height="'+this.setSize.img_height+'"></canvas></div><div class="verify-bar-area"><span  class="verify-msg"></span></div>';
+
+        	this.$element.append(panelHtml);
+
+
+        	this.htmlDoms = {
+        		img_panel : this.$element.find('.verify-img-panel'),
+        		bar_area : this.$element.find('.verify-bar-area'),
+        		msg : this.$element.find('.verify-msg'),
+        	};
+
+    		this.htmlDoms.img_panel.css({'width': this.setSize.img_width, 'height': this.setSize.img_height, 'background-size' : this.setSize.img_width + ' '+ this.setSize.img_height, 'margin-bottom': this.options.vSpace + 'px'});
+    		this.htmlDoms.bar_area.css({'width': this.options.barSize.width, 'height': this.options.barSize.height, 'line-height':this.options.barSize.height});
+
+    	},
+
+    	//绘制合成的图片
+    	drawImg : function(obj, img) {
+    		//准备canvas环境
+	       	var canvas = this.$element.find('canvas')[0];
+	      	//var canvas=document.getElementById("myCanvas");
+	       	var ctx=canvas.getContext("2d");
+
+	       	// 绘制图片
+	       	ctx.drawImage(img,0,0, parseInt(this.setSize.img_width), parseInt(this.setSize.img_height));
+
+	       	// 绘制水印
+	       	var fontSizeArr = ['italic small-caps bold 20px microsoft yahei', 'small-caps normal 25px arial', '34px microsoft yahei'];
+	       	var fontStr = '天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往秋收冬藏闰余成岁律吕调阳云腾致雨露结为霜金生丽水玉出昆冈剑号巨阙珠称夜光果珍李柰菜重芥姜海咸河淡鳞潜羽翔龙师火帝鸟官人皇始制文字乃服衣裳推位让国有虞陶唐吊民伐罪周发殷汤坐朝问道垂拱平章爱育黎首臣伏戎羌遐迩体率宾归王';	//不重复的汉字
+
+
+	       	var fontChars = [];
+
+	       	var avg = Math.floor(parseInt(this.setSize.img_width)/(parseInt(this.options.defaultNum)+1));
+	       	var tmp_index = '';
+	       	var color2Num = Math.floor(Math.random() * 5);
+
+	       	for(var i = 1; i <= this.options.defaultNum; i++) {
+
+	       		fontChars[i-1] = this.getChars(fontStr, fontChars);
+
+	       		tmp_index = Math.floor(Math.random()*3);
+	       		ctx.font = fontSizeArr[tmp_index];
+		       	ctx.fillStyle = _code_color2[color2Num];
+
+		       	if(Math.floor(Math.random() * 2) == 1) {
+		       		var tmp_y = Math.floor(parseInt(this.setSize.img_height)/2) + tmp_index*20 + 20;
+		       	}else {
+		       		var tmp_y = Math.floor(parseInt(this.setSize.img_height)/2) - tmp_index*20;
+		       	}
+
+		       	ctx.fillText(fontChars[i-1],avg * i, tmp_y);
+		       	this.fontPos[i-1] = {'char': fontChars[i-1], 'x': avg * i, 'y': tmp_y};
+
+	       	}
+
+	       	for(var i = 0; i < (this.options.defaultNum-this.options.checkNum); i++) {
+	       		this.shuffle(this.fontPos).pop();
+	       	}
+
+	       	var msgStr = '';
+	       	for(var i = 0; i < this.fontPos.length; i++) {
+	       		msgStr += this.fontPos[i].char + ',';
+	       	}
+
+	       	this.htmlDoms.msg.text('请顺序点击【' + msgStr.substring(0,msgStr.length-1) + '】');
+
+	       	return this.fontPos;
+    	},
+
+    	//获取坐标
+    	getMousePos :function(obj, event) {
+            var e = event || window.event;
+            var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
+            var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
+            var x = e.clientX - ($(obj).offset().left - $(window).scrollLeft());
+    		var y = e.clientY - ($(obj).offset().top - $(window).scrollTop());
+
+            return {'x': x, 'y': y};
+     	},
+
+     	//递归去重
+     	getChars : function(fontStr, fontChars) {
+
+     		var tmp_rand = parseInt(Math.floor(Math.random() * fontStr.length));
+     		if(tmp_rand > 0) {
+     			tmp_rand = tmp_rand - 1;
+     		}
+
+     		tmp_char = fontStr.charAt(tmp_rand);
+       		if($.inArray(tmp_char, fontChars) == -1) {
+       			return tmp_char;
+       		}else {
+       			return Points.prototype.getChars(fontStr, fontChars);
+       		}
+     	},
+
+		//洗牌数组
+       	shuffle : function(arr) {
+			var m = arr.length, i;
+			while (m) {
+				i = (Math.random() * m--) >>> 0;
+				[arr[m], arr[i]] = [arr[i], arr[m]]
+			}
+			return arr;
+		},
+
+       	//创建坐标点
+       	createPoint : function (pos) {
+       		this.htmlDoms.img_panel.append('<div class="point-area" style="background-color:#1abd6c;color:#fff;z-index:9999;width:30px;height:30px;text-align:center;line-height:30px;border-radius: 50%;position:absolute;top:'+parseInt(pos.y-10)+'px;left:'+parseInt(pos.x-10)+'px;">'+this.num+'</div>');
+       		return ++this.num;
+       	},
+
+       	//比对坐标点
+       	comparePos : function (fontPos, checkPosArr) {
+
+       		var flag = true;
+       		for(var i = 0; i < fontPos.length; i++) {
+       			if(!(parseInt(checkPosArr[i].x) + 40 > fontPos[i].x && parseInt(checkPosArr[i].x) - 40 < fontPos[i].x && parseInt(checkPosArr[i].y) + 40 > fontPos[i].y && parseInt(checkPosArr[i].y) - 40 < fontPos[i].y)) {
+       				flag = false;
+       				break;
+       			}
+       		}
+
+       		return flag;
+       	},
+
+       	//刷新
+        refresh: function() {
+        	var _this = this;
+        	this.$element.find('.point-area').remove();
+        	this.fontPos = [];
+        	this.checkPosArr = [];
+        	this.num = 1;
+
+        	this.img_rand = Math.floor(Math.random() * this.options.imgName.length);			//随机的背景图片
+        	var img = new Image();
+		    img.src = this.options.imgName[this.img_rand];
+
+
+		 	// 加载完成开始绘制
+		 	$(img).on('load', function(e) {
+        		this.fontPos = _this.drawImg(_this, this);
+        	});
+
+        },
+
+    };
+
+    //在插件中使用codeVerify对象
+    $.fn.codeVerify = function(options, callbacks) {
+        var code = new Code(this, options);
+        code.init();
+    };
+
+    //在插件中使用slideVerify对象
+    $.fn.slideVerify = function(options, callbacks) {
+        var slide = new Slide(this, options);
+        slide.init();
+    };
+
+    //在插件中使用clickVerify对象
+    $.fn.pointsVerify = function(options, callbacks) {
+        var points = new Points(this, options);
+        points.init();
+    };
+
+})(jQuery, window, document);

文件差異過大導致無法顯示
+ 321 - 0
public/verifys/yz.js


+ 39 - 0
src/App.vue

@@ -0,0 +1,39 @@
+<template>
+	<div id="app" class="">
+		<router-view></router-view>
+	</div>
+</template>
+
+<script>
+	export default {
+		name: 'app',
+		created() {
+			
+		}
+	}
+</script>
+
+<style>
+
+	* {
+		padding: 0;
+		margin: 0;
+		box-sizing: border-box;
+	}
+
+	html,
+	body {
+		width: 100%;
+		height: 100%;
+	}
+
+	#app {
+		height: 100%;
+	}
+
+	body {
+		padding: 0;
+		margin: 0;
+
+	}
+</style>

+ 13 - 0
src/assets/css/canvas-bg-1.css

@@ -0,0 +1,13 @@
+#canvas {
+	position: fixed;
+	top: 0;
+	left: 0;
+	width: 100%;
+	margin: 0;
+	overflow: hidden;
+	background: hsla(0, 5%, 5%, 1);
+	background-repeat: no-repeat;
+	background-attachment: fixed;
+	background-image: linear-gradient(to right top, hsla(0, 5%, 15%, 0.5), hsla(0, 5%, 5%, 1));
+	background-image: -moz-linear-gradient(to right top, hsla(0, 5%, 15%, 0.5), hsla(0, 5%, 5%, 1));
+}

+ 6 - 0
src/assets/css/canvas-bg-2.css

@@ -0,0 +1,6 @@
+#canvas {
+	background: rgba(0,0,0,1);
+	position: absolute;
+	left: 0;
+	top: 0;
+}

+ 5 - 0
src/assets/css/canvas-bg-3.css

@@ -0,0 +1,5 @@
+#canvas {
+    position: fixed;
+    left: 0;
+    top: 0;
+}

+ 5 - 0
src/assets/css/canvas-bg-4.css

@@ -0,0 +1,5 @@
+#canvas {
+    position: fixed;
+    left: 0;
+    top: 0;
+}

+ 5 - 0
src/assets/css/canvas-bg-5.css

@@ -0,0 +1,5 @@
+#canvas {
+    position: fixed;
+    left: 0;
+    top: 0;
+}

+ 9 - 0
src/assets/css/element-variables.scss

@@ -0,0 +1,9 @@
+/* 改变主题色变量 */
+$--color-primary: #00c292 !default;
+$--color-success: #67c23a !default;
+$--color-warning: #e6a23c !default;
+$--color-danger: #f56c6c !default;
+$--color-info: #909399 !default;
+/* 改变 icon 字体路径变量,必需 */
+$--font-path: '~element-ui/lib/theme-chalk/fonts';
+@import "~element-ui/packages/theme-chalk/src/index";

+ 47 - 0
src/assets/css/style.scss

@@ -0,0 +1,47 @@
+.form-content {
+background: #ffffff;
+padding: 10px 10px 0 10px;
+}
+.table-content {
+background: #ffffff;
+padding: 0 10px;
+}
+.pagination-content {
+margin-top: 10px;
+padding-bottom: 10px;
+text-align: right;
+}
+.detail-form-content{
+background: #ffffff;
+padding: 10px;
+.el-input{
+    min-width: 200px;
+    max-width: 600px;
+}
+}
+.bg {
+position: absolute;
+top: 0;
+left: 0;
+height: 100%;
+}
+.login-form {
+position: absolute;
+top: 0;
+right: 0;
+width: 350px;
+height: 100%;
+background: #ffffff;
+padding: 0 60px;
+font-size: 18px;
+font-weight: bold;
+}
+.h1 {
+margin-top: 80px;
+font-size: 20px;
+font-weight: bold;
+}
+.btn-login {
+margin-top: 50px;
+width: 100%;
+}

二進制
src/assets/img/32.png


二進制
src/assets/img/404.png


二進制
src/assets/img/64.png


二進制
src/assets/img/QRcode.png


二進制
src/assets/img/avator.png


二進制
src/assets/img/bg.jpg


二進制
src/assets/img/captcha.jpg


二進制
src/assets/img/jiahao.png


二進制
src/assets/img/login.png


二進制
src/assets/img/logo.png


二進制
src/assets/img/password.png


二進制
src/assets/img/role.png


二進制
src/assets/img/test/jianshe.png


二進制
src/assets/img/test/jiaotong.png


二進制
src/assets/img/test/nongye.png


二進制
src/assets/img/test/weixin.png


二進制
src/assets/img/test/zhifubao.png


二進制
src/assets/img/test/zhongguo.png


二進制
src/assets/img/username.png


+ 85 - 0
src/assets/js/canvas-bg-1.js

@@ -0,0 +1,85 @@
+export default function canvasBg(){
+	window.requestAnimFrame = (function() {
+		return window.requestAnimationFrame ||
+			window.webkitRequestAnimationFrame ||
+			window.mozRequestAnimationFrame ||
+			window.oRequestAnimationFrame ||
+			window.msRequestAnimationFrame ||
+			function(callback) {
+				window.setTimeout(callback, 1000 / 60);
+			};
+	})();
+	var c = document.getElementById('canvas');
+	var $ = c.getContext('2d');
+	var w = c.width = window.innerWidth;
+	var h = c.height = window.innerHeight;
+	var _w = w * 0.5;
+	var _h = h * 0.5;
+	var arr = [];
+	var cnt = 0;
+
+	window.addEventListener('load', resize);
+	window.addEventListener('resize', resize, false);
+
+	function resize() {
+		c.width = w = window.innerWidth;
+		c.height = h = window.innerHeight;
+		c.style.position = 'absolute';
+		c.style.left = (window.innerWidth - w) *
+			.01 + 'px';
+		c.style.top = (window.innerHeight - h) *
+			.01 + 'px';
+	}
+
+	function anim() {
+		cnt++;
+		if (cnt % 6) draw();
+		window.requestAnimFrame(anim);
+	}
+	anim();
+
+	function draw() {
+		var splot = {
+			x: rng(_w - 900, _w + 900),
+			y: rng(_h - 900, _h + 900),
+			r: rng(20, 80),
+			spX: rng(-1, 1),
+			spY: rng(-1, 1)
+		};
+
+		arr.push(splot);
+		while (arr.length > 100) {
+			arr.shift();
+		}
+		$.clearRect(0, 0, w, h);
+
+		for (var i = 0; i < arr.length; i++) {
+
+			splot = arr[i];;
+			$.fillStyle = rndCol();
+			$.beginPath();
+			$.arc(splot.x, splot.y, splot.r, 0, Math.PI * 2, true);
+			$.shadowBlur = 80;
+			$.shadowOffsetX = 2;
+			$.shadowOffsetY = 2;
+			$.shadowColor = rndCol();
+			$.globalCompositeOperation = 'lighter';
+			$.fill();
+
+			splot.x = splot.x + splot.spX;
+			splot.y = splot.y + splot.spY;
+			splot.r = splot.r * 0.96;
+		}
+	}
+
+	function rndCol() {
+		var r = Math.floor(Math.random() * 180);
+		var g = Math.floor(Math.random() * 60);
+		var b = Math.floor(Math.random() * 100);
+		return "rgb(" + r + "," + g + "," + b + ")";
+	}
+
+	function rng(min, max) {
+		return Math.floor(Math.random() * (max - min + 1)) + min;
+	}
+}

+ 191 - 0
src/assets/js/canvas-bg-2.js

@@ -0,0 +1,191 @@
+export default function canvasBg(){
+	var w = window.innerWidth;
+	var h = window.innerHeight;
+	var ctx = document.getElementById('canvas');
+	
+	window.addEventListener('load', resize);
+	window.addEventListener('resize', resize, false);
+	
+	function resize() {
+		ctx.width = w = window.innerWidth;
+		ctx.height = h = window.innerHeight;
+	}
+	
+	resize();
+	
+	let ctxfr = ctx.getContext('2d');
+	
+	// min and max radius, radius threshold and percentage of filled circles
+	var radMin = 5,
+		radMax = 125,
+		filledCircle = 60, //percentage of filled circles
+		concentricCircle = 30, //percentage of concentric circles
+		radThreshold = 25; //IFF special, over this radius concentric, otherwise filled
+	
+	//min and max speed to move
+	var speedMin = 0.3,
+		speedMax = 2.5;
+	
+	//max reachable opacity for every circle and blur effect
+	var maxOpacity = 0.6;
+	
+	//default palette choice
+	var colors = ['52,168,83', '117,95,147', '199,108,23', '194,62,55', '0,172,212', '120,120,120'],
+		bgColors = ['52,168,83', '117,95,147', '199,108,23', '194,62,55', '0,172,212', '120,120,120'],
+		circleBorder = 10,
+		backgroundLine = bgColors[0];
+	var backgroundMlt = 0.85;
+	
+	//min distance for links
+	var linkDist = Math.min(canvas.width, canvas.height) / 2.4,
+		lineBorder = 2.5;
+	
+	//most importantly: number of overall circles and arrays containing them
+	var maxCircles = 12,
+		points = [],
+		pointsBack = [];
+	
+	//populating the screen
+	for (var i = 0; i < maxCircles * 2; i++) points.push(new Circle());
+	for (var i = 0; i < maxCircles; i++) pointsBack.push(new Circle(true));
+	
+	//experimental vars
+	var circleExp = 1,
+		circleExpMax = 1.003,
+		circleExpMin = 0.997,
+		circleExpSp = 0.00004,
+		circlePulse = false;
+	
+	//circle class
+	function Circle(background) {
+		//if background, it has different rules
+		this.background = (background || false);
+		this.x = randRange(-canvas.width / 2, canvas.width / 2);
+		this.y = randRange(-canvas.height / 2, canvas.height / 2);
+		this.radius = background ? hyperRange(radMin, radMax) * backgroundMlt : hyperRange(radMin, radMax);
+		this.filled = this.radius < radThreshold ? (randint(0, 100) > filledCircle ? false : 'full') : (randint(0, 100) >
+			concentricCircle ? false : 'concentric');
+		this.color = background ? bgColors[randint(0, bgColors.length - 1)] : colors[randint(0, colors.length - 1)];
+		this.borderColor = background ? bgColors[randint(0, bgColors.length - 1)] : colors[randint(0, colors.length - 1)];
+		this.opacity = 0.05;
+		this.speed = (background ? randRange(speedMin, speedMax) / backgroundMlt : randRange(speedMin, speedMax)); // * (radMin / this.radius);
+		this.speedAngle = Math.random() * 2 * Math.PI;
+		this.speedx = Math.cos(this.speedAngle) * this.speed;
+		this.speedy = Math.sin(this.speedAngle) * this.speed;
+		var spacex = Math.abs((this.x - (this.speedx < 0 ? -1 : 1) * (canvas.width / 2 + this.radius)) / this.speedx),
+			spacey = Math.abs((this.y - (this.speedy < 0 ? -1 : 1) * (canvas.height / 2 + this.radius)) / this.speedy);
+		this.ttl = Math.min(spacex, spacey);
+	};
+	
+	Circle.prototype.init = function() {
+		Circle.call(this, this.background);
+	}
+	
+	//support functions
+	//generate random int a<=x<=b
+	function randint(a, b) {
+		return Math.floor(Math.random() * (b - a + 1) + a);
+	}
+	//generate random float
+	function randRange(a, b) {
+		return Math.random() * (b - a) + a;
+	}
+	//generate random float more likely to be close to a
+	function hyperRange(a, b) {
+		return Math.random() * Math.random() * Math.random() * (b - a) + a;
+	}
+	
+	//rendering function
+	function drawCircle(ctx, circle) {
+		//circle.radius *= circleExp;
+		var radius = circle.background ? circle.radius *= circleExp : circle.radius /= circleExp;
+		ctx.beginPath();
+		ctx.arc(circle.x, circle.y, radius * circleExp, 0, 2 * Math.PI, false);
+		ctx.lineWidth = Math.max(1, circleBorder * (radMin - circle.radius) / (radMin - radMax));
+		ctx.strokeStyle = ['rgba(', circle.borderColor, ',', circle.opacity, ')'].join('');
+		if (circle.filled == 'full') {
+			ctx.fillStyle = ['rgba(', circle.borderColor, ',', circle.background ? circle.opacity * 0.8 : circle.opacity, ')']
+				.join('');
+			ctx.fill();
+			ctx.lineWidth = 0;
+			ctx.strokeStyle = ['rgba(', circle.borderColor, ',', 0, ')'].join('');
+		}
+		ctx.stroke();
+		if (circle.filled == 'concentric') {
+			ctx.beginPath();
+			ctx.arc(circle.x, circle.y, radius / 2, 0, 2 * Math.PI, false);
+			ctx.lineWidth = Math.max(1, circleBorder * (radMin - circle.radius) / (radMin - radMax));
+			ctx.strokeStyle = ['rgba(', circle.color, ',', circle.opacity, ')'].join('');
+			ctx.stroke();
+		}
+		circle.x += circle.speedx;
+		circle.y += circle.speedy;
+		if (circle.opacity < (circle.background ? maxOpacity : 1)) circle.opacity += 0.01;
+		circle.ttl--;
+	}
+	
+	//initializing function
+	function init() {
+		window.requestAnimationFrame(draw);
+	}
+	
+	//rendering function
+	function draw() {
+	
+		if (circlePulse) {
+			if (circleExp < circleExpMin || circleExp > circleExpMax) circleExpSp *= -1;
+			circleExp += circleExpSp;
+		}
+	
+		ctxfr.globalCompositeOperation = 'destination-over';
+		ctxfr.clearRect(0, 0, canvas.width, canvas.height); // clear canvas
+	
+		ctxfr.save();
+		ctxfr.translate(canvas.width / 2, canvas.height / 2);
+	
+		//function to render each single circle, its connections and to manage its out of boundaries replacement
+		function renderPoints(ctx, arr) {
+			for (var i = 0; i < arr.length; i++) {
+				var circle = arr[i];
+				//checking if out of boundaries
+				if (circle.ttl < 0) {}
+				var xEscape = canvas.width / 2 + circle.radius,
+					yEscape = canvas.height / 2 + circle.radius;
+				if (circle.ttl < -20) arr[i].init(arr[i].background);
+				//if (Math.abs(circle.y) > yEscape || Math.abs(circle.x) > xEscape) arr[i].init(arr[i].background);
+				drawCircle(ctx, circle);
+			}
+			for (var i = 0; i < arr.length - 1; i++) {
+				for (var j = i + 1; j < arr.length; j++) {
+					var deltax = arr[i].x - arr[j].x;
+					var deltay = arr[i].y - arr[j].y;
+					var dist = Math.pow(Math.pow(deltax, 2) + Math.pow(deltay, 2), 0.5);
+					//if the circles are overlapping, no laser connecting them
+					if (dist <= arr[i].radius + arr[j].radius) continue;
+					//otherwise we connect them only if the dist is < linkDist
+					if (dist < linkDist) {
+						var xi = (arr[i].x < arr[j].x ? 1 : -1) * Math.abs(arr[i].radius * deltax / dist);
+						var yi = (arr[i].y < arr[j].y ? 1 : -1) * Math.abs(arr[i].radius * deltay / dist);
+						var xj = (arr[i].x < arr[j].x ? -1 : 1) * Math.abs(arr[j].radius * deltax / dist);
+						var yj = (arr[i].y < arr[j].y ? -1 : 1) * Math.abs(arr[j].radius * deltay / dist);
+						ctx.beginPath();
+						ctx.moveTo(arr[i].x + xi, arr[i].y + yi);
+						ctx.lineTo(arr[j].x + xj, arr[j].y + yj);
+						var samecolor = arr[i].color == arr[j].color;
+						ctx.strokeStyle = ["rgba(", arr[i].borderColor, ",", Math.min(arr[i].opacity, arr[j].opacity) * ((linkDist -
+							dist) / linkDist), ")"].join("");
+						ctx.lineWidth = (arr[i].background ? lineBorder * backgroundMlt : lineBorder) * ((linkDist - dist) / linkDist); //*((linkDist-dist)/linkDist);
+						ctx.stroke();
+					}
+				}
+			}
+		}
+	
+		renderPoints(ctxfr, points);
+		ctxfr.restore();
+	
+		window.requestAnimationFrame(draw);
+	}
+	
+	init();
+}

+ 175 - 0
src/assets/js/canvas-bg-3.js

@@ -0,0 +1,175 @@
+export default function canvasBg() {
+    var canvas,
+        ctx,
+        width,
+        height,
+        size,
+        lines,
+        tick;
+
+    function line() {
+        this.path = [];
+        this.speed = rand(10, 20);
+        this.count = randInt(10, 30);
+        this.x = width / 2, +1;
+        this.y = height / 2 + 1;
+        this.target = {
+            x: width / 2,
+            y: height / 2
+        };
+        this.dist = 0;
+        this.angle = 0;
+        this.hue = tick / 5;
+        this.life = 1;
+        this.updateAngle();
+        this.updateDist();
+    }
+
+    line.prototype.step = function(i) {
+        this.x += Math.cos(this.angle) * this.speed;
+        this.y += Math.sin(this.angle) * this.speed;
+
+        this.updateDist();
+
+        if (this.dist < this.speed) {
+            this.x = this.target.x;
+            this.y = this.target.y;
+            this.changeTarget();
+        }
+
+        this.path.push({
+            x: this.x,
+            y: this.y
+        });
+        if (this.path.length > this.count) {
+            this.path.shift();
+        }
+
+        this.life -= 0.001;
+
+        if (this.life <= 0) {
+            this.path = null;
+            lines.splice(i, 1);
+        }
+    };
+
+    line.prototype.updateDist = function() {
+        var dx = this.target.x - this.x,
+            dy = this.target.y - this.y;
+        this.dist = Math.sqrt(dx * dx + dy * dy);
+    }
+
+    line.prototype.updateAngle = function() {
+        var dx = this.target.x - this.x,
+            dy = this.target.y - this.y;
+        this.angle = Math.atan2(dy, dx);
+    }
+
+    line.prototype.changeTarget = function() {
+        var randStart = randInt(0, 3);
+        switch (randStart) {
+            case 0: // up
+                this.target.y = this.y - size;
+                break;
+            case 1: // right
+                this.target.x = this.x + size;
+                break;
+            case 2: // down
+                this.target.y = this.y + size;
+                break;
+            case 3: // left
+                this.target.x = this.x - size;
+        }
+        this.updateAngle();
+    };
+
+    line.prototype.draw = function(i) {
+        ctx.beginPath();
+        var rando = rand(0, 10);
+        for (var j = 0, length = this.path.length; j < length; j++) {
+            ctx[(j === 0) ? 'moveTo' : 'lineTo'](this.path[j].x + rand(-rando, rando), this.path[j].y +
+                rand(-rando, rando));
+        }
+        ctx.strokeStyle = 'hsla(' + rand(this.hue, this.hue + 30) + ', 80%, 55%, ' + (this.life / 3) + ')';
+        ctx.lineWidth = rand(0.1, 2);
+        ctx.stroke();
+    };
+
+    function rand(min, max) {
+        return Math.random() * (max - min) + min;
+    }
+
+    function randInt(min, max) {
+        return Math.floor(min + Math.random() * (max - min + 1));
+    };
+
+    function init() {
+        canvas = document.getElementById('canvas');
+        ctx = canvas.getContext('2d');
+        size = 30;
+        lines = [];
+        reset();
+        loop();
+    }
+
+    function reset() {
+        width = Math.ceil(window.innerWidth / 2) * 2;
+        height = Math.ceil(window.innerHeight / 2) * 2;
+        tick = 0;
+
+        lines.length = 0;
+        canvas.width = width;
+        canvas.height = height;
+    }
+
+    function create() {
+        if (tick % 10 === 0) {
+            lines.push(new line());
+        }
+    }
+
+    function step() {
+        var i = lines.length;
+        while (i--) {
+            lines[i].step(i);
+        }
+    }
+
+    function clear() {
+        ctx.globalCompositeOperation = 'destination-out';
+        ctx.fillStyle = 'hsla(0, 0%, 0%, 0.1)';
+        ctx.fillRect(0, 0, width, height);
+        ctx.globalCompositeOperation = 'lighter';
+    }
+
+    function draw() {
+        ctx.save();
+        ctx.translate(width / 2, height / 2);
+        ctx.rotate(tick * 0.001);
+        var scale = 0.8 + Math.cos(tick * 0.02) * 0.2;
+        ctx.scale(scale, scale);
+        ctx.translate(-width / 2, -height / 2);
+        var i = lines.length;
+        while (i--) {
+            lines[i].draw(i);
+        }
+        ctx.restore();
+    }
+
+    function loop() {
+        requestAnimationFrame(loop);
+        create();
+        step();
+        clear();
+        draw();
+        tick++;
+    }
+
+    function onresize() {
+        reset();
+    }
+
+    window.addEventListener('resize', onresize);
+
+    init();
+}

+ 335 - 0
src/assets/js/canvas-bg-4.js

@@ -0,0 +1,335 @@
+export default function canvasBg() {
+    var num = 200;
+    var w = window.innerWidth;
+    var h = window.innerHeight;
+    var max = 100;
+    var _x = 0;
+    var _y = 0;
+    var _z = 150;
+    var dtr = function(d) {
+        return d * Math.PI / 180;
+    };
+    var canvas = document.getElementById("canvas");
+
+    var rnd = function() {
+        return Math.sin(Math.floor(Math.random() * 360) * Math.PI / 180);
+    };
+    var dist = function(p1, p2, p3) {
+        return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2) + Math.pow(p2.z - p1.z, 2));
+    };
+
+    var cam = {
+        obj: {
+            x: _x,
+            y: _y,
+            z: _z
+        },
+        dest: {
+            x: 0,
+            y: 0,
+            z: 1
+        },
+        dist: {
+            x: 0,
+            y: 0,
+            z: 200
+        },
+        ang: {
+            cplane: 0,
+            splane: 0,
+            ctheta: 0,
+            stheta: 0
+        },
+        zoom: 1,
+        disp: {
+            x: w / 2,
+            y: h / 2,
+            z: 0
+        },
+        upd: function() {
+            cam.dist.x = cam.dest.x - cam.obj.x;
+            cam.dist.y = cam.dest.y - cam.obj.y;
+            cam.dist.z = cam.dest.z - cam.obj.z;
+            cam.ang.cplane = -cam.dist.z / Math.sqrt(cam.dist.x * cam.dist.x + cam.dist.z * cam.dist.z);
+            cam.ang.splane = cam.dist.x / Math.sqrt(cam.dist.x * cam.dist.x + cam.dist.z * cam.dist.z);
+            cam.ang.ctheta = Math.sqrt(cam.dist.x * cam.dist.x + cam.dist.z * cam.dist.z) / Math.sqrt(cam.dist.x *
+                cam.dist.x + cam.dist.y * cam.dist.y + cam.dist.z * cam.dist.z);
+            cam.ang.stheta = -cam.dist.y / Math.sqrt(cam.dist.x * cam.dist.x + cam.dist.y * cam.dist.y + cam.dist
+                .z * cam.dist.z);
+        }
+    };
+
+    var trans = {
+        parts: {
+            sz: function(p, sz) {
+                return {
+                    x: p.x * sz.x,
+                    y: p.y * sz.y,
+                    z: p.z * sz.z
+                };
+            },
+            rot: {
+                x: function(p, rot) {
+                    return {
+                        x: p.x,
+                        y: p.y * Math.cos(dtr(rot.x)) - p.z * Math.sin(dtr(rot.x)),
+                        z: p.y * Math.sin(dtr(rot.x)) + p.z * Math.cos(dtr(rot.x))
+                    };
+                },
+                y: function(p, rot) {
+                    return {
+                        x: p.x * Math.cos(dtr(rot.y)) + p.z * Math.sin(dtr(rot.y)),
+                        y: p.y,
+                        z: -p.x * Math.sin(dtr(rot.y)) + p.z * Math.cos(dtr(rot.y))
+                    };
+                },
+                z: function(p, rot) {
+                    return {
+                        x: p.x * Math.cos(dtr(rot.z)) - p.y * Math.sin(dtr(rot.z)),
+                        y: p.x * Math.sin(dtr(rot.z)) + p.y * Math.cos(dtr(rot.z)),
+                        z: p.z
+                    };
+                }
+            },
+            pos: function(p, pos) {
+                return {
+                    x: p.x + pos.x,
+                    y: p.y + pos.y,
+                    z: p.z + pos.z
+                };
+            }
+        },
+        pov: {
+            plane: function(p) {
+                return {
+                    x: p.x * cam.ang.cplane + p.z * cam.ang.splane,
+                    y: p.y,
+                    z: p.x * -cam.ang.splane + p.z * cam.ang.cplane
+                };
+            },
+            theta: function(p) {
+                return {
+                    x: p.x,
+                    y: p.y * cam.ang.ctheta - p.z * cam.ang.stheta,
+                    z: p.y * cam.ang.stheta + p.z * cam.ang.ctheta
+                };
+            },
+            set: function(p) {
+                return {
+                    x: p.x - cam.obj.x,
+                    y: p.y - cam.obj.y,
+                    z: p.z - cam.obj.z
+                };
+            }
+        },
+        persp: function(p) {
+            return {
+                x: p.x * cam.dist.z / p.z * cam.zoom,
+                y: p.y * cam.dist.z / p.z * cam.zoom,
+                z: p.z * cam.zoom,
+                p: cam.dist.z / p.z
+            };
+        },
+        disp: function(p, disp) {
+            return {
+                x: p.x + disp.x,
+                y: -p.y + disp.y,
+                z: p.z + disp.z,
+                p: p.p
+            };
+        },
+        steps: function(_obj_, sz, rot, pos, disp) {
+            var _args = trans.parts.sz(_obj_, sz);
+            _args = trans.parts.rot.x(_args, rot);
+            _args = trans.parts.rot.y(_args, rot);
+            _args = trans.parts.rot.z(_args, rot);
+            _args = trans.parts.pos(_args, pos);
+            _args = trans.pov.plane(_args);
+            _args = trans.pov.theta(_args);
+            _args = trans.pov.set(_args);
+            _args = trans.persp(_args);
+            _args = trans.disp(_args, disp);
+            return _args;
+        }
+    };
+
+    var threeD = function(param) {
+        this.transIn = {};
+        this.transOut = {};
+        this.transIn.vtx = (param.vtx);
+        this.transIn.sz = (param.sz);
+        this.transIn.rot = (param.rot);
+        this.transIn.pos = (param.pos);
+    };
+
+    threeD.prototype.vupd = function() {
+        this.transOut = trans.steps(
+
+            this.transIn.vtx,
+            this.transIn.sz,
+            this.transIn.rot,
+            this.transIn.pos,
+            cam.disp
+        );
+    };
+
+    var Build = function() {
+        this.vel = 0.04;
+        this.lim = 360;
+        this.diff = 200;
+        this.initPos = 100;
+        this.toX = _x;
+        this.toY = _y;
+        this.canvas = canvas;
+        this.go();
+    };
+
+    Build.prototype.go = function() {
+        this.canvas.width = window.innerWidth;
+        this.canvas.height = window.innerHeight;
+        this.$ = this.canvas.getContext("2d");
+        this.$.globalCompositeOperation = 'source-over';
+        this.varr = [];
+        this.dist = [];
+        this.calc = [];
+
+        for (var i = 0, len = num; i < len; i++) {
+            this.add();
+        }
+
+        this.rotObj = {
+            x: 0,
+            y: 0,
+            z: 0
+        };
+        this.objSz = {
+            x: w / 5,
+            y: h / 5,
+            z: w / 5
+        };
+    };
+
+    Build.prototype.add = function() {
+        this.varr.push(new threeD({
+            vtx: {
+                x: rnd(),
+                y: rnd(),
+                z: rnd()
+            },
+            sz: {
+                x: 0,
+                y: 0,
+                z: 0
+            },
+            rot: {
+                x: 20,
+                y: -20,
+                z: 0
+            },
+            pos: {
+                x: this.diff * Math.sin(360 * Math.random() * Math.PI / 180),
+                y: this.diff * Math.sin(360 * Math.random() * Math.PI / 180),
+                z: this.diff * Math.sin(360 * Math.random() * Math.PI / 180)
+            }
+        }));
+        this.calc.push({
+            x: 360 * Math.random(),
+            y: 360 * Math.random(),
+            z: 360 * Math.random()
+        });
+    };
+
+    Build.prototype.upd = function() {
+        cam.obj.x += (this.toX - cam.obj.x) * 0.05;
+        cam.obj.y += (this.toY - cam.obj.y) * 0.05;
+    };
+
+    Build.prototype.draw = function() {
+        this.$.clearRect(0, 0, this.canvas.width, this.canvas.height);
+        cam.upd();
+        this.rotObj.x += 0.1;
+        this.rotObj.y += 0.1;
+        this.rotObj.z += 0.1;
+
+        for (var i = 0; i < this.varr.length; i++) {
+            for (var val in this.calc[i]) {
+                if (this.calc[i].hasOwnProperty(val)) {
+                    this.calc[i][val] += this.vel;
+                    if (this.calc[i][val] > this.lim) this.calc[i][val] = 0;
+                }
+            }
+
+            this.varr[i].transIn.pos = {
+                x: this.diff * Math.cos(this.calc[i].x * Math.PI / 180),
+                y: this.diff * Math.sin(this.calc[i].y * Math.PI / 180),
+                z: this.diff * Math.sin(this.calc[i].z * Math.PI / 180)
+            };
+            this.varr[i].transIn.rot = this.rotObj;
+            this.varr[i].transIn.sz = this.objSz;
+            this.varr[i].vupd();
+            if (this.varr[i].transOut.p < 0) continue;
+            var g = this.$.createRadialGradient(this.varr[i].transOut.x, this.varr[i].transOut.y, this.varr[i]
+                .transOut.p, this.varr[i].transOut.x, this.varr[i].transOut.y, this.varr[i].transOut.p * 2);
+            this.$.globalCompositeOperation = 'lighter';
+            g.addColorStop(0, 'hsla(255, 255%, 255%, 1)');
+            g.addColorStop(.6, 'hsla(' + (i + 2) + ',85%, 40%,1)');
+            g.addColorStop(1, 'hsla(' + (i) + ',85%, 40%,.5)');
+            // console.log(this.varr[i].transOut.x, this.varr[i].transOut.y, this.varr[i].transOut.p * 2, 0, Math.PI * 2, false)
+            this.$.fillStyle = g;
+            this.$.beginPath();
+            this.$.arc(this.varr[i].transOut.x, this.varr[i].transOut.y, this.varr[i].transOut.p * 2, 0, Math
+                .PI * 2, false);
+            this.$.fill();
+            this.$.closePath();
+        }
+    };
+    Build.prototype.anim = function() {
+        window.requestAnimationFrame = (function() {
+            return window.requestAnimationFrame ||
+                function(callback, element) {
+                    window.setTimeout(callback, 1000 / 60);
+                };
+        })();
+        var anim = function() {
+            this.upd();
+            this.draw();
+            window.requestAnimationFrame(anim);
+        }.bind(this);
+        window.requestAnimationFrame(anim);
+    };
+
+    Build.prototype.run = function() {
+        this.anim();
+
+        window.addEventListener('mousemove', function(e) {
+            this.toX = (e.clientX - this.canvas.width / 2) * -0.8;
+            this.toY = (e.clientY - this.canvas.height / 2) * 0.8;
+        }.bind(this));
+        window.addEventListener('touchmove', function(e) {
+            e.preventDefault();
+            this.toX = (e.touches[0].clientX - this.canvas.width / 2) * -0.8;
+            this.toY = (e.touches[0].clientY - this.canvas.height / 2) * 0.8;
+        }.bind(this));
+        window.addEventListener('mousedown', function(e) {
+            for (var i = 0; i < 100; i++) {
+                this.add();
+            }
+        }.bind(this));
+        window.addEventListener('touchstart', function(e) {
+            e.preventDefault();
+            for (var i = 0; i < 100; i++) {
+                this.add();
+            }
+        }.bind(this));
+    };
+
+    var app = new Build();
+    app.run();
+
+    window.addEventListener('resize', function() {
+        // canvas.width = w = window.innerWidth;
+        // canvas.height = h = window.innerHeight;
+        var app = new Build();
+        app.run();
+    });
+}

+ 154 - 0
src/assets/js/canvas-bg-5.js

@@ -0,0 +1,154 @@
+export default function canvasBg() {
+    var canvas = document.getElementById('canvas'),
+            ctx = canvas.getContext('2d')
+        canvas.width = window.innerWidth;
+        canvas.height = window.innerHeight;
+        ctx.lineWidth = .3;
+        ctx.strokeStyle = (new Color(150)).style;
+
+        var mousePosition = {
+            x: 30 * canvas.width / 100,
+            y: 30 * canvas.height / 100
+        };
+
+        var dots = {
+            nb: 750,
+            distance: 50,
+            d_radius: 100,
+            array: []
+        };
+
+        function colorValue(min) {
+            return Math.floor(Math.random() * 255 + min);
+        }
+
+        function createColorStyle(r, g, b) {
+            return 'rgba(' + r + ',' + g + ',' + b + ', 0.8)';
+        }
+
+        function mixComponents(comp1, weight1, comp2, weight2) {
+            return (comp1 * weight1 + comp2 * weight2) / (weight1 + weight2);
+        }
+
+        function averageColorStyles(dot1, dot2) {
+            var color1 = dot1.color,
+                color2 = dot2.color;
+
+            var r = mixComponents(color1.r, dot1.radius, color2.r, dot2.radius),
+                g = mixComponents(color1.g, dot1.radius, color2.g, dot2.radius),
+                b = mixComponents(color1.b, dot1.radius, color2.b, dot2.radius);
+            return createColorStyle(Math.floor(r), Math.floor(g), Math.floor(b));
+        }
+
+        function Color(min) {
+            min = min || 0;
+            this.r = colorValue(min);
+            this.g = colorValue(min);
+            this.b = colorValue(min);
+            this.style = createColorStyle(this.r, this.g, this.b);
+        }
+
+        function Dot() {
+            this.x = Math.random() * canvas.width;
+            this.y = Math.random() * canvas.height;
+
+            this.vx = -.5 + Math.random();
+            this.vy = -.5 + Math.random();
+
+            this.radius = Math.random() * 2;
+
+            this.color = new Color();
+            // console.log(this);
+        }
+
+        Dot.prototype = {
+            draw: function() {
+                ctx.beginPath();
+                ctx.fillStyle = this.color.style;
+                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
+                ctx.fill();
+            }
+        };
+
+        function createDots() {
+            for (i = 0; i < dots.nb; i++) {
+                dots.array.push(new Dot());
+            }
+        }
+
+        function moveDots() {
+            for (i = 0; i < dots.nb; i++) {
+
+                var dot = dots.array[i];
+
+                if (dot.y < 0 || dot.y > canvas.height) {
+                    dot.vx = dot.vx;
+                    dot.vy = -dot.vy;
+                } else if (dot.x < 0 || dot.x > canvas.width) {
+                    dot.vx = -dot.vx;
+                    dot.vy = dot.vy;
+                }
+                dot.x += dot.vx;
+                dot.y += dot.vy;
+            }
+        }
+
+        function connectDots() {
+            for (i = 0; i < dots.nb; i++) {
+                for (j = 0; j < dots.nb; j++) {
+                    i_dot = dots.array[i];
+                    j_dot = dots.array[j];
+
+                    if ((i_dot.x - j_dot.x) < dots.distance && (i_dot.y - j_dot.y) < dots.distance && (i_dot.x -
+                            j_dot.x) > -dots.distance && (i_dot.y - j_dot.y) > -dots.distance) {
+                        if ((i_dot.x - mousePosition.x) < dots.d_radius && (i_dot.y - mousePosition.y) < dots
+                            .d_radius && (i_dot.x - mousePosition.x) > -dots.d_radius && (i_dot.y - mousePosition
+                                .y) > -dots.d_radius) {
+                            ctx.beginPath();
+                            ctx.strokeStyle = averageColorStyles(i_dot, j_dot);
+                            ctx.moveTo(i_dot.x, i_dot.y);
+                            ctx.lineTo(j_dot.x, j_dot.y);
+                            ctx.stroke();
+                            ctx.closePath();
+                        }
+                    }
+                }
+            }
+        }
+
+        function drawDots() {
+            for (i = 0; i < dots.nb; i++) {
+                var dot = dots.array[i];
+                dot.draw();
+            }
+        }
+
+        function animateDots() {
+            ctx.clearRect(0, 0, canvas.width, canvas.height);
+            moveDots();
+            connectDots();
+            drawDots();
+
+            requestAnimationFrame(animateDots);
+        }
+        
+        canvas.addEventListener('mousemove', function(e) {
+            mousePosition.x = e.pageX;
+            mousePosition.y = e.pageY;
+        })
+        // canvas.on('mousemove', function(e) {
+        //     mousePosition.x = e.pageX;
+        //     mousePosition.y = e.pageY;
+        // });
+        canvas.addEventListener('mouseleave', function(e) {
+            mousePosition.x = canvas.width / 2;
+            mousePosition.y = canvas.height / 2;
+        })
+        // canvas.on('mouseleave', function(e) {
+        //     mousePosition.x = canvas.width / 2;
+        //     mousePosition.y = canvas.height / 2;
+        // });
+
+        createDots();
+        requestAnimationFrame(animateDots);
+}

+ 43 - 0
src/components/SvgIcon/index.vue

@@ -0,0 +1,43 @@
+<template>
+  <svg :class="svgClass" aria-hidden="true" v-on="$listeners">
+    <use :xlink:href="iconName" />
+  </svg>
+</template>
+
+<script>
+export default {
+  name: 'SvgIcon',
+  props: {
+    iconClass: {
+      type: String,
+      required: true
+    },
+    className: {
+      type: String,
+      default: ''
+    }
+  },
+  computed: {
+    iconName() {
+      return `#icon-${this.iconClass}`
+    },
+    svgClass() {
+      if (this.className) {
+        return 'svg-icon ' + this.className
+      } else {
+        return 'svg-icon'
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>

+ 91 - 0
src/components/common/BreadCrumbs.vue

@@ -0,0 +1,91 @@
+<template>
+	<div class="breadcrumb-preview">
+		<el-breadcrumb :style='{"fontSize":"inherit","lineHeight":"1"}' separator="●">
+			<transition-group name="breadcrumb" class="box">
+				<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
+					<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.name }}</span>
+					<a v-else @click.prevent="handleLink(item)">
+						<span class="icon iconfont icon-home19" :style='{"margin":"0 2px","lineHeight":"1","fontSize":"inherit","color":"inherit","display":"none"}'></span>首页
+					</a>
+				</el-breadcrumb-item>
+			</transition-group>
+		</el-breadcrumb>
+	</div>
+</template>
+
+<script>
+import pathToRegexp from 'path-to-regexp'
+import { generateTitle } from '@/utils/i18n'
+export default {
+  data() {
+    return {
+      levelList: null
+    }
+  },
+  watch: {
+    $route() {
+      this.getBreadcrumb()
+    }
+  },
+  created() {
+    this.getBreadcrumb()
+  },
+  methods: {
+    generateTitle,
+    getBreadcrumb() {
+      // only show routes with meta.title
+      let route = this.$route
+      let matched = route.matched.filter(item => item.meta)
+      const first = matched[0]
+      matched = [{ path: '/index' }].concat(matched)
+
+      this.levelList = matched.filter(item => item.meta)
+    },
+    isDashboard(route) {
+      const name = route && route.name
+      if (!name) {
+        return false
+      }
+      return name.trim().toLocaleLowerCase() === 'Index'.toLocaleLowerCase()
+    },
+    pathCompile(path) {
+      // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
+      const { params } = this.$route
+      var toPath = pathToRegexp.compile(path)
+      return toPath(params)
+    },
+    handleLink(item) {
+      const { redirect, path } = item
+      if (redirect) {
+        this.$router.push(redirect)
+        return
+      }
+      if(path){
+      		  this.$router.push(path)
+      }else{
+      		  this.$router.push('/')
+      }
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+	.el-breadcrumb {
+		& /deep/ .el-breadcrumb__separator {
+		  		  margin: 0 15px;
+		  		  color: #333;
+		  		  font-weight: 500;
+		  		}
+		
+		& /deep/ .el-breadcrumb__inner a {
+		  		  color: #000;
+		  		  display: inline-block;
+		  		}
+		
+		& /deep/ .el-breadcrumb__inner {
+		  		  color: #0977fd;
+		  		  display: inline-block;
+		  		}
+	}
+</style>

+ 267 - 0
src/components/common/Editor.vue

@@ -0,0 +1,267 @@
+<template>
+	<div>
+		<!-- 图片上传组件辅助-->
+		<el-upload :class="refname + 'upload'" :action="getActionUrl" name="file" :headers="header" :show-file-list="false"
+			:on-success="uploadSuccess" :on-error="uploadError" :before-upload="beforeUpload"></el-upload>
+
+		<quill-editor class="editor" v-model="value" :ref="myQuillEditor" :options="editorOption"
+			@blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @change="onEditorChange($event)"></quill-editor>
+	</div>
+</template>
+<script>
+	// 工具栏配置
+	const toolbarOptions = [
+		["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
+		["blockquote", "code-block"], // 引用  代码块
+		[{
+			header: 1
+		}, {
+			header: 2
+		}], // 1、2 级标题
+		[{
+			list: "ordered"
+		}, {
+			list: "bullet"
+		}], // 有序、无序列表
+		[{
+			script: "sub"
+		}, {
+			script: "super"
+		}], // 上标/下标
+		[{
+			indent: "-1"
+		}, {
+			indent: "+1"
+		}], // 缩进
+		// [{'direction': 'rtl'}],                         // 文本方向
+		[{
+			size: ["small", false, "large", "huge"]
+		}], // 字体大小
+		[{
+			header: [1, 2, 3, 4, 5, 6, false]
+		}], // 标题
+		[{
+			color: []
+		}, {
+			background: []
+		}], // 字体颜色、字体背景颜色
+		[{
+			font: []
+		}], // 字体种类
+		[{
+			align: []
+		}], // 对齐方式
+		["clean"], // 清除文本格式
+		["link", "image", "video"], // 链接、图片、视频
+	];
+	var _EditorOption_ = function(page_this) {
+		return {
+			modules: {
+				toolbar: {
+					container: toolbarOptions,
+					handlers: {
+						image(value) {
+							if (value) {
+								console.log(document.querySelector("." + page_this.refname + "upload input"))
+								// 触发input框选择图片文件
+								document.querySelector("." + page_this.refname + "upload input").click();
+							} else {
+								this.quill.format("image", false);
+							}
+						}
+					},
+				},
+			},
+			placeholder: "请输入正文",
+		};
+	};
+
+	import {
+		quillEditor
+	} from "vue-quill-editor";
+	import "quill/dist/quill.core.css";
+	import "quill/dist/quill.snow.css";
+	import "quill/dist/quill.bubble.css";
+
+	export default {
+		props: {
+			/*编辑器的内容*/
+			value: {
+				type: String
+			},
+			action: {
+				type: String
+			},
+			/*图片大小*/
+			maxSize: {
+				type: Number,
+				default: 4000 //kb
+			},
+			myQuillEditor: {
+				type: String
+			}
+		},
+
+		components: {
+			quillEditor
+		},
+
+		data() {
+			return {
+				refname: this.myQuillEditor,
+				content: this.value,
+				quillUpdateImg: false, // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示
+				editorOption: _EditorOption_(this),
+
+				// serverUrl: `${base.url}sys/storage/uploadSwiper?token=${storage.get('token')}`, // 这里写你要上传的图片服务器地址
+				header: {
+					// token: sessionStorage.token
+					'Token': this.$storage.get("Token")
+				} // 有的图片服务器要求请求头需要有token
+			};
+		},
+		computed: {
+			// 计算属性的 getter
+			getActionUrl: function() {
+				// return this.$base.url + this.action + "?token=" + this.$storage.get("token");
+				return `/${this.$base.name}/` + this.action;
+			}
+		},
+		methods: {
+			onEditorBlur() {
+				//失去焦点事件
+			},
+			onEditorFocus() {
+				//获得焦点事件
+			},
+			onEditorChange() {
+				//内容改变事件
+				this.$emit("input", this.value);
+			},
+			// 富文本图片上传前
+			beforeUpload() {
+				// 显示loading动画
+				this.quillUpdateImg = true;
+			},
+
+			uploadSuccess(res, file) {
+				// res为图片服务器返回的数据
+				// 获取富文本组件实例
+				let quill = this.$refs[this.refname].quill;
+				// 如果上传成功
+				if (res.code === 0) {
+					// 获取光标所在位置
+					let length = quill.getSelection().index;
+					// 插入图片  res.url为服务器返回的图片地址
+					quill.insertEmbed(length, "image", this.$base.url + "upload/" + res.file);
+					// 调整光标到最后
+					quill.setSelection(length + 1);
+				} else {
+					this.$message.error("图片插入失败");
+				}
+				// loading动画消失
+				this.quillUpdateImg = false;
+			},
+			// 富文本图片上传失败
+			uploadError() {
+				// loading动画消失
+				this.quillUpdateImg = false;
+				this.$message.error("图片插入失败");
+			}
+		}
+	};
+</script>
+
+<style>
+	.editor {
+		line-height: normal !important;
+	}
+
+	.ql-snow .ql-tooltip[data-mode="link"]::before {
+		content: "请输入链接地址:";
+	}
+
+	.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
+		border-right: 0px;
+		content: "保存";
+		padding-right: 0px;
+	}
+
+	.ql-snow .ql-tooltip[data-mode="video"]::before {
+		content: "请输入视频地址:";
+	}
+
+	.ql-container {
+		height: 400px;
+	}
+
+	.ql-snow .ql-picker.ql-size .ql-picker-label::before,
+	.ql-snow .ql-picker.ql-size .ql-picker-item::before {
+		content: "14px";
+	}
+
+	.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
+	.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
+		content: "10px";
+	}
+
+	.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
+	.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
+		content: "18px";
+	}
+
+	.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
+	.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
+		content: "32px";
+	}
+
+	.ql-snow .ql-picker.ql-header .ql-picker-label::before,
+	.ql-snow .ql-picker.ql-header .ql-picker-item::before {
+		content: "文本";
+	}
+
+	.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
+	.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
+		content: "标题1";
+	}
+
+	.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
+	.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
+		content: "标题2";
+	}
+
+	.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
+	.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
+		content: "标题3";
+	}
+
+	.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
+	.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
+		content: "标题4";
+	}
+
+	.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
+	.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
+		content: "标题5";
+	}
+
+	.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
+	.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
+		content: "标题6";
+	}
+
+	.ql-snow .ql-picker.ql-font .ql-picker-label::before,
+	.ql-snow .ql-picker.ql-font .ql-picker-item::before {
+		content: "标准字体";
+	}
+
+	.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
+	.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
+		content: "衬线字体";
+	}
+
+	.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
+	.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
+		content: "等宽字体";
+	}
+</style>

+ 144 - 0
src/components/common/ExcelFileUpload.vue

@@ -0,0 +1,144 @@
+<template>
+  <div>
+    <!-- 上传文件组件 -->
+    <el-upload
+      ref="upload"
+      :action="getActionUrl"
+      list-type="picture-card"
+      accept=".xls,.xlsx"
+      :limit="limit"
+      :headers="myHeaders"
+      :on-exceed="handleExceed"
+      :on-preview="handleUploadPreview"
+      :on-remove="handleRemove"
+      :on-success="handleUploadSuccess"
+      :on-error="handleUploadErr"
+      :before-upload="handleBeforeUpload"
+      :show-file-list="false"
+    >
+      <i class="el-icon-plus"></i>
+      <div slot="tip" class="el-upload__tip" style="color:#838fa1;">{{tip}}</div>
+    </el-upload>
+    <el-dialog :visible.sync="dialogVisible" size="tiny" append-to-body>
+      <img width="100%" :src="dialogImageUrl" alt>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import storage from "@/utils/storage";
+import base from "@/utils/base";
+export default {
+  data() {
+    return {
+      // 查看大图
+      dialogVisible: false,
+      // 查看大图
+      dialogImageUrl: "",
+      // 组件渲染图片的数组字段,有特殊格式要求
+      fileList: [],
+      fileUrlList: [],
+      myHeaders:{}
+    };
+  },
+  props: ["tip", "action", "limit", "multiple", "fileUrls"],
+  mounted() {
+    this.init();
+    this.myHeaders= {
+      'Token':storage.get("Token")
+    }
+  },
+  watch: {
+    fileUrls: function(val, oldVal) {
+      //   console.log("new: %s, old: %s", val, oldVal);
+      this.init();
+    }
+  },
+  computed: {
+    // 计算属性的 getter
+    getActionUrl: function() {
+		console.log(123)
+		this.fileList = []
+      // return base.url + this.action + "?token=" + storage.get("token");
+      return `/${this.$base.name}/` + this.action;
+    }
+  },
+  methods: {
+    // 初始化
+    init() {
+      //   console.log(this.fileUrls);
+      if (this.fileUrls) {
+        this.fileUrlList = this.fileUrls.split(",");
+        let fileArray = [];
+        this.fileUrlList.forEach(function(item, index) {
+          var url = item;
+          var name = index;
+          var file = {
+            name: name,
+            url: url
+          };
+          fileArray.push(file);
+        });
+        this.setFileList(fileArray);
+      }
+    },
+    handleBeforeUpload(file) {
+    
+    },
+    // 上传文件成功后执行
+    handleUploadSuccess(res, file, fileList) {
+      if (res && res.code === 0) {
+        fileList[fileList.length - 1]["url"] = "upload/" + file.response.file;
+        this.setFileList(fileList);
+        this.$emit("change", this.fileUrlList.join(","));
+        this.$message.success("文件导入成功");
+      } else {
+        this.$message.error(res.msg);
+      }
+    },
+    // 图片上传失败
+    handleUploadErr(err, file, fileList) {
+      this.$message.error("文件导入失败");
+    },
+    // 移除图片
+    handleRemove(file, fileList) {
+      this.setFileList(fileList);
+      this.$emit("change", this.fileUrlList.join(","));
+    },
+    // 查看大图
+    handleUploadPreview(file) {
+      this.dialogImageUrl = file.url;
+      this.dialogVisible = true;
+    },
+    // 限制图片数量
+    handleExceed(files, fileList) {
+      this.$message.warning(`最多上传${this.limit}张图片`);
+    },
+    // 重新对fileList进行赋值
+    setFileList(fileList) {
+      var fileArray = [];
+      var fileUrlArray = [];
+      // 有些图片不是公开的,所以需要携带token信息做权限校验
+      var token = storage.get("token");
+      let _this = this;
+      fileList.forEach(function(item, index) {
+        var url = item.url.split("?")[0];
+    if(!url.startsWith("http")) {
+      url = _this.$base.url+url
+    }
+        var name = item.name;
+        var file = {
+          name: name,
+          url: url + "?token=" + token
+        };
+        fileArray.push(file);
+        fileUrlArray.push(url);
+      });
+      this.fileList = fileArray;
+      this.fileUrlList = fileUrlArray;
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+</style>
+

+ 165 - 0
src/components/common/FileUpload.vue

@@ -0,0 +1,165 @@
+<template>
+	<div>
+		<!-- 上传文件组件 -->
+		<el-upload v-if="type==1" ref="upload" :action="getActionUrl" list-type="picture-card" :multiple="multiple" :limit="limit"
+			:headers="myHeaders" :file-list="fileList" :on-exceed="handleExceed" :on-preview="handleUploadPreview"
+			:on-remove="handleRemove" :on-success="handleUploadSuccess" :on-error="handleUploadErr"
+			:before-upload="handleBeforeUpload">
+			<i class="el-icon-plus"></i>
+			<div slot="tip" class="el-upload__tip">{{tip}}</div>
+		</el-upload>
+		<el-upload v-else drag ref="upload" :action="getActionUrl" :multiple="multiple" :limit="limit"
+			:headers="myHeaders" :file-list="fileList" :on-exceed="handleExceed" :on-preview="handleUploadPreview"
+			:on-remove="handleRemove" :on-success="handleUploadSuccess" :on-error="handleUploadErr"
+			:before-upload="handleBeforeUpload">
+			<i class="el-icon-upload"></i>
+			  <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+			<div slot="tip" class="el-upload__tip">{{tip}}</div>
+		</el-upload>
+		<el-dialog :visible.sync="dialogVisible" size="tiny" append-to-body>
+			<img width="100%" v-if="type==1" :src="dialogImageUrl" alt>
+			<video width="100%" v-if="type==2" :src="dialogImageUrl" alt controls />
+		</el-dialog>
+	</div>
+</template>
+<script>
+	import storage from "@/utils/storage";
+	import base from "@/utils/base";
+	export default {
+		data() {
+			return {
+				// 查看大图
+				dialogVisible: false,
+				// 查看大图
+				dialogImageUrl: "",
+				// 组件渲染图片的数组字段,有特殊格式要求
+				fileList: [],
+				fileUrlList: [],
+				myHeaders: {}
+			};
+		},
+		props: {
+			tip: {
+				type: String
+			},
+			action: {
+				type: String
+			},
+			/*图片大小*/
+			limit: {
+				type: Number,
+				default: 3 //kb
+			},
+			multiple: {
+				type: Boolean,
+				default: false
+			},
+			fileUrls: {
+				type: String
+			},
+			type: {
+				type: Number,
+				default: 1
+			}
+		},
+		mounted() {
+			this.init();
+			this.myHeaders = {
+				'Token': storage.get("Token")
+			}
+		},
+		watch: {
+			fileUrls: function(val, oldVal) {
+				//   console.log("new: %s, old: %s", val, oldVal);
+				this.init();
+			}
+		},
+		computed: {
+			// 计算属性的 getter
+			getActionUrl: function() {
+				// return base.url + this.action + "?token=" + storage.get("token");
+				return `/${this.$base.name}/` + this.action;
+			}
+		},
+		methods: {
+			// 初始化
+			init() {
+				//   console.log(this.fileUrls);
+				if (this.fileUrls) {
+					this.fileUrlList = this.fileUrls.split(",w").length>1?this.fileUrls:this.fileUrls.split(',');
+					let fileArray = [];
+					this.fileUrlList.forEach(function(item, index) {
+						var url = item;
+						var name = index;
+						var file = {
+							name: name,
+							url: url
+						};
+						fileArray.push(file);
+					});
+					this.setFileList(fileArray);
+				}
+			},
+			handleBeforeUpload(file) {
+
+			},
+			// 上传文件成功后执行
+			handleUploadSuccess(res, file, fileList) {
+				if (res && res.code === 0) {
+					fileList[fileList.length - 1]["url"] = "upload/" + file.response.file;
+					this.setFileList(fileList);
+					this.$emit("change", this.fileUrlList.join(","));
+				} else {
+					this.$message.error(res.msg);
+				}
+			},
+			// 图片上传失败
+			handleUploadErr(err, file, fileList) {
+				this.$message.error("文件上传失败");
+			},
+			// 移除图片
+			handleRemove(file, fileList) {
+				this.setFileList(fileList);
+				this.$emit("change", this.fileUrlList.join(","));
+			},
+			// 查看大图
+			handleUploadPreview(file) {
+				if(this.type>2){
+					window.open(file.url)
+					return false
+				}
+				this.dialogImageUrl = file.url;
+				this.dialogVisible = true;
+			},
+			// 限制图片数量
+			handleExceed(files, fileList) {
+				this.$message.warning(`最多上传${this.limit}张图片`);
+			},
+			// 重新对fileList进行赋值
+			setFileList(fileList) {
+				var fileArray = [];
+				var fileUrlArray = [];
+				// 有些图片不是公开的,所以需要携带token信息做权限校验
+				var token = storage.get("token");
+				let _this = this;
+				fileList.forEach(function(item, index) {
+					var url = item.url.split("?")[0];
+					if (!url.startsWith("http")) {
+						url = _this.$base.url + url
+					}
+					var name = item.name;
+					var file = {
+						name: name,
+						url: url + "?token=" + token
+					};
+					fileArray.push(file);
+					fileUrlArray.push(url);
+				});
+				this.fileList = fileArray;
+				this.fileUrlList = fileUrlArray;
+			}
+		}
+	};
+</script>
+<style lang="scss" scoped>
+</style>

+ 343 - 0
src/components/common/img.vue

@@ -0,0 +1,343 @@
+<template>
+  <el-dialog title="拍照上传" :visible.sync="visible" width="1065px">
+    <div class="box">
+      <video id="videoCamera" class="canvas" :width="videoWidth" :height="videoHeight" autoPlay></video>
+      <canvas id="canvasCamera" class="canvas" :width="videoWidth" :height="videoHeight"></canvas>
+    </div>
+    <div slot="footer" style="display:flex">
+		<el-upload
+		  :action="$base.url + 'file/upload'"
+		  :on-success="uploadSuccess"
+		  :show-file-list="false"
+		  accept=".jpg,.png,.jpge"
+		  style="margin-right:10px">
+		  <el-button icon="el-icon-upload2" size="small">
+		    上传图片
+		  </el-button>
+		</el-upload>
+      
+      <el-button @click="drawImage" icon="el-icon-camera" size="small">
+        拍照
+      </el-button>
+      <el-button v-if="os" @click="getCompetence" icon="el-icon-video-camera" size="small">
+        打开摄像头
+      </el-button>
+      <el-button v-else @click="stopNavigator" icon="el-icon-switch-button" size="small">
+        关闭摄像头
+      </el-button>
+      <el-button @click="resetCanvas" icon="el-icon-refresh" size="small">
+        重置
+      </el-button>
+      <el-button @click="onCancel" icon="el-icon-circle-close" size="small">
+        完成
+      </el-button>
+    </div>
+  </el-dialog>
+</template>
+<script>
+  export default {
+    name: "XXX",
+    data() {
+      return {
+		baseUrl:`/${this.$base.name}/`,
+        visible: false, //弹窗
+        loading: false, //上传按钮加载
+        os: false, //控制摄像头开关
+        thisVideo: null,
+        thisContext: null,
+        thisCancas: null,
+        videoWidth: 500,
+        videoHeight: 400,
+        postOptions: [],
+        CertCtl: '',
+        // 遮罩层
+        loading: true,
+        // 选中数组
+        ids: [],
+        // 非单个禁用
+        single: true,
+        // 非多个禁用
+        multiple: true,
+        // 总条数
+        total: 0,
+        // 项目人员表格数据
+        akworkerList: [],
+        //工种类别数据字典
+        workerTypeOptions: [],
+        // 弹出层标题
+        title: "",
+        // 是否显示弹出层
+        open: false,
+        // 查询参数
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          imgSrc: undefined,
+        },
+        // 表单参数
+
+        form: {},
+
+        // 表单校验
+
+        rules: {
+
+        }
+
+      };
+
+    },
+
+    created() {
+      // this.onTake()
+    },
+	
+    methods: {
+
+      /*调用摄像头拍照开始*/
+
+      onTake() {
+
+        this.visible = true;
+
+        this.getCompetence();
+
+      },
+
+      onCancel() {
+		this.uploadImg()
+        this.visible = false;
+        /* this.resetCanvas();*/
+
+        this.stopNavigator();
+
+      },
+	  uploadSuccess(e){
+		  this.visible = false;
+		  this.$emit('imgChange', e.file)
+	  },
+		uploadImg(){
+			let param = new FormData()
+			  param.append('file',this.base64toFile(this.imgSrc))
+			this.$http.post('file/upload',param).then(res=>{
+				this.$emit('imgChange', res.data.file)
+			})
+		},
+		base64toFile (dataurl, filename = 'file') {
+		  let arr = dataurl.split(',')
+		        let mime = arr[0].match(/:(.*?);/)[1]
+		        let suffix = mime.split('/')[1]
+		        let bstr = atob(arr[1])
+		        let n = bstr.length
+		        let u8arr = new Uint8Array(n)
+		        while (n--) {
+		          u8arr[n] = bstr.charCodeAt(n)
+		        }
+		        let file = new File([u8arr], `${filename}.${suffix}`, {
+		          type: mime
+		        })
+		        return file
+		},
+      // 调用摄像头权限
+
+      getCompetence() {
+
+        //必须在model中render后才可获取到dom节点,直接获取无法获取到model中的dom节点
+
+        this.$nextTick(() => {
+
+          const _this = this;
+
+          this.os = false; //切换成关闭摄像头
+
+          this.thisCancas = document.getElementById('canvasCamera');
+
+          this.thisContext = this.thisCancas.getContext('2d');
+
+          this.thisVideo = document.getElementById('videoCamera');
+
+          // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
+
+          if (navigator.mediaDevices === undefined) {
+
+            navigator.menavigatordiaDevices = {}
+
+          }
+
+          // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
+
+          // 使用getUserMedia,因为它会覆盖现有的属性。
+
+          // 这里,如果缺少getUserMedia属性,就添加它。
+
+          if (navigator.mediaDevices.getUserMedia === undefined) {
+
+            navigator.mediaDevices.getUserMedia = function(constraints) {
+
+              // 首先获取现存的getUserMedia(如果存在)
+
+              let getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator
+                .getUserMedia;
+
+              // 有些浏览器不支持,会返回错误信息
+
+              // 保持接口一致
+
+              if (!getUserMedia) {
+
+                return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
+
+              }
+
+              // 否则,使用Promise将调用包装到旧的navigator.getUserMedia
+
+              return new Promise(function(resolve, reject) {
+
+                getUserMedia.call(navigator, constraints, resolve, reject)
+
+              })
+
+            }
+
+          }
+
+          const constraints = {
+
+            audio: false,
+
+            video: {
+              width: _this.videoWidth,
+              height: _this.videoHeight,
+              transform: 'scaleX(-1)'
+            }
+
+          };
+
+          navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
+
+            // 旧的浏览器可能没有srcObject
+
+            if ('srcObject' in _this.thisVideo) {
+
+              _this.thisVideo.srcObject = stream
+
+            } else {
+
+              // 避免在新的浏览器中使用它,因为它正在被弃用。
+
+              _this.thisVideo.src = window.URL.createObjectURL(stream)
+
+            }
+
+            _this.thisVideo.onloadedmetadata = function(e) {
+
+              _this.thisVideo.play()
+
+            }
+
+          }).catch(err => {
+
+            this.$notify({
+
+              title: '警告',
+
+              message: '没有开启摄像头权限或浏览器版本不兼容.',
+
+              type: 'warning'
+
+            });
+
+          });
+
+        });
+
+      },
+
+      //绘制图片
+
+      drawImage() {
+
+        // 点击,canvas画图
+
+        this.thisContext.drawImage(this.thisVideo, 0, 0, this.videoWidth, this.videoHeight);
+
+        // 获取图片base64链接
+
+        this.imgSrc = this.thisCancas.toDataURL('image/png');
+
+        /*const imgSrc=this.imgSrc;*/
+
+      },
+
+      //清空画布
+
+      clearCanvas(id) {
+
+        let c = document.getElementById(id);
+
+        let cxt = c.getContext("2d");
+
+        cxt.clearRect(0, 0, c.width, c.height);
+
+      },
+
+      //重置画布
+
+      resetCanvas() {
+
+        this.imgSrc = "";
+
+        this.clearCanvas('canvasCamera');
+
+      },
+
+      //关闭摄像头
+
+      stopNavigator() {
+
+        if (this.thisVideo && this.thisVideo !== null) {
+
+          this.thisVideo.srcObject.getTracks()[0].stop();
+
+          this.os = true; //切换成打开摄像头
+
+        }
+
+      },
+
+      /*调用摄像头拍照结束*/
+
+    }
+
+  };
+</script>
+<style rel="stylesheet/scss" lang="scss" scoped>
+
+  .avatar-uploader .el-upload {
+    border: 1px dashed #ccc;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+
+  .avatar-uploader-icon {
+    font-size: 28px;
+    color: #8c939d;
+    width: 178px;
+    height: 178px;
+    line-height: 178px;
+    text-align: center;
+    border: 1px dashed #ccc;
+  }
+
+  .avatar {
+    width: 178px;
+    height: 178px;
+    display: block;
+  }
+</style>

+ 166 - 0
src/components/common/timeMethod.js

@@ -0,0 +1,166 @@
+class TimeMethod {
+
+	constructor() {}
+
+	//日期格式化
+	addZero(data) {
+		if (parseInt(data) < 10) {
+			return "0" + String(data);
+		}
+		return data;
+	}
+
+	/**
+	 * 获取当前日期
+	 */
+	getNowTime() {
+		const myDate = new Date();
+		const year = myDate.getFullYear();
+		const mouth = this.addZero(myDate.getMonth() + 1);
+		const day = this.addZero(myDate.getDate());
+		const hour = this.addZero(myDate.getHours());
+		const minute = this.addZero(myDate.getMinutes());
+		const second = this.addZero(myDate.getSeconds());
+		return year + '-' + mouth + '-' + day + 'T' + hour + ':' + minute + ':' + second
+	}
+
+	/**
+	 * 根据时间返回标准字符串时间
+	 * @param {Object} time
+	 */
+	getTime(time) {
+		const myDate = new Date(time);
+		const year = myDate.getFullYear();
+		const mouth = this.addZero(myDate.getMonth() + 1);
+		const day = this.addZero(myDate.getDate());
+		const hour = this.addZero(myDate.getHours());
+		const minute = this.addZero(myDate.getMinutes());
+		const second = this.addZero(myDate.getSeconds());
+		return year + '-' + mouth + '-' + day + 'T' + hour + ':' + minute + ':' + second
+	}
+
+	/**
+	 * @param {Object} timestamp
+	 * @param {Object} type
+	 * 时间戳转时间
+	 */
+	timestampToTime(timestamp, type) {
+		if (String(timestamp).length === 10) {
+			//时间戳为10位需*1000
+			var date = new Date(timestamp * 1000);
+		} else {
+			var date = new Date(timestamp);
+		}
+		const Y = date.getFullYear() + '-';
+		const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
+		const D = date.getDate() + ' ';
+		const h = date.getHours() + ':';
+		const m = date.getMinutes() + ':';
+		const s = date.getSeconds();
+		if (type === "date") {
+			return Y + M + D;
+		} else {
+			return Y + M + D + h + m + s;
+		}
+	}
+
+
+	/**
+	 * @param {Object} time
+	 * 时间转时间戳
+	 */
+	timeToTimestamp(time) {
+		//精确到秒,毫秒用000代替 :Date.parse(date); 
+		return new Date(time).getTime();
+	}
+
+
+	/**
+	 * @param {Object} startTime
+	 * @param {Object} endTime
+	 * 日期计算
+	 */
+	calculateTime(startTime, endTime) {
+		return new Date(startTime) - new Date(endTime)
+	}
+
+	/**
+	 * @param {Object} time
+	 * 日期转星期
+	 */
+	getDateToWeek(time) {
+		let weekArrayList = [{
+				"weekID": 7,
+				"weekName": "星期日"
+			},
+			{
+				"weekID": 1,
+				"weekName": "星期一"
+			},
+			{
+				"weekID": 2,
+				"weekName": "星期二"
+			},
+			{
+				"weekID": 3,
+				"weekName": "星期三"
+			},
+			{
+				"weekID": 4,
+				"weekName": "星期四"
+			},
+			{
+				"weekID": 5,
+				"weekName": "星期五"
+			},
+			{
+				"weekID": 6,
+				"weekName": "星期六"
+			}
+		];
+		return weekArrayList[new Date(time).getDay()]
+	}
+
+	/**
+	 * @param {Object} date
+	 *  yyyy-MM-dd HH:mm:ss转为   yyyy-MM-ddTHH:mm:ss
+	 */
+	timeFormat(date, type) {
+		if (type == "T")
+			return date.replace(" ", "T")
+		else
+			return date.replace("T", " ")
+	}
+
+	/**
+	 * @param {Object} time
+	 * 定时器
+	 */
+	timeSleep(time) {
+		return new Promise((resolve) => setTimeout(resolve, time))
+	}
+
+
+	/**
+	 * 根据日期加减计算日期
+	 * @param dayCount
+	 */
+	countDateStr(dayCount) {
+		let dd = new Date();
+		dd.setDate(dd.getDate() + dayCount);
+		let ms = dd.getTime();
+		return new Date(ms).toJSON();
+	}
+
+	/**
+	 * @param {Object} time
+	 * 日期中时间置0
+	 */
+	setTimeZero(time) {
+		return time.slice(0, 10) + 'T00:00:00.000+00:00';
+	}
+
+}
+
+
+export default new TimeMethod();

+ 315 - 0
src/components/common/timeable.vue

@@ -0,0 +1,315 @@
+<template>
+	<div>
+		<div class="panel">
+			<el-table :data="timetable" :span-method="objectSpanMethod" border
+				:header-cell-style="{background:'#d9e5fd', color:'black', fontWeight: 1000}"
+				:cell-style="tableCellStyle">
+				<el-table-column prop="sjd" label="时间段" width="80" align="center">
+				</el-table-column>
+				<el-table-column prop="jc" label="节次" width="120" align="center">
+					<template slot-scope="scope">
+						<div v-html="scope.row.jc"></div>
+					</template>
+				</el-table-column>
+				<el-table-column prop="mon" label="星期一" align="center">
+					<template slot-scope="scope">
+						<h4>{{ scope.row.mon.title }}</h4>
+						<div v-html="scope.row.mon.content"></div>
+					</template>
+				</el-table-column>
+				<el-table-column prop="tue" label="星期二" align="center">
+					<template slot-scope="scope">
+						<h4>{{ scope.row.tue.title }}</h4>
+						<div v-html="scope.row.tue.content"></div>
+					</template>
+				</el-table-column>
+				<el-table-column prop="wed" label="星期三" align="center">
+					<template slot-scope="scope">
+						<h4>{{ scope.row.wed.title }}</h4>
+						<div v-html="scope.row.wed.content"></div>
+					</template>
+				</el-table-column>
+				<el-table-column prop="thu" label="星期四" align="center">
+					<template slot-scope="scope">
+						<h4>{{ scope.row.thu.title }}</h4>
+						<div v-html="scope.row.thu.content"></div>
+					</template>
+				</el-table-column>
+				<el-table-column prop="fri" label="星期五" align="center">
+					<template slot-scope="scope">
+						<h4>{{ scope.row.fri.title }}</h4>
+						<div v-html="scope.row.fri.content"></div>
+					</template>
+				</el-table-column>
+				<el-table-column prop="sat" label="星期六" align="center">
+					<template slot-scope="scope">
+						<h4>{{ scope.row.sat.title }}</h4>
+						<div v-html="scope.row.sat.content"></div>
+					</template>
+				</el-table-column>
+				<el-table-column prop="sun" label="星期日" align="center">
+					<template slot-scope="scope">
+						<h4>{{ scope.row.sun.title }}</h4>
+						<div v-html="scope.row.sun.content"></div>
+					</template>
+				</el-table-column>
+			</el-table>
+		</div>
+	</div>
+</template>
+<script>
+	export default {
+		props: {
+			// 下午节次数
+			afternoonLength: {
+				type: [String, Number],
+				default: 4
+			},
+			morningLength: {
+				type: [String, Number],
+				default: 4
+			},
+			// 总节次
+			length: {
+				type: [String, Number],
+				default: 12
+			},
+			// 课表数据
+			events: {
+				type: Array,
+				default: () => []
+			},
+			time: {
+				type: Array,
+				default: () => []
+			}
+		},
+		data() {
+			return {
+				// 课程表数据
+				timetable: [],
+				hoverOrderArr: [],
+				weeks: ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'],
+				allPalette: ['#f05261', '#48a8e4', '#ffd061', '#52db9a', '#70d3e6', '#52db9a', '#3f51b5',
+					'#f3d147', '#4adbc3', '#673ab7', '#f3db49', '#76bfcd', '#b495e1', '#ff9800', '#8bc34a'
+				]
+			}
+		},
+		mounted() {
+			this.makeTimetable()
+		},
+		watch: {
+			events: {
+				handler(newVal, oldVal) {
+					this.mergeData()
+				},
+				deep: true
+			},
+			time: {
+				handler(newVal, oldVal) {
+					this.makeTimetable()
+				},
+				deep: true
+			},
+		},
+		created() {},
+		methods: {
+			getRandomInt(min, max) {
+			  min = Math.ceil(min);
+			  max = Math.floor(max);
+			  return Math.floor(Math.random() * (max - min + 1)) + min;
+			},
+			// 单元格添加背景色
+			tableCellStyle(row) {
+				if (row.column.property != 'jc' && row.column.property != 'sjd' && row.row[row.column.property].title !==
+					undefined) {
+					return `background-color:${this.allPalette[this.getRandomInt(0,this.allPalette.length - 1)]};color: #fff; border-radius:10px`
+				}
+			},
+			// 构造课程表完整数据
+			makeTimetable() {
+				this.timetable = []
+				for (let i = 0; i < this.time.length; i++) {
+					let one = {
+						sjd: this.time[i].sjd,
+						jc: Number(this.time[i].sectionnum) + '<br><div style="font-size: 12px">(' + this.time[i]
+							.starttime + '-' + this.time[i].endtime + ')</div>',
+						jc1: i + 1,
+						mon: {},
+						tue: {},
+						wed: {},
+						thu: {},
+						fri: {},
+						sat: {},
+						sun: {}
+					}
+					this.timetable.push(one)
+				}
+				this.mergeData()
+				this.$forceUpdate()
+			},
+			dateState(date = new Date()) {
+				// 获取当前小时
+				let hours = date.getHours()
+				if (hours <= 12) {
+					return '上午'
+				} else if (hours > 12 && hours <= 18) {
+					return '下午'
+				} else {
+					return '晚上'
+				}
+			},
+			mergeData() {
+				// 合并数据
+				if (this.events.length > 0 && this.timetable.length > 0) {
+					for (let i = 0; i < this.events.length; i++) {
+						// 获取星期几
+						let week = this.weeks[this.events[i].week - 1]
+						this.timetable[this.events[i].start - 1][week] = this.events[i]
+					}
+				}
+				console.log(this.timetable)
+			},
+			objectSpanMethod({
+				row,
+				column,
+				rowIndex,
+				columnIndex
+			}) {
+				const weeks = this.weeks[columnIndex - 2];
+				if (columnIndex === 0) {
+					if (rowIndex < this.morningLength) {
+						if (rowIndex === 0) {
+							return {
+								rowspan: this.morningLength,
+								colspan: 1
+							}
+						} else {
+							return {
+								rowspan: 0,
+								colspan: 0
+							}
+						}
+					} else if (rowIndex > this.morningLength - 1 && rowIndex < (this.morningLength + this
+						.afternoonLength)) {
+						if (rowIndex === this.morningLength) {
+							return {
+								rowspan: this.afternoonLength,
+								colspan: 1
+							}
+						} else {
+							return {
+								rowspan: 0,
+								colspan: 0
+							}
+						}
+					} else {
+						if (rowIndex === (this.morningLength + this.afternoonLength)) {
+							return {
+								rowspan: this.length - this.morningLength - this.afternoonLength,
+								colspan: 1
+							}
+						} else {
+							return {
+								rowspan: 0,
+								colspan: 0
+							}
+						}
+					}
+				}
+				if (columnIndex >= 2) {
+					if (row[weeks].title !== undefined &&row.jc1 === row[weeks].start) {
+						return {
+							rowspan: row[weeks].end - row[weeks].start + 1,
+							colspan: 1
+						}
+					} else if(this.timetable.some(r => r[weeks].start <= row.jc1 && r[weeks].end >= row.jc1)) {
+						return {
+							rowspan: 0,
+							colspan: 1
+						}
+					}
+				}
+				// if (columnIndex === 3) {
+				// 	console.log(row)
+				// 	if (row.tue.title !== undefined) {
+				// 		return {
+				// 			rowspan: row.tue.end - row.tue.start + 1,
+				// 			colspan: 1
+				// 		}
+				// 	} else {
+				// 		return {
+				// 			rowspan: 1,
+				// 			colspan: 1
+				// 		}
+				// 	}
+				// }
+				// if (columnIndex === 4) {
+				// 	if (row.wed.title !== undefined) {
+				// 		return {
+				// 			rowspan: row.wed.end - row.wed.start + 1,
+				// 			colspan: 1
+				// 		}
+				// 	} else {
+				// 		return {
+				// 			rowspan: 1,
+				// 			colspan: 1
+				// 		}
+				// 	}
+				// }
+				// if (columnIndex === 5) {
+				// 	if (row.thu.title !== undefined) {
+				// 		return {
+				// 			rowspan: row.thu.end - row.thu.start + 1,
+				// 			colspan: 1
+				// 		}
+				// 	} else {
+				// 		return {
+				// 			rowspan: 1,
+				// 			colspan: 1
+				// 		}
+				// 	}
+				// }
+				// if (columnIndex === 6) {
+				// 	if (row.fri.title !== undefined) {
+				// 		return {
+				// 			rowspan: row.fri.end - row.fri.start + 1,
+				// 			colspan: 1
+				// 		}
+				// 	} else {
+				// 		return {
+				// 			rowspan: 1,
+				// 			colspan: 1
+				// 		}
+				// 	}
+				// }
+				// if (columnIndex === 7) {
+				// 	if (row.sat.title !== undefined) {
+				// 		return {
+				// 			rowspan: row.sat.end - row.sat.start + 1,
+				// 			colspan: 1
+				// 		}
+				// 	} else {
+				// 		return {
+				// 			rowspan: 1,
+				// 			colspan: 1
+				// 		}
+				// 	}
+				// }
+				// if (columnIndex === 8) {
+				// 	if (row.sun.title !== undefined) {
+				// 		return {
+				// 			rowspan: row.sun.end - row.sun.start + 1,
+				// 			colspan: 1
+				// 		}
+				// 	} else {
+				// 		return {
+				// 			rowspan: 1,
+				// 			colspan: 1
+				// 		}
+				// 	}
+				// }
+			}
+		}
+	}
+</script>

+ 78 - 0
src/components/common/tmap.vue

@@ -0,0 +1,78 @@
+<template>
+	<div class="mapComponents" id="container"></div>
+</template>
+
+<script>
+	import AMapLoader from "@amap/amap-jsapi-loader";
+	window._AMapSecurityConfig = {
+	  securityJsCode: "4d8f1bda690b722d8a547dabb51a9933",
+	};
+	export default {
+		data() {
+			return {
+				map: null,
+			}
+		},
+		mounted() {
+			// this.initAMap();
+		},
+		props: ['longitude1','longitude2','latitude1','latitude2'],
+		methods: {
+			mapClose(){
+				console.log(11)
+				this.map.destroy();
+			},
+			initAMap(longitude1,longitude2,latitude1,latitude2) {
+				let that = this
+				AMapLoader.reset()
+				AMapLoader.load({
+						key: "5c1c06db19e483c5b00dc052ca37848b", // 申请好的Web端开发者Key,首次调用 load 时必填
+						version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
+						// plugins: ['AMap.Driving'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
+					})
+					.then((AMap) => {
+						this.map = new AMap.Map("container", {
+							// 设置地图容器id
+							// viewMode: "3D", // 是否为3D地图模式
+							zoom: 14, // 初始化地图级别
+							center: [longitude1, latitude1], //地图显示中心点坐标
+						});
+						if(longitude1&&longitude2&&latitude1&&latitude2){
+							AMap.plugin('AMap.Driving',
+								function() {
+									var driving = new AMap.Driving({
+										map: that.map,
+									}); //驾车路线规划
+									driving.search(
+										new AMap.LngLat(longitude1, latitude1),
+										new AMap.LngLat(longitude2, latitude2),
+										function(status, result) {
+											console.log(status)
+											// result 即是对应的驾车导航信息,相关数据结构文档请参考  https://lbs.amap.com/api/javascript-api/reference/route-search#m_DrivingResult
+											if (status === "complete") {
+												console.log("绘制驾车路线完成", result);
+											} else {
+												console.log("获取驾车数据失败:" + result);
+											}
+										}
+									);
+								}
+							);
+						}else {
+							this.$message.error('起终点经纬度不完整')
+						}
+					})
+					.catch((e) => {
+						console.log(e);
+					});
+			},
+		}
+	}
+</script>
+
+<style>
+	.mapComponents{
+		width: 100%;
+		height: 500px;
+	}
+</style>

文件差異過大導致無法顯示
+ 1 - 0
src/components/echarts/china.json


+ 56 - 0
src/components/index/IndexAside.vue

@@ -0,0 +1,56 @@
+<template>
+  <el-aside class="index-aside" width="200px">
+    <div class="index-aside-inner">
+      <el-menu default-active="1">
+        <el-menu-item @click="menuHandler('/')" index="1">
+          <!-- <i class="el-icon-s-home"></i> -->
+          首页
+        </el-menu-item>
+        <sub-menu
+          v-for="menu in menuList"
+          :key="menu.menuId"
+          :menu="menu"
+          :dynamicMenuRoutes="dynamicMenuRoutes"
+        ></sub-menu>
+      </el-menu>
+    </div>
+  </el-aside>
+</template>
+<script>
+import SubMenu from "@/components/index/IndexAsideSub";
+export default {
+  data() {
+    return {
+      menuList: [],
+      dynamicMenuRoutes: []
+    };
+  },
+  components: {
+    SubMenu
+  },
+  mounted() {
+    // 获取动态菜单数据并且渲染
+    this.menuList = JSON.parse(sessionStorage.getItem("menuList") || "[]");
+    this.dynamicMenuRoutes = JSON.parse(
+      sessionStorage.getItem("dynamicMenuRoutes") || "[]"
+    );
+  },
+  methods: {
+    menuHandler(path) {
+      this.$router.push({ path: path });
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.index-aside {
+  margin-top: 80px;
+  overflow: hidden;
+  .index-aside-inner {
+    width: 217px;
+    height: 100%;
+    overflow-y: scroll;
+  }
+}
+</style>
+

文件差異過大導致無法顯示
+ 923 - 0
src/components/index/IndexAsideStatic.vue


+ 51 - 0
src/components/index/IndexAsideSub.vue

@@ -0,0 +1,51 @@
+<template>
+  <el-submenu v-if="menu.list && menu.list.length >= 1" :index="menu.menuId + ''">
+    <template slot="title">
+      <span>{{ menu.name }}</span>
+    </template>
+    <sub-menu
+      v-for="item in menu.list"
+      :key="item.menuId"
+      :menu="item"
+      :dynamicMenuRoutes="dynamicMenuRoutes"
+    ></sub-menu>
+  </el-submenu>
+  <el-menu-item v-else :index="menu.menuId + ''" @click="gotoRouteHandle(menu)">
+    <span>{{ menu.name }}</span>
+  </el-menu-item>
+</template>
+
+<script>
+import SubMenu from "./IndexAsideSub";
+export default {
+  name: "sub-menu",
+  props: {
+    menu: {
+      type: Object,
+      required: true
+    },
+    dynamicMenuRoutes: {
+      type: Array,
+      required: true
+    }
+  },
+  components: {
+    SubMenu
+  },
+  methods: {
+    // 通过menuId与动态(菜单)路由进行匹配跳转至指定路由
+    gotoRouteHandle(menu) {
+      var route = this.dynamicMenuRoutes.filter(
+        item => item.meta.menuId === menu.menuId
+      );
+      if (route.length >= 1) {
+        if (route[0].component != null) {
+          this.$router.replace({ name: route[0].name });
+        } else {
+          this.$router.push({ name: "404" });
+        }
+      }
+    }
+  }
+};
+</script>

+ 419 - 0
src/components/index/IndexHeader.vue

@@ -0,0 +1,419 @@
+<template>
+	<div class="navbar">
+		<div class="title">
+			<span class="title-name">{{this.$project.projectName}}</span>
+		</div>
+		<!-- 天气 -->
+		<div class="weather" v-if="weather.day">
+			<div>{{weather.city}}</div>
+			<div>{{weather.day.tem}}°</div>
+			<div>{{weather.day.wea}}</div>
+			<div>{{weather.day.win}}</div>
+			<div>{{weather.day.win_speed}}</div>
+		</div>
+		<!-- 时间 -->
+		<div class="times">{{times}}</div>
+		<el-dropdown class="dropdown-box" @command="handleCommand" trigger="click">
+			<div class="el-dropdown-link">
+				<el-image v-if="user" :src="avatar?this.$base.url + avatar : require('@/assets/img/avator.png')" fit="cover"></el-image>
+				<span class="label">欢迎您,</span>
+				<span class="nickname">{{this.$storage.get('adminName')}}</span>
+				<span class="icon iconfont icon-xiala"></span>
+			</div>
+			<el-dropdown-menu class="top-el-dropdown-menu" slot="dropdown">
+				<el-dropdown-item class="item1" :command="''">
+					<span class="icon iconfont icon-home19"></span>
+					首页
+				</el-dropdown-item>
+				<el-dropdown-item class="item2" :command="'center'">
+					<span class="icon iconfont icon-touxiang03"></span>
+					个人中心
+				</el-dropdown-item>
+				<el-dropdown-item v-if="isAuth('hasBoard','查看')" class="item3" :command="'board'">
+					<span class="icon iconfont icon-fanhui12"></span>
+					看板
+				</el-dropdown-item>
+				<el-dropdown-item v-if="this.$storage.get('role')=='管理员'" class="item3" :command="'backUp'">
+					<span class="icon iconfont icon-fanhui12"></span>
+					数据备份
+				</el-dropdown-item>
+				<el-dropdown-item v-if="this.$storage.get('role')=='管理员'" class="item3" :command="'analyze'">
+					<span class="icon iconfont icon-fanhui12"></span>
+					数据分析
+				</el-dropdown-item>
+				<el-dropdown-item class="item4" :command="'logout'">
+					<span class="icon iconfont icon-fanhui13"></span>
+					退出登录
+				</el-dropdown-item>
+			</el-dropdown-menu>
+		</el-dropdown>
+	</div>
+</template>
+
+<script>
+	import {
+		Loading
+	} from 'element-ui';
+	import axios from 'axios';
+	export default {
+		data() {
+			return {
+				dialogVisible: false,
+				ruleForm: {},
+				user: null,
+				// 时间
+				times: '',
+				// 天气
+				weather: {},
+			};
+		},
+		created() {
+			this.$nextTick(() => {
+				// 获取时间
+				this.setTimes()
+			})
+			// 获取天气
+			this.getWeather()
+		},
+		computed: {
+			avatar(){
+				return this.$storage.get('headportrait')?this.$storage.get('headportrait'):''
+			},
+		},
+		mounted() {
+			let sessionTable = this.$storage.get("sessionTable")
+			this.$http({
+				url: sessionTable + '/session',
+				method: "get"
+			}).then(({
+				data
+			}) => {
+				if (data && data.code === 0) {
+					if(sessionTable == 'qiye') {
+						this.$storage.set('headportrait',data.data.touxiang)
+					}
+					if(sessionTable == 'users') {
+						this.$storage.set('headportrait',data.data.image)
+					}
+					this.$storage.set('userForm',JSON.stringify(data.data))
+					this.user = data.data;
+					this.$storage.set('userid',data.data.id);
+				} else {
+					let message = this.$message
+					message.error(data.msg);
+				}
+			});
+		},
+		methods: {
+			// 获取当前时间
+			setTimes() {
+				setInterval(()=>{
+					let d = new Date()
+					this.times = d.getFullYear() + '-' + ((d.getMonth() + 1)<10?('0' + (d.getMonth() + 1)):(d.getMonth() + 1)) + '-' + (d.getDate()<10?('0' + d.getDate()):d.getDate()) + ' ' + (d.getHours()<10?('0' + d.getHours()):d.getHours()) + ':' + (d.getMinutes()<10?('0' + d.getMinutes()):d.getMinutes()) + ':' + (d.getSeconds()<10?('0' + d.getSeconds()):d.getSeconds())
+				},1000)
+			},
+			// 获取当前城市天气
+			getWeather(){
+				axios({
+					method: 'get',
+					url: 'http://gfeljm.tianqiapi.com/free/v2031?appid=69475998&appsecret=rldbX1Zl'
+				}).then(res => {
+					this.weather = res.data
+				})
+			},
+			handleCommand(name) {
+				if (name == 'logout') {
+					this.onLogout()
+				} 
+				else if (name == 'board'){
+					this.toBoard()
+				}
+				else if (name == 'backUp'){
+					this.backUp()
+				}
+				else if (name == 'analyze'){
+					this.analyzeClick()
+				}
+				else {
+					let router = this.$router
+					name = '/'+name
+					router.push(name)
+				}
+			},
+			onLogout() {
+				let storage = this.$storage
+				let router = this.$router
+				storage.clear()
+				this.$store.dispatch('tagsView/delAllViews')
+				router.replace({
+					name: "login"
+				});
+			},
+			onIndexTap(){
+				localStorage.setItem("frontToken", localStorage.getItem("Token"));
+				localStorage.setItem("frontRole", localStorage.getItem("role"));
+				localStorage.setItem("frontSessionTable", localStorage.getItem("sessionTable"));
+				localStorage.setItem("frontHeadportrait", localStorage.getItem("headportrait"));
+				localStorage.setItem("UserTableName", localStorage.getItem("sessionTable"));
+				localStorage.setItem("frontUserid", localStorage.getItem("userid"));
+				localStorage.setItem("username", localStorage.getItem("adminName"));
+				window.location.href = `${this.$base.indexUrl}`
+			},
+			toBoard(){
+				let routeData = this.$router.resolve({ path: '/board'});
+				window.open(routeData.href, '_blank');
+			},
+			analyzeClick() {
+				this.$confirm('是否进行大数据分析?', '数据分析提示', {
+					confirmButtonText: '是',
+					cancelButtonText: '否',
+					type: 'warning'
+				}).then(() => {
+					let loading = null;
+					loading = Loading.service({
+						target: this.$refs['roleMenuBox'],
+						fullscreen: false,
+						text: '数据分析中,请稍等...'
+					})
+					this.$http({
+						url: '/hive/analyze',
+						method: "get"
+					}).then(({
+						data
+					}) => {
+						if(loading) loading.close()
+						if(data.code==0){
+							this.$message({
+								message: '数据分析完成',
+								type: 'success',
+								duration: 1500,
+							});
+						}
+					},err=>{
+						if(loading) loading.close()
+					});
+				});
+			},
+			backUp() {
+				this.$confirm('是否备份数据库?', '数据备份提示', {
+					confirmButtonText: '是',
+					cancelButtonText: '否',
+					type: 'warning'
+				}).then(() => {
+					this.$http({
+						url: '/mysqldump',
+						method: "get"
+					}).then(({
+						data
+					}) => {
+						if (data) {
+							const binaryData = [];
+							binaryData.push(data);
+							const objectUrl = window.URL.createObjectURL(new Blob(binaryData, {
+								type: 'application/pdf;chartset=UTF-8'
+							}))
+							const a = document.createElement('a')
+							a.href = objectUrl
+							a.download = 'mysql.dmp'
+							// a.click()
+							// 下面这个写法兼容火狐
+							a.dispatchEvent(new MouseEvent('click', {
+								bubbles: true,
+								cancelable: true,
+								view: window
+							}))
+							window.URL.revokeObjectURL(data)
+							message.message("数据备份成功")
+						} else {
+							let message = this.$message
+							message.error(data.msg);
+						}
+					});
+				});
+			},
+		}
+	};
+</script>
+
+
+<style lang="scss" scoped>
+	.navbar {
+		.title {
+			top: 13px;
+			left: 40px;
+			display: block;
+			position: absolute;
+			.title-name {
+				padding: 0;
+				color: #fff;
+				font-weight: 600;
+				font-size: 28px;
+				line-height: 60px;
+				float: left;
+			}
+		}
+		.weather {
+			padding: 0;
+			margin: 0 20px;
+			color: inherit;
+			display: flex;
+			font-size: inherit;
+			justify-content: center;
+			align-items: center;
+			div:nth-child(1) {
+				padding: 0 4px;
+				color: inherit;
+				font-size: inherit;
+				line-height: 44px;
+			}
+			div:nth-child(2) {
+				padding: 0 4px;
+				color: inherit;
+				font-size: inherit;
+				line-height: 44px;
+			}
+			div:nth-child(3) {
+				padding: 0 4px;
+				color: inherit;
+				font-size: inherit;
+				line-height: 44px;
+			}
+			div:nth-child(4) {
+				padding: 0 4px;
+				color: inherit;
+				font-size: inherit;
+				line-height: 44px;
+			}
+			div:nth-child(5) {
+				padding: 0 4px;
+				color: inherit;
+				font-size: inherit;
+				line-height: 44px;
+			}
+		}
+		.times {
+			padding: 0;
+			margin: 0 100px 0 0;
+			color: inherit;
+			font-size: inherit;
+			line-height: 30px;
+		}
+		.dropdown-box {
+			color: inherit;
+			display: flex;
+			font-size: inherit;
+			right: 20px;
+			.el-dropdown-link {
+				display: flex;
+				align-items: center;
+				.el-image {
+					border-radius: 100%;
+					margin: 0 10px;
+					object-fit: cover;
+					display: inline-block;
+					width: 42px;
+					height: 42px;
+				}
+				.label {
+					color: inherit;
+					display: none;
+					font-size: inherit;
+					line-height: 32px;
+				}
+				.nickname {
+					color: inherit;
+					font-size: inherit;
+					line-height: 32px;
+				}
+				.iconfont {
+					margin: 0 0 0 5px;
+					color: rgba(255,255,255,.6);
+					font-size: 14px;
+				}
+			}
+			.top-el-dropdown-menu {
+				border: 1px solid #EBEEF5;
+				border-radius: 4px;
+				padding: 10px 0;
+				box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
+				margin: 18px 0;
+				background: #FFF;
+				li.el-dropdown-menu__item.item1 {
+					cursor: pointer;
+					padding: 0 20px;
+					margin: 0;
+					outline: 0;
+					color: #606266;
+					background: #fff;
+					font-size: 14px;
+					line-height: 36px;
+					list-style: none;
+					.iconfont {
+						margin: 0 4px 0 0;
+							color: #000;
+							font-size: 14px;
+						}
+				}
+				li.el-dropdown-menu__item.item1:hover {
+					background: #ecf5ff;
+				}
+				li.el-dropdown-menu__item.item2 {
+					cursor: pointer;
+					padding: 0 20px;
+					margin: 0;
+					outline: 0;
+					color: #606266;
+					background: #fff;
+					font-size: 14px;
+					line-height: 36px;
+					list-style: none;
+					.iconfont {
+						margin: 0 4px 0 0;
+							color: #000;
+							font-size: 14px;
+						}
+				}
+				li.el-dropdown-menu__item.item2:hover {
+					background: #ecf5ff;
+				}
+				li.el-dropdown-menu__item.item3 {
+					cursor: pointer;
+					padding: 0 20px;
+					margin: 0;
+					outline: 0;
+					color: #606266;
+					background: #fff;
+					font-size: 14px;
+					line-height: 36px;
+					list-style: none;
+					.iconfont {
+						margin: 0 4px 0 0;
+						color: #000;
+						font-size: 14px;
+					}
+				}
+				li.el-dropdown-menu__item.item3:hover {
+					background: #ecf5ff;
+				}
+				li.el-dropdown-menu__item.item4 {
+					cursor: pointer;
+					padding: 0 20px;
+					margin: 0;
+					color: #606266;
+					background: #fff;
+					font-size: 14px;
+					line-height: 36px;
+					list-style: none;
+					.iconfont {
+						margin: 0 4px 0 0;
+						color: #000;
+						font-size: 14px;
+					}
+				}
+				li.el-dropdown-menu__item.item4:hover {
+					background: #ecf5ff;
+				}
+			}
+		}
+	}
+</style>

文件差異過大導致無法顯示
+ 160 - 0
src/components/index/IndexMain.vue


+ 85 - 0
src/components/index/TagsView/ScrollPane.vue

@@ -0,0 +1,85 @@
+<template>
+  <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
+    <slot />
+  </el-scrollbar>
+</template>
+
+<script>
+const tagAndTagSpacing = 4 // tagAndTagSpacing
+
+export default {
+  name: 'ScrollPane',
+  data() {
+    return {
+      left: 0
+    }
+  },
+  computed: {
+    scrollWrapper() {
+      return this.$refs.scrollContainer.$refs.wrap
+    }
+  },
+  methods: {
+    handleScroll(e) {
+      const eventDelta = e.wheelDelta || -e.deltaY * 40
+      const $scrollWrapper = this.scrollWrapper
+      $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
+    },
+    moveToTarget(currentTag) {
+      const $container = this.$refs.scrollContainer.$el
+      const $containerWidth = $container.offsetWidth
+      const $scrollWrapper = this.scrollWrapper
+      const tagList = this.$parent.$refs.tag
+
+      let firstTag = null
+      let lastTag = null
+
+      // find first tag and last tag
+      if (tagList.length > 0) {
+        firstTag = tagList[0]
+        lastTag = tagList[tagList.length - 1]
+      }
+
+      if (firstTag === currentTag) {
+        $scrollWrapper.scrollLeft = 0
+      } else if (lastTag === currentTag) {
+        $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
+      } else {
+        // find preTag and nextTag
+        const currentIndex = tagList.findIndex(item => item === currentTag)
+        const prevTag = tagList[currentIndex - 1]
+        const nextTag = tagList[currentIndex + 1]
+
+        // the tag's offsetLeft after of nextTag
+        const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
+
+        // the tag's offsetLeft before of prevTag
+        const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
+
+        if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
+          $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
+        } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
+          $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.scroll-container {
+  white-space: nowrap;
+  position: relative;
+  overflow: hidden;
+  width: 100%;
+  /deep/ {
+    .el-scrollbar__bar {
+      bottom: 0px;
+    }
+    .el-scrollbar__wrap {
+      height: 49px;
+    }
+  }
+}
+</style>

+ 315 - 0
src/components/index/TagsView/index.vue

@@ -0,0 +1,315 @@
+<template>
+	<div id="tags-view-container" class="tags-view-container" :style='{"padding":"4px 30px","margin":"10px 0","borderColor":"#d8dce5","background":"#fff","borderWidth":"0 0 1px","display":"none","width":"100%","borderStyle":"solid","height":"34px"}'>
+		<scroll-pane ref="scrollPane" class="tags-view-wrapper">
+			<div class="tags-view-box" :style='{"width":"100%","whiteSpace":"nowrap","position":"relative","background":"#fff"}'>
+				<router-link v-for="tag in visitedViews" ref="tag" :key="tag.path" :class="isActive(tag)?'active':''"
+					:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" tag="span" class="tags-view-item"
+					@click.middle.native="closeSelectedTag(tag)" @contextmenu.prevent.native="openMenu(tag,$event)">
+					<span class="text">{{ tag.name }}</span>
+					<span v-if="!tag.meta.affix" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
+				</router-link>
+			</div>
+		</scroll-pane>
+		<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
+			<li v-if="!(selectedTag.meta&&selectedTag.meta.affix)" @click="closeSelectedTag(selectedTag)">Close</li>
+			<li @click="closeAllTags(selectedTag)">Close All</li>
+		</ul>
+	</div>
+</template>
+
+<script>
+	import ScrollPane from './ScrollPane'
+	import path from 'path'
+	import {
+		generateTitle
+	} from '@/utils/i18n'
+	import menu from '@/utils/menu'
+	import { routes } from '@/router/router-static.js'
+	
+	export default {
+		components: {
+			ScrollPane
+		},
+		data() {
+			return {
+				visible: false,
+				top: 0,
+				left: 0,
+				selectedTag: {},
+				affixTags: [],
+				routes: []
+			}
+		},
+		computed: {
+			visitedViews() {
+				return this.$store.state.tagsView.visitedViews
+			},
+			// routes() {
+			//   return this.$store.state.menu.routes
+			// }
+		},
+		watch: {
+			$route() {
+				this.addTags()
+				this.moveToCurrentTag()
+			},
+			visible(value) {
+				if (value) {
+					document.body.addEventListener('click', this.closeMenu)
+				} else {
+					document.body.removeEventListener('click', this.closeMenu)
+				}
+			}
+		},
+		mounted() {
+			this.initTags()
+			this.addTags()
+		},
+		created() {
+			this.routes = menu
+			
+			let menuList = []
+			const menus = menu.list()
+			if (menus) {
+				menuList = menus
+			} else {
+				let params = {
+					page: 1,
+					limit: 1,
+					sort: 'id',
+				}
+			
+				this.$http({
+					url: "menu/list",
+					method: "get",
+					params: params
+				}).then(({
+					data
+				}) => {
+					if (data && data.code === 0) {
+						menuList = JSON.parse(data.data.list[0].menujson);
+						this.$storage.set("menus", menuList);
+					}
+				})
+			}
+			this.role = this.$storage.get('role')
+			
+			for (let i = 0; i < menuList.length; i++) {
+				if (menuList[i].roleName == this.role) {
+					this.routes = menuList[i].backMenu;
+					break;
+				}
+			}
+			this.routes = routes.concat(this.routes);
+			// console.log(this.visitedViews)
+			// console.log(this.routes)
+			// this.initTags()
+			// this.addTags()
+		},
+		methods: {
+			isActive(route) {
+				return route.path === this.$route.path
+			},
+			filterAffixTags(routes, basePath = '/') {
+				let tags = []
+				routes.forEach(route => {
+					if (route.meta && route.meta.affix) {
+						const tagPath = path.resolve(basePath, route.path)
+						tags.push({
+							fullPath: tagPath,
+							path: tagPath,
+							name: route.name,
+							meta: {
+								...route.meta
+							}
+						})
+					}
+					if (route.children) {
+						const tempTags = this.filterAffixTags(route.children, route.path)
+						if (tempTags.length >= 1) {
+							tags = [...tags, ...tempTags]
+						}
+					}
+				})
+				return tags
+			},
+			generateTitle,
+			initTags() {
+				const affixTags = this.affixTags = this.filterAffixTags(this.routes)
+				for (const tag of affixTags) {
+					// Must have tag name
+					if (tag.name) {
+						this.$store.dispatch('tagsView/addVisitedView', tag)
+					}
+				}
+			},
+			addTags() {
+				const {
+					name
+				} = this.$route
+				if (name) {
+					this.$store.dispatch('tagsView/addView', this.$route)
+				}
+				return false
+			},
+			moveToCurrentTag() {
+				const tags = this.$refs.tag
+				this.$nextTick(() => {
+					for (const tag of tags) {
+						if (tag.to.path === this.$route.path) {
+							this.$refs.scrollPane.moveToTarget(tag)
+							// when query is different then update
+							if (tag.to.fullPath !== this.$route.fullPath) {
+								this.$store.dispatch('tagsView/updateVisitedView', this.$route)
+							}
+							break
+						}
+					}
+				})
+			},
+			refreshSelectedTag(view) {
+				this.$store.dispatch('tagsView/delCachedView', view).then(() => {
+					const {
+						fullPath
+					} = view
+					this.$nextTick(() => {
+						this.$router.replace({
+							path: '/redirect' + fullPath
+						})
+					})
+				})
+			},
+			closeSelectedTag(view) {
+				this.$store.dispatch('tagsView/delView', view).then(({
+					visitedViews
+				}) => {
+					if (this.isActive(view)) {
+						this.toLastView(visitedViews, view)
+					}
+				})
+			},
+			closeOthersTags() {
+				this.$router.push(this.selectedTag)
+				this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
+					this.moveToCurrentTag()
+				})
+			},
+			closeAllTags(view) {
+				this.$store.dispatch('tagsView/delAllViews').then(({
+					visitedViews
+				}) => {
+					if (this.affixTags.some(tag => tag.path === view.path)) {
+						return
+					}
+					this.toLastView(visitedViews, view)
+				})
+			},
+			toLastView(visitedViews, view) {
+				const latestView = visitedViews.slice(-1)[0]
+				if (latestView) {
+					this.$router.push(latestView)
+				} else {
+					// now the default is to redirect to the home page if there is no tags-view,
+					// you can adjust it according to your needs.
+					if (view.name === 'Dashboard') {
+						// to reload home page
+						this.$router.replace({
+							path: '/redirect' + view.fullPath
+						})
+					} else {
+						this.$router.push('/')
+					}
+				}
+			},
+			openMenu(tag, e) {
+				const menuMinWidth = 105
+				const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
+				const offsetWidth = this.$el.offsetWidth // container width
+				const maxLeft = offsetWidth - menuMinWidth // left boundary
+				const left = e.clientX - offsetLeft + 15 // 15: margin right
+
+				if (left > maxLeft) {
+					this.left = maxLeft
+				} else {
+					this.left = left
+				}
+
+				this.top = e.clientY
+				this.visible = true
+				this.selectedTag = tag
+			},
+			closeMenu() {
+				this.visible = false
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.tags-view-container {
+		height: 34px;
+		width: 100%;
+		background: #fff;
+		border-bottom: 1px solid #d8dce5;
+		box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
+
+		.contextmenu {
+			margin: 0;
+			background: #fff;
+			z-index: 3000;
+			position: absolute;
+			list-style-type: none;
+			padding: 5px 0;
+			border-radius: 4px;
+			font-size: 12px;
+			font-weight: 400;
+			color: #333;
+			box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
+
+			li {
+				margin: 0;
+				padding: 7px 16px;
+				cursor: pointer;
+
+				&:hover {
+					background: #eee;
+				}
+			}
+		}
+	}
+	
+	.tags-view-container .tags-view-wrapper .tags-view-item {
+				cursor: pointer;
+				padding: 0 8px;
+				margin: 0 5px 0 0;
+				color: #333;
+				display: inline-block;
+				font-size: 12px;
+				border-color: #d8dce5;
+				line-height: 25px;
+				background: #fff;
+				width: auto;
+				border-width: 1px 1px 0 1px;
+				border-style: solid;
+				height: 25px;
+			}
+	
+	.tags-view-container .tags-view-wrapper .tags-view-item:hover {
+				background: rgba(64, 158, 255, .1);
+			}
+	
+	.tags-view-container .tags-view-wrapper .tags-view-item.active {
+				color: #fff;
+				background: rgb(64, 158, 255);
+			}
+	
+	.tags-view-container .tags-view-wrapper .tags-view-item .text {
+				color: inherit;
+				font-size: inherit;
+			}
+	
+	.tags-view-container .tags-view-wrapper .tags-view-item .el-icon-close {
+				color: inherit;
+				font-size: inherit;
+			}
+</style>

+ 9 - 0
src/icons/index.js

@@ -0,0 +1,9 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg component
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const req = require.context('./svg/svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+requireAll(req)

文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/404.svg


文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/articleEdit.svg


文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/banner.svg


文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/bug.svg


文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/build.svg


文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/cfg.svg


文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/channel.svg


+ 1 - 0
src/icons/svg/chart.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><defs><style/></defs><path d="M64 448h256v512H64V448zm640-192h256v704H704V256zM384 64h256v896H384V64z"/></svg>

文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/clipboard.svg


+ 1 - 0
src/icons/svg/code.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M318.578 819.2L17.067 512l301.51-307.2 45.512 45.511L96.71 512l267.38 261.689zm386.844 0l-45.51-45.511L927.288 512 659.91 250.311l45.511-45.511L1006.933 512zM540.786 221.867l55.75 11.15-113.379 569.116-55.75-11.093z"/></svg>

+ 1 - 0
src/icons/svg/component.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><defs><style/></defs><path d="M64 64h384v384H64V64zm0 512h384v384H64V576zm512 0h384v384H576V576zm192-128c106.039 0 192-85.961 192-192S874.039 64 768 64s-192 85.961-192 192 85.961 192 192 192z"/></svg>

文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/contacts.svg


文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/dashboard.svg


文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/date.svg


文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/dept.svg


文件差異過大導致無法顯示
+ 1 - 0
src/icons/svg/dict.svg


+ 0 - 0
src/icons/svg/documentation.svg


部分文件因文件數量過多而無法顯示