diff --git a/admin/css/cropper.css b/admin/css/cropper.css
new file mode 100644
index 0000000000000000000000000000000000000000..2ebd8296370e16c4019b94d57c1d26ae114db019
--- /dev/null
+++ b/admin/css/cropper.css
@@ -0,0 +1,274 @@
+/*!
+ * Cropper v0.9.1
+ * https://github.com/fengyuanchen/cropper
+ *
+ * Copyright (c) 2014-2015 Fengyuan Chen and contributors
+ * Released under the MIT license
+ *
+ * Date: 2015-03-21T04:58:27.265Z
+ */
+
+ .cropper-container {
+ position: relative;
+ overflow: hidden;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-tap-highlight-color: transparent;
+ -webkit-touch-callout: none
+}
+
+ .cropper-container img {
+ display: block;
+ width: 100%;
+ min-width: 0 !important;
+ max-width: none !important;
+ height: 100%;
+ min-height: 0 !important;
+ max-height: none !important;
+ image-orientation: 0deg !important
+ }
+
+.cropper-canvas, .cropper-crop-box, .cropper-drag-box, .cropper-modal {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0
+}
+
+.cropper-drag-box {
+ background-color: #fff;
+ filter: alpha(opacity=0);
+ opacity: 0
+}
+
+.cropper-modal {
+ background-color: #000;
+ filter: alpha(opacity=50);
+ opacity: .5
+}
+
+.cropper-view-box {
+ display: block;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ outline: #69f solid 1px;
+ outline-color: rgba(102,153,255,.75)
+}
+
+.cropper-dashed {
+ position: absolute;
+ display: block;
+ filter: alpha(opacity=50);
+ border: 0 dashed #fff;
+ opacity: .5
+}
+
+ .cropper-dashed.dashed-h {
+ top: 33.33333333%;
+ left: 0;
+ width: 100%;
+ height: 33.33333333%;
+ border-top-width: 1px;
+ border-bottom-width: 1px
+ }
+
+ .cropper-dashed.dashed-v {
+ top: 0;
+ left: 33.33333333%;
+ width: 33.33333333%;
+ height: 100%;
+ border-right-width: 1px;
+ border-left-width: 1px
+ }
+
+.cropper-face, .cropper-line, .cropper-point {
+ position: absolute;
+ display: block;
+ width: 100%;
+ height: 100%;
+ filter: alpha(opacity=10);
+ opacity: .1
+}
+
+.cropper-face {
+ top: 0;
+ left: 0;
+ cursor: move;
+ background-color: #fff
+}
+
+.cropper-line {
+ background-color: #69f
+}
+
+ .cropper-line.line-e {
+ top: 0;
+ right: -3px;
+ width: 5px;
+ cursor: e-resize
+ }
+
+ .cropper-line.line-n {
+ top: -3px;
+ left: 0;
+ height: 5px;
+ cursor: n-resize
+ }
+
+ .cropper-line.line-w {
+ top: 0;
+ left: -3px;
+ width: 5px;
+ cursor: w-resize
+ }
+
+ .cropper-line.line-s {
+ bottom: -3px;
+ left: 0;
+ height: 5px;
+ cursor: s-resize
+ }
+
+.cropper-point {
+ width: 5px;
+ height: 5px;
+ background-color: #69f;
+ filter: alpha(opacity=75);
+ opacity: .75
+}
+
+ .cropper-point.point-e {
+ top: 50%;
+ right: -3px;
+ margin-top: -3px;
+ cursor: e-resize
+ }
+
+ .cropper-point.point-n {
+ top: -3px;
+ left: 50%;
+ margin-left: -3px;
+ cursor: n-resize
+ }
+
+ .cropper-point.point-w {
+ top: 50%;
+ left: -3px;
+ margin-top: -3px;
+ cursor: w-resize
+ }
+
+ .cropper-point.point-s {
+ bottom: -3px;
+ left: 50%;
+ margin-left: -3px;
+ cursor: s-resize
+ }
+
+ .cropper-point.point-ne {
+ top: -3px;
+ right: -3px;
+ cursor: ne-resize
+ }
+
+ .cropper-point.point-nw {
+ top: -3px;
+ left: -3px;
+ cursor: nw-resize
+ }
+
+ .cropper-point.point-sw {
+ bottom: -3px;
+ left: -3px;
+ cursor: sw-resize
+ }
+
+ .cropper-point.point-se {
+ right: -3px;
+ bottom: -3px;
+ width: 20px;
+ height: 20px;
+ cursor: se-resize;
+ filter: alpha(opacity=100);
+ opacity: 1
+ }
+
+ .cropper-point.point-se:before {
+ position: absolute;
+ right: -50%;
+ bottom: -50%;
+ display: block;
+ width: 200%;
+ height: 200%;
+ content: " ";
+ background-color: #69f;
+ filter: alpha(opacity=0);
+ opacity: 0
+ }
+
+@media (min-width:768px) {
+ .cropper-point.point-se {
+ width: 15px;
+ height: 15px
+ }
+}
+
+@media (min-width:992px) {
+ .cropper-point.point-se {
+ width: 10px;
+ height: 10px
+ }
+}
+
+@media (min-width:1200px) {
+ .cropper-point.point-se {
+ width: 5px;
+ height: 5px;
+ filter: alpha(opacity=75);
+ opacity: .75
+ }
+}
+
+.cropper-bg {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC)
+}
+
+.cropper-invisible {
+ filter: alpha(opacity=0);
+ opacity: 0
+}
+
+.cropper-hide {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: -1;
+ width: auto !important;
+ min-width: 0 !important;
+ max-width: none !important;
+ height: auto !important;
+ min-height: 0 !important;
+ max-height: none !important;
+ filter: alpha(opacity=0);
+ opacity: 0
+}
+
+.cropper-hidden {
+ display: none !important
+}
+
+.cropper-move {
+ cursor: move
+}
+
+.cropper-crop {
+ cursor: crosshair
+}
+
+.cropper-disabled .cropper-canvas, .cropper-disabled .cropper-face, .cropper-disabled .cropper-line, .cropper-disabled .cropper-point {
+ cursor: not-allowed
+}
diff --git a/component/layui/lay/extends/cropper.js b/component/layui/lay/extends/cropper.js
new file mode 100644
index 0000000000000000000000000000000000000000..6d774977cbafa228bd022693c5e939aa68f919a1
--- /dev/null
+++ b/component/layui/lay/extends/cropper.js
@@ -0,0 +1,3087 @@
+/*!
+ * Cropper v3.0.0
+ */
+
+layui.define(['jquery'], function (exports) {
+ var $ = layui.jquery;
+ $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
+
+ var DEFAULTS = {
+ // Define the view mode of the cropper
+ viewMode: 0, // 0, 1, 2, 3
+
+ // Define the dragging mode of the cropper
+ dragMode: 'crop', // 'crop', 'move' or 'none'
+
+ // Define the aspect ratio of the crop box
+ aspectRatio: NaN,
+
+ // An object with the previous cropping result data
+ data: null,
+
+ // A selector for adding extra containers to preview
+ preview: '',
+
+ // Re-render the cropper when resize the window
+ responsive: true,
+
+ // Restore the cropped area after resize the window
+ restore: true,
+
+ // Check if the current image is a cross-origin image
+ checkCrossOrigin: true,
+
+ // Check the current image's Exif Orientation information
+ checkOrientation: true,
+
+ // Show the black modal
+ modal: true,
+
+ // Show the dashed lines for guiding
+ guides: true,
+
+ // Show the center indicator for guiding
+ center: true,
+
+ // Show the white modal to highlight the crop box
+ highlight: true,
+
+ // Show the grid background
+ background: true,
+
+ // Enable to crop the image automatically when initialize
+ autoCrop: true,
+
+ // Define the percentage of automatic cropping area when initializes
+ autoCropArea: 0.8,
+
+ // Enable to move the image
+ movable: true,
+
+ // Enable to rotate the image
+ rotatable: true,
+
+ // Enable to scale the image
+ scalable: true,
+
+ // Enable to zoom the image
+ zoomable: true,
+
+ // Enable to zoom the image by dragging touch
+ zoomOnTouch: true,
+
+ // Enable to zoom the image by wheeling mouse
+ zoomOnWheel: true,
+
+ // Define zoom ratio when zoom the image by wheeling mouse
+ wheelZoomRatio: 0.1,
+
+ // Enable to move the crop box
+ cropBoxMovable: true,
+
+ // Enable to resize the crop box
+ cropBoxResizable: true,
+
+ // Toggle drag mode between "crop" and "move" when click twice on the cropper
+ toggleDragModeOnDblclick: true,
+
+ // Size limitation
+ minCanvasWidth: 0,
+ minCanvasHeight: 0,
+ minCropBoxWidth: 0,
+ minCropBoxHeight: 0,
+ minContainerWidth: 200,
+ minContainerHeight: 100,
+
+ // Shortcuts of events
+ ready: null,
+ cropstart: null,
+ cropmove: null,
+ cropend: null,
+ crop: null,
+ zoom: null
+ };
+
+ var TEMPLATE = '
' + '
' + '
' + '
' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
' + '
';
+
+ var REGEXP_DATA_URL_HEAD = /^data:.*,/;
+ var REGEXP_USERAGENT = /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i;
+ var navigator = typeof window !== 'undefined' ? window.navigator : null;
+ var IS_SAFARI_OR_UIWEBVIEW = navigator && REGEXP_USERAGENT.test(navigator.userAgent);
+ var fromCharCode = String.fromCharCode;
+
+ function isNumber(n) {
+ return typeof n === 'number' && !isNaN(n);
+ }
+
+ function isUndefined(n) {
+ return typeof n === 'undefined';
+ }
+
+ function toArray(obj, offset) {
+ var args = [];
+
+ // This is necessary for IE8
+ if (isNumber(offset)) {
+ args.push(offset);
+ }
+
+ return args.slice.apply(obj, args);
+ }
+
+ // Custom proxy to avoid jQuery's guid
+ function proxy(fn, context) {
+ for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
+ args[_key - 2] = arguments[_key];
+ }
+
+ return function () {
+ for (var _len2 = arguments.length, args2 = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+ args2[_key2] = arguments[_key2];
+ }
+
+ return fn.apply(context, args.concat(toArray(args2)));
+ };
+ }
+
+ function objectKeys(obj) {
+ var keys = [];
+
+ $.each(obj, function (key) {
+ keys.push(key);
+ });
+
+ return keys;
+ }
+
+ function isCrossOriginURL(url) {
+ var parts = url.match(/^(https?:)\/\/([^:/?#]+):?(\d*)/i);
+
+ return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port);
+ }
+
+ function addTimestamp(url) {
+ var timestamp = 'timestamp=' + new Date().getTime();
+
+ return url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp;
+ }
+
+ function getImageSize(image, callback) {
+ // Modern browsers (ignore Safari, #120 & #509)
+ if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) {
+ callback(image.naturalWidth, image.naturalHeight);
+ return;
+ }
+
+ // IE8: Don't use `new Image()` here (#319)
+ var newImage = document.createElement('img');
+
+ newImage.onload = function load() {
+ callback(this.width, this.height);
+ };
+
+ newImage.src = image.src;
+ }
+
+ function getTransform(options) {
+ var transforms = [];
+ var translateX = options.translateX;
+ var translateY = options.translateY;
+ var rotate = options.rotate;
+ var scaleX = options.scaleX;
+ var scaleY = options.scaleY;
+
+ if (isNumber(translateX) && translateX !== 0) {
+ transforms.push('translateX(' + translateX + 'px)');
+ }
+
+ if (isNumber(translateY) && translateY !== 0) {
+ transforms.push('translateY(' + translateY + 'px)');
+ }
+
+ // Rotate should come first before scale to match orientation transform
+ if (isNumber(rotate) && rotate !== 0) {
+ transforms.push('rotate(' + rotate + 'deg)');
+ }
+
+ if (isNumber(scaleX) && scaleX !== 1) {
+ transforms.push('scaleX(' + scaleX + ')');
+ }
+
+ if (isNumber(scaleY) && scaleY !== 1) {
+ transforms.push('scaleY(' + scaleY + ')');
+ }
+
+ return transforms.length ? transforms.join(' ') : 'none';
+ }
+
+ function getRotatedSizes(data, isReversed) {
+ var deg = Math.abs(data.degree) % 180;
+ var arc = (deg > 90 ? 180 - deg : deg) * Math.PI / 180;
+ var sinArc = Math.sin(arc);
+ var cosArc = Math.cos(arc);
+ var width = data.width;
+ var height = data.height;
+ var aspectRatio = data.aspectRatio;
+ var newWidth = void 0;
+ var newHeight = void 0;
+
+ if (!isReversed) {
+ newWidth = width * cosArc + height * sinArc;
+ newHeight = width * sinArc + height * cosArc;
+ } else {
+ newWidth = width / (cosArc + sinArc / aspectRatio);
+ newHeight = newWidth / aspectRatio;
+ }
+
+ return {
+ width: newWidth,
+ height: newHeight
+ };
+ }
+
+ function getSourceCanvas(image, data, options) {
+ var canvas = $('