diff --git a/public/static/plugs/layui_exts/cascader.css b/public/static/plugs/layui_exts/cascader.css
new file mode 100644
index 000000000..2997f818c
--- /dev/null
+++ b/public/static/plugs/layui_exts/cascader.css
@@ -0,0 +1,1654 @@
+.el-cascader-panel .layui-icon, .el-cascader .layui-icon {
+ font-size: 12px;
+}
+
+/* layui表单验证不通过颜色 */
+.layui-form-danger + .el-cascader .el-input__inner {
+ border-color: #FF5722 !important;
+}
+
+/* 在layui表单中宽度自动撑满 */
+.layui-form .el-cascader {
+ width: 100%;
+}
+
+/*弹出面板*/
+.el-popper .popper__arrow, .el-popper .popper__arrow:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid
+}
+
+.el-popper .popper__arrow {
+ border-width: 6px;
+ filter: drop-shadow(0 2px 12px rgba(0, 0, 0, .03))
+}
+
+.el-popper .popper__arrow:after {
+ content: " ";
+ border-width: 6px
+}
+
+.el-popper[x-placement^=top] {
+ margin-bottom: 12px
+}
+
+.el-popper[x-placement^=top] .popper__arrow {
+ bottom: -6px;
+ left: 50%;
+ margin-right: 3px;
+ border-top-color: #ebeef5;
+ border-bottom-width: 0
+}
+
+.el-popper[x-placement^=top] .popper__arrow:after {
+ bottom: 1px;
+ margin-left: -6px;
+ border-top-color: #fff;
+ border-bottom-width: 0
+}
+
+.el-popper[x-placement^=bottom] {
+ margin-top: 12px
+}
+
+.el-popper[x-placement^=bottom] .popper__arrow {
+ top: -6px;
+ left: 50%;
+ margin-right: 3px;
+ border-top-width: 0;
+ border-bottom-color: #ebeef5
+}
+
+.el-popper[x-placement^=bottom] .popper__arrow:after {
+ top: 1px;
+ margin-left: -6px;
+ border-top-width: 0;
+ border-bottom-color: #fff
+}
+
+.el-popper[x-placement^=right] {
+ margin-left: 12px
+}
+
+.el-popper[x-placement^=right] .popper__arrow {
+ top: 50%;
+ left: -6px;
+ margin-bottom: 3px;
+ border-right-color: #ebeef5;
+ border-left-width: 0
+}
+
+.el-popper[x-placement^=right] .popper__arrow:after {
+ bottom: -6px;
+ left: 1px;
+ border-right-color: #fff;
+ border-left-width: 0
+}
+
+.el-popper[x-placement^=left] {
+ margin-right: 12px
+}
+
+.el-popper[x-placement^=left] .popper__arrow {
+ top: 50%;
+ right: -6px;
+ margin-bottom: 3px;
+ border-right-width: 0;
+ border-left-color: #ebeef5
+}
+
+.el-popper[x-placement^=left] .popper__arrow:after {
+ right: 1px;
+ bottom: -6px;
+ margin-left: -6px;
+ border-right-width: 0;
+ border-left-color: #fff
+}
+
+.el-tag {
+ background-color: #ecf5ff;
+ display: inline-block;
+ height: 32px;
+ padding: 0 10px;
+ line-height: 30px;
+ font-size: 12px;
+ color: #409eff;
+ border: 1px solid #d9ecff;
+ border-radius: 4px;
+ box-sizing: border-box;
+ white-space: nowrap
+}
+
+.el-tag.is-hit {
+ border-color: #409eff
+}
+
+.el-tag .el-tag__close {
+ color: #409eff
+}
+
+.el-tag .el-tag__close:hover {
+ color: #fff;
+ background-color: #409eff
+}
+
+.el-tag.el-tag--info {
+ background-color: #f4f4f5;
+ border-color: #e9e9eb;
+ color: #909399
+}
+
+.el-tag.el-tag--info.is-hit {
+ border-color: #909399
+}
+
+.el-tag.el-tag--info .el-tag__close {
+ color: #909399
+}
+
+.el-tag.el-tag--info .el-tag__close:hover {
+ color: #fff;
+ background-color: #909399
+}
+
+.el-tag.el-tag--success {
+ background-color: #f0f9eb;
+ border-color: #e1f3d8;
+ color: #67c23a
+}
+
+.el-tag.el-tag--success.is-hit {
+ border-color: #67c23a
+}
+
+.el-tag.el-tag--success .el-tag__close {
+ color: #67c23a
+}
+
+.el-tag.el-tag--success .el-tag__close:hover {
+ color: #fff;
+ background-color: #67c23a
+}
+
+.el-tag.el-tag--warning {
+ background-color: #fdf6ec;
+ border-color: #faecd8;
+ color: #e6a23c
+}
+
+.el-tag.el-tag--warning.is-hit {
+ border-color: #e6a23c
+}
+
+.el-tag.el-tag--warning .el-tag__close {
+ color: #e6a23c
+}
+
+.el-tag.el-tag--warning .el-tag__close:hover {
+ color: #fff;
+ background-color: #e6a23c
+}
+
+.el-tag.el-tag--danger {
+ background-color: #fef0f0;
+ border-color: #fde2e2;
+ color: #f56c6c
+}
+
+.el-tag.el-tag--danger.is-hit {
+ border-color: #f56c6c
+}
+
+.el-tag.el-tag--danger .el-tag__close {
+ color: #f56c6c
+}
+
+.el-tag.el-tag--danger .el-tag__close:hover {
+ color: #fff;
+ background-color: #f56c6c
+}
+
+.el-tag .el-icon-close {
+ border-radius: 50%;
+ text-align: center;
+ position: relative;
+ cursor: pointer;
+ font-size: 12px;
+ height: 16px;
+ width: 16px;
+ line-height: 16px;
+ vertical-align: middle;
+ top: -1px;
+ right: -5px
+}
+
+.el-tag .el-icon-close:before {
+ display: block
+}
+
+.el-tag--dark {
+ background-color: #409eff;
+ color: #fff
+}
+
+.el-tag--dark, .el-tag--dark.is-hit {
+ border-color: #409eff
+}
+
+.el-tag--dark .el-tag__close {
+ color: #fff
+}
+
+.el-tag--dark .el-tag__close:hover {
+ color: #fff;
+ background-color: #66b1ff
+}
+
+.el-tag--dark.el-tag--info {
+ background-color: #909399;
+ border-color: #909399;
+ color: #fff
+}
+
+.el-tag--dark.el-tag--info.is-hit {
+ border-color: #909399
+}
+
+.el-tag--dark.el-tag--info .el-tag__close {
+ color: #fff
+}
+
+.el-tag--dark.el-tag--info .el-tag__close:hover {
+ color: #fff;
+ background-color: #a6a9ad
+}
+
+.el-tag--dark.el-tag--success {
+ background-color: #67c23a;
+ border-color: #67c23a;
+ color: #fff
+}
+
+.el-tag--dark.el-tag--success.is-hit {
+ border-color: #67c23a
+}
+
+.el-tag--dark.el-tag--success .el-tag__close {
+ color: #fff
+}
+
+.el-tag--dark.el-tag--success .el-tag__close:hover {
+ color: #fff;
+ background-color: #85ce61
+}
+
+.el-tag--dark.el-tag--warning {
+ background-color: #e6a23c;
+ border-color: #e6a23c;
+ color: #fff
+}
+
+.el-tag--dark.el-tag--warning.is-hit {
+ border-color: #e6a23c
+}
+
+.el-tag--dark.el-tag--warning .el-tag__close {
+ color: #fff
+}
+
+.el-tag--dark.el-tag--warning .el-tag__close:hover {
+ color: #fff;
+ background-color: #ebb563
+}
+
+.el-tag--dark.el-tag--danger {
+ background-color: #f56c6c;
+ border-color: #f56c6c;
+ color: #fff
+}
+
+.el-tag--dark.el-tag--danger.is-hit {
+ border-color: #f56c6c
+}
+
+.el-tag--dark.el-tag--danger .el-tag__close {
+ color: #fff
+}
+
+.el-tag--dark.el-tag--danger .el-tag__close:hover {
+ color: #fff;
+ background-color: #f78989
+}
+
+.el-tag--plain {
+ background-color: #fff;
+ border-color: #b3d8ff;
+ color: #409eff
+}
+
+.el-tag--plain.is-hit {
+ border-color: #409eff
+}
+
+.el-tag--plain .el-tag__close {
+ color: #409eff
+}
+
+.el-tag--plain .el-tag__close:hover {
+ color: #fff;
+ background-color: #409eff
+}
+
+.el-tag--plain.el-tag--info {
+ background-color: #fff;
+ border-color: #d3d4d6;
+ color: #909399
+}
+
+.el-tag--plain.el-tag--info.is-hit {
+ border-color: #909399
+}
+
+.el-tag--plain.el-tag--info .el-tag__close {
+ color: #909399
+}
+
+.el-tag--plain.el-tag--info .el-tag__close:hover {
+ color: #fff;
+ background-color: #909399
+}
+
+.el-tag--plain.el-tag--success {
+ background-color: #fff;
+ border-color: #c2e7b0;
+ color: #67c23a
+}
+
+.el-tag--plain.el-tag--success.is-hit {
+ border-color: #67c23a
+}
+
+.el-tag--plain.el-tag--success .el-tag__close {
+ color: #67c23a
+}
+
+.el-tag--plain.el-tag--success .el-tag__close:hover {
+ color: #fff;
+ background-color: #67c23a
+}
+
+.el-tag--plain.el-tag--warning {
+ background-color: #fff;
+ border-color: #f5dab1;
+ color: #e6a23c
+}
+
+.el-tag--plain.el-tag--warning.is-hit {
+ border-color: #e6a23c
+}
+
+.el-tag--plain.el-tag--warning .el-tag__close {
+ color: #e6a23c
+}
+
+.el-tag--plain.el-tag--warning .el-tag__close:hover {
+ color: #fff;
+ background-color: #e6a23c
+}
+
+.el-tag--plain.el-tag--danger {
+ background-color: #fff;
+ border-color: #fbc4c4;
+ color: #f56c6c
+}
+
+.el-tag--plain.el-tag--danger.is-hit {
+ border-color: #f56c6c
+}
+
+.el-tag--plain.el-tag--danger .el-tag__close {
+ color: #f56c6c
+}
+
+.el-tag--plain.el-tag--danger .el-tag__close:hover {
+ color: #fff;
+ background-color: #f56c6c
+}
+
+.el-tag--medium {
+ height: 28px;
+ line-height: 26px
+}
+
+.el-tag--medium .el-icon-close {
+ transform: scale(.8)
+}
+
+.el-tag--small {
+ height: 24px;
+ padding: 0 8px;
+ line-height: 22px
+}
+
+.el-tag--small .el-icon-close {
+ transform: scale(.8)
+}
+
+.el-tag--mini {
+ height: 20px;
+ padding: 0 5px;
+ line-height: 19px
+}
+
+.el-tag--mini .el-icon-close {
+ margin-left: -3px;
+ transform: scale(.7)
+}
+
+.el-checkbox {
+ color: #606266;
+ font-weight: 500;
+ font-size: 14px;
+ position: relative;
+ cursor: pointer;
+ display: inline-block;
+ white-space: nowrap;
+ user-select: none;
+ margin-right: 30px
+}
+
+.el-checkbox.is-bordered {
+ padding: 9px 20px 9px 10px;
+ border-radius: 4px;
+ border: 1px solid #dcdfe6;
+ box-sizing: border-box;
+ line-height: normal;
+ height: 40px
+}
+
+.el-checkbox.is-bordered.is-checked {
+ border-color: #409eff
+}
+
+.el-checkbox.is-bordered.is-disabled {
+ border-color: #ebeef5;
+ cursor: not-allowed
+}
+
+.el-checkbox.is-bordered + .el-checkbox.is-bordered {
+ margin-left: 10px
+}
+
+.el-checkbox.is-bordered.el-checkbox--medium {
+ padding: 7px 20px 7px 10px;
+ border-radius: 4px;
+ height: 36px
+}
+
+.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label {
+ line-height: 17px;
+ font-size: 14px
+}
+
+.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner {
+ height: 14px;
+ width: 14px
+}
+
+.el-checkbox.is-bordered.el-checkbox--small {
+ padding: 5px 15px 5px 10px;
+ border-radius: 3px;
+ height: 32px
+}
+
+.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label {
+ line-height: 15px;
+ font-size: 12px
+}
+
+.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner {
+ height: 12px;
+ width: 12px
+}
+
+.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner:after {
+ height: 6px;
+ width: 2px
+}
+
+.el-checkbox.is-bordered.el-checkbox--mini {
+ padding: 3px 15px 3px 10px;
+ border-radius: 3px;
+ height: 28px
+}
+
+.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label {
+ line-height: 12px;
+ font-size: 12px
+}
+
+.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner {
+ height: 12px;
+ width: 12px
+}
+
+.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner:after {
+ height: 6px;
+ width: 2px
+}
+
+.el-checkbox__input {
+ white-space: nowrap;
+ cursor: pointer;
+ outline: none;
+ display: inline-block;
+ line-height: 1;
+ position: relative;
+ vertical-align: middle
+}
+
+.el-checkbox__input.is-disabled .el-checkbox__inner {
+ background-color: #edf2fc;
+ border-color: #dcdfe6;
+ cursor: not-allowed
+}
+
+.el-checkbox__input.is-disabled .el-checkbox__inner:after {
+ cursor: not-allowed;
+ border-color: #c0c4cc
+}
+
+.el-checkbox__input.is-disabled .el-checkbox__inner + .el-checkbox__label {
+ cursor: not-allowed
+}
+
+.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner {
+ background-color: #f2f6fc;
+ border-color: #dcdfe6
+}
+
+.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner:after {
+ border-color: #c0c4cc
+}
+
+.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner {
+ background-color: #f2f6fc;
+ border-color: #dcdfe6
+}
+
+.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner:before {
+ background-color: #c0c4cc;
+ border-color: #c0c4cc
+}
+
+.el-checkbox__input.is-disabled + span.el-checkbox__label {
+ color: #c0c4cc;
+ cursor: not-allowed
+}
+
+.el-checkbox__input.is-checked .el-checkbox__inner {
+ background-color: #409eff;
+ border-color: #409eff;
+}
+
+.el-checkbox__input.is-checked .el-checkbox__inner:after {
+ transform: rotate(45deg) scaleY(1);
+}
+
+.el-checkbox__input.is-checked + .el-checkbox__label {
+ color: #409eff
+}
+
+.el-checkbox__input.is-focus .el-checkbox__inner {
+ border-color: #409eff
+}
+
+.el-checkbox__input.is-indeterminate .el-checkbox__inner {
+ background-color: #409eff;
+ border-color: #409eff
+}
+
+.el-checkbox__input.is-indeterminate .el-checkbox__inner:before {
+ content: "";
+ position: absolute;
+ display: block;
+ background-color: #fff;
+ height: 2px;
+ transform: scale(.5);
+ left: 0;
+ right: 0;
+ top: 5px
+}
+
+.el-checkbox__input.is-indeterminate .el-checkbox__inner:after {
+ display: none
+}
+
+.el-checkbox__inner {
+ display: inline-block;
+ position: relative;
+ border: 1px solid #dcdfe6;
+ border-radius: 2px;
+ box-sizing: border-box;
+ width: 14px;
+ height: 14px;
+ background-color: #fff;
+ z-index: 1;
+ transition: border-color .25s cubic-bezier(.71, -.46, .29, 1.46), background-color .25s cubic-bezier(.71, -.46, .29, 1.46);
+}
+
+.el-checkbox__inner:hover {
+ border-color: #409eff
+}
+
+.el-checkbox__inner:after {
+ box-sizing: content-box;
+ content: "";
+ border: 1px solid #fff;
+ border-left: 0;
+ border-top: 0;
+ height: 7px;
+ left: 4px;
+ position: absolute;
+ top: 1px;
+ transform: rotate(45deg) scaleY(0);
+ width: 3px;
+ transition: transform .15s ease-in .05s;
+ transform-origin: center
+}
+
+.el-checkbox__original {
+ opacity: 0;
+ outline: none;
+ position: absolute;
+ margin: 0;
+ width: 0;
+ height: 0;
+ z-index: -1
+}
+
+.el-checkbox__label {
+ display: inline-block;
+ padding-left: 10px;
+ line-height: 19px;
+ font-size: 14px
+}
+
+.el-checkbox:last-of-type {
+ margin-right: 0
+}
+
+.el-checkbox-button, .el-checkbox-button__inner {
+ position: relative;
+ display: inline-block
+}
+
+.el-checkbox-button__inner {
+ line-height: 1;
+ font-weight: 500;
+ white-space: nowrap;
+ vertical-align: middle;
+ cursor: pointer;
+ background: #fff;
+ border: 1px solid #dcdfe6;
+ border-left: 0;
+ color: #606266;
+ -webkit-appearance: none;
+ text-align: center;
+ box-sizing: border-box;
+ outline: none;
+ margin: 0;
+ transition: all .3s cubic-bezier(.645, .045, .355, 1);
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ -ms-user-select: none;
+ padding: 12px 20px;
+ font-size: 14px;
+ border-radius: 0
+}
+
+.el-checkbox-button__inner.is-round {
+ padding: 12px 20px
+}
+
+.el-checkbox-button__inner:hover {
+ color: #409eff
+}
+
+.el-checkbox-button__inner [class*=el-icon-] {
+ line-height: .9
+}
+
+.el-checkbox-button__inner [class*=el-icon-] + span {
+ margin-left: 5px
+}
+
+.el-checkbox-button__original {
+ opacity: 0;
+ outline: none;
+ position: absolute;
+ margin: 0;
+ z-index: -1
+}
+
+.el-checkbox-button.is-checked .el-checkbox-button__inner {
+ color: #fff;
+ background-color: #409eff;
+ border-color: #409eff;
+ box-shadow: -1px 0 0 0 #8cc5ff
+}
+
+.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner {
+ border-left-color: #409eff
+}
+
+.el-checkbox-button.is-disabled .el-checkbox-button__inner {
+ color: #c0c4cc;
+ cursor: not-allowed;
+ background-image: none;
+ background-color: #fff;
+ border-color: #ebeef5;
+ box-shadow: none
+}
+
+.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner {
+ border-left-color: #ebeef5
+}
+
+.el-checkbox-button:first-child .el-checkbox-button__inner {
+ border-left: 1px solid #dcdfe6;
+ border-radius: 4px 0 0 4px;
+ box-shadow: none !important
+}
+
+.el-checkbox-button.is-focus .el-checkbox-button__inner {
+ border-color: #409eff
+}
+
+.el-checkbox-button:last-child .el-checkbox-button__inner {
+ border-radius: 0 4px 4px 0
+}
+
+.el-checkbox-button--medium .el-checkbox-button__inner {
+ padding: 10px 20px;
+ font-size: 14px;
+ border-radius: 0
+}
+
+.el-checkbox-button--medium .el-checkbox-button__inner.is-round {
+ padding: 10px 20px
+}
+
+.el-checkbox-button--small .el-checkbox-button__inner {
+ padding: 9px 15px;
+ font-size: 12px;
+ border-radius: 0
+}
+
+.el-checkbox-button--small .el-checkbox-button__inner.is-round {
+ padding: 9px 15px
+}
+
+.el-checkbox-button--mini .el-checkbox-button__inner {
+ padding: 7px 15px;
+ font-size: 12px;
+ border-radius: 0
+}
+
+.el-checkbox-button--mini .el-checkbox-button__inner.is-round {
+ padding: 7px 15px
+}
+
+.el-checkbox-group {
+ font-size: 0
+}
+
+.el-radio {
+ color: #606266;
+ font-weight: 500;
+ line-height: 1;
+ position: relative;
+ cursor: pointer;
+ display: inline-block;
+ white-space: nowrap;
+ outline: none;
+ font-size: 14px;
+ margin-right: 30px;
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ -ms-user-select: none
+}
+
+.el-radio.is-bordered {
+ padding: 12px 20px 0 10px;
+ border-radius: 4px;
+ border: 1px solid #dcdfe6;
+ box-sizing: border-box;
+ height: 40px
+}
+
+.el-radio.is-bordered.is-checked {
+ border-color: #409eff
+}
+
+.el-radio.is-bordered.is-disabled {
+ cursor: not-allowed;
+ border-color: #ebeef5
+}
+
+.el-radio.is-bordered + .el-radio.is-bordered {
+ margin-left: 10px
+}
+
+.el-radio--medium.is-bordered {
+ padding: 10px 20px 0 10px;
+ border-radius: 4px;
+ height: 36px
+}
+
+.el-radio--medium.is-bordered .el-radio__label {
+ font-size: 14px
+}
+
+.el-radio--medium.is-bordered .el-radio__inner {
+ height: 14px;
+ width: 14px
+}
+
+.el-radio--small.is-bordered {
+ padding: 8px 15px 0 10px;
+ border-radius: 3px;
+ height: 32px
+}
+
+.el-radio--small.is-bordered .el-radio__label {
+ font-size: 12px
+}
+
+.el-radio--small.is-bordered .el-radio__inner {
+ height: 12px;
+ width: 12px
+}
+
+.el-radio--mini.is-bordered {
+ padding: 6px 15px 0 10px;
+ border-radius: 3px;
+ height: 28px
+}
+
+.el-radio--mini.is-bordered .el-radio__label {
+ font-size: 12px
+}
+
+.el-radio--mini.is-bordered .el-radio__inner {
+ height: 12px;
+ width: 12px
+}
+
+.el-radio:last-child {
+ margin-right: 0
+}
+
+.el-radio__input {
+ white-space: nowrap;
+ cursor: pointer;
+ outline: none;
+ display: inline-block;
+ line-height: 1;
+ position: relative;
+ vertical-align: middle
+}
+
+.el-radio__input.is-disabled .el-radio__inner {
+ background-color: #f5f7fa;
+ border-color: #e4e7ed;
+ cursor: not-allowed
+}
+
+.el-radio__input.is-disabled .el-radio__inner:after {
+ cursor: not-allowed;
+ background-color: #f5f7fa
+}
+
+.el-radio__input.is-disabled .el-radio__inner + .el-radio__label {
+ cursor: not-allowed
+}
+
+.el-radio__input.is-disabled.is-checked .el-radio__inner {
+ background-color: #f5f7fa;
+ border-color: #e4e7ed
+}
+
+.el-radio__input.is-disabled.is-checked .el-radio__inner:after {
+ background-color: #c0c4cc
+}
+
+.el-radio__input.is-disabled + span.el-radio__label {
+ color: #c0c4cc;
+ cursor: not-allowed
+}
+
+.el-radio__input.is-checked .el-radio__inner {
+ border-color: #409eff;
+ background: #409eff
+}
+
+.el-radio__input.is-checked .el-radio__inner:after {
+ transform: translate(-50%, -50%) scale(1)
+}
+
+.el-radio__input.is-checked + .el-radio__label {
+ color: #409eff
+}
+
+.el-radio__input.is-focus .el-radio__inner {
+ border-color: #409eff
+}
+
+.el-radio__inner {
+ border: 1px solid #dcdfe6;
+ border-radius: 100%;
+ width: 14px;
+ height: 14px;
+ background-color: #fff;
+ position: relative;
+ cursor: pointer;
+ display: inline-block;
+ box-sizing: border-box
+}
+
+.el-radio__inner:hover {
+ border-color: #409eff
+}
+
+.el-radio__inner:after {
+ width: 4px;
+ height: 4px;
+ border-radius: 100%;
+ background-color: #fff;
+ content: "";
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%) scale(0);
+ transition: transform .15s ease-in
+}
+
+.el-radio__original {
+ opacity: 0;
+ outline: none;
+ position: absolute;
+ z-index: -1;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ margin: 0
+}
+
+.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner {
+ /*box-shadow: 0 0 2px 2px #409eff*/
+}
+
+/*滚动条*/
+.el-scrollbar {
+ overflow: hidden;
+ position: relative
+}
+
+.el-scrollbar:active > .el-scrollbar__bar, .el-scrollbar:focus > .el-scrollbar__bar, .el-scrollbar:hover > .el-scrollbar__bar {
+ opacity: 1;
+ transition: opacity .34s ease-out
+}
+
+.el-scrollbar__wrap {
+ overflow: scroll;
+ height: 100%
+}
+
+.el-scrollbar__wrap--hidden-default {
+ scrollbar-width: none
+}
+
+.el-scrollbar__wrap--hidden-default::-webkit-scrollbar {
+ width: 0;
+ height: 0
+}
+
+.el-scrollbar__thumb {
+ position: relative;
+ display: block;
+ width: 0;
+ height: 0;
+ cursor: pointer;
+ border-radius: inherit;
+ background-color: rgba(144, 147, 153, .3);
+ transition: background-color .3s
+}
+
+.el-scrollbar__thumb:hover {
+ background-color: rgba(144, 147, 153, .5)
+}
+
+.el-scrollbar__bar {
+ position: absolute;
+ right: 2px;
+ bottom: 2px;
+ z-index: 1;
+ border-radius: 4px;
+ opacity: 0;
+ transition: opacity .12s ease-out
+}
+
+.el-scrollbar__bar.is-vertical {
+ width: 6px;
+ top: 2px
+}
+
+.el-scrollbar__bar.is-vertical > div {
+ width: 100%
+}
+
+.el-scrollbar__bar.is-horizontal {
+ height: 6px;
+ left: 2px
+}
+
+.el-scrollbar__bar.is-horizontal > div {
+ height: 100%
+}
+
+.el-cascader {
+ display: inline-block;
+ position: relative;
+ font-size: 14px;
+ line-height: 40px
+}
+
+.el-cascader:not(.is-disabled):hover .el-input__inner {
+ cursor: pointer;
+ border-color: #c0c4cc
+}
+
+.el-cascader .el-input {
+ cursor: pointer
+}
+
+.el-cascader .el-input .el-input__inner {
+ text-overflow: ellipsis
+}
+
+.el-cascader .el-input .el-input__inner:focus {
+ border-color: #409eff
+}
+
+.el-cascader .el-input .el-icon-arrow-down {
+ display: inline-block;
+ transition: transform .3s;
+ font-size: 14px
+}
+
+.el-cascader .el-input .el-icon-arrow-down.is-reverse {
+ transform: rotate(180deg)
+}
+
+.el-cascader .el-input .el-icon-circle-close:hover {
+ color: #909399
+}
+
+.el-cascader .el-input.is-focus .el-input__inner {
+ border-color: #409eff
+}
+
+.el-cascader--medium {
+ font-size: 14px;
+ line-height: 36px
+}
+
+.el-cascader--small {
+ font-size: 13px;
+ line-height: 32px
+}
+
+.el-cascader--mini {
+ font-size: 12px;
+ line-height: 28px
+}
+
+.el-cascader.is-disabled .el-cascader__label {
+ z-index: 2;
+ color: #c0c4cc
+}
+
+.el-cascader__dropdown {
+ margin: 5px 0;
+ font-size: 14px;
+ background: #fff;
+ border: 1px solid #e4e7ed;
+ border-radius: 4px;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1)
+}
+
+.el-cascader__tags {
+ position: absolute;
+ left: 0;
+ right: 30px;
+ top: 50%;
+ transform: translateY(-50%);
+ display: flex;
+ flex-wrap: wrap;
+ line-height: normal;
+ text-align: left;
+ box-sizing: border-box
+}
+
+.el-cascader__tags .el-tag {
+ display: inline-flex;
+ align-items: center;
+ max-width: 100%;
+ margin: 2px 0 2px 6px;
+ text-overflow: ellipsis;
+ background: #f0f2f5
+}
+
+.el-cascader__tags .el-tag:not(.is-hit) {
+ border-color: transparent
+}
+
+.el-cascader__tags .el-tag > span {
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis
+}
+
+.el-cascader__tags .el-tag .el-icon-close {
+ flex: none;
+ background-color: #c0c4cc;
+ color: #fff
+}
+
+.el-cascader__tags .el-tag .el-icon-close:hover {
+ background-color: #909399
+}
+
+.el-cascader__suggestion-panel {
+ border-radius: 4px
+}
+
+.el-cascader__suggestion-list {
+ max-height: 204px;
+ margin: 0;
+ padding: 6px 0;
+ font-size: 14px;
+ color: #606266;
+ text-align: center
+}
+
+.el-cascader__suggestion-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ height: 34px;
+ padding: 0 15px;
+ text-align: left;
+ outline: none;
+ cursor: pointer
+}
+
+.el-cascader__suggestion-item:focus, .el-cascader__suggestion-item:hover {
+ background: #f5f7fa
+}
+
+.el-cascader__suggestion-item.is-checked {
+ color: #409eff;
+ font-weight: 700
+}
+
+.el-cascader__suggestion-item .el-icon-check {
+ margin-right: 15px;
+}
+
+.el-cascader__suggestion-item > span {
+ margin-right: 10px
+}
+
+.el-cascader__empty-text {
+ margin: 10px 0;
+ color: #c0c4cc
+}
+
+.el-cascader__search-input {
+ flex: 1;
+ height: 24px;
+ min-width: 60px;
+ margin: 2px 0 2px 15px;
+ padding: 0;
+ color: #606266;
+ border: none;
+ outline: none;
+ box-sizing: border-box
+}
+
+.el-cascader__search-input::placeholder {
+ color: #c0c4cc
+}
+
+/*cascader面板*/
+.el-cascader-panel {
+ display: flex;
+ border-radius: 4px;
+ font-size: 14px
+}
+
+.el-cascader-panel.is-bordered {
+ border: 1px solid #e4e7ed;
+ border-radius: 4px
+}
+
+.el-cascader-menu {
+ min-width: 180px;
+ box-sizing: border-box;
+ color: #606266;
+ border-right: 1px solid #e4e7ed
+}
+
+.el-cascader-menu:last-child {
+ border-right: none
+}
+
+.el-cascader-menu:last-child .el-cascader-node {
+ padding-right: 26px
+}
+
+.el-cascader-menu__wrap {
+ height: 204px
+}
+
+.el-cascader-menu__list {
+ position: relative;
+ min-height: 100%;
+ padding: 6px 0;
+ list-style: none;
+ box-sizing: border-box;
+}
+
+.el-cascader-menu__hover-zone {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none
+}
+
+.el-cascader-menu__empty-text {
+ position: absolute;
+ top: 50%;
+ left: 46%;
+ transform: translate(-50%, -50%);
+ text-align: center;
+ color: #c0c4cc
+}
+
+.el-cascader-node {
+ position: relative;
+ display: flex;
+ align-items: center;
+ padding: 0 25px 0 15px;
+ height: 34px;
+ line-height: 34px;
+ outline: none
+}
+
+.el-cascader-node.is-selectable.in-active-path {
+ color: #606266
+}
+
+.el-cascader-node.in-active-path, .el-cascader-node.is-active, .el-cascader-node.is-selectable.in-checked-path {
+ color: #409eff;
+ font-weight: 700
+}
+
+.el-cascader-node:not(.is-disabled) {
+ cursor: pointer
+}
+
+.el-cascader-node:not(.is-disabled):focus, .el-cascader-node:not(.is-disabled):hover {
+ background: #f5f7fa
+}
+
+.el-cascader-node.is-disabled {
+ color: #c0c4cc;
+ cursor: not-allowed
+}
+
+.el-cascader-node__prefix {
+ position: absolute;
+ left: 10px
+}
+
+.el-cascader-node__postfix {
+ position: absolute;
+ right: 10px
+}
+
+.el-cascader-node__label {
+ flex: 1;
+ padding: 0 10px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis
+}
+
+.el-cascader-node > .el-radio {
+ margin-right: 0
+}
+
+.el-cascader-node > .el-radio .el-radio__label {
+ padding-left: 0
+}
+
+/*输入框*/
+.el-input {
+ position: relative;
+ font-size: 14px;
+ display: inline-block;
+ width: 100%
+}
+
+.el-input::-webkit-scrollbar {
+ z-index: 11;
+ width: 6px
+}
+
+.el-input::-webkit-scrollbar:horizontal {
+ height: 6px
+}
+
+.el-input::-webkit-scrollbar-thumb {
+ border-radius: 5px;
+ width: 6px;
+ background: #b4bccc
+}
+
+.el-input::-webkit-scrollbar-corner, .el-input::-webkit-scrollbar-track {
+ background: #fff
+}
+
+.el-input::-webkit-scrollbar-track-piece {
+ background: #fff;
+ width: 6px
+}
+
+.el-input .el-input__clear {
+ color: #c0c4cc;
+ font-size: 14px;
+ cursor: pointer;
+ transition: color .2s cubic-bezier(.645, .045, .355, 1)
+}
+
+.el-input .el-input__clear:hover {
+ color: #909399
+}
+
+.el-input .el-input__count {
+ height: 100%;
+ display: inline-flex;
+ align-items: center;
+ color: #909399;
+ font-size: 12px
+}
+
+.el-input .el-input__count .el-input__count-inner {
+ background: #fff;
+ line-height: normal;
+ display: inline-block;
+ padding: 0 5px
+}
+
+.el-input__inner {
+ -webkit-appearance: none;
+ background-color: #fff;
+ background-image: none;
+ border-radius: 4px;
+ border: 1px solid #dcdfe6;
+ box-sizing: border-box;
+ color: #606266;
+ display: inline-block;
+ font-size: inherit;
+ height: 40px;
+ line-height: 40px;
+ outline: none;
+ padding: 0 15px;
+ transition: border-color .2s cubic-bezier(.645, .045, .355, 1);
+ width: 100%
+}
+
+.el-input__inner::-ms-reveal {
+ display: none
+}
+
+.el-input__inner::placeholder {
+ color: #c0c4cc
+}
+
+.el-input__inner:hover {
+ border-color: #c0c4cc
+}
+
+.el-input__inner:focus {
+ outline: none;
+ border-color: #409eff
+}
+
+.el-input__suffix {
+ position: absolute;
+ height: 100%;
+ right: 5px;
+ top: 0;
+ text-align: center;
+ color: #c0c4cc;
+ transition: all .3s;
+ pointer-events: none;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.el-input__suffix-inner {
+ pointer-events: all
+}
+
+.el-input__prefix {
+ position: absolute;
+ left: 5px;
+ top: 0;
+ color: #c0c4cc
+}
+
+.el-input__icon, .el-input__prefix {
+ height: 100%;
+ text-align: center;
+ transition: all .3s
+}
+
+.el-input__icon {
+ width: 25px;
+ line-height: 40px
+}
+
+.el-input__icon:after {
+ content: "";
+ height: 100%;
+ width: 0;
+ display: inline-block;
+ vertical-align: middle
+}
+
+.el-input__validateIcon {
+ pointer-events: none
+}
+
+.el-input.is-active .el-input__inner {
+ outline: none;
+ border-color: #409eff
+}
+
+.el-input.is-disabled .el-input__inner {
+ background-color: #f5f7fa;
+ border-color: #e4e7ed;
+ color: #c0c4cc;
+ cursor: not-allowed
+}
+
+.el-input.is-disabled .el-input__inner::placeholder {
+ color: #c0c4cc
+}
+
+.el-input.is-disabled .el-input__icon {
+ cursor: not-allowed
+}
+
+.el-input.is-exceed .el-input__inner {
+ border-color: #f56c6c
+}
+
+.el-input.is-exceed .el-input__suffix .el-input__count {
+ color: #f56c6c
+}
+
+.el-input--suffix .el-input__inner {
+ padding-right: 30px
+}
+
+.el-input--prefix .el-input__inner {
+ padding-left: 30px
+}
+
+.el-input--medium {
+ font-size: 14px
+}
+
+.el-input--medium .el-input__inner {
+ height: 36px;
+ line-height: 36px
+}
+
+.el-input--medium .el-input__icon {
+ line-height: 36px
+}
+
+.el-input--small {
+ font-size: 13px
+}
+
+.el-input--small .el-input__inner {
+ height: 32px;
+ line-height: 32px
+}
+
+.el-input--small .el-input__icon {
+ line-height: 32px
+}
+
+.el-input--mini {
+ font-size: 12px
+}
+
+.el-input--mini .el-input__inner {
+ height: 28px;
+ line-height: 28px
+}
+
+.el-input--mini .el-input__icon {
+ line-height: 28px
+}
+
+.el-input-group {
+ line-height: normal;
+ display: inline-table;
+ width: 100%;
+ border-collapse: separate;
+ border-spacing: 0
+}
+
+.el-input-group > .el-input__inner {
+ vertical-align: middle;
+ display: table-cell
+}
+
+.el-input-group__append, .el-input-group__prepend {
+ background-color: #f5f7fa;
+ color: #909399;
+ vertical-align: middle;
+ display: table-cell;
+ position: relative;
+ border: 1px solid #dcdfe6;
+ border-radius: 4px;
+ padding: 0 20px;
+ width: 1px;
+ white-space: nowrap
+}
+
+.el-input-group__append:focus, .el-input-group__prepend:focus {
+ outline: none
+}
+
+.el-input-group__append .el-button, .el-input-group__append .el-select, .el-input-group__prepend .el-button, .el-input-group__prepend .el-select {
+ display: inline-block;
+ margin: -10px -20px
+}
+
+.el-input-group__append button.el-button, .el-input-group__append div.el-select .el-input__inner, .el-input-group__append div.el-select:hover .el-input__inner, .el-input-group__prepend button.el-button, .el-input-group__prepend div.el-select .el-input__inner, .el-input-group__prepend div.el-select:hover .el-input__inner {
+ border-color: transparent;
+ background-color: transparent;
+ color: inherit;
+ border-top: 0;
+ border-bottom: 0
+}
+
+.el-input-group__append .el-button, .el-input-group__append .el-input, .el-input-group__prepend .el-button, .el-input-group__prepend .el-input {
+ font-size: inherit
+}
+
+.el-input-group__prepend {
+ border-right: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0
+}
+
+.el-input-group__append {
+ border-left: 0
+}
+
+.el-input-group--prepend .el-input__inner, .el-input-group__append {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0
+}
+
+.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner {
+ border-color: transparent
+}
+
+.el-input-group--append .el-input__inner {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0
+}
+
+.el-input-group--append .el-select .el-input.is-focus .el-input__inner {
+ border-color: transparent
+}
+
+.el-input__inner::-ms-clear {
+ display: none;
+ width: 0;
+ height: 0
+}
+
+::-webkit-scrollbar {
+ width: 0;
+}
diff --git a/public/static/plugs/layui_exts/cascader.js b/public/static/plugs/layui_exts/cascader.js
new file mode 100644
index 000000000..229b233af
--- /dev/null
+++ b/public/static/plugs/layui_exts/cascader.js
@@ -0,0 +1,2085 @@
+/**
+ * 仿element-ui,级联选择器
+ * 已实现单选、多选、无关联选择
+ * 其他功能:组件禁用、节点禁用、自定义属性、自定义空面板提示,自定义无选择时的提示、多选标签折叠、回显、搜索、动态加载、最大选中数量限制、禁用项固定等操作。
+ * element-ui没有的功能:最大选中数量限制、禁用项固定
+ * author: yixiaco
+ * gitee: https://gitee.com/yixiacoco/lay_cascader
+ * github: https://github.com/yixiaco/lay_cascader
+ */
+layui.define(["jquery"], function (exports) {
+ var $ = layui.jquery;
+
+ /**
+ * 级联各项节点对象
+ * @param data 原始对象信息
+ * @param cascader 级联对象
+ * @param level 层级,从0开始
+ * @param parentNode 父节点对象
+ * @constructor
+ */
+ function Node(data, cascader, level, parentNode) {
+ this.data = data;
+ this.cascader = cascader;
+ this.config = cascader.config;
+ this.props = cascader.props;
+ this.level = level;
+ this.parentNode = parentNode;
+ // 引入的icon图标
+ this.icons = cascader.icons;
+ //该节点是否被选中 0:未选中,1:选中,2:不定
+ this._checked = 0;
+ // 是否正在加载中
+ this._loading = false;
+ // 每个Node的唯一标识
+ this.nodeId = cascader.data.nodeId++;
+ }
+
+ Node.prototype = {
+ constructor: Node,
+ /** 最顶级父节点 */
+ get topParentNode() {
+ return !this.parentNode && this || this.topParentNode;
+ },
+ /** 子节点 */
+ childrenNode: undefined,
+ get loading() {
+ return this._loading;
+ },
+ set loading(loading) {
+ var $li = this.$li;
+ if ($li) {
+ var rightIcon = this.icons.right;
+ var loadingIcon = this.icons.loading;
+ var $i = $li.find('i');
+ if (loading) {
+ $i.addClass(loadingIcon);
+ $i.removeClass(rightIcon);
+ } else {
+ $i.addClass(rightIcon);
+ $i.removeClass(loadingIcon);
+ }
+ }
+ return this._loading = loading;
+ },
+ /** 当前节点的显示文本 */
+ get label() {
+ return this.data[this.props.label];
+ },
+ /** 当前节点的值 */
+ get value() {
+ return this.data[this.props.value];
+ },
+ /** 是否禁用 */
+ get disabled() {
+ var multiple = this.props.multiple;
+ var maxSize = this.config.maxSize;
+ var checkedNodeIds = this.cascader.data.checkedNodeIds;
+ var disabledName = this.props.disabled;
+ var checkStrictly = this.props.checkStrictly;
+ // 检查是否超过最大值限制
+ if (multiple && maxSize !== 0) {
+ if (checkedNodeIds.length >= maxSize && checkedNodeIds.indexOf(this.nodeId) === -1) {
+ // 如果是关联的多选,需要查询叶子节点是否有被选中的项
+ if (!checkStrictly) {
+ var leafChildren = this.getAllLeafChildren();
+ var nodeIds = leafChildren.map(function (value) {
+ return value.nodeId
+ });
+ // 如果叶子节点不包含,则直接返回true
+ if (!nodeIds.some(function (nodeId) {
+ return checkedNodeIds.indexOf(nodeId) !== -1;
+ })) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+ }
+ if (!checkStrictly) {
+ var path = this.path;
+ return path.some(function (node) {
+ return node.data[disabledName];
+ });
+ } else {
+ return this.data[disabledName];
+ }
+ },
+ /** 子节点数据 */
+ get children() {
+ return this.data[this.props.children];
+ },
+ set children(children) {
+ this.data[this.props.children] = children;
+ },
+ /** 叶子节点 */
+ get leaf() {
+ var leaf = this.data[this.props.leaf];
+ if (typeof leaf === 'boolean') {
+ return leaf;
+ }
+ // 如果children不为空,则判断是否是子节点
+ if (this.children) {
+ return this.children.length <= 0;
+ }
+ return true;
+ },
+ /** 当前单选值 */
+ get activeNodeId() {
+ return this.cascader.data.activeNodeId;
+ },
+ /** 当前复选框值 */
+ get checkedNodeIds() {
+ return this.cascader.data.checkedNodeIds;
+ },
+ /** 路径 */
+ get path() {
+ var parentNode = this.parentNode;
+ if (parentNode) {
+ return parentNode.path.concat([this]);
+ } else {
+ return [this];
+ }
+ },
+ /** 是否正在搜索中 */
+ get isFiltering() {
+ return this.cascader.isFiltering;
+ },
+ /** 输入框的tag标签 */
+ get $tag() {
+ var cascader = this.cascader;
+ var showAllLevels = this.config.showAllLevels;
+ var disabled = this.config.disabled;
+ var nodeDisabled = this.disabled;
+ var disabledFixed = this.config.disabledFixed;
+
+ var label = this.getPathLabel(showAllLevels);
+ var $tag = cascader.get$tag(label, !disabled && (!nodeDisabled || !disabledFixed));
+ var self = this;
+ $tag.find('i').click(function (event) {
+ event.stopPropagation();
+ self.selectedValue();
+ cascader.removeTag(self.value, self);
+ });
+ return $tag;
+ },
+ /**
+ * 完整路径的标签
+ * @param showAllLevels
+ * @returns {string}
+ */
+ getPathLabel: function (showAllLevels) {
+ var path = this.path;
+ var separator = this.config.separator;
+
+ var label;
+ if (showAllLevels) {
+ label = path.map(function (node) {
+ return node.label;
+ }).join(separator);
+ } else {
+ label = path[path.length - 1].label;
+ }
+ return label;
+ },
+ /**
+ * 初始化
+ */
+ init: function () {
+ var multiple = this.props.multiple;
+ var checkStrictly = this.props.checkStrictly;
+ var fromIcon = this.icons.from;
+ var rightIcon = this.icons.right;
+ var icon = '';
+ var label = this.label;
+ if (!this.leaf) {
+ icon = rightIcon;
+ }
+ this.$li = $('
');
+
+ // 节点渲染
+ if (!multiple && !checkStrictly) {
+ this._renderRadio();
+ } else if (!multiple && checkStrictly) {
+ this._renderRadioCheckStrictly();
+ } else if (multiple && !checkStrictly) {
+ this._renderMultiple();
+ } else if (multiple && checkStrictly) {
+ this._renderMultipleCheckStrictly();
+ }
+ },
+ /**
+ * 初始化可搜索li
+ */
+ initSuggestionLi: function () {
+ var label = this.getPathLabel(true);
+ this.$suggestionLi = $('' + label + '');
+ // 节点渲染
+ this._renderFiltering();
+ },
+ /**
+ * 绑定到菜单中
+ * @param $list li节点
+ */
+ bind: function ($list) {
+ this.init();
+ $list.append(this.$li);
+ },
+ /**
+ * 绑定可搜索到列表中
+ * @param $list
+ */
+ bindSuggestion: function ($list) {
+ this.initSuggestionLi();
+ $list.append(this.$suggestionLi);
+ },
+ /**
+ * 可搜索渲染
+ * @private
+ */
+ _renderFiltering: function () {
+ var $li = this.$suggestionLi;
+ var nodeId = this.nodeId;
+ var fromIcon = this.icons.from;
+ var okIcon = this.icons.ok;
+ var self = this;
+ var cascader = this.cascader;
+ var multiple = this.props.multiple;
+
+ var icon = '';
+ $li.click(function (event) {
+ event.stopPropagation();
+ self.selectedValue();
+ if (multiple) {
+ if (self.checkedNodeIds.indexOf(nodeId) === -1) {
+ $li.removeClass('is-checked');
+ $li.find('.el-icon-check').remove();
+ } else {
+ $li.addClass('is-checked');
+ $li.append(icon);
+ }
+ } else {
+ // 关闭面板
+ cascader.close();
+ }
+ });
+
+ if (multiple && self.checkedNodeIds.indexOf(nodeId) !== -1
+ || !multiple && self.activeNodeId === nodeId) {
+ $li.addClass('is-checked');
+ $li.append(icon)
+ }
+ },
+ /**
+ * 单选&&关联
+ * @private
+ */
+ _renderRadio: function () {
+ var $li = this.$li;
+ var nodeId = this.nodeId;
+ var fromIcon = this.icons.from;
+ var okIcon = this.icons.ok;
+ var level = this.level;
+ var leaf = this.leaf;
+ var self = this;
+ var cascader = this.cascader;
+ var activeNode = this.cascader.data.activeNode;
+ var parentNode = this.parentNode;
+
+ if (self.activeNodeId && activeNode.path.some(function (node) {
+ return node.nodeId === nodeId;
+ })) {
+ if (self.activeNodeId === nodeId) {
+ $li.prepend('');
+ }
+ $li.addClass('is-active');
+ $li.addClass('in-checked-path');
+ }
+
+ // 是否禁用
+ if (this.disabled) {
+ $li.addClass('is-disabled');
+ return;
+ }
+
+ $li.addClass('is-selectable');
+
+ if (parentNode) {
+ parentNode.$li.siblings().removeClass('in-active-path');
+ parentNode.$li.addClass('in-active-path');
+ }
+
+ // 触发下一个节点
+ this._liClick(function (event) {
+ event.stopPropagation();
+ var childrenNode = self.childrenNode;
+ if (leaf && event.type === 'click') {
+ self.selectedValue();
+ // 关闭面板
+ cascader.close();
+ }
+ // 添加下级菜单
+ cascader._appendMenu(childrenNode, level + 1, self);
+ });
+ },
+ /**
+ * 单选&&非关联
+ * @private
+ */
+ _renderRadioCheckStrictly: function () {
+ var $li = this.$li;
+ var nodeId = this.nodeId;
+ var level = this.level;
+ var leaf = this.leaf;
+ var self = this;
+ var cascader = this.cascader;
+ var activeNode = cascader.data.activeNode;
+ var parentNode = this.parentNode;
+
+ $li.addClass('is-selectable');
+ // 任意一级单选
+ var $radio = $('');
+ this.$radio = $radio;
+ $li.prepend($radio);
+ if (parentNode) {
+ parentNode.$li.siblings().removeClass('in-active-path');
+ parentNode.$li.addClass('in-active-path');
+ }
+
+ // 触发下一个节点
+ this._liClick(function (event) {
+ event.stopPropagation();
+ var childrenNode = self.childrenNode;
+ if (!self.disabled && leaf && event.type === 'click') {
+ self.selectedValue();
+ }
+ // 添加下级菜单
+ cascader._appendMenu(childrenNode, level + 1, self);
+ });
+
+ if (self.activeNodeId && activeNode.path.some(function (node) {
+ return node.nodeId === nodeId;
+ })) {
+ if (self.activeNodeId === nodeId) {
+ $radio.find('.el-radio__input').addClass('is-checked');
+ }
+ $li.addClass('is-active');
+ $li.addClass('in-checked-path');
+ }
+
+ if (this.disabled) {
+ $radio.addClass('is-disabled');
+ $radio.find('.el-radio__input').addClass('is-disabled');
+ return;
+ }
+ // 选中事件
+ $radio.click(function (event) {
+ event.preventDefault();
+ !leaf && self.selectedValue();
+ });
+ },
+ /**
+ * 多选&&关联
+ * @private
+ */
+ _renderMultiple: function () {
+ var $li = this.$li;
+ var level = this.level;
+ var leaf = this.leaf;
+ var self = this;
+ var cascader = this.cascader;
+ var checked = this._checked;
+ var parentNode = this.parentNode;
+
+ $li.addClass('el-cascader-node');
+
+ // 多选框
+ var $checked = $('');
+ this.$checked = $checked;
+ $li.prepend($checked);
+
+ // 渲染
+ if (checked === 1) {
+ this.$checked.find('.el-checkbox__input').addClass('is-checked');
+ } else if (checked === 2) {
+ this.$checked.find('.el-checkbox__input').addClass('is-indeterminate');
+ }
+
+ if (parentNode) {
+ parentNode.$li.siblings().removeClass('in-active-path');
+ parentNode.$li.addClass('in-active-path');
+ }
+
+ // 触发下一个节点
+ this._liClick(function (event) {
+ event.stopPropagation();
+ var childrenNode = self.childrenNode;
+ if (!self.disabled && leaf && event.type === 'click') {
+ // 最后一级就默认选择
+ self.selectedValue();
+ }
+ // 添加下级菜单
+ cascader._appendMenu(childrenNode, level + 1, self);
+ });
+
+ if (this.disabled) {
+ $li.addClass('is-disabled');
+ $checked.addClass('is-disabled');
+ $checked.find('.el-checkbox__input').addClass('is-disabled');
+ return;
+ }
+
+ // 选中事件
+ $checked.click(function (event) {
+ event.preventDefault();
+ if (!leaf) {
+ var childrenNode = self.childrenNode;
+ self.selectedValue();
+ cascader._appendMenu(childrenNode, level + 1, self);
+ }
+ });
+ },
+ /**
+ * 多选&&非关联
+ * @private
+ */
+ _renderMultipleCheckStrictly: function () {
+ var $li = this.$li;
+ var level = this.level;
+ var leaf = this.leaf;
+ var self = this;
+ var cascader = this.cascader;
+ var checkedNodeIds = cascader.data.checkedNodeIds;
+ var checkedNodes = cascader.data.checkedNodes;
+ var nodeId = this.nodeId;
+ var parentNode = this.parentNode;
+
+ $li.addClass('el-cascader-node is-selectable');
+
+ // 多选框
+ var $checked = $('');
+ this.$checked = $checked;
+ $li.prepend($checked);
+
+ // 渲染
+ var exist = checkedNodes.some(function (node) {
+ return node.path.some(function (node) {
+ return node.nodeId === nodeId;
+ })
+ });
+ if (exist) {
+ $li.addClass('in-checked-path');
+ if (checkedNodeIds.indexOf(nodeId) !== -1) {
+ this.$checked.find('.el-checkbox__input').addClass('is-checked');
+ }
+ }
+
+ if (parentNode) {
+ parentNode.$li.siblings().removeClass('in-active-path');
+ parentNode.$li.addClass('in-active-path');
+ }
+
+ // 触发下一个节点
+ this._liClick(function (event) {
+ event.stopPropagation();
+ var childrenNode = self.childrenNode;
+ if (!self.disabled && leaf && event.type === 'click') {
+ // 最后一级就默认选择
+ self.selectedValue();
+ }
+ // 添加下级菜单
+ cascader._appendMenu(childrenNode, level + 1, self);
+ });
+
+ if (this.disabled) {
+ $checked.addClass('is-disabled');
+ $checked.find('.el-checkbox__input').addClass('is-disabled');
+ return;
+ }
+ // 选中事件
+ $checked.click(function (event) {
+ event.preventDefault();
+ if (!leaf) {
+ self.selectedValue();
+ var childrenNode = self.childrenNode;
+ // 添加下级菜单
+ cascader._appendMenu(childrenNode, level + 1, self);
+ }
+ });
+ },
+ /**
+ * 向上传递
+ * @param callback 执行方法,如果返回false,则中断执行
+ * @param advance 是否先执行一次
+ * @param self 自身
+ */
+ transferParent: function (callback, advance, self) {
+ if (!self) {
+ self = this;
+ }
+ if (this !== self || advance) {
+ var goOn = callback && callback(this);
+ if (goOn === false) {
+ return;
+ }
+ }
+ this.parentNode && this.parentNode.transferParent(callback, advance, self);
+ },
+ /**
+ * 向下传递
+ * @param callback 执行的方法,如果返回false,则中断执行
+ * @param advance 是否先执行一次
+ * @param self 自身
+ */
+ transferChildren: function (callback, advance, self) {
+ if (!self) {
+ self = this;
+ }
+ if (this !== self || advance) {
+ var goOn = callback && callback(this);
+ if (goOn === false) {
+ return;
+ }
+ }
+ var children = this.getChildren();
+ if (children && children.length > 0) {
+ for (var index in children) {
+ children[index].transferChildren(callback, advance, self);
+ }
+ }
+ },
+ /**
+ * 设置级联值
+ */
+ selectedValue: function () {
+ var nodeId = this.nodeId;
+ var cascader = this.cascader;
+ var multiple = this.props.multiple;
+ var checkStrictly = this.props.checkStrictly;
+ var leaf = this.leaf;
+ if (!multiple && (leaf || checkStrictly)) {
+ cascader._setActiveValue(nodeId, this);
+ } else if (multiple) {
+ var checkedNodeIds = cascader.data.checkedNodeIds;
+ var checkedNodes = cascader.data.checkedNodes;
+ var disabledFixed = this.config.disabledFixed;
+ var paths;
+ if (checkStrictly) {
+ var index = checkedNodeIds.indexOf(nodeId);
+ if (index === -1) {
+ paths = checkedNodes.concat([this]);
+ } else {
+ paths = checkedNodes.concat();
+ paths.splice(index, 1);
+ }
+ } else {
+ var allLeafChildren = this.getAllLeafChildren();
+ var checked;
+ if (this._checked !== 1 && disabledFixed) {
+ checked = this._getMultipleChecked(allLeafChildren);
+ } else {
+ checked = this._checked;
+ }
+ if (checked === 1) {
+ // 选中->未选中
+ paths = checkedNodes.filter(function (node1) {
+ return !allLeafChildren.some(function (node2) {
+ return node1.nodeId === node2.nodeId;
+ });
+ });
+ } else {
+ // 未选中、部分选中->选中
+ var add = allLeafChildren.filter(function (node) {
+ return checkedNodeIds.indexOf(node.nodeId) === -1;
+ });
+ paths = checkedNodes.concat(add);
+ }
+ }
+ var nodeIds = paths.map(function (node) {
+ return node.nodeId;
+ });
+ cascader._setCheckedValue(nodeIds, paths);
+ }
+ },
+ _liLoad: function (event, callback) {
+ var leaf = this.leaf;
+ var lazy = this.props.lazy;
+ var lazyLoad = this.props.lazyLoad;
+ var children = this.children;
+ var self = this;
+ var cascader = this.cascader;
+ var level = this.level;
+ var multiple = this.props.multiple;
+ var checkStrictly = this.props.checkStrictly;
+ if (!leaf && (!children || children.length === 0) && lazy) {
+ if (!self.loading) {
+ self.loading = true;
+ lazyLoad(self, function (nodes) {
+ self.loading = false;
+ self.setChildren(cascader.initNodes(nodes, level + 1, self));
+ self.children = nodes;
+ callback && callback(event);
+ // 多选&关联时,重新同步下父级节点的样式
+ multiple && !checkStrictly && self.transferParent(function (node) {
+ node.syncStyle();
+ }, true);
+ });
+ }
+ } else {
+ callback && callback(event);
+ }
+ },
+ /**
+ * 点击li事件
+ * @param callback
+ * @private
+ */
+ _liClick: function (callback) {
+ var leaf = this.leaf;
+ var $li = this.$li;
+ var self = this;
+
+ function load(event) {
+ self._liLoad(event, callback);
+ }
+
+ if (this.props.expandTrigger === "click" || leaf) {
+ $li.click(load);
+ }
+ if (this.props.expandTrigger === "hover") {
+ $li.mouseenter(load);
+ }
+ },
+ setChildren: function (children) {
+ this.childrenNode = children;
+ },
+ getChildren: function () {
+ return this.childrenNode;
+ },
+ /**
+ * 同步样式
+ */
+ syncStyle: function () {
+ var multiple = this.props.multiple;
+ var checkStrictly = this.props.checkStrictly;
+ if (multiple) {
+ //多选
+ if (checkStrictly) {
+ this._sync.syncMultipleCheckStrictly(this);
+ } else {
+ this._sync.syncMultiple(this);
+ }
+ } else {
+ //单选
+ if (checkStrictly) {
+ this._sync.syncRadioCheckStrictly(this);
+ } else {
+ this._sync.syncRadio(this);
+ }
+ }
+ },
+ /**
+ * 同步本节点样式
+ */
+ _sync: {
+ /**
+ * 同步单选关联样式
+ */
+ syncRadio: function (self) {
+ var $li = self.$li;
+ var fromIcon = self.icons.from;
+ var okIcon = self.icons.ok;
+ var multiple = self.props.multiple;
+ var checkStrictly = self.props.checkStrictly;
+ var nodeId = self.nodeId;
+ if (!$li || multiple || checkStrictly) {
+ return;
+ }
+ var activeNode = self.cascader.data.activeNode;
+ if (self.activeNodeId === nodeId) {
+ var ok = $li.find('.' + okIcon);
+ if (ok.length === 0) {
+ $li.prepend('');
+ }
+ } else {
+ $li.find('.' + okIcon).remove();
+ }
+ if (activeNode && activeNode.path.some(function (node) {
+ return node.nodeId === nodeId;
+ })) {
+ $li.addClass('is-active');
+ $li.addClass('in-checked-path');
+ } else {
+ $li.removeClass('is-active');
+ $li.removeClass('in-checked-path');
+ }
+ },
+ /**
+ * 同步单选非关联样式
+ */
+ syncRadioCheckStrictly: function (self) {
+ var $li = self.$li;
+ var checkStrictly = self.props.checkStrictly;
+ var multiple = self.props.multiple;
+ if (!$li || multiple || !checkStrictly) {
+ return;
+ }
+ var $radio = self.$radio;
+ var activeNode = self.cascader.data.activeNode;
+ var nodeId = self.nodeId;
+ if (self.activeNodeId === nodeId) {
+ $radio.find('.el-radio__input').addClass('is-checked');
+ } else {
+ $radio.find('.el-radio__input').removeClass('is-checked');
+ }
+ if (activeNode && activeNode.path.some(function (node) {
+ return node.nodeId === nodeId;
+ })) {
+ $li.addClass('is-active');
+ $li.addClass('in-checked-path');
+ } else {
+ $li.removeClass('is-active');
+ $li.removeClass('in-checked-path');
+ }
+ },
+ /**
+ * 同步多选关联样式
+ */
+ syncMultiple: function (self) {
+ var $li = self.$li;
+ var checkStrictly = self.props.checkStrictly;
+ var multiple = self.props.multiple;
+ var disabledFixed = self.config.disabledFixed;
+ if (!multiple || checkStrictly) {
+ return;
+ }
+ var allLeafChildren = self.getAllLeafChildren(disabledFixed);
+ // 全部未选中 0
+ // 全部选中 1
+ // 部分选中 2
+ var checked = self._getMultipleChecked(allLeafChildren);
+ self._checked = checked;
+ if (!$li) {
+ return;
+ }
+ var $checkbox = self.$checked.find('.el-checkbox__input');
+ if (checked === 0) {
+ $checkbox.removeClass('is-checked');
+ $checkbox.removeClass('is-indeterminate');
+ } else if (checked === 1) {
+ $checkbox.removeClass('is-indeterminate');
+ $checkbox.addClass('is-checked');
+ } else if (checked === 2) {
+ $checkbox.removeClass('is-checked');
+ $checkbox.addClass('is-indeterminate');
+ }
+ },
+ /**
+ * 同步多选非关联样式
+ */
+ syncMultipleCheckStrictly: function (self) {
+ var $li = self.$li;
+ var checkStrictly = self.props.checkStrictly;
+ var multiple = self.props.multiple;
+ if (!$li || !multiple || !checkStrictly) {
+ return;
+ }
+ var checkedNodes = self.cascader.data.checkedNodes;
+ var checkedNodeIds = self.checkedNodeIds;
+ var nodeId = self.nodeId;
+ var exist = checkedNodes.some(function (node) {
+ return node.path.some(function (node) {
+ return node.nodeId === nodeId;
+ });
+ });
+ var $checkbox = self.$checked.find('.el-checkbox__input');
+ if (checkedNodeIds.some(function (checkedNodeId) {
+ return checkedNodeId === nodeId;
+ })) {
+ // 选中
+ $checkbox.addClass('is-checked');
+ } else {
+ // 未选中
+ $checkbox.removeClass('is-checked');
+ }
+ if (exist) {
+ $li.addClass('in-checked-path');
+ } else {
+ $li.removeClass('in-checked-path');
+ }
+ }
+ },
+ /**
+ * 获取叶子节点value值
+ * @param disabled 是否包含禁用,默认不包含
+ * @returns {Node[]|*[]}
+ */
+ getAllLeafChildren: function (disabled) {
+ var leaf = this.leaf;
+ if (leaf) {
+ return [this];
+ } else {
+ var leafs = [];
+ this.transferChildren(function (node) {
+ if (node.disabled && !disabled) {
+ return false;
+ }
+ node.leaf && leafs.push(node);
+ });
+ return leafs;
+ }
+ },
+ /**
+ * 展开当前节点
+ */
+ expandPanel: function () {
+ var path = this.path;
+ var cascader = this.cascader;
+ path.forEach(function (node, index, array) {
+ if (index !== array.length - 1) {
+ var childrenNode = node.childrenNode;
+ cascader._appendMenu(childrenNode, node.level + 1, node.parentNode);
+ }
+ });
+ },
+ _getMultipleChecked: function (leafNodes) {
+ var cascader = this.cascader;
+ var checkedNodeIds = cascader.data.checkedNodeIds;
+ var allLeafIds = leafNodes.map(function (node) {
+ return node.nodeId;
+ });
+ // 全部未选中 0
+ // 全部选中 1
+ // 部分选中 2
+ var checked = 0;
+ for (var i = 0; i < allLeafIds.length; i++) {
+ var child = allLeafIds[i];
+ if (checked === 2) {
+ break;
+ }
+ if (checkedNodeIds.indexOf(child) !== -1) {
+ if (i > 0 && checked !== 1) {
+ checked = 2;
+ } else {
+ checked = 1;
+ }
+ } else {
+ // 当全部选中时,则改为部分选中,否则全部未选中
+ checked = checked === 1 ? 2 : 0;
+ }
+ }
+ return checked;
+ }
+ };
+
+ function Cascader(config) {
+ this.config = $.extend(true, {
+ elem: '', //绑定元素
+ value: null, //预设值
+ options: [], //可选项数据源,键名可通过 Props 属性配置
+ empty: '暂无数据', //无匹配选项时的内容
+ placeholder: '请选择',//输入框占位文本
+ disabled: false, //是否禁用
+ clearable: false, //是否支持清空选项
+ showAllLevels: true, //输入框中是否显示选中值的完整路径
+ collapseTags: false, //多选模式下是否折叠Tag
+ minCollapseTagsNumber: 1, //最小折叠标签数
+ separator: ' / ', //选项分隔符
+ filterable: false, //是否可搜索选项
+ filterMethod: function (node, keyword) {
+ return node.path.some(function (node) {
+ return node.label.indexOf(keyword) !== -1;
+ });
+ }, //自定义搜索逻辑,第一个参数是节点node,第二个参数是搜索关键词keyword,通过返回布尔值表示是否命中
+ debounce: 300, //搜索关键词输入的去抖延迟,毫秒
+ beforeFilter: function (value) {
+ return true;
+ },//筛选之前的钩子,参数为输入的值,若返回 false,则停止筛选
+ popperClass: '', // 自定义浮层类名 string
+ extendClass: false, //继承class样式
+ extendStyle: false, //继承style样式
+ disabledFixed: false, //固定禁用项,使禁用项不被清理删除,禁用项只能通过函数添加或初始值添加,默认禁用项不可被函数或初始值添加
+ maxSize: 0, // 多选选中的最大数量,0表示不限制
+ props: {
+ strictMode: false, //严格模式,设置value严格按照层级结构.例如:[[1,2,3],[1,2,4]]
+ expandTrigger: 'click', //次级菜单的展开方式 string click / hover 'click'
+ multiple: false, //是否多选 boolean - false
+ checkStrictly: false, //是否严格的遵守父子节点不互相关联 boolean - false
+ lazy: false, //是否动态加载子节点,需与 lazyLoad 方法结合使用 boolean - false
+ lazyLoad: function (node, resolve) {
+ }, //加载动态数据的方法,仅在 lazy 为 true 时有效 function(node, resolve),node为当前点击的节点,resolve为数据加载完成的回调(必须调用)
+ value: 'value', //指定选项的值为选项对象的某个属性值 string — 'value'
+ label: 'label', //指定选项标签为选项对象的某个属性值 string — 'label'
+ children: 'children', //指定选项的子选项为选项对象的某个属性值 string — 'children'
+ disabled: 'disabled', //指定选项的禁用为选项对象的某个属性值 string — 'disabled'
+ leaf: 'leaf' //指定选项的叶子节点的标志位为选项对象的某个属性值 string — 'leaf'
+ }
+ }, config);
+ this.data = {
+ nodeId: 1, //nodeId的自增值
+ nodes: [], //存储Node对象
+ menuData: [], //压入菜单的数据
+ activeNodeId: null, //存放NodeId
+ activeNode: null, //存放Node
+ checkedNodeIds: [], //存放多个NodeId
+ checkedNodes: [] //存放多个Node
+ };
+ // 面板是否展开
+ this.showPanel = false;
+ this.event = {
+ // 值变更事件
+ change: [],
+ // 打开事件
+ open: [],
+ // 关闭事件
+ close: []
+ }
+ // 是否正在搜索中
+ this.filtering = false;
+ // 初始化
+ this._init();
+ // 面板关闭事件id
+ this.closeEventId = 0;
+ // 是否进入maxSize模式
+ this._maxSizeMode = false;
+ }
+
+ Cascader.prototype = {
+ constructor: Cascader,
+ get props() {
+ return this.config.props;
+ },
+ get isFiltering() {
+ return this.filtering;
+ },
+ set isFiltering(filtering) {
+ if (this.filtering === filtering) {
+ return;
+ }
+ this.filtering = !!filtering;
+ var $panel = this.$panel;
+ if (this.filtering) {
+ $panel.find('.el-cascader-panel').hide();
+ $panel.find('.el-cascader__suggestion-panel').show();
+ } else {
+ $panel.find('.el-cascader-panel').show();
+ $panel.find('.el-cascader__suggestion-panel').hide();
+ this.$tagsInput && this.$tagsInput.val('')
+ }
+ },
+ set maxSizeMode(maxSizeMode) {
+ if (this._maxSizeMode !== maxSizeMode) {
+ this._maxSizeMode = maxSizeMode;
+ this.refreshMenu();
+ }
+ },
+ icons: {
+ from: 'layui-icon',
+ down: 'layui-icon-down',
+ close: 'layui-icon-close',
+ right: 'layui-icon-right',
+ ok: 'layui-icon-ok',
+ loading: 'layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop'
+ },
+ // 初始化
+ _init: function () {
+ this._checkConfig();
+ // 初始化输入框
+ this._initInput();
+ // 初始化面板
+ this._initPanel();
+ // 初始化选项值
+ this.setOptions(this.config.options);
+ var self = this;
+ // 监听滚动条
+ $(window).scroll(function () {
+ self._resetXY();
+ });
+ // 监听窗口
+ $(window).resize(function () {
+ self._resetXY();
+ });
+ // 点击事件,展开面板
+ this.$div.click(function (event) {
+ if (self.config.disabled) {
+ return;
+ }
+ var show = self.showPanel;
+ if (!show) {
+ self.open();
+ } else {
+ self.close();
+ }
+ });
+ },
+ /**
+ * 检查配置
+ * @private
+ */
+ _checkConfig: function () {
+ var elem = this.config.elem;
+ if (!elem || $(elem).length === 0) {
+ throw new Error("缺少elem节点选择器");
+ }
+ var maxSize = this.config.maxSize;
+ if (typeof maxSize !== 'number' || maxSize < 0) {
+ throw new Error("maxSize应是一个大于等于0的有效的number值");
+ }
+ if (!Array.isArray(this.config.options)) {
+ throw new Error("options不是一个有效的数组");
+ }
+ },
+ /**
+ * 初始化根目录
+ * @private
+ */
+ _initRoot: function () {
+ var lazy = this.props.lazy;
+ var lazyLoad = this.props.lazyLoad;
+ var self = this;
+ var nodes = this.data.nodes;
+ if (nodes.length > 0 || !lazy) {
+ this._appendMenu(nodes, 0);
+ } else if (lazy) {
+ this._appendMenu(nodes, 0);
+ lazyLoad({
+ root: true,
+ level: 0
+ }, function (nodes) {
+ self.data.nodes = self.initNodes(nodes, 0, null);
+ self._appendMenu(self.data.nodes, 0);
+ });
+ }
+ },
+ /**
+ * 设置选项值
+ * @param options
+ */
+ setOptions: function (options) {
+ this.config.options = options;
+ // 初始化节点
+ this.data.nodes = this.initNodes(options, 0, null);
+ // 初始化根目录
+ this._initRoot();
+ // 初始化值
+ this.setValue(this.config.value);
+ },
+ // 面板定位
+ _resetXY: function () {
+ var $div = this.$div;
+ var offset = $div.offset();
+ var $panel = this.$panel;
+ if ($panel) {
+ var windowHeight = window.innerHeight;
+ var windowWidth = window.innerWidth;
+ var panelHeight = $panel.height();
+ var panelWidth = $panel.width();
+ var divHeight = $div.height();
+ var boundingClientRect = $div[0].getBoundingClientRect();
+ var $arrow = $panel.find('.popper__arrow');
+
+ // 距离右边界的偏差值
+ var offsetDiff = Math.min(windowWidth - boundingClientRect.x - panelWidth - 5, 0);
+
+ var bottomHeight = windowHeight - (boundingClientRect.top + divHeight);
+ if (bottomHeight < panelHeight && boundingClientRect.top > panelHeight + 20) {
+ $panel.attr('x-placement', 'top-start')
+ // 向上
+ $panel.css({
+ top: offset.top - 20 - panelHeight + 'px',
+ left: offset.left + offsetDiff + 'px'
+ });
+ } else {
+ $panel.attr('x-placement', 'bottom-start');
+ // 距离底部边界的偏差值
+ var yOffset = Math.max(panelHeight - (windowHeight - boundingClientRect.y - divHeight - 15), 0);
+ // 向下
+ $panel.css({
+ top: offset.top + divHeight - yOffset + 'px',
+ left: offset.left + offsetDiff + 'px'
+ });
+ }
+ // 箭头偏移
+ $arrow.css("left", 35 - offsetDiff + "px");
+ }
+ },
+ get $menus() {
+ return this.$panel && this.$panel.find('.el-cascader-panel .el-cascader-menu');
+ },
+ // 初始化输入框
+ _initInput: function () {
+ var $e = $(this.config.elem);
+ var self = this;
+ // 当绑定的元素带有value属性,并且对象未设置值时,设置一个初始值
+ if (this.config.value === null && $e.attr('value')) {
+ this.config.value = $e.attr('value');
+ }
+ var placeholder = this.config.placeholder;
+ var fromIcon = this.icons.from;
+ var downIcon = this.icons.down;
+ var multiple = this.props.multiple;
+ var extendClass = this.config.extendClass;
+ var extendStyle = this.config.extendStyle;
+
+ this.$div = $('');
+ if (extendStyle) {
+ var style = $e.attr('style');
+ if (style) {
+ this.$div.attr('style', style);
+ }
+ }
+ if (extendClass) {
+ var className = $e.attr('class');
+ if (className) {
+ className.split(' ').forEach(function (name) {
+ self.$div.addClass(name);
+ });
+ }
+ }
+ this.$input = $('' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '
')
+ this.$div.append(this.$input);
+ this.$inputRow = this.$input.find('.el-input__inner');
+ // 多选标签
+ if (multiple) {
+ this.$tags = $('');
+ this.$div.append(this.$tags);
+ }
+ this._initHideElement($e);
+ // 替换元素
+ $e.replaceWith(this.$div);
+ this.$icon = this.$input.find('i');
+ this._initFilterableInputEvent();
+ this.disabled(this.config.disabled);
+ },
+ /**
+ * 初始化隐藏元素input,主要用于layui的表单验证
+ * @param $e
+ * @private
+ */
+ _initHideElement: function ($e) {
+ // 保存原始元素
+ var attributes = $e[0].attributes;
+ var $input = $('');
+ var keys = Object.keys(attributes);
+ for (var key in keys) {
+ var attribute = attributes[key];
+ $input.attr(attribute.name, attribute.value);
+ }
+ $input.hide();
+ $input.attr('type', 'hidden')
+ this.$ec = $input;
+ $e.before($input);
+ },
+ /**
+ * 初始化可搜索监听事件
+ * @private
+ */
+ _initFilterableInputEvent: function () {
+ var filterable = this.config.filterable;
+ if (!filterable) {
+ return;
+ }
+ var timeoutID;
+ var multiple = this.props.multiple;
+ var debounce = this.config.debounce;
+ var placeholder = this.config.placeholder;
+ var beforeFilter = this.config.beforeFilter;
+ var filterMethod = this.config.filterMethod;
+ var checkStrictly = this.props.checkStrictly;
+ var self = this;
+
+ function filter(event) {
+ var input = this;
+ if (timeoutID) {
+ clearTimeout(timeoutID);
+ }
+ timeoutID = setTimeout(function () {
+ timeoutID = null;
+ var val = $(input).val();
+ if (!val) {
+ self.isFiltering = false;
+ return;
+ }
+ self.open();
+ if (typeof beforeFilter === 'function' && beforeFilter(val)) {
+ self.isFiltering = true;
+ var nodes = self.getNodes();
+ var filterNodes = nodes.filter(function (node) {
+ var disabled;
+ if (checkStrictly) {
+ disabled = node.disabled;
+ } else {
+ disabled = node.path.some(function (node) {
+ return node.disabled;
+ });
+ }
+ if ((node.leaf || checkStrictly) && !disabled) {
+ if (typeof filterMethod === 'function' && filterMethod(node, val)) {
+ // 命中
+ return true;
+ }
+ }
+ return false;
+ });
+ self._setSuggestionMenu(filterNodes);
+ }
+ }, debounce);
+ }
+
+ if (multiple) {
+ // 多选可搜索
+ this.$tagsInput = $('');
+ var $tagsInput = this.$tagsInput;
+ this.$tags.append($tagsInput);
+ $tagsInput.on('keydown', filter);
+ $tagsInput.click(function (event) {
+ if (self.isFiltering) {
+ event.stopPropagation();
+ }
+ });
+ } else {
+ var $inputRow = this.$inputRow;
+ // 单选可搜索
+ $inputRow.removeAttr('readonly');
+ $inputRow.on('keydown', filter);
+ $inputRow.click(function (event) {
+ if (self.isFiltering) {
+ event.stopPropagation();
+ }
+ });
+ }
+ },
+ // 初始化面板(panel(1))
+ _initPanel: function () {
+ var $panel = this.$panel;
+ var popperClass = this.config.popperClass || '';
+ if (!$panel) {
+ // z-index:解决和layer.open默认19891016的冲突
+ this.$panel = $('');
+ $panel = this.$panel;
+ $panel.appendTo('body');
+ $panel.click(function (event) {
+ // 阻止事件冒泡
+ event.stopPropagation();
+ });
+ // 初始化可搜索面板
+ this._initSuggestionPanel();
+ }
+ },
+ /**
+ * 添加菜单(panel(1)->menu(n))
+ * @param nodes 当前层级数据
+ * @param level 层级,从0开始
+ * @param parentNode 父级节点
+ * @param _menuItem 刷新时,传入的当前菜单的item数据
+ * @private
+ */
+ _appendMenu: function (nodes, level, parentNode, _menuItem) {
+ this._removeMenu(level);
+
+ if (parentNode && parentNode.leaf) {
+ return;
+ }
+
+ var menuData = this.data.menuData;
+ var $div = $('');
+ // 重新添加菜单
+ this.$panel.find('.el-cascader-panel').append($div);
+ // 渲染细项
+ this._appendLi($div, nodes);
+ var menuItem = {nodes: nodes, level: level, parentNode: parentNode, scrollbar: {top: 0, left: 0}};
+ if (_menuItem) {
+ menuItem.scrollbar = _menuItem.scrollbar
+ }
+ // 渲染滚动条
+ this._initScrollbar($div, menuItem);
+ // 重新定位面板
+ this._resetXY();
+ menuData.push(menuItem);
+ },
+ /**
+ * 移除菜单
+ * @param level
+ * @private
+ */
+ _removeMenu: function(level) {
+ // 除了上一层的所有菜单全部移除
+ var number = level - 1;
+ if (number !== -1) {
+ this.$panel.find('.el-cascader-panel .el-cascader-menu:gt(' + number + ')').remove();
+ } else {
+ this.$panel.find('.el-cascader-panel .el-cascader-menu').remove();
+ }
+ // 保存菜单数据
+ var menuData = this.data.menuData;
+ if (menuData.length > level) {
+ menuData.splice(level, menuData.length - level);
+ }
+ },
+ /**
+ * 添加细项(panel(1)->menu(n)->li(n))
+ * @param $menu 当前菜单对象
+ * @param nodes 当前层级数据
+ * @private
+ */
+ _appendLi: function ($menu, nodes) {
+ var $list = $menu.find('.el-cascader-menu__list');
+ if (!nodes || nodes.length === 0) {
+ var isEmpty = this.config.empty;
+ $list.append('');
+ return;
+ }
+ $.each(nodes, function (index, node) {
+ node.bind($list);
+ });
+ },
+ /**
+ * 刷新菜单面板
+ */
+ refreshMenu: function () {
+ // 先复制一个数组,避免刷新菜单时,数组的数据被改变
+ var data = this.data.menuData.concat([]);
+ var self = this;
+ data.forEach(function (data) {
+ self._appendMenu(data.nodes, data.level, data.parentNode, data);
+ })
+ },
+ /**
+ * 初始化可搜索面板
+ * @private
+ */
+ _initSuggestionPanel: function () {
+ var filterable = this.config.filterable;
+ if (!filterable) {
+ return;
+ }
+ var $suggestionPanel = this.$suggestionPanel;
+ if (!$suggestionPanel) {
+ this.$suggestionPanel = $('');
+ $suggestionPanel = this.$suggestionPanel;
+ this.$panel.find('.popper__arrow').before($suggestionPanel);
+ $suggestionPanel.click(function (event) {
+ // 阻止事件冒泡
+ event.stopPropagation();
+ });
+ }
+ },
+ /**
+ * 设置可搜索菜单
+ * @param nodes
+ * @private
+ */
+ _setSuggestionMenu: function (nodes) {
+ var $suggestionPanel = this.$suggestionPanel;
+ var $list = $suggestionPanel.find('.el-cascader__suggestion-list');
+ $list.empty();
+ $suggestionPanel.find('.el-scrollbar__bar').remove();
+ if (!nodes || nodes.length === 0) {
+ $list.append('无匹配数据');
+ return;
+ }
+ $.each(nodes, function (index, node) {
+ node.bindSuggestion($list);
+ });
+ this._initScrollbar($suggestionPanel,{scrollbar: {top: 0, left: 0}});
+ this._resetXY();
+ },
+ /**
+ * 初始化节点数据
+ * @param data 原始数据
+ * @param level 层级
+ * @param parentNode 父级节点
+ * @returns {*[]}
+ */
+ initNodes: function (data, level, parentNode) {
+ var nodes = [];
+ for (var key in data) {
+ var datum = data[key];
+ var node = new Node(datum, this, level, parentNode);
+ nodes.push(node);
+ if (node.children && node.children.length > 0) {
+ node.setChildren(this.initNodes(node.children, level + 1, node));
+ }
+ }
+ return nodes;
+ },
+ /**
+ * 设置单选值
+ * @param nodeId 节点id
+ * @param node 节点对象
+ * @private
+ */
+ _setActiveValue: function (nodeId, node) {
+ if (this.data.activeNodeId !== nodeId) {
+ var activeNode = this.data.activeNode;
+ this.data.activeNodeId = nodeId;
+ this.data.activeNode = node;
+ activeNode && activeNode.transferParent(function (node) {
+ node.syncStyle();
+ }, true);
+ node && node.transferParent(function (node) {
+ node.syncStyle();
+ }, true);
+ // 填充路径
+ this.change(node && node.value, node);
+ if (nodeId !== null) {
+ this._setClear();
+ }
+ }
+ },
+ /**
+ * 设置多选值
+ * @param nodeIds 值数组
+ * @param nodes 节点数组
+ * @private
+ */
+ _setCheckedValue: function (nodeIds, nodes) {
+ var checkedNodes = this.data.checkedNodes;
+ var maxSize = this.config.maxSize;
+ var maxSizeMode;
+ if (nodeIds.length > 0 && maxSize !== 0 && nodeIds.length >= maxSize) {
+ nodeIds = nodeIds.slice(0, maxSize);
+ nodes = nodes.slice(0, maxSize);
+ maxSizeMode = true
+ } else {
+ maxSizeMode = false
+ }
+ this.data.checkedNodeIds = nodeIds || [];
+ this.data.checkedNodes = nodes || [];
+ var syncPath = [];
+ var syncNodeIds = [];
+ checkedNodes.forEach(function (node) {
+ node.path.forEach(function (node) {
+ if (syncNodeIds.indexOf(node.nodeId) === -1) {
+ syncPath.push(node);
+ syncNodeIds.push(node.nodeId);
+ }
+ });
+ });
+ nodes.forEach(function (node) {
+ node.path.forEach(function (node) {
+ if (syncNodeIds.indexOf(node.nodeId) === -1) {
+ syncPath.push(node);
+ syncNodeIds.push(node.nodeId);
+ }
+ });
+ });
+ syncPath.forEach(function (node) {
+ node.syncStyle();
+ });
+ // 填充路径
+ this.change(nodes.map(function (node) {
+ return node.value;
+ }), nodes);
+ this._setClear();
+ this.maxSizeMode = maxSizeMode;
+ },
+ /**
+ * 设置值
+ * @param value
+ */
+ setValue: function (value) {
+ if (this.data.activeNodeId || this.data.checkedNodeIds.length > 0) {
+ // 清空值
+ this.clearCheckedNodes();
+ }
+ if (!value) {
+ return;
+ }
+ var strictMode = this.props.strictMode;
+ if (strictMode) {
+ if (!Array.isArray(value)) {
+ throw new Error("严格模式下,value必须是一个包含父子节点数组结构.");
+ }
+ }
+ var nodes = this.getNodes(this.data.nodes);
+ var checkStrictly = this.props.checkStrictly;
+ var multiple = this.props.multiple;
+ var disabledFixed = this.config.disabledFixed;
+ if (multiple) {
+ var paths = nodes.filter(function (node) {
+ if ((checkStrictly || node.leaf) && (!node.disabled || disabledFixed)) {
+ if (strictMode) {
+ // 严格模式下
+ // some:命中一个就为true
+ // every:全部命中为true
+ return value.some(function (levelValue) {
+ if (!Array.isArray(levelValue)) {
+ throw new Error("多选严格模式下,value必须是一个二维数组结构.");
+ }
+ var path = node.path;
+ return levelValue.length === path.length && levelValue.every(function (rowValue, index) {
+ return path[index].value === rowValue;
+ });
+ })
+ } else {
+ return value.indexOf(node.value) !== -1;
+ }
+ }
+ return false;
+ });
+ var nodeIds = paths.map(function (node) {
+ return node.nodeId;
+ });
+ this._setCheckedValue(nodeIds, paths);
+ // 展开第一个节点
+ if (paths.length > 0) {
+ var first = paths[0];
+ first.expandPanel();
+ }
+ } else {
+ for (var i = 0; i < nodes.length; i++) {
+ var node = nodes[i];
+ if ((checkStrictly || node.leaf)) {
+ var is = false;
+ if (strictMode) {
+ // 严格模式下
+ // every:全部命中为true
+ var path = node.path;
+ is = value.length === path.length && value.every(function (rowValue, index) {
+ return path[index].value === rowValue;
+ });
+ } else if (node.value === value) {
+ is = true;
+ }
+ if (is) {
+ this._setActiveValue(node.nodeId, node);
+ // 展开节点
+ node.expandPanel();
+ break;
+ }
+ }
+ }
+ }
+ },
+ /**
+ * 递归获取扁平的节点
+ * @param nodes
+ * @param container
+ * @returns {*[]}
+ */
+ getNodes: function (nodes, container) {
+ if (!container) {
+ container = [];
+ }
+ if (!nodes) {
+ nodes = this.data.nodes;
+ }
+ var self = this;
+ nodes.forEach(function (node) {
+ container.push(node);
+ var children = node.getChildren();
+ if (children) {
+ self.getNodes(children, container);
+ }
+ });
+ return container;
+ },
+ /**
+ * 初始化滚动条
+ * @param $menu 菜单的dom节点对象
+ * @param menuItem 当前菜单数据
+ * @private
+ */
+ _initScrollbar: function ($menu, menuItem) {
+ var $div = $('');
+ $menu.append($div);
+ var vertical = $($div[1]).find('.el-scrollbar__thumb');
+ var onhoriztal = $($div[0]).find('.el-scrollbar__thumb');
+ var scrollbar = $menu.find('.el-scrollbar__wrap');
+ var $panel = this.$panel;
+ var $lis = $menu.find('li');
+ var height = Math.max($panel.height(), $menu.height());
+ var hScale = (height - 6) / ($lis.height() * $lis.length);
+ var wScale = $panel.width() / $lis.width();
+
+ // 滚动条监听事件
+ function _scrollbarEvent(scrollTop, scrollLeft) {
+ if (hScale < 1) {
+ vertical.css('height', hScale * 100 + '%');
+ vertical.css('transform', 'translateY(' + scrollTop / $menu.height() * 100 + '%)');
+ }
+ if (wScale < 1) {
+ onhoriztal.css('width', wScale * 100 + '%');
+ onhoriztal.css('transform', 'translateY(' + scrollLeft / $menu.width() * 100 + '%)');
+ }
+ }
+
+ // 拖动事件
+ vertical.mousedown(function (event) {
+ event.stopImmediatePropagation();
+ event.stopPropagation();
+ // 禁止文本选择事件
+ var selectstart = function () {
+ return false;
+ };
+ $(document).bind("selectstart", selectstart);
+ var y = event.clientY;
+ var scrollTop = scrollbar.scrollTop();
+ // 移动事件
+ var mousemove = function (event) {
+ event.stopImmediatePropagation();
+ var number = scrollTop + (event.clientY - y) / hScale;
+ scrollbar.scrollTop(number);
+ };
+ $(document).bind('mousemove', mousemove);
+ // 鼠标松开事件
+ $(document).one('mouseup', function (event) {
+ event.stopPropagation();
+ event.stopImmediatePropagation();
+ $(document).off('mousemove', mousemove);
+ $(document).off('selectstart', selectstart);
+ });
+ });
+ // 监听滚动条事件
+ scrollbar.scroll(function () {
+ var scroll = $(this);
+ menuItem.scrollbar.top = scroll.scrollTop()
+ menuItem.scrollbar.left = scroll.scrollLeft()
+ _scrollbarEvent(menuItem.scrollbar.top, menuItem.scrollbar.left);
+ });
+
+ // 初始化滚动条
+ scrollbar.scrollTop(menuItem.scrollbar.top);
+ _scrollbarEvent(menuItem.scrollbar.top, menuItem.scrollbar.left);
+ },
+ // 填充路径
+ _fillingPath: function () {
+ var multiple = this.props.multiple;
+ var showAllLevels = this.config.showAllLevels;
+ var separator = this.config.separator;
+ var collapseTags = this.config.collapseTags;
+ var $inputRow = this.$inputRow;
+ var placeholder = this.config.placeholder;
+ var self = this;
+ if (!multiple) {
+ var activeNode = this.data.activeNode;
+ var path = activeNode && activeNode.path || [];
+ if (showAllLevels) {
+ this._$inputRowSetValue(path.map(function (node) {
+ return node.label;
+ }).join(separator));
+ } else {
+ this._$inputRowSetValue(activeNode && activeNode.label || "");
+ }
+ } else {
+ // 复选框
+
+ // 删除标签
+ this.$tags.find('.el-tag').remove();
+ var $tagsInput = this.$tagsInput;
+ // 清除高度
+ $inputRow.css('height', '');
+ var checkedNodes = this.data.checkedNodes;
+ var minCollapseTagsNumber = Math.max(this.config.minCollapseTagsNumber, 1);
+ if (checkedNodes.length > 0) {
+ var tags = [];
+ var paths = checkedNodes;
+ if (collapseTags) {
+ // 折叠tags
+ paths = checkedNodes.slice(0, Math.min(checkedNodes.length, minCollapseTagsNumber));
+ }
+ paths.forEach(function (node) {
+ tags.push(node.$tag);
+ });
+ // 判断标签是否折叠
+ if (collapseTags) {
+ // 判断标签最小折叠数
+ if (checkedNodes.length > minCollapseTagsNumber) {
+ tags.push(self.get$tag('+ ' + (checkedNodes.length - minCollapseTagsNumber), false));
+ }
+ }
+ tags.forEach(function (tag) {
+ if ($tagsInput) {
+ $tagsInput.before(tag)
+ } else {
+ self.$tags.append(tag);
+ }
+ });
+ }
+ var tagHeight = self.$tags.height();
+ var inputHeight = $inputRow.height();
+ if (tagHeight > inputHeight) {
+ $inputRow.css('height', tagHeight + 4 + 'px');
+ }
+ // 重新定位
+ this._resetXY();
+ if (checkedNodes.length > 0) {
+ $inputRow.removeAttr('placeholder');
+ $tagsInput && $tagsInput.removeAttr('placeholder', placeholder);
+ } else {
+ $inputRow.attr('placeholder', placeholder);
+ $tagsInput && $tagsInput.attr('placeholder', placeholder);
+ }
+ }
+ },
+ /**
+ * 设置单选输入框的值
+ * @param label
+ * @private
+ */
+ _$inputRowSetValue: function (label) {
+ label = label || "";
+ var $inputRow = this.$inputRow;
+ $inputRow.attr('value', label); //防止被重置
+ $inputRow.val(label);
+ },
+ /**
+ * 获取复选框标签对象
+ * @param label
+ * @param showCloseIcon 是否显示关闭的icon
+ * @returns {jQuery|HTMLElement|*}
+ */
+ get$tag: function (label, showCloseIcon) {
+ var fromIcon = this.icons.from;
+ var closeIcon = this.icons.close;
+ var icon = showCloseIcon ? '' : '';
+ return $('' + label + '' + icon + '');
+ },
+ // 设置可清理
+ _setClear: function () {
+ var self = this;
+
+ function enter() {
+ self.$icon.removeClass(self.icons.down);
+ self.$icon.addClass(self.icons.close);
+ }
+
+ function out() {
+ self.$icon.removeClass(self.icons.close);
+ self.$icon.addClass(self.icons.down);
+ }
+
+ self.$div.mouseenter(function () {
+ enter();
+ });
+ self.$div.mouseleave(function () {
+ out();
+ });
+ self.$icon.off('click');
+ var multiple = this.props.multiple;
+ var clear;
+ if (multiple) {
+ clear = this.data.checkedNodeIds.length > 0;
+ } else {
+ clear = !!this.data.activeNodeId;
+ }
+ if (clear && !this.config.disabled && this.config.clearable) {
+ self.$icon.one('click', function (event) {
+ event.stopPropagation();
+ self.close();
+ self.clearCheckedNodes();
+ out();
+ self.$icon.off('mouseenter');
+ self.$div.off('mouseenter');
+ self.$div.off('mouseleave');
+ });
+ } else {
+ out();
+ self.$icon.off('mouseenter');
+ self.$div.off('mouseenter');
+ self.$div.off('mouseleave');
+ }
+ },
+ // 禁用
+ disabled: function (isDisabled) {
+ this.config.disabled = !!isDisabled;
+ if (this.config.disabled) {
+ this.$div.addClass('is-disabled');
+ this.$div.find('.el-input--suffix').addClass('is-disabled');
+ this.$inputRow.attr('disabled', 'disabled');
+ this.$tagsInput && this.$tagsInput.attr('disabled', 'disabled').hide()
+ } else {
+ this.$div.removeClass('is-disabled');
+ this.$div.find('.el-input--suffix').removeClass('is-disabled');
+ this.$inputRow.removeAttr('disabled');
+ this.$tagsInput && this.$tagsInput.removeAttr('disabled').show();
+ }
+ // 重新设置是否可被清理
+ this._setClear();
+ // 重新填充路径
+ this._fillingPath();
+ },
+ /**
+ * 当选中节点变化时触发 选中节点的值
+ * @param value 值
+ * @param node 节点
+ */
+ change: function (value, node) {
+ var multiple = this.props.multiple;
+ if (multiple) {
+ if (value && value.length > 0) {
+ this.$ec.attr('value', JSON.stringify(value));
+ // this.$ec.val(JSON.stringify(value));
+ } else {
+ this.$ec.removeAttr('value');
+ // this.$ec.val('');
+ }
+ } else {
+ this.$ec.attr('value', value || "");
+ // this.$ec.val(value);
+ }
+ // 填充路径
+ this._fillingPath();
+ this.event.change.forEach(function (e) {
+ typeof e === 'function' && e(value, node)
+ })
+ },
+ /**
+ * 当失去焦点时触发 (event: Event)
+ * @param eventId 不为空时,必须与closeEventId值相等,防止旧事件触发
+ */
+ close: function (eventId) {
+ if (this.showPanel && (!eventId || this.closeEventId === eventId)) {
+ this.showPanel = false;
+ this.$div.find('.layui-icon-down').removeClass('is-reverse');
+ this.$panel.slideUp(100);
+ this.visibleChange(false);
+ // 聚焦颜色
+ this.$input.removeClass('is-focus');
+ // 可搜索
+ var filterable = this.config.filterable;
+ if (filterable) {
+ this.isFiltering = false;
+ this._fillingPath();
+ }
+ this.event.close.forEach(function (e) {
+ typeof e === 'function' && e()
+ })
+ }
+ },
+ /**
+ * 当获得焦点时触发 (event: Event)
+ */
+ open: function () {
+ if (!this.showPanel) {
+ this.showPanel = true;
+ this.closeEventId++;
+ var self = this;
+ // 当前传播事件结束后,添加点击背景关闭面板事件
+ setTimeout(function () {
+ $(document).one('click', self.close.bind(self, self.closeEventId));
+ });
+ // 重新定位面板
+ this._resetXY();
+ // 箭头icon翻转
+ this.$div.find('.layui-icon-down').addClass('is-reverse');
+ this.$panel.slideDown(200);
+ this.visibleChange(true);
+ // 聚焦颜色
+ this.$input.addClass('is-focus');
+ this.event.open.forEach(function (e) {
+ typeof e === 'function' && e()
+ })
+ }
+ },
+ /**
+ * 下拉框出现/隐藏时触发
+ * @param visible 出现则为 true,隐藏则为 false
+ */
+ visibleChange: function (visible) {
+ },
+ /**
+ * 在多选模式下,移除Tag时触发 移除的Tag对应的节点的值
+ * @param tagValue 节点的值
+ * @param node 节点对象
+ */
+ removeTag: function (tagValue, node) {
+ },
+ /**
+ * 获取选中的节点值
+ * @returns {null|[]}
+ */
+ getCheckedValues: function () {
+ var strictMode = this.props.strictMode;
+ if (this.props.multiple) {
+ var checkedNodes = this.data.checkedNodes;
+ if (strictMode) {
+ return checkedNodes.map(function (node) {
+ return node.path.map(function (node1) {
+ return node1.value;
+ });
+ });
+ }
+ return checkedNodes.map(function (node) {
+ return node.value;
+ });
+ } else {
+ var activeNode = this.data.activeNode;
+ if (strictMode) {
+ return activeNode && activeNode.path.map(function (node) {
+ return node.value;
+ })
+ }
+ return activeNode && activeNode.value;
+ }
+ },
+ /**
+ * 获取选中的节点
+ * @returns {null|[]}
+ */
+ getCheckedNodes: function () {
+ var strictMode = this.props.strictMode;
+ if (this.props.multiple) {
+ var checkedNodes = this.data.checkedNodes;
+ if (strictMode) {
+ return checkedNodes && checkedNodes.map(function (node) {
+ return node.path;
+ });
+ }
+ return checkedNodes;
+ } else {
+ var activeNode = this.data.activeNode;
+ if (strictMode) {
+ return activeNode && activeNode.path;
+ }
+ return activeNode;
+ }
+ },
+ /**
+ * 清空选中的节点
+ * @param force 强制清理禁用固定节点
+ */
+ clearCheckedNodes: function (force) {
+ var multiple = this.props.multiple;
+ if (multiple) {
+ var disabledFixed = this.config.disabledFixed;
+ if (!force && disabledFixed) {
+ //禁用项被固定,则过滤出禁用项的选值出来
+ var checkedNodes = this.data.checkedNodes;
+ var disNodes = checkedNodes.filter(function (node) {
+ return node.disabled;
+ });
+ var nodeIds = disNodes.map(function (node) {
+ return node.nodeId;
+ });
+ this._setCheckedValue(nodeIds, disNodes);
+ } else {
+ this._setCheckedValue([], []);
+ }
+ } else {
+ this._setActiveValue(null, null);
+ }
+ }
+ };
+
+ var thisCas = function () {
+ var self = this;
+ return {
+ /**
+ * 设置选项值
+ * @param options
+ */
+ setOptions: function (options) {
+ self.setOptions(options);
+ },
+ /**
+ * 覆盖当前值
+ * @param value 单选时传对象,多选时传数组
+ */
+ setValue: function (value) {
+ self.setValue(value);
+ },
+ /**
+ * 当节点变更时,执行回调
+ * @param callback function(value,node){}
+ */
+ changeEvent: function (callback) {
+ self.event.change.push(callback);
+ },
+ /**
+ * 当面板关闭时,执行回调
+ * @param callback function(){}
+ */
+ closeEvent: function (callback) {
+ self.event.close.push(callback);
+ },
+ /**
+ * 当面板打开时,执行回调
+ * @param callback function(){}
+ */
+ openEvent: function (callback) {
+ self.event.open.push(callback);
+ },
+ /**
+ * 禁用组件
+ * @param disabled true/false
+ */
+ disabled: function (disabled) {
+ self.disabled(disabled);
+ },
+ /**
+ * 收起面板
+ */
+ close: function () {
+ self.close();
+ },
+ /**
+ * 展开面板
+ */
+ open: function () {
+ self.open();
+ },
+ /**
+ * 获取选中的节点,如需获取路径,使用node.path获取,将获取各级节点的node对象
+ * @returns {[]|*}
+ */
+ getCheckedNodes: function () {
+ return self.getCheckedNodes();
+ },
+ /**
+ * 获取选中的值
+ * @returns {[]|*}
+ */
+ getCheckedValues: function () {
+ return self.getCheckedValues();
+ },
+ /**
+ * 清空选中的节点
+ * @param force 强制清理禁用固定节点
+ */
+ clearCheckedNodes: function (force) {
+ self.clearCheckedNodes(force);
+ },
+ /**
+ * 展开面板到节点所在的层级
+ * @param value 节点值,只能传单个值,不允许传数组
+ */
+ expandNode: function (value) {
+ var nodes = self.getNodes(self.data.nodes);
+ for (var i = 0; i < nodes.length; i++) {
+ var node = nodes[i];
+ if (node.value === value) {
+ node.expandPanel();
+ break;
+ }
+ }
+ },
+ /**
+ * 获取当前配置副本
+ */
+ getConfig: function () {
+ return $.extend(true, {}, self.config);
+ },
+ /**
+ * 获取数据对象副本
+ * @returns {*}
+ */
+ getData: function () {
+ return $.extend(true, {}, self.data);
+ }
+ };
+ };
+
+ exports('layCascader', function (option) {
+ var ins = new Cascader(option);
+ return thisCas.call(ins);
+ });
+});