commit
65e2715746
@ -0,0 +1,847 @@
|
||||
/* 常用辅助css */
|
||||
|
||||
/* ==================
|
||||
布局
|
||||
==================== */
|
||||
|
||||
/* -- flex弹性布局 -- */
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.basis-xs {
|
||||
flex-basis: 20%;
|
||||
}
|
||||
|
||||
.basis-sm {
|
||||
flex-basis: 40%;
|
||||
}
|
||||
|
||||
.basis-df {
|
||||
flex-basis: 50%;
|
||||
}
|
||||
|
||||
.basis-lg {
|
||||
flex-basis: 60%;
|
||||
}
|
||||
|
||||
.basis-xl {
|
||||
flex-basis: 80%;
|
||||
}
|
||||
|
||||
.flex-sub {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.flex-twice {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.flex-treble {
|
||||
flex: 3;
|
||||
}
|
||||
|
||||
.flex-direction {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.align-start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.align-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.align-stretch {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.self-start {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.self-center {
|
||||
align-self: flex-center;
|
||||
}
|
||||
|
||||
.self-end {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.self-stretch {
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.align-stretch {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.justify-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.justify-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.justify-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.justify-around {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
/* -- 内外边距 -- */
|
||||
|
||||
.margin-0 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.margin-xs {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.margin-sm {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.margin {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.margin-lg {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.margin-xl {
|
||||
margin: 25px;
|
||||
}
|
||||
|
||||
.margin-top-xs {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.margin-top-sm {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.margin-top {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.margin-top-lg {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.margin-top-xl {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.margin-right-xs {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.margin-right-sm {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.margin-right {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.margin-right-lg {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.margin-right-xl {
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.margin-bottom-xs {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.margin-bottom-sm {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.margin-bottom {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.margin-bottom-lg {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.margin-bottom-xl {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.margin-left-xs {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.margin-left-sm {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.margin-left {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.margin-left-lg {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.margin-left-xl {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.margin-lr-xs {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.margin-lr-sm {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.margin-lr {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.margin-lr-lg {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.margin-lr-xl {
|
||||
margin-left: 25px;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.margin-tb-xs {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.margin-tb-sm {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.margin-tb {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.margin-tb-lg {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.margin-tb-xl {
|
||||
margin-top: 25px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.padding-0 {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.padding-xs {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.padding-sm {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.padding {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.padding-lg {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.padding-xl {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.padding-top-xs {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.padding-top-sm {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.padding-top {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.padding-top-lg {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.padding-top-xl {
|
||||
padding-top: 25px;
|
||||
}
|
||||
|
||||
.padding-right-xs {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.padding-right-sm {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.padding-right {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.padding-right-lg {
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.padding-right-xl {
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
.padding-bottom-xs {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.padding-bottom-sm {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.padding-bottom {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.padding-bottom-lg {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.padding-bottom-xl {
|
||||
padding-bottom: 25px;
|
||||
}
|
||||
|
||||
.padding-left-xs {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.padding-left-sm {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.padding-left {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.padding-left-lg {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.padding-left-xl {
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.padding-lr-xs {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.padding-lr-sm {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.padding-lr {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.padding-lr-lg {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.padding-lr-xl {
|
||||
padding-left: 25px;
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
.padding-tb-xs {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.padding-tb-sm {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.padding-tb {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.padding-tb-lg {
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.padding-tb-xl {
|
||||
padding-top: 25px;
|
||||
padding-bottom: 25px;
|
||||
}
|
||||
|
||||
/* -- 浮动 -- */
|
||||
|
||||
.cf::after,
|
||||
.cf::before {
|
||||
content: " ";
|
||||
display: table;
|
||||
}
|
||||
|
||||
.cf::after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.fl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.fr {
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
||||
/* ==================
|
||||
背景
|
||||
==================== */
|
||||
|
||||
.line-red::after,
|
||||
.lines-red::after {
|
||||
border-color: #e54d42;
|
||||
}
|
||||
|
||||
.line-orange::after,
|
||||
.lines-orange::after {
|
||||
border-color: #f37b1d;
|
||||
}
|
||||
|
||||
.line-yellow::after,
|
||||
.lines-yellow::after {
|
||||
border-color: #fbbd08;
|
||||
}
|
||||
|
||||
.line-olive::after,
|
||||
.lines-olive::after {
|
||||
border-color: #8dc63f;
|
||||
}
|
||||
|
||||
.line-green::after,
|
||||
.lines-green::after {
|
||||
border-color: #39b54a;
|
||||
}
|
||||
|
||||
.line-cyan::after,
|
||||
.lines-cyan::after {
|
||||
border-color: #1cbbb4;
|
||||
}
|
||||
|
||||
.line-blue::after,
|
||||
.lines-blue::after {
|
||||
border-color: #0081ff;
|
||||
}
|
||||
|
||||
.line-purple::after,
|
||||
.lines-purple::after {
|
||||
border-color: #6739b6;
|
||||
}
|
||||
|
||||
.line-mauve::after,
|
||||
.lines-mauve::after {
|
||||
border-color: #9c26b0;
|
||||
}
|
||||
|
||||
.line-pink::after,
|
||||
.lines-pink::after {
|
||||
border-color: #e03997;
|
||||
}
|
||||
|
||||
.line-brown::after,
|
||||
.lines-brown::after {
|
||||
border-color: #a5673f;
|
||||
}
|
||||
|
||||
.line-grey::after,
|
||||
.lines-grey::after {
|
||||
border-color: #8799a3;
|
||||
}
|
||||
|
||||
.line-gray::after,
|
||||
.lines-gray::after {
|
||||
border-color: #aaaaaa;
|
||||
}
|
||||
|
||||
.line-black::after,
|
||||
.lines-black::after {
|
||||
border-color: #333333;
|
||||
}
|
||||
|
||||
.line-white::after,
|
||||
.lines-white::after {
|
||||
border-color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-red {
|
||||
background-color: #e54d42;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-orange {
|
||||
background-color: #f37b1d;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-yellow {
|
||||
background-color: #fbbd08;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.bg-olive {
|
||||
background-color: #8dc63f;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-green {
|
||||
background-color: #39b54a;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-cyan {
|
||||
background-color: #1cbbb4;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-blue {
|
||||
background-color: #0081ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-purple {
|
||||
background-color: #6739b6;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-mauve {
|
||||
background-color: #9c26b0;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-pink {
|
||||
background-color: #e03997;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-brown {
|
||||
background-color: #a5673f;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-grey {
|
||||
background-color: #8799a3;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-gray {
|
||||
background-color: #f0f0f0;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.bg-black {
|
||||
background-color: #333333;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
background-color: #ffffff;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.bg-red.light {
|
||||
color: #e54d42;
|
||||
background-color: #fadbd9;
|
||||
}
|
||||
|
||||
.bg-orange.light {
|
||||
color: #f37b1d;
|
||||
background-color: #fde6d2;
|
||||
}
|
||||
|
||||
.bg-yellow.light {
|
||||
color: #fbbd08;
|
||||
background-color: #fef2ced2;
|
||||
}
|
||||
|
||||
.bg-olive.light {
|
||||
color: #8dc63f;
|
||||
background-color: #e8f4d9;
|
||||
}
|
||||
|
||||
.bg-green.light {
|
||||
color: #39b54a;
|
||||
background-color: #d7f0dbff;
|
||||
}
|
||||
|
||||
.bg-cyan.light {
|
||||
color: #1cbbb4;
|
||||
background-color: #d2f1f0;
|
||||
}
|
||||
|
||||
.bg-blue.light {
|
||||
color: #0081ff;
|
||||
background-color: #cce6ff;
|
||||
}
|
||||
|
||||
.bg-purple.light {
|
||||
color: #6739b6;
|
||||
background-color: #e1d7f0;
|
||||
}
|
||||
|
||||
.bg-mauve.light {
|
||||
color: #9c26b0;
|
||||
background-color: #ebd4ef;
|
||||
}
|
||||
|
||||
.bg-pink.light {
|
||||
color: #e03997;
|
||||
background-color: #f9d7ea;
|
||||
}
|
||||
|
||||
.bg-brown.light {
|
||||
color: #a5673f;
|
||||
background-color: #ede1d9;
|
||||
}
|
||||
|
||||
.bg-grey.light {
|
||||
color: #8799a3;
|
||||
background-color: #e7ebed;
|
||||
}
|
||||
|
||||
.bg-gradual-red {
|
||||
background-image: linear-gradient(45deg, #f43f3b, #ec008c);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-gradual-orange {
|
||||
background-image: linear-gradient(45deg, #ff9700, #ed1c24);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-gradual-green {
|
||||
background-image: linear-gradient(45deg, #39b54a, #8dc63f);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-gradual-purple {
|
||||
background-image: linear-gradient(45deg, #9000ff, #5e00ff);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-gradual-pink {
|
||||
background-image: linear-gradient(45deg, #ec008c, #6739b6);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.bg-gradual-blue {
|
||||
background-image: linear-gradient(45deg, #0081ff, #1cbbb4);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* ==================
|
||||
文本
|
||||
==================== */
|
||||
|
||||
.text-xs {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.text-df {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.text-xl {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.text-xxl {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.text-sl {
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.text-xsl {
|
||||
font-size: 60px;
|
||||
}
|
||||
|
||||
.text-Abc {
|
||||
text-transform: Capitalize;
|
||||
}
|
||||
|
||||
.text-ABC {
|
||||
text-transform: Uppercase;
|
||||
}
|
||||
|
||||
.text-abc {
|
||||
text-transform: Lowercase;
|
||||
}
|
||||
|
||||
|
||||
.text-cut {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.text-bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-content {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.text-red,
|
||||
.line-red,
|
||||
.lines-red {
|
||||
color: #e54d42;
|
||||
}
|
||||
|
||||
.text-orange,
|
||||
.line-orange,
|
||||
.lines-orange {
|
||||
color: #f37b1d;
|
||||
}
|
||||
|
||||
.text-yellow,
|
||||
.line-yellow,
|
||||
.lines-yellow {
|
||||
color: #fbbd08;
|
||||
}
|
||||
|
||||
.text-olive,
|
||||
.line-olive,
|
||||
.lines-olive {
|
||||
color: #8dc63f;
|
||||
}
|
||||
|
||||
.text-green,
|
||||
.line-green,
|
||||
.lines-green {
|
||||
color: #39b54a;
|
||||
}
|
||||
|
||||
.text-cyan,
|
||||
.line-cyan,
|
||||
.lines-cyan {
|
||||
color: #1cbbb4;
|
||||
}
|
||||
|
||||
.text-blue,
|
||||
.line-blue,
|
||||
.lines-blue {
|
||||
color: #0081ff;
|
||||
}
|
||||
|
||||
.text-purple,
|
||||
.line-purple,
|
||||
.lines-purple {
|
||||
color: #6739b6;
|
||||
}
|
||||
|
||||
.text-mauve,
|
||||
.line-mauve,
|
||||
.lines-mauve {
|
||||
color: #9c26b0;
|
||||
}
|
||||
|
||||
.text-pink,
|
||||
.line-pink,
|
||||
.lines-pink {
|
||||
color: #e03997;
|
||||
}
|
||||
|
||||
.text-brown,
|
||||
.line-brown,
|
||||
.lines-brown {
|
||||
color: #a5673f;
|
||||
}
|
||||
|
||||
.text-grey,
|
||||
.line-grey,
|
||||
.lines-grey {
|
||||
color: #8799a3;
|
||||
}
|
||||
|
||||
.text-gray,
|
||||
.line-gray,
|
||||
.lines-gray {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.text-black,
|
||||
.line-black,
|
||||
.lines-black {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.text-white,
|
||||
.line-white,
|
||||
.lines-white {
|
||||
color: #ffffff;
|
||||
}
|
@ -0,0 +1,365 @@
|
||||
@charset "utf-8";
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#app-menu ul {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#app-menu li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#app-menu {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.weixin-preview {
|
||||
position: relative;
|
||||
width: 320px;
|
||||
height: 540px;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
border: 1px solid #e7e7eb;
|
||||
}
|
||||
|
||||
.weixin-preview a {
|
||||
text-decoration: none;
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
.weixin-preview .weixin-hd .weixin-title {
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 33px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.weixin-preview .weixin-header{
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
background-color: #616161;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.weixin-preview .weixin-menu {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-top: 1px solid #e7e7e7;
|
||||
background-position: 0 0;
|
||||
background-repeat: no-repeat;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
/*一级*/
|
||||
.weixin-preview .weixin-menu .menu-item {
|
||||
position: relative;
|
||||
float: left;
|
||||
line-height: 50px;
|
||||
height: 50px;
|
||||
text-align: center;
|
||||
width: 33.33%;
|
||||
border-left: 1px solid #e7e7e7;
|
||||
cursor: pointer;
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
/*二级*/
|
||||
.weixin-preview .weixin-sub-menu {
|
||||
position: absolute;
|
||||
bottom: 60px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-top: 1px solid #d0d0d0;
|
||||
margin-bottom: 0px;
|
||||
background: #fafafa;
|
||||
display: block;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.weixin-preview .weixin-sub-menu .menu-sub-item {
|
||||
line-height: 50px;
|
||||
height: 50px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
border: 1px solid #d0d0d0;
|
||||
border-top-width: 0px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
.weixin-preview .weixin-sub-menu .menu-sub-item.on-drag-over{
|
||||
border-top: 2px solid #44b549;
|
||||
}
|
||||
|
||||
.weixin-preview .menu-arrow {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
.weixin-preview .arrow_in {
|
||||
bottom: -4px;
|
||||
display: inline-block;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border-width: 6px 6px 0px;
|
||||
border-style: solid dashed dashed;
|
||||
border-color: #fafafa transparent transparent;
|
||||
}
|
||||
|
||||
.weixin-preview .arrow_out {
|
||||
bottom: -5px;
|
||||
display: inline-block;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border-width: 6px 6px 0px;
|
||||
border-style: solid dashed dashed;
|
||||
border-color: #d0d0d0 transparent transparent;
|
||||
}
|
||||
|
||||
.weixin-preview .menu-item .menu-item-title, .weixin-preview .menu-sub-item .menu-item-title {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
.weixin-preview .menu-item.current, .weixin-preview .menu-sub-item.current {
|
||||
border: 1px solid #44b549;
|
||||
background: #fff;
|
||||
color: #44b549;
|
||||
}
|
||||
|
||||
.weixin-preview .weixin-sub-menu.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.weixin-preview .icon_menu_dot {
|
||||
/* background: url(../images/index_z354723.png) 0px -36px no-repeat; */
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
margin-right: 2px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.weixin-preview .icon14_menu_add {
|
||||
/* background: url(../images/index_z354723.png) 0px 0px no-repeat; */
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.weixin-preview li:hover .icon14_menu_add {
|
||||
/* background: url(../images/index_z354723.png) 0px -18px no-repeat; */
|
||||
}
|
||||
|
||||
.weixin-preview .menu-item:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.weixin-preview .menu-sub-item:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.weixin-preview li.current:hover {
|
||||
background: #fff;
|
||||
color: #44b549;
|
||||
}
|
||||
|
||||
/*菜单内容*/
|
||||
.weixin-menu-detail {
|
||||
width: 600px;
|
||||
padding: 0px 20px 5px;
|
||||
background-color: #f4f5f9;
|
||||
border: 1px solid #e7e7eb;
|
||||
float: left;
|
||||
min-height: 540px;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-name {
|
||||
float: left;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-del {
|
||||
float: right;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
color: #459ae9;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-input-group {
|
||||
width: 540px;
|
||||
margin: 10px 0 30px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-label {
|
||||
float: left;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
width: 80px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-input {
|
||||
float: left;
|
||||
width: 380px
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-input-text {
|
||||
border: 0px;
|
||||
outline: 0px;
|
||||
background: #fff;
|
||||
width: 300px;
|
||||
padding: 5px 0px 5px 0px;
|
||||
margin-left: 10px;
|
||||
text-indent: 10px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-tips {
|
||||
color: #8d8d8d;
|
||||
padding-top: 4px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-tips.cursor {
|
||||
color: #459ae9;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-input .menu-tips {
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-content {
|
||||
padding: 16px 20px;
|
||||
border: 1px solid #e7e7eb;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-content .menu-input-group {
|
||||
margin: 0px 0 10px 0;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-content .menu-label {
|
||||
text-align: left;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-content .menu-input-text {
|
||||
border: 1px solid #e7e7eb;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-content .menu-tips {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-msg-content {
|
||||
padding: 0;
|
||||
border: 1px solid #e7e7eb;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-msg-content .menu-msg-head {
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #e7e7eb;
|
||||
line-height: 38px;
|
||||
height: 38px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-msg-content .menu-msg-panel {
|
||||
padding: 30px 50px;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-msg-content .menu-msg-select {
|
||||
padding: 40px 20px;
|
||||
border: 2px dotted #d9dadc;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-msg-content .menu-msg-select:hover {
|
||||
border-color: #b3b3b3;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-msg-content strong {
|
||||
display: block;
|
||||
padding-top: 3px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.weixin-menu-detail .menu-msg-content .menu-msg-title {
|
||||
float: left;
|
||||
width: 310px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.icon36_common {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.icon_msg_sender {
|
||||
margin-right: 3px;
|
||||
margin-top: -2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
/* background: url(../images/msg_tab_z25df2d.png) 0 -270px no-repeat; */
|
||||
}
|
||||
|
||||
.weixin-btn-group {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
margin: 30px 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.weixin-btn-group .btn {
|
||||
width: 100px;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
#material-list {
|
||||
padding: 20px;
|
||||
overflow-y: scroll;
|
||||
height: 558px;
|
||||
}
|
||||
|
||||
#news-list {
|
||||
padding: 20px;
|
||||
overflow-y: scroll;
|
||||
height: 558px;
|
||||
}
|
||||
|
||||
#material-list table {
|
||||
width: 100%;
|
||||
}
|
@ -0,0 +1,412 @@
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.15;
|
||||
color: #303133;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
a {
|
||||
color: mix(#fff, $--color-primary, 20%);
|
||||
text-decoration: none;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: $--color-primary;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
/* Utils
|
||||
------------------------------ */
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
content: " ";
|
||||
display: table;
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
/* Animation
|
||||
------------------------------ */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity .5s;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Reset element-ui
|
||||
------------------------------ */
|
||||
.site-wrapper {
|
||||
.el-pagination {
|
||||
margin-top: 15px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Layout
|
||||
------------------------------ */
|
||||
.site-wrapper {
|
||||
position: relative;
|
||||
min-width: 1180px;
|
||||
}
|
||||
|
||||
|
||||
/* Sidebar fold
|
||||
------------------------------ */
|
||||
.site-sidebar--fold {
|
||||
.site-navbar__header,
|
||||
.site-navbar__brand,
|
||||
.site-sidebar,
|
||||
.site-sidebar__inner,
|
||||
.el-menu.site-sidebar__menu {
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
.site-navbar__body,
|
||||
.site-content__wrapper {
|
||||
margin-left: 64px;
|
||||
}
|
||||
|
||||
.site-navbar__brand {
|
||||
&-lg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-mini {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.site-sidebar,
|
||||
.site-sidebar__inner {
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
.site-sidebar__menu-icon {
|
||||
margin-right: 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.site-content--tabs > .el-tabs > .el-tabs__header {
|
||||
left: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
// animation
|
||||
.site-navbar__header,
|
||||
.site-navbar__brand,
|
||||
.site-navbar__body,
|
||||
.site-sidebar,
|
||||
.site-sidebar__inner,
|
||||
.site-sidebar__menu.el-menu,
|
||||
.site-sidebar__menu-icon,
|
||||
.site-content__wrapper,
|
||||
.site-content--tabs > .el-tabs .el-tabs__header {
|
||||
transition: inline-block .3s, left .3s, width .3s, margin-left .3s, font-size .3s;
|
||||
}
|
||||
|
||||
|
||||
/* Navbar
|
||||
------------------------------ */
|
||||
.site-navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 1030;
|
||||
height: 50px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, .08);
|
||||
background-color: $navbar--background-color;
|
||||
|
||||
&--inverse {
|
||||
.site-navbar__body {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
> .el-menu-item,
|
||||
> .el-submenu > .el-submenu__title {
|
||||
color: #fff;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: mix(#000, $navbar--background-color, 15%);
|
||||
}
|
||||
}
|
||||
|
||||
> .el-menu-item.is-active,
|
||||
> .el-submenu.is-active > .el-submenu__title {
|
||||
border-bottom-color: mix(#fff, $navbar--background-color, 85%);
|
||||
}
|
||||
|
||||
.el-menu-item i,
|
||||
.el-submenu__title i,
|
||||
.el-dropdown {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu--popup-bottom-start {
|
||||
background-color: $navbar--background-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__header {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 230px;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__brand {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
width: 230px;
|
||||
height: 50px;
|
||||
margin: 0;
|
||||
line-height: 50px;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
color: #fff;
|
||||
|
||||
&-lg,
|
||||
&-mini {
|
||||
margin: 0 5px;
|
||||
color: #fff;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-mini {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__switch {
|
||||
font-size: 18px;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
border-bottom: none !important;
|
||||
|
||||
* {
|
||||
vertical-align: inherit;
|
||||
}
|
||||
|
||||
.el-dropdown-link {
|
||||
> img {
|
||||
width: 36px;
|
||||
height: auto;
|
||||
margin-right: 5px;
|
||||
border-radius: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__body {
|
||||
position: relative;
|
||||
margin-left: 230px;
|
||||
padding-right: 15px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
&__menu {
|
||||
float: left;
|
||||
background-color: transparent;
|
||||
border-bottom: 0;
|
||||
|
||||
&--right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
a:focus,
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.el-menu-item,
|
||||
.el-submenu > .el-submenu__title {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
.el-submenu > .el-menu {
|
||||
top: 55px;
|
||||
}
|
||||
|
||||
.el-badge {
|
||||
display: inline;
|
||||
z-index: 2;
|
||||
|
||||
&__content {
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Sidebar
|
||||
------------------------------ */
|
||||
.site-sidebar {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 1020;
|
||||
width: 230px;
|
||||
overflow: hidden;
|
||||
|
||||
&--dark,
|
||||
&--dark-popper {
|
||||
background-color: $sidebar--background-color-dark;
|
||||
|
||||
.site-sidebar__menu.el-menu,
|
||||
> .el-menu--popup {
|
||||
background-color: $sidebar--background-color-dark;
|
||||
|
||||
.el-menu-item,
|
||||
.el-submenu > .el-submenu__title {
|
||||
color: $sidebar--color-text-dark;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: mix(#fff, $sidebar--color-text-dark, 50%);
|
||||
background-color: mix(#fff, $sidebar--background-color-dark, 2.5%);
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu,
|
||||
.el-submenu.is-opened {
|
||||
background-color: mix(#000, $sidebar--background-color-dark, 15%);
|
||||
}
|
||||
|
||||
.el-menu-item.is-active,
|
||||
.el-submenu.is-active > .el-submenu__title {
|
||||
color: mix(#fff, $sidebar--color-text-dark, 80%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__inner {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
padding-bottom: 15px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
&__menu.el-menu {
|
||||
width: 230px;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
&__menu-icon {
|
||||
width: 24px;
|
||||
margin-right: 5px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: inherit !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Content
|
||||
------------------------------ */
|
||||
.site-content {
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
|
||||
&__wrapper {
|
||||
position: relative;
|
||||
padding-top: 50px;
|
||||
margin-left: 230px;
|
||||
min-height: 100%;
|
||||
background: $content--background-color;
|
||||
}
|
||||
|
||||
&--tabs {
|
||||
padding: 55px 0 0;
|
||||
}
|
||||
|
||||
> .el-tabs {
|
||||
> .el-tabs__header {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 230px;
|
||||
right: 0;
|
||||
z-index: 930;
|
||||
padding: 0 55px 0 15px;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .12), 0 0 6px 0 rgba(0, 0, 0, .04);
|
||||
background-color: #fff;
|
||||
|
||||
> .el-tabs__nav-wrap {
|
||||
margin-bottom: 0;
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .el-tabs__content {
|
||||
padding: 0 15px 15px;
|
||||
|
||||
> .site-tabs__tools {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
right: 0;
|
||||
z-index: 931;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
font-size: 16px;
|
||||
line-height: 40px;
|
||||
background-color: $content--background-color;
|
||||
cursor: pointer;
|
||||
|
||||
.el-icon--right {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__expand-icon {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
vertical-align: middle;
|
||||
margin-right: 5px;
|
||||
}
|
@ -0,0 +1,447 @@
|
||||
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/* Document
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Correct the line height in all browsers.
|
||||
* 2. Prevent adjustments of font size after orientation changes in
|
||||
* IE on Windows Phone and in iOS.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.15; /* 1 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/* Sections
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the margin in all browsers (opinionated).
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
footer,
|
||||
header,
|
||||
nav,
|
||||
section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the font size and margin on `h1` elements within `section` and
|
||||
* `article` contexts in Chrome, Firefox, and Safari.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
* 1. Add the correct display in IE.
|
||||
*/
|
||||
|
||||
figcaption,
|
||||
figure,
|
||||
main { /* 1 */
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct margin in IE 8.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in Firefox.
|
||||
* 2. Show the overflow in Edge and IE.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Remove the gray background on active links in IE 10.
|
||||
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent; /* 1 */
|
||||
-webkit-text-decoration-skip: objects; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
|
||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font style in Android 4.3-.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct background and color in IE 9-.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||
* all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
audio,
|
||||
video {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in iOS 4-7.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the border on images inside links in IE 10-.
|
||||
*/
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the overflow in IE.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Change the font styles in all browsers (opinionated).
|
||||
* 2. Remove the margin in Firefox and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: sans-serif; /* 1 */
|
||||
font-size: 100%; /* 1 */
|
||||
line-height: 1.15; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the overflow in IE.
|
||||
* 1. Show the overflow in Edge.
|
||||
*/
|
||||
|
||||
button,
|
||||
input { /* 1 */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||
* 1. Remove the inheritance of text transform in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select { /* 1 */
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
|
||||
* controls in Android 4.
|
||||
* 2. Correct the inability to style clickable types in iOS and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
html [type="button"], /* 1 */
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner border and padding in Firefox.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the focus styles unset by the previous rule.
|
||||
*/
|
||||
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: 1px dotted ButtonText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the padding in Firefox.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
padding: 0.35em 0.75em 0.625em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the text wrapping in Edge and IE.
|
||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||
* 3. Remove the padding so developers are not caught out when they zero out
|
||||
* `fieldset` elements in all browsers.
|
||||
*/
|
||||
|
||||
legend {
|
||||
box-sizing: border-box; /* 1 */
|
||||
color: inherit; /* 2 */
|
||||
display: table; /* 1 */
|
||||
max-width: 100%; /* 1 */
|
||||
padding: 0; /* 3 */
|
||||
white-space: normal; /* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct display in IE 9-.
|
||||
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
progress {
|
||||
display: inline-block; /* 1 */
|
||||
vertical-align: baseline; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default vertical scrollbar in IE.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in IE 10-.
|
||||
* 2. Remove the padding in IE 10-.
|
||||
*/
|
||||
|
||||
[type="checkbox"],
|
||||
[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
*/
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the odd appearance in Chrome and Safari.
|
||||
* 2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
outline-offset: -2px; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
[type="search"]::-webkit-search-cancel-button,
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
* 2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/* Interactive
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Add the correct display in IE 9-.
|
||||
* 1. Add the correct display in Edge, IE, and Firefox.
|
||||
*/
|
||||
|
||||
details, /* 1 */
|
||||
menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the correct display in all browsers.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/* Scripting
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
canvas {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE.
|
||||
*/
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hidden
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10-.
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
// 站点主色
|
||||
// tips: 要达到整站主题修改效果, 请确保[$--color-primary]站点主色与[/src/element-ui-theme/index.js]文件中[import './element-[#17B3A3]/index.css']当前主题色一致
|
||||
$--color-primary: #409EFF;
|
||||
|
||||
// Navbar
|
||||
$navbar--background-color: $--color-primary;
|
||||
|
||||
// Sidebar
|
||||
$sidebar--background-color-dark: #263238;
|
||||
$sidebar--color-text-dark: #8a979e;
|
||||
|
||||
// Content
|
||||
$content--background-color: #f1f4f5;
|
@ -0,0 +1,5 @@
|
||||
@import "normalize";
|
||||
// api: https://github.com/necolas/normalize.css/
|
||||
@import "variables";
|
||||
// 站点变量
|
||||
@import "base";
|
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<svg :class="getClassName" :width="width" :height="height" aria-hidden="true">
|
||||
<use :xlink:href="getName"></use>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'icon-svg',
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
className: {
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
type: String
|
||||
},
|
||||
height: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getName() {
|
||||
return `#icon-${this.name}`
|
||||
},
|
||||
getClassName() {
|
||||
return [
|
||||
'icon-svg',
|
||||
`icon-svg__${this.name}`,
|
||||
this.className && /\S/.test(this.className) ? `${this.className}` : ''
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<el-table-column :prop="prop" v-bind="$attrs">
|
||||
<template slot-scope="scope">
|
||||
<span @click.prevent="toggleHandle(scope.$index, scope.row)" :style="childStyles(scope.row)">
|
||||
<i :class="iconClasses(scope.row)" :style="iconStyles(scope.row)"></i>
|
||||
{{ scope.row[prop] }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import isArray from 'lodash/isArray'
|
||||
export default {
|
||||
name: 'table-tree-column',
|
||||
props: {
|
||||
prop: {
|
||||
type: String
|
||||
},
|
||||
treeKey: {
|
||||
type: String,
|
||||
default: 'id'
|
||||
},
|
||||
parentKey: {
|
||||
type: String,
|
||||
default: 'parentId'
|
||||
},
|
||||
levelKey: {
|
||||
type: String,
|
||||
default: '_level'
|
||||
},
|
||||
childKey: {
|
||||
type: String,
|
||||
default: 'children'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
childStyles(row) {
|
||||
return { 'padding-left': (row[this.levelKey] > 1 ? row[this.levelKey] * 7 : 0) + 'px' }
|
||||
},
|
||||
iconClasses(row) {
|
||||
return [!row._expanded ? 'el-icon-caret-right' : 'el-icon-caret-bottom']
|
||||
},
|
||||
iconStyles(row) {
|
||||
return { 'visibility': this.hasChild(row) ? 'visible' : 'hidden' }
|
||||
},
|
||||
hasChild(row) {
|
||||
return (isArray(row[this.childKey]) && row[this.childKey].length >= 1) || false
|
||||
},
|
||||
// 切换处理
|
||||
toggleHandle(index, row) {
|
||||
if (this.hasChild(row)) {
|
||||
var data = this.$parent.store.states.data.slice(0)
|
||||
data[index]._expanded = !data[index]._expanded
|
||||
if (data[index]._expanded) {
|
||||
data = data.splice(0, index + 1).concat(row[this.childKey]).concat(data)
|
||||
} else {
|
||||
data = this.removeChildNode(data, row[this.treeKey])
|
||||
}
|
||||
this.$parent.store.commit('setData', data)
|
||||
this.$nextTick(() => {
|
||||
this.$parent.doLayout()
|
||||
})
|
||||
}
|
||||
},
|
||||
// 移除子节点
|
||||
removeChildNode(data, parentId) {
|
||||
var parentIds = isArray(parentId) ? parentId : [parentId]
|
||||
if (parentId.length <= 0) {
|
||||
return data
|
||||
}
|
||||
var ids = []
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (parentIds.indexOf(data[i][this.parentKey]) !== -1 && parentIds.indexOf(data[i][this.treeKey]) === -1) {
|
||||
data[i]._expanded = false
|
||||
ids.push(data.splice(i, 1)[0][this.treeKey])
|
||||
i--
|
||||
}
|
||||
}
|
||||
return this.removeChildNode(data, ids)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div class="tinymce-editor">
|
||||
<editor v-model="myValue" :init="init" @onExecCommand="onExecCommand"></editor>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Editor from "@tinymce/tinymce-vue";
|
||||
|
||||
var cos;
|
||||
export default {
|
||||
name: "tinymce-editor",
|
||||
components: {
|
||||
Editor
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
init: {
|
||||
language_url: "./tinymce/zh_CN.js", //public目录下
|
||||
language: "zh_CN",
|
||||
height: 500,
|
||||
plugins: "lists image media table paste link searchreplace anchor code preview pagebreak importcss",
|
||||
toolbar: "undo redo searchreplace | formatselect pagebreak | bold italic forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists link anchor image media table | removeformat code preview", //工具栏展示项
|
||||
toolbar_drawer: false,
|
||||
image_advtab: true,
|
||||
object_resizing: false,
|
||||
paste_data_images: true,
|
||||
content_css: "./tinymce/article.css",
|
||||
images_upload_handler: (blobInfo, success, failure) => {
|
||||
this.uploadFile(blobInfo.blob()).then(fileUrl => success(fileUrl)).catch(err => failure(err))
|
||||
}
|
||||
},
|
||||
myValue: this.value,
|
||||
uploading: false,
|
||||
cosConfig: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// console.log('tinymce-editor mounted:',this.value)
|
||||
tinymce.init({});
|
||||
this.cosInit();
|
||||
},
|
||||
methods: {
|
||||
cosInit() {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl("/sys/oss/config"),
|
||||
method: "get",
|
||||
params: this.$http.adornParams()
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.cosConfig = data.config;
|
||||
} else {
|
||||
this.$message.error("请先配置云存储相关信息!");
|
||||
}
|
||||
});
|
||||
},
|
||||
onExecCommand(e) {
|
||||
//console.log(e)
|
||||
},
|
||||
uploadFile(file) {
|
||||
this.uploading = true;
|
||||
return new Promise((resolve, reject) => {
|
||||
let formData = new FormData();
|
||||
formData.append("file", file);
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/oss/upload'),
|
||||
method: 'post',
|
||||
data: formData
|
||||
}).then(({ data }) => {
|
||||
console.log(data)
|
||||
if (data && data.code === 200) {
|
||||
this.$emit('uploaded', data.url)
|
||||
resolve(data.url)
|
||||
} else {
|
||||
this.$message.error("文件上传失败:" + data.msg)
|
||||
reject(data.msg)
|
||||
}
|
||||
this.uploading = false;
|
||||
}).catch(err=>reject(err))
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(newValue) {
|
||||
this.myValue = newValue;
|
||||
},
|
||||
myValue(newValue) {
|
||||
this.$emit("input", newValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div class="panel">
|
||||
<el-tooltip class="item" effect="dark" :content="msg.inOut?'公众号发出的消息':'来自用户的消息'" placement="right">
|
||||
<el-tag size="mini" v-if="msg.inOut" class="margin-right el-icon-upload2" type="info"></el-tag>
|
||||
<el-tag size="mini" v-else class="margin-right el-icon-download"></el-tag>
|
||||
</el-tooltip>
|
||||
<span class="panel-content">
|
||||
<span v-if="msg.msgType=='text'" v-html="msg.detail.content"></span>
|
||||
<span v-else-if="msg.msgType=='event'" >
|
||||
<el-tag size="mini" type="warning" effect="plain">事件</el-tag>
|
||||
<el-tag size="mini" type="info" effect="plain">{{msg.detail.event}}</el-tag>
|
||||
{{msg.detail.eventKey}}
|
||||
</span>
|
||||
<span v-else-if="msg.msgType=='transfer_customer_service'">
|
||||
<el-tag size="mini" type="warning" effect="plain">事件</el-tag>
|
||||
<el-tag size="mini" type="info" effect="plain">消息转客服</el-tag>
|
||||
</span>
|
||||
<span v-else>
|
||||
<el-tag size="mini" effect="plain">{{XmlMsgType[msg.msgType]}}</el-tag>
|
||||
后台不支持预览
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name:'wx-msg-preview',
|
||||
props:{
|
||||
msg:Object
|
||||
},
|
||||
computed:mapState({
|
||||
XmlMsgType:state=>state.message.XmlMsgType,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.panel,.panel a{
|
||||
color: #999;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<el-dialog title="公众号用户标签管理" :close-on-click-modal="false" :visible.sync="dialogVisible">
|
||||
<div class="panel flex flex-wrap" v-loading="submitting">
|
||||
<el-tag v-for="tag in wxUserTags" closable @click="editTag(tag.id,tag.name)" @close="deleteTag(tag.id)" :disable-transitions="false" :key="tag.id">
|
||||
{{tag.id}} {{tag.name}}
|
||||
</el-tag>
|
||||
<el-input class="input-new-tag" v-if="inputVisible" placeholder="回车确认" v-model="inputValue" ref="saveTagInput" size="small" @keyup.enter.native="addTag">
|
||||
</el-input>
|
||||
<el-button v-else class="button-new-tag" size="small" @click="showInput">+ 添加</el-button>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible=false">关闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'wx-user-tags-manager',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible:false,
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
submitting:false,
|
||||
}
|
||||
},
|
||||
computed: mapState({
|
||||
wxUserTags:state=>state.wxUserTags.tags
|
||||
}),
|
||||
mounted() {
|
||||
this.getWxUserTags();
|
||||
},
|
||||
methods: {
|
||||
show(){
|
||||
this.dialogVisible=true;
|
||||
},
|
||||
getWxUserTags() {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/manage/wxUserTags/list'),
|
||||
method: 'get',
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.$store.commit('wxUserTags/updateTags', data.list)
|
||||
} else {
|
||||
this.$message.error(data.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteTag(tagid) {
|
||||
if(this.submitting){
|
||||
return
|
||||
}
|
||||
this.$confirm(`确定删除标签?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.submitting=true
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/manage/wxUserTags/delete/'+tagid),
|
||||
method: 'post',
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.getWxUserTags();
|
||||
this.$emit('change');
|
||||
} else {
|
||||
this.$message.error(data.msg)
|
||||
}
|
||||
this.submitting=false;
|
||||
})
|
||||
})
|
||||
},
|
||||
showInput() {
|
||||
this.inputVisible = true;
|
||||
this.$nextTick(_ => {
|
||||
this.$refs.saveTagInput.$refs.input.focus();
|
||||
});
|
||||
},
|
||||
addTag() {
|
||||
let newTagName = this.inputValue;
|
||||
this.saveTag(newTagName)
|
||||
this.inputVisible = false;
|
||||
this.inputValue = '';
|
||||
},
|
||||
editTag(tagid,orignName=''){
|
||||
this.$prompt('请输入新标签名称', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
inputValue:orignName,
|
||||
inputPattern: /^.{1,30}$/,
|
||||
inputErrorMessage: '名称1-30字符'
|
||||
}).then(({ value }) => {
|
||||
console.log(value)
|
||||
this.saveTag(value,tagid)
|
||||
})
|
||||
},
|
||||
saveTag(name,tagid){
|
||||
if(this.submitting){
|
||||
return
|
||||
}
|
||||
this.submitting=true
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/manage/wxUserTags/save'),
|
||||
method: 'post',
|
||||
data:this.$http.adornData({
|
||||
id : tagid?tagid:undefined,
|
||||
name : name
|
||||
})
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.getWxUserTags();
|
||||
this.$emit('change');
|
||||
} else {
|
||||
this.$message.error(data.msg)
|
||||
}
|
||||
this.submitting=false;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.panel {
|
||||
flex: 1;
|
||||
}
|
||||
.el-tag,.button-new-tag {
|
||||
margin: 5px;
|
||||
}
|
||||
.input-new-tag {
|
||||
width: inherit;
|
||||
}
|
||||
</style>
|
@ -0,0 +1 @@
|
||||
module.exports = file => () => import('@/views/' + file + '.vue')
|
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* 全站路由配置
|
||||
*
|
||||
* 建议:
|
||||
* 1. 代码中路由统一使用name属性跳转(不使用path属性)
|
||||
*/
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import http from '@/utils/httpRequest'
|
||||
import { isURL } from '@/utils/validate'
|
||||
import { clearLoginInfo } from '@/utils'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const _import = require('./import-views')
|
||||
// 全局路由(无需嵌套上左右整体布局)
|
||||
const globalRoutes = [
|
||||
{ path: '/404', component: () => import('@/views/common/404'), name: '404', meta: { title: '404未找到' } },
|
||||
{ path: '/login', component: () => import('@/views/common/login'), name: 'login', meta: { title: '登录' } }
|
||||
]
|
||||
|
||||
// 主入口路由(需嵌套上左右整体布局)
|
||||
const mainRoutes = {
|
||||
path: '/',
|
||||
component: () => import('@/views/main'),
|
||||
name: 'main',
|
||||
redirect: { name: 'home' },
|
||||
meta: { title: '主入口整体布局' },
|
||||
children: [
|
||||
// 通过meta对象设置路由展示方式
|
||||
// 1. isTab: 是否通过tab展示内容, true: 是, false: 否
|
||||
// 2. iframeUrl: 是否通过iframe嵌套展示内容, '以http[s]://开头': 是, '': 否
|
||||
// 提示: 如需要通过iframe嵌套展示内容, 但不通过tab打开, 请自行创建组件使用iframe处理!
|
||||
{ path: '/home', component: () => import('@/views/common/home'), name: 'home', meta: { title: '首页' } },
|
||||
{ path: '/theme', component: () => import('@/views/common/theme'), name: 'theme', meta: { title: '主题' } },
|
||||
],
|
||||
beforeEnter(to, from, next) {
|
||||
let token = Vue.cookie.get('token')
|
||||
if (!token || !/\S/.test(token)) {
|
||||
clearLoginInfo()
|
||||
next({ name: 'login' })
|
||||
}
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'hash',
|
||||
scrollBehavior: () => ({ y: 0 }),
|
||||
isAddDynamicMenuRoutes: false, // 是否已经添加动态(菜单)路由
|
||||
routes: globalRoutes.concat(mainRoutes)
|
||||
})
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
// 添加动态(菜单)路由
|
||||
// 1. 已经添加 or 全局路由, 直接访问
|
||||
// 2. 获取菜单列表, 添加并保存本地存储
|
||||
if (router.options.isAddDynamicMenuRoutes || fnCurrentRouteType(to, globalRoutes) === 'global') {
|
||||
next()
|
||||
} else {
|
||||
http({
|
||||
url: http.adornUrl('/sys/menu/nav'),
|
||||
method: 'get',
|
||||
params: http.adornParams()
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
fnAddDynamicMenuRoutes(data.menuList)
|
||||
router.options.isAddDynamicMenuRoutes = true
|
||||
sessionStorage.setItem('menuList', JSON.stringify(data.menuList || '[]'))
|
||||
sessionStorage.setItem('permissions', JSON.stringify(data.permissions || '[]'))
|
||||
next({ ...to, replace: true })
|
||||
} else {
|
||||
sessionStorage.setItem('menuList', '[]')
|
||||
sessionStorage.setItem('permissions', '[]')
|
||||
next()
|
||||
}
|
||||
}).catch((e) => {
|
||||
console.log(`%c${e} 请求菜单列表和权限失败,跳转至登录页!!`, 'color:blue')
|
||||
router.push({ name: 'login' })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 判断当前路由类型, global: 全局路由, main: 主入口路由
|
||||
* @param {*} route 当前路由
|
||||
*/
|
||||
function fnCurrentRouteType(route, globalRoutes = []) {
|
||||
var temp = []
|
||||
for (var i = 0; i < globalRoutes.length; i++) {
|
||||
if (route.path === globalRoutes[i].path) {
|
||||
return 'global'
|
||||
} else if (globalRoutes[i].children && globalRoutes[i].children.length >= 1) {
|
||||
temp = temp.concat(globalRoutes[i].children)
|
||||
}
|
||||
}
|
||||
return temp.length >= 1 ? fnCurrentRouteType(route, temp) : 'main'
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加动态(菜单)路由
|
||||
* @param {*} menuList 菜单列表
|
||||
* @param {*} routes 递归创建的动态(菜单)路由
|
||||
*/
|
||||
function fnAddDynamicMenuRoutes(menuList = [], routes = []) {
|
||||
var temp = []
|
||||
for (var i = 0; i < menuList.length; i++) {
|
||||
if (menuList[i].list && menuList[i].list.length >= 1) {
|
||||
temp = temp.concat(menuList[i].list)
|
||||
} else if (menuList[i].url && /\S/.test(menuList[i].url)) {
|
||||
menuList[i].url = menuList[i].url.replace(/^\//, '')
|
||||
var route = {
|
||||
path: menuList[i].url.replace('/', '-'),
|
||||
component: null,
|
||||
name: menuList[i].url.replace('/', '-'),
|
||||
meta: {
|
||||
menuId: menuList[i].menuId,
|
||||
title: menuList[i].name,
|
||||
isDynamic: true,
|
||||
isTab: true,
|
||||
iframeUrl: ''
|
||||
}
|
||||
}
|
||||
// url以http[s]://开头, 通过iframe展示
|
||||
if (isURL(menuList[i].url)) {
|
||||
route['path'] = `i-${menuList[i].menuId}`
|
||||
route['name'] = `i-${menuList[i].menuId}`
|
||||
route['meta']['iframeUrl'] = menuList[i].url
|
||||
} else {
|
||||
try {
|
||||
route['component'] = _import(`modules/${menuList[i].url}`) || null
|
||||
// route['component'] = ()=>import(`@/views/modules/${menuList[i].url}.vue`) || null
|
||||
} catch (e) { }
|
||||
}
|
||||
routes.push(route)
|
||||
}
|
||||
}
|
||||
if (temp.length >= 1) {
|
||||
fnAddDynamicMenuRoutes(temp, routes)
|
||||
} else {
|
||||
mainRoutes.name = 'main-dynamic'
|
||||
mainRoutes.children = routes
|
||||
router.addRoutes([
|
||||
mainRoutes,
|
||||
{ path: '*', redirect: { name: '404' } }
|
||||
])
|
||||
sessionStorage.setItem('dynamicMenuRoutes', JSON.stringify(mainRoutes.children || '[]'))
|
||||
console.log('\n')
|
||||
console.log('%c!<-------------------- 动态(菜单)路由 s -------------------->', 'color:blue')
|
||||
console.log(mainRoutes.children)
|
||||
console.log('%c!<-------------------- 动态(菜单)路由 e -------------------->', 'color:blue')
|
||||
}
|
||||
}
|
||||
export default router
|
@ -0,0 +1,24 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import common from './modules/common'
|
||||
import user from './modules/user'
|
||||
import article from './modules/article'
|
||||
import message from './modules/message'
|
||||
import wxUserTags from './modules/wxUserTags'
|
||||
import wxAccount from './modules/wxAccount'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
modules: {
|
||||
common,
|
||||
user,
|
||||
article,
|
||||
message,
|
||||
wxUserTags,
|
||||
wxAccount
|
||||
},
|
||||
mutations: {
|
||||
},
|
||||
strict: true
|
||||
})
|
@ -0,0 +1,12 @@
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
ARTICLE_TYPES: {
|
||||
1: '普通文章',
|
||||
5: '帮助中心',
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
import router from '@/router'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
// 页面文档可视高度(随窗口改变大小)
|
||||
documentClientHeight: 0,
|
||||
// 导航条, 布局风格, defalut(默认) / inverse(反向)
|
||||
navbarLayoutType: 'default',
|
||||
// 侧边栏, 布局皮肤, light(浅色) / dark(黑色)
|
||||
sidebarLayoutSkin: 'dark',
|
||||
// 侧边栏, 折叠状态
|
||||
sidebarFold: false,
|
||||
// 侧边栏, 菜单
|
||||
menuList: [],
|
||||
menuActiveName: '',
|
||||
// 内容, 是否需要刷新
|
||||
contentIsNeedRefresh: false,
|
||||
// 主入口标签页
|
||||
mainTabs: [],
|
||||
mainTabsActiveName: ''
|
||||
},
|
||||
mutations: {
|
||||
updateDocumentClientHeight(state, height) {
|
||||
state.documentClientHeight = height
|
||||
},
|
||||
updateNavbarLayoutType(state, type) {
|
||||
state.navbarLayoutType = type
|
||||
},
|
||||
updateSidebarLayoutSkin(state, skin) {
|
||||
state.sidebarLayoutSkin = skin
|
||||
},
|
||||
updateSidebarFold(state, fold) {
|
||||
state.sidebarFold = fold
|
||||
},
|
||||
updateMenuList(state, list) {
|
||||
state.menuList = list
|
||||
},
|
||||
updateMenuActiveName(state, name) {
|
||||
state.menuActiveName = name
|
||||
},
|
||||
updateContentIsNeedRefresh(state, status) {
|
||||
state.contentIsNeedRefresh = status
|
||||
},
|
||||
updateMainTabs(state, tabs) {
|
||||
state.mainTabs = tabs
|
||||
},
|
||||
updateMainTabsActiveName(state, name) {
|
||||
state.mainTabsActiveName = name
|
||||
},
|
||||
removeTab(state, tabName) {
|
||||
state.mainTabs = state.mainTabs.filter(item => item.name !== tabName)
|
||||
if (state.mainTabs.length >= 1) {
|
||||
// 当前选中tab被删除
|
||||
if (tabName === state.mainTabsActiveName) {
|
||||
var tab = state.mainTabs[state.mainTabs.length - 1]
|
||||
router.push({ name: tab.name, query: tab.query, params: tab.params }, () => {
|
||||
state.mainTabsActiveName = tab.name
|
||||
})
|
||||
}
|
||||
} else {
|
||||
state.menuActiveName = ''
|
||||
router.push({ name: 'home' })
|
||||
}
|
||||
},
|
||||
closeCurrentTab(state) {
|
||||
this.commit('common/removeTab', state.mainTabsActiveName)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
XmlMsgType:{
|
||||
"text":"文字",
|
||||
"image":"图片",
|
||||
"voice":"语音",
|
||||
"shortvideo":"短视频",
|
||||
"video":"视频",
|
||||
"news":"图文",
|
||||
"music":"音乐",
|
||||
"location":"位置",
|
||||
"link":"链接",
|
||||
"event":"事件",
|
||||
"transfer_customer_service":"转客服"
|
||||
},
|
||||
KefuMsgType: {
|
||||
"text": "文本消息",
|
||||
"image": "图片消息",
|
||||
"voice": "语音消息",
|
||||
"video": "视频消息",
|
||||
"music": "音乐消息",
|
||||
"news": "文章链接",
|
||||
"mpnews": "公众号图文消息",
|
||||
"wxcard": "卡券消息",
|
||||
"miniprogrampage": "小程序消息",
|
||||
"msgmenu": "菜单消息"
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
id: 0,
|
||||
name: ''
|
||||
},
|
||||
mutations: {
|
||||
updateId(state, id) {
|
||||
state.id = id
|
||||
},
|
||||
updateName(state, name) {
|
||||
state.name = name
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import Vue from 'vue'
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
ACCOUNT_TYPES:{
|
||||
1:'订阅号',
|
||||
2:'服务号'
|
||||
},
|
||||
accountList:[],
|
||||
selectedAppid:''
|
||||
},
|
||||
mutations: {
|
||||
updateAccountList (state, list) {
|
||||
state.accountList = list
|
||||
if(!list.length)return
|
||||
if(!state.selectedAppid){
|
||||
let appidCookie = Vue.cookie.get('appid')
|
||||
let selectedAppid = appidCookie?appidCookie:list[0].appid
|
||||
this.commit('wxAccount/selectAccount',selectedAppid)
|
||||
}
|
||||
},
|
||||
selectAccount (state, appid) {
|
||||
Vue.cookie.set('appid',appid)
|
||||
let oldAppid = state.selectedAppid
|
||||
state.selectedAppid = appid
|
||||
if(oldAppid){//切换账号时刷新网页
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
tags:[]
|
||||
},
|
||||
mutations: {
|
||||
updateTags (state, tags) {
|
||||
state.tags = tags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,77 @@
|
||||
import Vue from 'vue'
|
||||
import axios from 'axios'
|
||||
import router from '@/router'
|
||||
import qs from 'qs'
|
||||
import merge from 'lodash/merge'
|
||||
import { clearLoginInfo } from '@/utils'
|
||||
const baseUrl = '/wx'
|
||||
|
||||
const http = axios.create({
|
||||
timeout: 1000 * 30,
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 请求拦截
|
||||
*/
|
||||
http.interceptors.request.use(config => {
|
||||
config.headers['token'] = Vue.cookie.get('token') // 请求头带上token
|
||||
return config
|
||||
}, error => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
/**
|
||||
* 响应拦截
|
||||
*/
|
||||
http.interceptors.response.use(response => {
|
||||
if (response.data && response.data.code === 401) { // 401, token失效
|
||||
clearLoginInfo()
|
||||
router.push({ name: 'login' })
|
||||
}
|
||||
return response
|
||||
}, error => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
/**
|
||||
* 请求地址处理
|
||||
* @param {*} actionName action方法名称
|
||||
*/
|
||||
http.adornUrl = (actionName) => {
|
||||
// 非生产环境 && 开启代理, 接口前缀统一使用[/proxyApi/]前缀做代理拦截!
|
||||
return baseUrl + actionName
|
||||
}
|
||||
|
||||
/**
|
||||
* get请求参数处理
|
||||
* @param {*} params 参数对象
|
||||
* @param {*} openDefultParams 是否开启默认参数?
|
||||
*/
|
||||
http.adornParams = (params = {}, openDefultParams = true) => {
|
||||
var defaults = {
|
||||
't': new Date().getTime()
|
||||
}
|
||||
return openDefultParams ? merge(defaults, params) : params
|
||||
}
|
||||
|
||||
/**
|
||||
* post请求数据处理
|
||||
* @param {*} data 数据对象
|
||||
* @param {*} openDefultdata 是否开启默认数据?
|
||||
* @param {*} contentType 数据格式
|
||||
* json: 'application/json; charset=utf-8'
|
||||
* form: 'application/x-www-form-urlencoded; charset=utf-8'
|
||||
*/
|
||||
http.adornData = (data = {}, openDefultdata = true, contentType = 'json') => {
|
||||
var defaults = {
|
||||
't': new Date().getTime()
|
||||
}
|
||||
data = openDefultdata ? merge(defaults, data) : data
|
||||
return contentType === 'json' ? JSON.stringify(data) : qs.stringify(data)
|
||||
}
|
||||
|
||||
export default http
|
@ -0,0 +1,58 @@
|
||||
import Vue from 'vue'
|
||||
import router from '@/router'
|
||||
import store from '@/store'
|
||||
|
||||
/**
|
||||
* 获取uuid
|
||||
*/
|
||||
export function getUUID() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
|
||||
return (c === 'x' ? (Math.random() * 16 | 0) : ('r&0x3' | '0x8')).toString(16)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有权限
|
||||
* @param {*} key
|
||||
*/
|
||||
export function isAuth(key) {
|
||||
return JSON.parse(sessionStorage.getItem('permissions') || '[]').indexOf(key) !== -1 || false
|
||||
}
|
||||
|
||||
/**
|
||||
* 树形数据转换
|
||||
* @param {*} data
|
||||
* @param {*} id
|
||||
* @param {*} pid
|
||||
*/
|
||||
export function treeDataTranslate(data, id = 'id', pid = 'parentId') {
|
||||
var res = []
|
||||
var temp = {}
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
temp[data[i][id]] = data[i]
|
||||
}
|
||||
for (var k = 0; k < data.length; k++) {
|
||||
if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) {
|
||||
if (!temp[data[k][pid]]['children']) {
|
||||
temp[data[k][pid]]['children'] = []
|
||||
}
|
||||
if (!temp[data[k][pid]]['_level']) {
|
||||
temp[data[k][pid]]['_level'] = 1
|
||||
}
|
||||
data[k]['_level'] = temp[data[k][pid]]._level + 1
|
||||
temp[data[k][pid]]['children'].push(data[k])
|
||||
} else {
|
||||
res.push(data[k])
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除登录信息
|
||||
*/
|
||||
export function clearLoginInfo() {
|
||||
Vue.cookie.delete('token')
|
||||
//store.commit('resetStore')
|
||||
router.options.isAddDynamicMenuRoutes = false
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 邮箱
|
||||
* @param {*} s
|
||||
*/
|
||||
export function isEmail(s) {
|
||||
return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s)
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
* @param {*} s
|
||||
*/
|
||||
export function isMobile(s) {
|
||||
return /^1[0-9]{10}$/.test(s)
|
||||
}
|
||||
|
||||
/**
|
||||
* 电话号码
|
||||
* @param {*} s
|
||||
*/
|
||||
export function isPhone(s) {
|
||||
return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s)
|
||||
}
|
||||
|
||||
/**
|
||||
* URL地址
|
||||
* @param {*} s
|
||||
*/
|
||||
export function isURL(s) {
|
||||
return /^http[s]?:\/\/.*/.test(s)
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<div class="mod-home">
|
||||
<h3>欢迎使用微信管理系统</h3>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.mod-home {
|
||||
line-height: 2.5;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,184 @@
|
||||
<template>
|
||||
<div class="site-wrapper site-page--login">
|
||||
<div class="site-content__wrapper">
|
||||
<div class="site-content">
|
||||
<div class="brand-info">
|
||||
<h2 class="brand-info__text">微信后台管理系统</h2>
|
||||
<p class="brand-info__intro">微信公众号后台管理系统。</p>
|
||||
</div>
|
||||
<div class="login-main">
|
||||
<h3 class="login-title">管理员登录</h3>
|
||||
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" status-icon>
|
||||
<el-form-item prop="userName">
|
||||
<el-input v-model="dataForm.userName" placeholder="帐号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input v-model="dataForm.password" type="password" placeholder="密码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="captcha">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<el-input v-model="dataForm.captcha" placeholder="验证码">
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="10" class="login-captcha">
|
||||
<img :src="captchaPath" @click="getCaptcha()" alt="">
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button class="login-btn-submit" type="primary" @click="dataFormSubmit()">登录</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getUUID } from '@/utils'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
dataForm: {
|
||||
userName: '',
|
||||
password: '',
|
||||
uuid: '',
|
||||
captcha: ''
|
||||
},
|
||||
dataRule: {
|
||||
userName: [
|
||||
{ required: true, message: '帐号不能为空', trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '密码不能为空', trigger: 'blur' }
|
||||
],
|
||||
captcha: [
|
||||
{ required: true, message: '验证码不能为空', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
captchaPath: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getCaptcha()
|
||||
},
|
||||
methods: {
|
||||
// 提交表单
|
||||
dataFormSubmit() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/login'),
|
||||
method: 'post',
|
||||
data: this.$http.adornData({
|
||||
'username': this.dataForm.userName,
|
||||
'password': this.dataForm.password,
|
||||
'uuid': this.dataForm.uuid,
|
||||
'captcha': this.dataForm.captcha
|
||||
})
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.$cookie.set('token', data.token)
|
||||
this.$router.replace({ name: 'home' })
|
||||
} else {
|
||||
this.getCaptcha()
|
||||
this.$message.error(data.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取验证码
|
||||
getCaptcha() {
|
||||
this.dataForm.uuid = getUUID()
|
||||
this.captchaPath = this.$http.adornUrl(`/captcha?uuid=${this.dataForm.uuid}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.site-wrapper.site-page--login {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: rgba(38, 50, 56, 0.5);
|
||||
overflow: hidden;
|
||||
&:before {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
content: "";
|
||||
background-color: #fa8bff;
|
||||
background-image: linear-gradient(
|
||||
45deg,
|
||||
#fa8bff 0%,
|
||||
#2bd2ff 52%,
|
||||
#2bff88 90%
|
||||
);
|
||||
background-size: cover;
|
||||
}
|
||||
.site-content__wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
background-color: transparent;
|
||||
}
|
||||
.site-content {
|
||||
min-height: 100%;
|
||||
padding: 30px 500px 30px 30px;
|
||||
}
|
||||
.brand-info {
|
||||
margin: 220px 100px 0 90px;
|
||||
color: #fff;
|
||||
}
|
||||
.brand-info__text {
|
||||
margin: 0 0 22px 0;
|
||||
font-size: 48px;
|
||||
font-weight: 400;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.brand-info__intro {
|
||||
margin: 10px 0;
|
||||
font-size: 16px;
|
||||
line-height: 1.58;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.login-main {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 150px 60px 180px;
|
||||
width: 470px;
|
||||
min-height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
.login-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
.login-captcha {
|
||||
overflow: hidden;
|
||||
> img {
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.login-btn-submit {
|
||||
width: 100%;
|
||||
margin-top: 38px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<el-form>
|
||||
<h2>布局设置</h2>
|
||||
<el-form-item label="导航条类型">
|
||||
<el-radio-group v-model="navbarLayoutType">
|
||||
<el-radio label="default" border>default</el-radio>
|
||||
<el-radio label="inverse" border>inverse</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="侧边栏皮肤">
|
||||
<el-radio-group v-model="sidebarLayoutSkin">
|
||||
<el-radio label="light" border>light</el-radio>
|
||||
<el-radio label="dark" border>dark</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
navbarLayoutType: {
|
||||
get() { return this.$store.state.common.navbarLayoutType },
|
||||
set(val) { this.$store.commit('common/updateNavbarLayoutType', val) }
|
||||
},
|
||||
sidebarLayoutSkin: {
|
||||
get() { return this.$store.state.common.sidebarLayoutSkin },
|
||||
set(val) { this.$store.commit('common/updateSidebarLayoutSkin', val) }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div @click="selectFile">
|
||||
<input type="file" ref="fileInput" v-show="false" @change="onFileChange" />
|
||||
<div>{{uploading?infoText:'上传文件'}}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "oss-uploader",
|
||||
data() {
|
||||
return {
|
||||
uploading: false,
|
||||
infoText: "上传中...",
|
||||
cosConfig: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/oss/config'),
|
||||
method: 'get',
|
||||
params: this.$http.adornParams()
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200 && data.config.type) {
|
||||
this.cosConfig = data.config
|
||||
} else {
|
||||
this.$message.error('请先配置云存储相关信息!')
|
||||
}
|
||||
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
selectFile() {//选择文件
|
||||
if (!this.uploading) {
|
||||
this.$refs.fileInput.click();
|
||||
}
|
||||
},
|
||||
onFileChange() {
|
||||
let file = this.$refs.fileInput.files[0];
|
||||
this.uploading = true;
|
||||
let formData = new FormData();
|
||||
formData.append("file", file)
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/oss/upload'),
|
||||
method: 'post',
|
||||
data: formData
|
||||
}).then(({ data }) => {
|
||||
console.log(data)
|
||||
if (data && data.code === 200) {
|
||||
this.$emit('uploaded', data.url)
|
||||
} else {
|
||||
this.$message.error("文件上传失败:" + data.msg)
|
||||
}
|
||||
this.uploading = false;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<div class="mod-oss">
|
||||
<el-form :inline="true" :model="dataForm">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="configHandle()">云存储配置</el-button>
|
||||
<el-button type="primary">
|
||||
<OssUploader @uploaded="getDataList"></OssUploader>
|
||||
</el-button>
|
||||
<el-button type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0">批量删除</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="dataList" border v-loading="dataListLoading" @selection-change="selectionChangeHandle" style="width: 100%;">
|
||||
<el-table-column type="selection" header-align="center" align="center" width="50">
|
||||
</el-table-column>
|
||||
<el-table-column prop="id" header-align="center" align="center" width="80" label="ID">
|
||||
</el-table-column>
|
||||
<el-table-column prop="url" header-align="center" align="center" label="URL地址">
|
||||
<div slot-scope="scope">
|
||||
<img class="image-sm" v-if="isImageUrl(scope.row.url)" :src="scope.row.url" />
|
||||
<a :href="scope.row.url" target="_blank" v-else>{{scope.row.url}}</a>
|
||||
</div>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createDate" header-align="center" align="center" width="180" label="创建时间">
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" header-align="center" align="center" width="150" label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click="deleteHandle(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" :total="totalCount" layout="total, sizes, prev, pager, next, jumper">
|
||||
</el-pagination>
|
||||
<!-- 弹窗, 云存储配置 -->
|
||||
<config v-show="configVisible" ref="config"></config>
|
||||
<!-- 弹窗, 上传文件 -->
|
||||
<upload v-show="uploadVisible" ref="upload" @refreshDataList="getDataList"></upload>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
dataForm: {},
|
||||
dataList: [],
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
dataListLoading: false,
|
||||
dataListSelections: [],
|
||||
configVisible: false,
|
||||
uploadVisible: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Config: () => import('./oss-config'),
|
||||
OssUploader: () => import('./oss-uploader')
|
||||
},
|
||||
activated() {
|
||||
this.getDataList()
|
||||
},
|
||||
methods: {
|
||||
// 获取数据列表
|
||||
getDataList() {
|
||||
this.dataListLoading = true
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/oss/list'),
|
||||
method: 'get',
|
||||
params: this.$http.adornParams({
|
||||
'page': this.pageIndex,
|
||||
'limit': this.pageSize,
|
||||
'sidx': 'id',
|
||||
'order': 'desc'
|
||||
})
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.dataList = data.page.list
|
||||
this.totalCount = data.page.totalCount
|
||||
} else {
|
||||
this.dataList = []
|
||||
this.totalCount = 0
|
||||
}
|
||||
this.dataListLoading = false
|
||||
})
|
||||
},
|
||||
// 每页数
|
||||
sizeChangeHandle(val) {
|
||||
this.pageSize = val
|
||||
this.pageIndex = 1
|
||||
this.getDataList()
|
||||
},
|
||||
// 当前页
|
||||
currentChangeHandle(val) {
|
||||
this.pageIndex = val
|
||||
this.getDataList()
|
||||
},
|
||||
// 多选
|
||||
selectionChangeHandle(val) {
|
||||
this.dataListSelections = val
|
||||
},
|
||||
// 云存储配置
|
||||
configHandle() {
|
||||
this.configVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.config.init()
|
||||
})
|
||||
},
|
||||
// 上传文件
|
||||
uploadHandle() {
|
||||
this.uploadVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.upload.init()
|
||||
})
|
||||
},
|
||||
// 删除
|
||||
deleteHandle(id) {
|
||||
var ids = id ? [id] : this.dataListSelections.map(item => item.id)
|
||||
this.$confirm(`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/oss/delete'),
|
||||
method: 'post',
|
||||
data: this.$http.adornData(ids, false)
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.$message({
|
||||
message: '操作成功',
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
onClose: () => this.getDataList()
|
||||
})
|
||||
} else {
|
||||
this.$message.error(data.msg)
|
||||
}
|
||||
})
|
||||
}).catch(() => { })
|
||||
},
|
||||
isImageUrl(url) {
|
||||
return url && /.*\.(gif|jpg|jpeg|png|GIF|JPEG|JPG|PNG)/.test(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible">
|
||||
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px">
|
||||
<el-form-item label="参数名" prop="paramKey">
|
||||
<el-input v-model="dataForm.paramKey" placeholder="参数名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="参数值" prop="paramValue">
|
||||
<el-input v-model="dataForm.paramValue" placeholder="参数值"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="dataForm.remark" placeholder="备注"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="dataFormSubmit()">确定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
dataForm: {
|
||||
id: 0,
|
||||
paramKey: '',
|
||||
paramValue: '',
|
||||
remark: ''
|
||||
},
|
||||
dataRule: {
|
||||
paramKey: [
|
||||
{ required: true, message: '参数名不能为空', trigger: 'blur' }
|
||||
],
|
||||
paramValue: [
|
||||
{ required: true, message: '参数值不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init(id) {
|
||||
this.dataForm.id = id || 0
|
||||
this.visible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].resetFields()
|
||||
if (this.dataForm.id) {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl(`/sys/config/info/${this.dataForm.id}`),
|
||||
method: 'get',
|
||||
params: this.$http.adornParams()
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.dataForm.paramKey = data.config.paramKey
|
||||
this.dataForm.paramValue = data.config.paramValue
|
||||
this.dataForm.remark = data.config.remark
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
// 表单提交
|
||||
dataFormSubmit() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl(`/sys/config/${!this.dataForm.id ? 'save' : 'update'}`),
|
||||
method: 'post',
|
||||
data: this.$http.adornData({
|
||||
'id': this.dataForm.id || undefined,
|
||||
'paramKey': this.dataForm.paramKey,
|
||||
'paramValue': this.dataForm.paramValue,
|
||||
'remark': this.dataForm.remark
|
||||
})
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.$message({
|
||||
message: '操作成功',
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
onClose: () => {
|
||||
this.visible = false
|
||||
this.$emit('refreshDataList')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$message.error(data.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<div class="mod-config">
|
||||
<el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
|
||||
<el-form-item>
|
||||
<el-input v-model="dataForm.paramKey" placeholder="参数名" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="getDataList()">查询</el-button>
|
||||
<el-button type="primary" @click="addOrUpdateHandle()">新增</el-button>
|
||||
<el-button type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0">批量删除</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="dataList" border v-loading="dataListLoading" @selection-change="selectionChangeHandle" style="width: 100%;">
|
||||
<el-table-column type="selection" header-align="center" align="center" width="50">
|
||||
</el-table-column>
|
||||
<el-table-column prop="id" header-align="center" align="center" width="80" label="ID">
|
||||
</el-table-column>
|
||||
<el-table-column prop="paramKey" header-align="center" align="center" label="参数名">
|
||||
</el-table-column>
|
||||
<el-table-column prop="paramValue" header-align="center" align="center" label="参数值">
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" header-align="center" align="center" label="备注">
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" header-align="center" align="center" width="150" label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click="addOrUpdateHandle(scope.row.id)">修改</el-button>
|
||||
<el-button type="text" size="small" @click="deleteHandle(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" :total="totalCount" layout="total, sizes, prev, pager, next, jumper">
|
||||
</el-pagination>
|
||||
<!-- 弹窗, 新增 / 修改 -->
|
||||
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AddOrUpdate from './config-add-or-update'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
dataForm: {
|
||||
paramKey: ''
|
||||
},
|
||||
dataList: [],
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
dataListLoading: false,
|
||||
dataListSelections: [],
|
||||
addOrUpdateVisible: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
AddOrUpdate
|
||||
},
|
||||
activated() {
|
||||
this.getDataList()
|
||||
},
|
||||
methods: {
|
||||
// 获取数据列表
|
||||
getDataList() {
|
||||
this.dataListLoading = true
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/config/list'),
|
||||
method: 'get',
|
||||
params: this.$http.adornParams({
|
||||
'page': this.pageIndex,
|
||||
'limit': this.pageSize,
|
||||
'paramKey': this.dataForm.paramKey
|
||||
})
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.dataList = data.page.list
|
||||
this.totalCount = data.page.totalCount
|
||||
} else {
|
||||
this.dataList = []
|
||||
this.totalCount = 0
|
||||
}
|
||||
this.dataListLoading = false
|
||||
})
|
||||
},
|
||||
// 每页数
|
||||
sizeChangeHandle(val) {
|
||||
this.pageSize = val
|
||||
this.pageIndex = 1
|
||||
this.getDataList()
|
||||
},
|
||||
// 当前页
|
||||
currentChangeHandle(val) {
|
||||
this.pageIndex = val
|
||||
this.getDataList()
|
||||
},
|
||||
// 多选
|
||||
selectionChangeHandle(val) {
|
||||
this.dataListSelections = val
|
||||
},
|
||||
// 新增 / 修改
|
||||
addOrUpdateHandle(id) {
|
||||
this.addOrUpdateVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.addOrUpdate.init(id)
|
||||
})
|
||||
},
|
||||
// 删除
|
||||
deleteHandle(id) {
|
||||
var ids = id ? [id] : this.dataListSelections.map(item => item.id)
|
||||
this.$confirm(`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/config/delete'),
|
||||
method: 'post',
|
||||
data: this.$http.adornData(ids, false)
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.$message({
|
||||
message: '操作成功',
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
onClose: () => this.getDataList()
|
||||
})
|
||||
} else {
|
||||
this.$message.error(data.msg)
|
||||
}
|
||||
})
|
||||
}).catch(() => { })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div class="mod-log">
|
||||
<el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
|
||||
<el-form-item>
|
||||
<el-input v-model="dataForm.key" placeholder="用户名/用户操作" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="getDataList()">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="dataList" border v-loading="dataListLoading" style="width: 100%">
|
||||
<el-table-column prop="id" header-align="center" align="center" width="80" label="ID">
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" header-align="center" align="center" label="用户名">
|
||||
</el-table-column>
|
||||
<el-table-column prop="operation" header-align="center" align="center" label="用户操作">
|
||||
</el-table-column>
|
||||
<el-table-column prop="method" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="请求方法">
|
||||
</el-table-column>
|
||||
<el-table-column prop="params" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="请求参数">
|
||||
</el-table-column>
|
||||
<el-table-column prop="time" header-align="center" align="center" label="执行时长(毫秒)">
|
||||
</el-table-column>
|
||||
<el-table-column prop="ip" header-align="center" align="center" width="150" label="IP地址">
|
||||
</el-table-column>
|
||||
<el-table-column prop="createDate" header-align="center" align="center" width="180" label="创建时间">
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" :total="totalCount" layout="total, sizes, prev, pager, next, jumper">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
dataForm: {
|
||||
key: ''
|
||||
},
|
||||
dataList: [],
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
dataListLoading: false,
|
||||
selectionDataList: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getDataList()
|
||||
},
|
||||
methods: {
|
||||
// 获取数据列表
|
||||
getDataList() {
|
||||
this.dataListLoading = true
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/log/list'),
|
||||
method: 'get',
|
||||
params: this.$http.adornParams({
|
||||
'page': this.pageIndex,
|
||||
'limit': this.pageSize,
|
||||
'key': this.dataForm.key,
|
||||
'sidx': 'id',
|
||||
'order': 'desc'
|
||||
})
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.dataList = data.page.list
|
||||
this.totalCount = data.page.totalCount
|
||||
} else {
|
||||
this.dataList = []
|
||||
this.totalCount = 0
|
||||
}
|
||||
this.dataListLoading = false
|
||||
})
|
||||
},
|
||||
// 每页数
|
||||
sizeChangeHandle(val) {
|
||||
this.pageSize = val
|
||||
this.pageIndex = 1
|
||||
this.getDataList()
|
||||
},
|
||||
// 当前页
|
||||
currentChangeHandle(val) {
|
||||
this.pageIndex = val
|
||||
this.getDataList()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,218 @@
|
||||
<template>
|
||||
<el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible">
|
||||
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px">
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-radio-group v-model="dataForm.type">
|
||||
<el-radio v-for="(type, index) in dataForm.typeList" :label="index" :key="index">{{ type }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="dataForm.typeList[dataForm.type] + '名称'" prop="name">
|
||||
<el-input v-model="dataForm.name" :placeholder="dataForm.typeList[dataForm.type] + '名称'"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="上级菜单" prop="parentName">
|
||||
<el-popover ref="menuListPopover" placement="bottom-start" trigger="click">
|
||||
<el-tree :data="menuList" :props="menuListTreeProps" node-key="menuId" ref="menuListTree" @current-change="menuListTreeCurrentChangeHandle" :default-expand-all="true" :highlight-current="true" :expand-on-click-node="false">
|
||||
</el-tree>
|
||||
</el-popover>
|
||||
<el-input v-model="dataForm.parentName" v-popover:menuListPopover :readonly="true" placeholder="点击选择上级菜单" class="menu-list__input"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataForm.type === 1" label="菜单路由" prop="url">
|
||||
<el-input v-model="dataForm.url" placeholder="菜单路由"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataForm.type !== 0" label="授权标识" prop="perms">
|
||||
<el-input v-model="dataForm.perms" placeholder="多个用逗号分隔, 如: user:list,user:create"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="dataForm.type !== 2" label="菜单图标" prop="icon">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-input v-model="dataForm.icon" placeholder="菜单图标名称" class="icon-list__input"></el-input>
|
||||
</el-col>
|
||||
<el-col :span="12" class="icon-list__tips">
|
||||
<el-form-item v-if="dataForm.type !== 2" label="排序号" prop="orderNum">
|
||||
<el-input-number v-model="dataForm.orderNum" controls-position="right" :min="0" label="排序号"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<div>参考ElementUI图标库, <a href="https://element.eleme.cn/#/zh-CN/component/icon" target="_blank">找图标</a></div>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="dataFormSubmit()">确定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { treeDataTranslate } from '@/utils'
|
||||
export default {
|
||||
data() {
|
||||
var validateUrl = (rule, value, callback) => {
|
||||
if (this.dataForm.type === 1 && !/\S/.test(value)) {
|
||||
callback(new Error('菜单URL不能为空'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
visible: false,
|
||||
dataForm: {
|
||||
id: 0,
|
||||
type: 1,
|
||||
typeList: ['目录', '菜单', '按钮'],
|
||||
name: '',
|
||||
parentId: 0,
|
||||
parentName: '',
|
||||
url: '',
|
||||
perms: '',
|
||||
orderNum: 0,
|
||||
icon: '',
|
||||
},
|
||||
dataRule: {
|
||||
name: [
|
||||
{ required: true, message: '菜单名称不能为空', trigger: 'blur' }
|
||||
],
|
||||
parentName: [
|
||||
{ required: true, message: '上级菜单不能为空', trigger: 'change' }
|
||||
],
|
||||
url: [
|
||||
{ validator: validateUrl, trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
menuList: [],
|
||||
menuListTreeProps: {
|
||||
label: 'name',
|
||||
children: 'children'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init(id) {
|
||||
this.dataForm.id = id || 0
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/menu/select'),
|
||||
method: 'get',
|
||||
params: this.$http.adornParams()
|
||||
}).then(({ data }) => {
|
||||
this.menuList = treeDataTranslate(data.menuList, 'menuId')
|
||||
}).then(() => {
|
||||
this.visible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].resetFields()
|
||||
})
|
||||
}).then(() => {
|
||||
if (!this.dataForm.id) {
|
||||
// 新增
|
||||
this.menuListTreeSetCurrentNode()
|
||||
} else {
|
||||
// 修改
|
||||
this.$http({
|
||||
url: this.$http.adornUrl(`/sys/menu/info/${this.dataForm.id}`),
|
||||
method: 'get',
|
||||
params: this.$http.adornParams()
|
||||
}).then(({ data }) => {
|
||||
this.dataForm.id = data.menu.menuId
|
||||
this.dataForm.type = data.menu.type
|
||||
this.dataForm.name = data.menu.name
|
||||
this.dataForm.parentId = data.menu.parentId
|
||||
this.dataForm.url = data.menu.url
|
||||
this.dataForm.perms = data.menu.perms
|
||||
this.dataForm.orderNum = data.menu.orderNum
|
||||
this.dataForm.icon = data.menu.icon
|
||||
this.menuListTreeSetCurrentNode()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
// 菜单树选中
|
||||
menuListTreeCurrentChangeHandle(data, node) {
|
||||
this.dataForm.parentId = data.menuId
|
||||
this.dataForm.parentName = data.name
|
||||
},
|
||||
// 菜单树设置当前选中节点
|
||||
menuListTreeSetCurrentNode() {
|
||||
this.$refs.menuListTree.setCurrentKey(this.dataForm.parentId)
|
||||
this.dataForm.parentName = (this.$refs.menuListTree.getCurrentNode() || {})['name']
|
||||
},
|
||||
// 表单提交
|
||||
dataFormSubmit() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl(`/sys/menu/${!this.dataForm.id ? 'save' : 'update'}`),
|
||||
method: 'post',
|
||||
data: this.$http.adornData({
|
||||
'menuId': this.dataForm.id || undefined,
|
||||
'type': this.dataForm.type,
|
||||
'name': this.dataForm.name,
|
||||
'parentId': this.dataForm.parentId,
|
||||
'url': this.dataForm.url,
|
||||
'perms': this.dataForm.perms,
|
||||
'orderNum': this.dataForm.orderNum,
|
||||
'icon': this.dataForm.icon
|
||||
})
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.$message({
|
||||
message: '操作成功',
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
onClose: () => {
|
||||
this.visible = false
|
||||
this.$emit('refreshDataList')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$message.error(data.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.mod-menu {
|
||||
.menu-list__input,
|
||||
.icon-list__input {
|
||||
> .el-input__inner {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&__icon-popover {
|
||||
width: 458px;
|
||||
overflow: hidden;
|
||||
}
|
||||
&__icon-inner {
|
||||
width: 478px;
|
||||
max-height: 258px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
&__icon-list {
|
||||
width: 458px;
|
||||
padding: 0;
|
||||
margin: -8px 0 0 -8px;
|
||||
> .el-button {
|
||||
padding: 8px;
|
||||
margin: 8px 0 0 8px;
|
||||
> span {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.icon-list__tips {
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
color: #e6a23c;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div class="mod-menu">
|
||||
<el-form :inline="true" :model="dataForm">
|
||||
<el-form-item>
|
||||
<el-button v-if="isAuth('sys:menu:save')" type="primary" @click="addOrUpdateHandle()">新增</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table :data="dataList" row-key="menuId" border style="width: 100%; ">
|
||||
<el-table-column prop="name" header-align="center" min-width="150" label="名称">
|
||||
</el-table-column>
|
||||
<el-table-column prop="parentName" header-align="center" align="center" width="120" label="上级菜单">
|
||||
</el-table-column>
|
||||
<el-table-column header-align="center" align="center" label="图标">
|
||||
<template slot-scope="scope">
|
||||
<i :class="scope.row.icon"></i>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="type" header-align="center" align="center" label="类型">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.type === 0" size="small">目录</el-tag>
|
||||
<el-tag v-else-if="scope.row.type === 1" size="small" type="success">菜单</el-tag>
|
||||
<el-tag v-else-if="scope.row.type === 2" size="small" type="info">按钮</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="orderNum" header-align="center" align="center" label="排序号">
|
||||
</el-table-column>
|
||||
<el-table-column prop="url" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="菜单URL">
|
||||
</el-table-column>
|
||||
<el-table-column prop="perms" header-align="center" align="center" width="150" :show-overflow-tooltip="true" label="授权标识">
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" header-align="center" align="center" width="150" label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-button v-if="isAuth('sys:menu:update')" type="text" size="small" @click="addOrUpdateHandle(scope.row.menuId)">修改</el-button>
|
||||
<el-button v-if="isAuth('sys:menu:delete')" type="text" size="small" @click="deleteHandle(scope.row.menuId)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 弹窗, 新增 / 修改 -->
|
||||
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AddOrUpdate from './menu-add-or-update'
|
||||
import { treeDataTranslate } from '@/utils'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
dataForm: {},
|
||||
dataList: [],
|
||||
dataListLoading: false,
|
||||
addOrUpdateVisible: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
AddOrUpdate
|
||||
},
|
||||
activated() {
|
||||
this.getDataList()
|
||||
},
|
||||
methods: {
|
||||
// 获取数据列表
|
||||
getDataList() {
|
||||
this.dataListLoading = true
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/menu/list'),
|
||||
method: 'get',
|
||||
params: this.$http.adornParams()
|
||||
}).then(({ data }) => {
|
||||
this.dataList = treeDataTranslate(data, 'menuId')
|
||||
this.dataListLoading = false
|
||||
})
|
||||
},
|
||||
// 新增 / 修改
|
||||
addOrUpdateHandle(id) {
|
||||
this.addOrUpdateVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.addOrUpdate.init(id)
|
||||
})
|
||||
},
|
||||
// 删除
|
||||
deleteHandle(id) {
|
||||
this.$confirm(`确定对[id=${id}]进行[删除]操作?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl(`/sys/menu/delete/${id}`),
|
||||
method: 'post',
|
||||
data: this.$http.adornData()
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.$message({
|
||||
message: '操作成功',
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
onClose: () => this.getDataList()
|
||||
})
|
||||
} else {
|
||||
this.$message.error(data.msg)
|
||||
}
|
||||
})
|
||||
}).catch(() => { })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible">
|
||||
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px">
|
||||
<el-form-item label="角色名称" prop="roleName">
|
||||
<el-input v-model="dataForm.roleName" placeholder="角色名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="dataForm.remark" placeholder="备注"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item size="mini" label="授权">
|
||||
<el-tree :data="menuList" :props="menuListTreeProps" node-key="menuId" ref="menuListTree" :default-expand-all="true" show-checkbox>
|
||||
</el-tree>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="dataFormSubmit()">确定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { treeDataTranslate } from '@/utils'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
menuList: [],
|
||||
menuListTreeProps: {
|
||||
label: 'name',
|
||||
children: 'children'
|
||||
},
|
||||
dataForm: {
|
||||
id: 0,
|
||||
roleName: '',
|
||||
remark: ''
|
||||
},
|
||||
dataRule: {
|
||||
roleName: [
|
||||
{ required: true, message: '角色名称不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init(id) {
|
||||
this.dataForm.id = id || 0
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/sys/menu/list'),
|
||||
method: 'get',
|
||||
params: this.$http.adornParams()
|
||||
}).then(({ data }) => {
|
||||
this.menuList = treeDataTranslate(data, 'menuId')
|
||||
}).then(() => {
|
||||
this.visible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].resetFields()
|
||||
this.$refs.menuListTree.setCheckedKeys([])
|
||||
})
|
||||
}).then(() => {
|
||||
if (this.dataForm.id) {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl(`/sys/role/info/${this.dataForm.id}`),
|
||||
method: 'get',
|
||||
params: this.$http.adornParams()
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.dataForm.roleName = data.role.roleName
|
||||
this.dataForm.remark = data.role.remark
|
||||
data.role.menuIdList.forEach(item => {
|
||||
this.$refs.menuListTree.setChecked(item, true);
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
// 表单提交
|
||||
dataFormSubmit() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl(`/sys/role/${!this.dataForm.id ? 'save' : 'update'}`),
|
||||
method: 'post',
|
||||
data: this.$http.adornData({
|
||||
'roleId': this.dataForm.id || undefined,
|
||||
'roleName': this.dataForm.roleName,
|
||||
'remark': this.dataForm.remark,
|
||||
'menuIdList': [].concat(this.$refs.menuListTree.getCheckedKeys(), this.$refs.menuListTree.getHalfCheckedKeys())
|
||||
})
|
||||
}).then(({ data }) => {
|
||||
if (data && data.code === 200) {
|
||||
this.$message({
|
||||
message: '操作成功',
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
onClose: () => {
|
||||
this.visible = false
|
||||
this.$emit('refreshDataList')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$message.error(data.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
Loading…
Reference in new issue