chore: 重写初始提交(清空历史,整理后全量提交)
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
*@Name: 微新闻
|
||||
*@Author: xzw
|
||||
*@Copyright:layui.com
|
||||
*/
|
||||
|
||||
|
||||
#micronews-carouse{height: 300px; text-align: center;}
|
||||
#micronews-carouse>*[carousel-item] > *
|
||||
,#micronews-carouse .layui-carousel{background: none;}
|
||||
#micronews-carouse .layui-carousel img{ max-width: 100%;
|
||||
height: 300px;}
|
||||
|
||||
|
||||
.micronews .layui-fixbar li {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
margin-bottom: 1px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
font-size: 30px;
|
||||
background: #6294b5;
|
||||
color: rgb(255, 255, 255);
|
||||
opacity: 0.95;
|
||||
border-radius: 2px;}
|
||||
.micronews .layui-laypage .layui-laypage-curr .layui-laypage-em{background: #6394b5;}
|
||||
.micronews .layui-laypage-prev:hover ,.micronews .layui-laypage-next:hover{color: #6394b5;}
|
||||
.micronews .w1000{max-width: 1000px; margin:0 auto;}
|
||||
.micronews .layui-carousel>[carousel-item]>* {height: auto;}
|
||||
.micronews .layui-carousel-ind{margin-top: -20px;top: auto;bottom: 10px;}
|
||||
html, body{height: 100%;}
|
||||
/*header*/
|
||||
.micronews-header-wrap{border-bottom: 1px solid #6395b8; background: #fff;}
|
||||
.micronews-header{line-height: 70px; height: 70px; position: relative; font-size: 16px;}
|
||||
.micronews-header .logo,.micronews-header .nav,.micronews-header .search-bar,.micronews-header .search-bar button,.micronews-header .search-bar input{float: left;}
|
||||
.micronews-header .search-bar input{background: #f6f6f8;}
|
||||
.micronews-header .logo{width: 100px; text-align: center;}
|
||||
.micronews-header .nav{padding: 0 10px;}
|
||||
.micronews-header .nav a{display: inline-block; height: 70px; font-size: 16px; color: #222; padding:0 22px; float: left;}
|
||||
.micronews-header .nav a.active{background: #6294b5; color: #fff;}
|
||||
.micronews-header .nav a.active:hover{color:#fff;}
|
||||
.micronews-header .nav a:hover{color: #6294b5;}
|
||||
.micronews-header .search-bar{width: 280px; height: 38px; margin: 17px 0 0 20px; font-size: 14px;}
|
||||
.micronews-header .search-bar .layui-form-item{margin-bottom: 0;}
|
||||
.micronews-header .search-bar .layui-input-block{margin-left: 0; height: 38px;}
|
||||
.micronews-header .search-bar input{width: 229px; border:1px solid #e9eaec; border-right: none; border-radius: 2px 0px 0px 2px;}
|
||||
.micronews-header .search-bar button{width: 50px; background: #6294b5; padding:0; border-radius: 0 2px 2px 0px;}
|
||||
.micronews-header .login img{height: 100%;}
|
||||
.micronews-header .login{ position: absolute; right: 0; top: 0px; }
|
||||
.micronews-header .login a{color: #6294b5; display: inline-block; padding:0 10px;}
|
||||
.micronews-header .menu-icon{display: none;}
|
||||
.micronews-header .mobile-nav{display: none;}
|
||||
/*end-header*/
|
||||
|
||||
|
||||
/*baner*/
|
||||
.micronews .micronews-banner{margin: 40px auto 0 auto;}
|
||||
.micronews-banner .title{position: absolute; left: 20px; bottom: 14px; color: #fff; font-size: 22px; font-weight: 100;}
|
||||
/*end-baner*/
|
||||
|
||||
|
||||
/*content*/
|
||||
.micronews-container{padding: 30px 0 100px 0;}
|
||||
.micronews-container .layui-flow-more{margin:50px 0;}
|
||||
.micronews-container .layui-fluid{padding:0;}
|
||||
.micronews-container .main{padding-right: 50px;}
|
||||
.micronews-container .item{overflow:hidden; padding:20px 0; border-bottom: 1px solid #eaeaea;}
|
||||
.micronews-container .item img{float: left; margin-right: 30px;}
|
||||
.micronews-container .item h4{font-size: 20px; color: #222222; font-weight: bold; line-height: 32px; margin-bottom: 14px;}
|
||||
.micronews-container .b-txt .label{display:inline-block; padding: 0 4px; height:18px; line-height: 18px; background: #6294b5; font-size: 12px; cursor: pointer; color: #fff; border-radius: 2px; margin-right: 30px;}
|
||||
.micronews-container .b-txt .message{margin-right: 20px;}
|
||||
.micronews-container .b-txt .icon{color:#d2d6da; position: relative; top: 2px; cursor: pointer;}
|
||||
|
||||
|
||||
|
||||
.micronews-container .popular-info{background: #f5f6f7; border-top: 2px solid #6294b5; padding-bottom: 25px;}
|
||||
.micronews-container .popular-info .list{padding:16px 0;}
|
||||
.micronews-container .popular-info .list-item{position: relative;}
|
||||
.micronews-container .popular-info .list-item i.layui-badge-dot{margin:0 8px;}
|
||||
.micronews-container .layui-card{background: none; box-shadow:none;}
|
||||
.micronews-container .layui-card-body{padding:0 15px;}
|
||||
.micronews-container .layui-card-header{line-height: 50px; height: 50px;}
|
||||
.micronews-container .popular-info h3{line-height: 50px; font-size: 16px; color: #6294b5;}
|
||||
.micronews-container .popular-info .list:last-child{border-bottom: 0;}
|
||||
.micronews-container .popular-info .list{border-bottom: 1px solid #eaeaea; list-style-position: inside; list-style-type: decimal}
|
||||
.micronews-container .popular-info .list a{padding-right: 5px; padding-left: 10px;}
|
||||
.micronews-container .popular-info-tog i{display: block ;width: 4px; height: 4px; border-radius: 50%; color: #ceced0; position: absolute; top: 0; background: #cdcdcf; top: 26px; left: 8px;}
|
||||
.micronews-container .popular-info-tog .list{list-style-type: disc;}
|
||||
.micronews-container .popular-info-tog .list a{padding:0;}
|
||||
.micronews-container .popular-info-tog a{ margin-right:0; padding-right: 0; }
|
||||
.micronews-container .popular-info .heat-icon{display:inline-block; width: 12px; height: 16px; background: url(../img/heat.png) no-repeat center center; position: relative; top: 3px;}
|
||||
/*end-content*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*footer*/
|
||||
.micronews-footer-wrap{border-top: 2px solid #6294b5; color: #777777;}
|
||||
.micronews-footer{padding:36px 0 44px 0; position: relative;}
|
||||
.micronews-footer .ft-nav{margin-bottom: 24px;}
|
||||
.micronews-footer .ft-nav a{margin-right: 40px; color: #777777;}
|
||||
.micronews-footer .f-icon{position: absolute; right: 0; top: 46px;}
|
||||
.micronews-footer .w-icon{margin-right: 40px;}
|
||||
/*end-footer*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*micronews-details-container*/
|
||||
.micronews-details-container{padding:60px 0;}
|
||||
.micronews-details-container .main{margin-bottom: 50px;}
|
||||
|
||||
.micronews-details-container .b-txt{padding:10px 0; line-height: 35px;}
|
||||
.micronews-details-container .b-txt .icon{margin-right: 26px; color: }
|
||||
.micronews-details-container .b-txt .icon b{color: #ec414d;}
|
||||
.micronews-details-container .title{border-bottom: 1px solid #eaeaea;}
|
||||
.micronews-details-container .title h3{font-size: 24px;}
|
||||
.micronews-details-container .article{color: #555; padding: 10px 0 32px 0;}
|
||||
.micronews-details-container .article p{line-height: 30px;}
|
||||
.micronews-details-container .article p.mt30{margin-bottom: 30px;}
|
||||
.micronews-details-container .article .img-box{text-align: center; padding:12px; cursor: pointer;}
|
||||
.micronews-details-container .article .share-title{height: 30px; line-height: 30px;}
|
||||
.micronews-details-container .article .share-title .txt{position: relative; top: -4px; margin-right: 5px;}
|
||||
.micronews-details-container .article .share-title .icon{font-size: 26px; margin-right: 6px;}
|
||||
.micronews-details-container .article .share-title .icon.layui-icon-login-wechat{color: #3ab032;}
|
||||
.micronews-details-container .article .share-title .layui-icon-login-weibo{color: #f16420;}
|
||||
.micronews-details-container .article .share-title .layui-icon-login-qq{color: #04aed9;}
|
||||
.micronews-details-container .article .layui-btn{width: 96px; padding:0; height: 28px; line-height: 26px; background: #ec414d; border:1px solid #ec414d; margin-left: 37px; position: relative; top: -5px;}
|
||||
.micronews-details-container .article .layui-btn.active{background: #fff; color: #ec414d;}
|
||||
.micronews-details-container .article .layui-btn span{margin-left: 10px;}
|
||||
.micronews-details-container .leave-message .tit-box{line-height: 40px;}
|
||||
.micronews-details-container .leave-message .tit{font-size: 16px; margin-right: 28px;}
|
||||
.micronews-details-container .leave-message .tit-box .num{color: #b5b9bd;}
|
||||
.micronews-details-container .leave-message .tit-box b{color: #ec414d;}
|
||||
.micronews-details-container .leave-message .tear-box img{float: left;}
|
||||
.micronews-details-container .leave-message .tear-box form{padding-left: 50px; margin:10px 0;}
|
||||
.micronews-details-container .content-box .layui-form .layui-form-item{clear:none; margin-bottom: 0;}
|
||||
.micronews-details-container .content-box .layui-form .layui-btn{width: 90px; height: 30px; line-height: 30px; background: #6294b5; position: relative; z-index: 10; border-radius: 0}
|
||||
.micronews-details-container .content-box .layui-form .layui-textarea{border-radius: 0}
|
||||
.micronews-details-container .content-box .layui-form .message-text{position: absolute; height: 100%; width: 100%; padding:0 90px 0 0px; text-align: left; box-sizing: border-box; line-height: 30px;}
|
||||
.micronews-details-container .content-box .layui-form .message-text .txt{padding-left: 10px; border:1px solid #e6e6e6; height:100%; box-sizing: border-box; border-top:0; border-right: 0; color: #ec414d;}
|
||||
.micronews-details-container .content-box .layui-form .layui-input-block{margin-left: 0; min-height: 30px;}
|
||||
.micronews-details-container .content-box .ulCommentList{margin-bottom: 30px;}
|
||||
.micronews-details-container .content-box .ulCommentList .item-cont{padding-left: 50px;}
|
||||
.micronews-details-container .content-box .ulCommentList .cont{padding:10px 20px; background: #f5f6f7; word-wrap:break-word;}
|
||||
.micronews-details-container .liCont{padding:30px 0 0 0; border-bottom: 0;}
|
||||
.micronews-details-container .liCont img{float: left; width: 28px; height: 28px;}
|
||||
.micronews-details-container .cont .name{margin-right: 15px;}
|
||||
.micronews-details-container .cont .time{color: #6d6d6d; font-size: 12px;}
|
||||
.micronews-details-container .cont p{line-height: 26px;}
|
||||
.micronews-details-container .cont .text{color: #555;}
|
||||
/*end-micronews-details-container*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*micronews-list-container*/
|
||||
.micronews-list-container{padding-top: 16px;}
|
||||
.micronews-list-container h3{font-size: 16px; line-height: 50px; padding-left: 12px; font-weight: bold;}
|
||||
/*end-micronews-list-container*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*micronews-search-container*/
|
||||
.micronews-search-container p.num{color: #888888;}
|
||||
.micronews-search-container p.num span{color: #ec414d;}
|
||||
.micronews-search-container .item{border-bottom: 0; padding:30px 0;}
|
||||
.micronews-search-container .time{font-size: 14px; color: #868686; padding-left: 20px;}
|
||||
.micronews-search-container .item p{line-height: 30px; font-size: 16px;}
|
||||
/*end-micronews-search-container*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*micronews-login-container*/
|
||||
.micronews-login{width: 100%;min-height: 100%; background: url(../img/loadbg.jpg) no-repeat; background-size: cover;}
|
||||
.micronews-login-container .layui-form-item{margin:20px 0 0 0 ;}
|
||||
.micronews-login-container .agreement{margin-top: 0px;}
|
||||
.micronews-login-container .agreement a{color: #5980c5;}
|
||||
.micronews-login-container .wrap{ padding: 20px 40px; background: #fff; box-shadow: 1px 1px 10px 1px #ccc; box-sizing: border-box;}
|
||||
.micronews-login-container .wrap form{margin-bottom: 20px;}
|
||||
.micronews-login-container .form-box{margin:0 auto;width: 380px;padding-top: 20px;}
|
||||
.micronews-login-container .form-box h3{line-height: 60px;font-size: 28px; color: #5a94b9; text-align: center;}
|
||||
.micronews-login-container .layui-input-block{margin-left: 0; position: relative;}
|
||||
.micronews-login-container .layui-input-block span.txt{position: relative; top: 1px;}
|
||||
.micronews-login-container .agreement .layui-input-block{line-height: 36px;}
|
||||
.micronews-login-container .agreement .layui-unselect{margin:0;}
|
||||
.micronews-login-container .agreement .layui-unselect span{padding-right: 0;}
|
||||
.micronews-login-container .layui-input-block img{height: 36px; position: absolute; right: 1px; top: 1px; cursor: pointer;}
|
||||
.micronews-login-container .obtain{position: absolute; background: #eeeeee; right: 1px; top: 1px; height: 36px; color: #454545;}
|
||||
.micronews-login-container button{width: 100%; background: #6294b5;}
|
||||
.micronews-login-container .other-login{text-align: center;}
|
||||
.micronews-login-container .other-login a{margin:0 20px;}
|
||||
/*end-micronews-login-container*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*micronews-persInfo-content*/
|
||||
.micronews-persInfo-wrap{background: #f5f6f8;}
|
||||
.micronews-persInfo-content{padding:26px 0 90px 0;}
|
||||
.micronews-persInfo-content .main{margin:0 0 0 30px; padding-right: 0; background: #fff;}
|
||||
.micronews-persInfo-content .ulCommentList{padding:0 30px;}
|
||||
.micronews-persInfo-content .item{border-bottom: 0; padding:0;}
|
||||
.micronews-persInfo-content .item h4 {margin-bottom: 0}
|
||||
.micronews-persInfo-content .liCont{padding:30px 0; border-bottom: 1px solid #eaeaea;}
|
||||
.micronews-persInfo-content .liCont:last-child{border-bottom: 0;}
|
||||
.leave-message{min-height: 900px;}
|
||||
.micronews-persInfo-content .content-box{padding-bottom: 30px; display: none;}
|
||||
.micronews-persInfo-content .popular-info{background: #fff; border:0; padding: 60px 0 150px 0; text-align: center;}
|
||||
.micronews-persInfo-content .layui-card-header{height: auto; line-height: auto; border:0;}
|
||||
.micronews-persInfo-content .tab {margin-top: 30px; padding:0 60px;}
|
||||
.micronews-persInfo-content .tab li{ line-height: 40px; font-size: 16px; color: #666666; margin-bottom: 16px; cursor: pointer;}
|
||||
.micronews-persInfo-content .tab li.layui-this{border-bottom: 1px solid #6295b4; color: #6295b4;}
|
||||
/*end-micronews-persInfo-content*/
|
||||
|
||||
|
||||
/*中屏幕*/
|
||||
@media screen and (max-width: 1024px){
|
||||
.micronews-header{height: 60px; line-height: 60px;}
|
||||
.micronews-header .search-bar,.micronews-header .nav{display: none;}
|
||||
.micronews-header .logo{position: absolute; left: 50%; margin-left: -50px;}
|
||||
.micronews-banner .title{display: none;}
|
||||
.micronews-container .layui-fluid{padding:0 15px;}
|
||||
.micronews-footer{text-align: center;}
|
||||
|
||||
.micronews-footer .f-icon{position: static; margin-top: 20px;}
|
||||
.micronews-header .menu-icon{display: block; height: 100%; width:60px; cursor: pointer; text-align: center;}
|
||||
.micronews-header .menu-icon i{font-size: 26px; color: #6294b5;}
|
||||
.micronews-header .mobile-nav{display: none; position: absolute; top: 60px; left: 0; width: 100%; z-index: 100;}
|
||||
.micronews-header .mobile-nav li{display: block;}
|
||||
.micronews-header .mobile-nav .layui-nav{background: #fff; padding:0;}
|
||||
.micronews-header .mobile-nav .layui-nav a{color: #6294b5;}
|
||||
.micronews-header .mobile-nav .layui-nav .layui-this:after,.micronews-header .mobile-nav .layui-nav-bar{background: #6294b5; height: 3px;}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*小屏幕*/
|
||||
@media screen and (max-width: 768px){
|
||||
.micronews-container .main{padding-right: 0;}
|
||||
.micronews-details-container .article .img-box img{width: 100%;}
|
||||
.micronews-container .item img{float: none; margin:0 0 15px 0;}
|
||||
.micronews-container .item h4{font-size: 16px; line-height: 24px;}
|
||||
.micronews-footer .ft-nav a{display: block; margin:15px 0;}
|
||||
.micronews-login-container .form-box{padding:0 10px; width: auto; overflow-x: hidden;}
|
||||
.micronews-login-container .form-box form{width: 100%;}
|
||||
.micronews-login-container .form-box h3{line-height: 70px; font-size: 24px;}
|
||||
.micronews-persInfo-content .popular-info{padding:60px 0; margin-bottom: 20px;}
|
||||
.micronews-container .main{margin-left: 0;}
|
||||
#micronews-carouse{height: 150px;}
|
||||
#micronews-carouse img{height: 150px;}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
*@Name: 微新闻
|
||||
*@Author: xzw
|
||||
*@Copyright:layui.com
|
||||
*/
|
||||
layui.define(['carousel','jquery','element','flow','laytpl','element','laypage','form','util'],function(exports){
|
||||
var carousel = layui.carousel,$ = layui.$,flow = layui.flow,laytpl = layui.laytpl,element = layui.element,laypage = layui.laypage,form = layui.form,
|
||||
util = layui.util;
|
||||
|
||||
|
||||
|
||||
|
||||
// 模拟首页数据
|
||||
|
||||
var index = {
|
||||
|
||||
|
||||
// 移动端下面导航按钮
|
||||
common:function(){
|
||||
var off = true;
|
||||
$('.menu-icon').on('click',function(){
|
||||
if(off){
|
||||
$('.mobile-nav').addClass('layui-show')
|
||||
}else{
|
||||
$('.mobile-nav').removeClass('layui-show')
|
||||
}
|
||||
off = !off
|
||||
})
|
||||
},
|
||||
|
||||
// 首页轮播
|
||||
banner: function(){
|
||||
//轮播
|
||||
var elemBanner = $('#micronews-carouse'), ins1 = carousel.render({
|
||||
elem: elemBanner
|
||||
,width: '100%'
|
||||
,height: elemBanner.height() + 'px'
|
||||
,arrow: 'none'
|
||||
,interval: 5000
|
||||
});
|
||||
$(window).on('resize', function(){
|
||||
var width = $(this).prop('innerWidth');
|
||||
ins1.reload({
|
||||
height: (width > 768 ? 300 : 150) + 'px'
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 内容的留加载
|
||||
contFlow: function(){
|
||||
flow.load({
|
||||
elem: '#LAY_demo2' //流加载容器
|
||||
,scrollElem: '#LAY_demo2' //滚动条所在元素,一般不用填,此处只是演示需要。
|
||||
,isAuto: false
|
||||
,done: function(page, next){ //加载下一页
|
||||
var lis = [];
|
||||
//以jQuery的Ajax请求为例,请求下一页数据(注意:page是从2开始返回)
|
||||
$.get('/api/list?page='+page, function(res){
|
||||
//假设你的列表返回在data集合中
|
||||
var getTpl = demo.innerHTML
|
||||
|
||||
layui.each(res.data, function(index, item){
|
||||
laytpl(getTpl).render(item, function(html){
|
||||
lis.push(html)
|
||||
});
|
||||
});
|
||||
|
||||
//执行下一页渲染,第二参数为:满足“加载更多”的条件,即后面仍有分页
|
||||
//pages为Ajax返回的总页数,只有当前页小于总页数的情况下,才会继续出现加载更多
|
||||
next(lis.join(''), page < res.pages);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
,
|
||||
|
||||
// 分页
|
||||
Page:function(ele,count){
|
||||
laypage.render({
|
||||
elem: ele //注意,这里的 ele 是 ID,不用加 # 号
|
||||
,count: count //数据总数,从服务端得到
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// 输入留言
|
||||
EnterMessage: function(){
|
||||
$('.micronews-details-Publish').on('click',function(e){
|
||||
var event = e || event;
|
||||
var img = $(this).parents('form').siblings('a').find('img').attr('src');
|
||||
var messagetext = $(this).siblings('.message-text').find('.txt');
|
||||
var textarea = $(this).parents('.layui-form-item').siblings('.layui-form-text').children('.layui-input-block').children('textarea');
|
||||
if(!textarea.val()){
|
||||
messagetext.text('请输入留言')
|
||||
return;
|
||||
}
|
||||
var name = $(textarea).val();
|
||||
var view = $('.ulCommentList')
|
||||
var html = messageTpl.innerHTML;
|
||||
var data = {
|
||||
avatar : img,
|
||||
name : '我是锦鲤',
|
||||
cont : name,
|
||||
}
|
||||
$('.message-text .txt').text('')
|
||||
laytpl(html).render(data, function(html){
|
||||
view.prepend(html)
|
||||
});
|
||||
textarea.val("")
|
||||
return false;
|
||||
})
|
||||
},
|
||||
onInput: function(){
|
||||
// if (!("oninput" in document.body)) {
|
||||
// element.onpropertychange = function() {
|
||||
// if (event.propertyName == "value")
|
||||
// this.oninput && this.oninput(event);
|
||||
// }
|
||||
// }
|
||||
$("#onInput").bind("input propertychange",function(event){
|
||||
if(!$(this).val()){
|
||||
$('.message-text .txt').text('')
|
||||
return;
|
||||
}
|
||||
$('.message-text .txt').text('已经输入'+$(this).val().length+'字')
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
,
|
||||
//超出多少文件就省略号
|
||||
omitted: function(ele,num){
|
||||
$(ele).each(function() {
|
||||
var str = $(this).html();
|
||||
var subStr = str.substring(0, num);
|
||||
$(this).html(subStr + (str.length > num ? '...' : ''));
|
||||
});
|
||||
},
|
||||
|
||||
//搜索跳转的页面
|
||||
seachBtn: function(){
|
||||
$('.search-btn').on('click',function(){
|
||||
var inpVal = $(this).siblings('input').val();
|
||||
if(inpVal){
|
||||
window.location.href="search.html"
|
||||
};
|
||||
return false;
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
//获取验证码事件
|
||||
login: function(){
|
||||
var data = {
|
||||
status:true
|
||||
}
|
||||
$("#veriCodeBtn").click(function() {
|
||||
if(!/^1\d{10}$/.test($("#phone").val())){
|
||||
layer.msg("请输入正确的手机号");
|
||||
return false;
|
||||
}
|
||||
if(!$("#imgCode").val()){
|
||||
layer.msg("请输入验证码");
|
||||
return false;
|
||||
}
|
||||
var obj=this;
|
||||
if(data.status){
|
||||
$(obj).addClass(" layui-btn-disabled");
|
||||
$(obj).attr('disabled',"true");
|
||||
settime(obj);
|
||||
}
|
||||
})
|
||||
var countdown=60;
|
||||
function settime(obj) {
|
||||
if (countdown == 0) {
|
||||
obj.removeAttribute("disabled");
|
||||
obj.classList.remove("layui-btn-disabled")
|
||||
obj.value="获取验证码";
|
||||
countdown = 60;
|
||||
return;
|
||||
} else {
|
||||
|
||||
obj.value="重新发送(" + countdown + ")";
|
||||
countdown--;
|
||||
}
|
||||
setTimeout(function() { settime(obj) } ,1000)
|
||||
}
|
||||
form.on('submit(*)', function(data){
|
||||
window.location.href = 'index.html'
|
||||
return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。
|
||||
})
|
||||
}
|
||||
|
||||
// 右侧小箭头
|
||||
,arrowutil: function(){
|
||||
//固定 bar
|
||||
util.fixbar({
|
||||
click: function(type){
|
||||
if(type === 'bar1'){
|
||||
//
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
index.common()
|
||||
exports('index',index)
|
||||
});
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 671 KiB |
|
After Width: | Height: | Size: 183 KiB |
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* @Author: YwxApp <ywx@ywxapp.cn>
|
||||
* @Date: 2026-08-06 23:41:01
|
||||
* @LastEditors: YwxApp <ywx@ywxapp.cn>
|
||||
* @LastEditTime: 2026-08-06 23:43:05
|
||||
* @Description:
|
||||
* @FilePath: \ywxapp_dev\public\static\backend\json\console\prograss.js
|
||||
* @CustomString: Copyright (c) 2026 YwxApp
|
||||
*/
|
||||
{
|
||||
"code": 0
|
||||
,"msg": ""
|
||||
,"count": "100"
|
||||
,"data": [{
|
||||
"prograss": "开会"
|
||||
,"time": "一小时"
|
||||
,"complete": "已完成"
|
||||
,"LAY_CHECKED": true
|
||||
},{
|
||||
"prograss": "项目开发"
|
||||
,"time": "两小时"
|
||||
,"complete": "进行中"
|
||||
,"LAY_CHECKED": true
|
||||
},{
|
||||
"prograss": "陪吃饭"
|
||||
,"time": "一小时"
|
||||
,"complete": "未完成"
|
||||
},{
|
||||
"prograss": "修改小bug"
|
||||
,"time": "半小时"
|
||||
,"complete": "未完成"
|
||||
},{
|
||||
"prograss": "修改大bug"
|
||||
,"time": "两小时"
|
||||
,"complete": "未完成"
|
||||
},{
|
||||
"prograss": "修改小bug"
|
||||
,"time": "半小时"
|
||||
,"complete": "未完成"
|
||||
},{
|
||||
"prograss": "修改大bug"
|
||||
,"time": "两小时"
|
||||
,"complete": "未完成"
|
||||
}]
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('ad');
|
||||
|
||||
var positionMap = {
|
||||
'home_top': '首页顶部横幅',
|
||||
'home_side': '首页侧边',
|
||||
'popup': '全站弹窗',
|
||||
'list_bottom': '列表底部',
|
||||
'home_bottom': '首页底部',
|
||||
'content_top': '内容页顶部',
|
||||
'content_bottom': '内容页底部',
|
||||
'sidebar': '通用侧边栏',
|
||||
'float': '全站悬浮角标'
|
||||
};
|
||||
var typeMap = { 1: '图片', 2: '文字', 3: '代码' };
|
||||
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'title', minWidth: 160, title: '标题' },
|
||||
{ field: 'position', width: 120, title: '广告位', templet: function (d) { return positionMap[d.position] || d.position || '-'; } },
|
||||
{ field: 'type', width: 100, title: '类型', templet: function (d) { return typeMap[d.type] || d.type; } },
|
||||
{ field: 'sort', width: 100, title: '排序', sort: true },
|
||||
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'create_time', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title, position: data.field.position } });
|
||||
return false;
|
||||
});
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name=\"title\"]').val('');
|
||||
$('select[name=\"position\"]').val('');
|
||||
form.render('select');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: '', position: '' } });
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate': active.dataCreate({}); break;
|
||||
case 'dataDelete':
|
||||
var check = table.checkStatus('dataTable').data;
|
||||
active.dataDelete(check.map(function (i) { return i.id; }));
|
||||
break;
|
||||
case 'dataRecybin': active.dataRecybin(); break;
|
||||
}
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update': active.dataEdit(data); break;
|
||||
case 'delete': active.dataDelete([data.id]); break;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.put('update', { id: this.value, status: status })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) { layer.msg('操作成功'); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
table.reload('dataTable', {}, true);
|
||||
})
|
||||
.catch(function () { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑站点广告' : '添加站点广告';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
id: 'adFormLayer', title: title, content: formHtml, anim: "slideLeft", offset: "r",
|
||||
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
|
||||
success: function (layero, index) { callback(layero, index); form.render(); },
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var active = {
|
||||
dataDelete: function (ids, force) {
|
||||
if (ids.length === 0) { return layer.msg('请选择数据'); }
|
||||
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
|
||||
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
|
||||
});
|
||||
},
|
||||
dataCreate: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
if (field.status === undefined) field.status = 0;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataEdit: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataRecybin: function () {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
|
||||
layer.open({
|
||||
id: 'adRecybinLayer', title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
success: function () {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
|
||||
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '标题', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data) {
|
||||
http.put("restore", { ids: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '恢复失败'); }
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore': active.dataRestore(data); break;
|
||||
case 'forcedelete': active.dataForceDelete(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('ad', {});
|
||||
});
|
||||
@@ -0,0 +1,259 @@
|
||||
layui.define(['http', 'setter', 'auth', 'upload', 'form', 'layer', 'table'], function (exports) {
|
||||
var table = layui.table, form = layui.form, layer = layui.layer, $ = layui.$, upload = layui.upload, http = layui.http
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('addon');
|
||||
var ADDON_DEV = window.ADDON_DEV || 0;
|
||||
|
||||
// 清空后台侧栏菜单的本地缓存(Layui data 存储于 setter.appName 下,键为 'menus')。
|
||||
// 插件卸载/安装/启停会改变 admin_power 菜单,必须清掉缓存让侧栏重新向后端拉取,
|
||||
// 否则侧栏会一直显示(或一直缺)已变更插件的菜单。
|
||||
function clearMenuCache() {
|
||||
var appName = (layui.setter && layui.setter.appName) || 'backend';
|
||||
layui.data(appName, { key: 'menus', remove: true });
|
||||
// 兼容旧键名(历史版本曾写入 'menu')
|
||||
layui.data(appName, { key: 'menu', remove: true });
|
||||
}
|
||||
// ===== 渲染核心表格 =====
|
||||
var { access_token, refresh_token } = layui.setter.getTokens();
|
||||
table.render({
|
||||
elem: '#dataTable'
|
||||
, url: "index" // 此处应填写你真实的后端接口地址
|
||||
, cols: [[
|
||||
{ field: 'title', title: '插件名称', minWidth: 180 },
|
||||
{ field: 'name', title: '标识', width: 120 },
|
||||
{ field: 'author', title: '开发者', width: 120 }
|
||||
, { field: 'version', title: '版本号', width: 100, align: 'center' }
|
||||
, { field: 'description', title: '功能描述', minWidth: 250 }
|
||||
, { field: 'status', title: '运行状态', width: 110, align: 'center', templet: '#switchTpl' } // 绑定开关模板
|
||||
, { fixed: 'right', title: '操作', toolbar: '#operateTpl', width: 300, align: 'right' } // 绑定操作栏模板
|
||||
]]
|
||||
, page: true // 开启分页
|
||||
, limit: 10
|
||||
, limits: [10, 20, 50]
|
||||
, skin: 'line' // 设定表格风格为行边框风格
|
||||
, response: {
|
||||
statusName: 'code' // 状态码字段
|
||||
, statusCode: 0 // 成功状态码
|
||||
, msgName: 'message' // 提示信息字段(后端返回 message)
|
||||
, countName: 'count' // 数据总数字段
|
||||
, dataName: 'data' // 数据列表字段
|
||||
}
|
||||
, done: function (res, curr, count) {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
// 开发模式关闭时隐藏操作列的「设计」按钮
|
||||
// if (!ADDON_DEV) { $('.dev-design').remove(); }
|
||||
}
|
||||
});
|
||||
|
||||
// ===== 事件绑定(提前到这里:即便下方 upload/form 初始化出错,行内按钮依然可用) =====
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate':
|
||||
active.dataCreate({ pid: 0, type: 1 });
|
||||
break;
|
||||
case 'dataRecybin':
|
||||
active.dataRecybin();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
// 插件标识:优先用 name,缺失时回退到 id(后端 index 两种都返回)
|
||||
var addonName = data.name || data.id || '';
|
||||
switch (elem.event) {
|
||||
case 'update':
|
||||
active.dataEdit(data);
|
||||
break;
|
||||
case 'config':
|
||||
if (!addonName) { layer.msg('缺少插件标识', { icon: 2 }); break; }
|
||||
location.href = 'setting?addon=' + encodeURIComponent(addonName);
|
||||
break;
|
||||
case 'uninstall':
|
||||
if (!addonName) { layer.msg('缺少插件标识', { icon: 2 }); break; }
|
||||
active.uninstall(addonName);
|
||||
break;
|
||||
case 'more':
|
||||
var that = this;
|
||||
var dropdown = layui.dropdown;
|
||||
// 水平对齐方式
|
||||
dropdown.render({
|
||||
elem: that,
|
||||
align: 'center', // align 已配置在元素 `lay-options` 属性上
|
||||
show: true,accordion : true,
|
||||
data: [{
|
||||
title: '设计',
|
||||
id: 'design'
|
||||
}, {
|
||||
title: '打包',
|
||||
id: 'pack'
|
||||
}, {
|
||||
title: '发布',
|
||||
id: 'submitOfficial'
|
||||
}],
|
||||
click: function (data, othis) {
|
||||
switch (data.id) {
|
||||
case 'pack':
|
||||
// 触发后端 addon::pack 下载该插件的 zip 包(addon/temp/<name>-<version>.zip)
|
||||
if (!addonName) { layer.msg('缺少插件标识', { icon: 2 }); break; }
|
||||
window.location.href = 'pack?name=' + encodeURIComponent(addonName);
|
||||
break;
|
||||
case 'design':
|
||||
if (!addonName) { layer.msg('缺少插件标识', { icon: 2 }); break; }
|
||||
location.href = 'design?addon=' + encodeURIComponent(addonName);
|
||||
break;
|
||||
case 'submitOfficial':
|
||||
// 发布到官方市场:打包本机已装插件并 POST 到官方提交接口,进入待审核
|
||||
if (!addonName) { layer.msg('缺少插件标识', { icon: 2 }); break; }
|
||||
layer.confirm('确定将「' + (data.title || addonName) + '」发布到官方市场吗?\n提交后需官方审核通过才公开上架。', function (index) {
|
||||
layer.close(index);
|
||||
var loadIdx = layer.load(1, { shade: [0.3, '#fff'] });
|
||||
http.post('submitOfficial', { name: addonName })
|
||||
.then(function (res) {
|
||||
layer.close(loadIdx);
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.message || '已提交,等待官方审核', { icon: 1 });
|
||||
} else {
|
||||
layer.msg(res.message || res.msg || '提交失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
layer.close(loadIdx);
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
});
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
break;
|
||||
case 'default':
|
||||
console.warn('未处理的操作事件:', elem.event, data);
|
||||
}
|
||||
});
|
||||
|
||||
// 顶部功能按钮 + 行内操作共用
|
||||
var active = {
|
||||
uninstall: function (name) {
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '敏感操作,请验证口令'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
http.delete('uninstall', { name: name })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
clearMenuCache(); // 插件菜单已删除,清掉侧栏菜单缓存
|
||||
location.reload(); // 重新加载整页,侧栏立即刷新
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
batchDel: function () { // 批量卸载
|
||||
var checkStatus = table.checkStatus('dataTable');
|
||||
var data = checkStatus.data;
|
||||
if (data.length === 0) {
|
||||
layer.msg('请至少选中一项进行卸载', { icon: 0 });
|
||||
return;
|
||||
}
|
||||
layer.confirm('确定要批量卸载选中的 ' + data.length + ' 个插件吗?', function (index) {
|
||||
layer.msg('正在批量卸载...', { icon: 1 });
|
||||
table.reload('dataTable');
|
||||
layer.close(index);
|
||||
});
|
||||
},
|
||||
refresh: function () { // 刷新表格
|
||||
table.reload('dataTable');
|
||||
layer.msg('已刷新列表', { icon: 1 });
|
||||
}
|
||||
};
|
||||
|
||||
$('.layui-btn').on('click', function () {
|
||||
var type = $(this).data('type');
|
||||
active[type] && active[type].call(this);
|
||||
});
|
||||
|
||||
console.log(layui.setter.getTokens());
|
||||
var inst = upload.render({
|
||||
elem: '#buttonInstall',
|
||||
field: 'file',
|
||||
url: "upload", // 上传接口地址
|
||||
accept: 'file', // 只允许上传文件
|
||||
// 注意:不要设置 acceptMime。该属性会让浏览器文件选择框按 MIME 过滤,
|
||||
// 而 zip 在本机常被识别为 application/x-zip-compressed / application/octet-stream,
|
||||
// 导致选择框中插件包被置灰、无法选中。仅用 exts 在选完后校验后缀即可。
|
||||
exts: 'zip', // 仅允许 zip 插件包(后端 AddonService 只支持 zip)
|
||||
headers: { 'Authorization': `Bearer ${access_token}` }, // 鉴权
|
||||
|
||||
done: function (res) {
|
||||
// 上传成功的回调
|
||||
if (res.code == 0) {
|
||||
layer.msg('插件安装成功!', { icon: 1 });
|
||||
clearMenuCache(); // 插件菜单已变化,清掉侧栏菜单缓存
|
||||
location.reload(); // 重新加载整页,侧栏立即刷新
|
||||
} else {
|
||||
layer.msg('安装失败: ' + res.message, { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
// 上传失败的回调
|
||||
// 当上传失败时,可在此处生成「重新上传」按钮,并执行该方法重新触发上传提交
|
||||
/*
|
||||
$('#btn').on('click', function(){
|
||||
inst.upload();
|
||||
})
|
||||
*/
|
||||
}
|
||||
});
|
||||
// ===== 监听顶部搜索表单提交 =====
|
||||
form.on('submit(searchBtn)', function (data) {
|
||||
var field = data.field; // 获取搜索表单的值
|
||||
// 重载表格,将搜索条件传给后端
|
||||
table.reload('dataTable', {
|
||||
where: field,
|
||||
page: { curr: 1 } // 搜索后回到第一页
|
||||
});
|
||||
return false; // 阻止表单默认跳转
|
||||
});
|
||||
|
||||
// ===== 监听状态开关(启用/停用)的切换 =====
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var name = this.value; // value 绑定的是插件名 d.id
|
||||
var status = obj.elem.checked ? 1 : 0; // 根据开关状态赋值
|
||||
var action = status ? 'enable' : 'disable';
|
||||
var that = obj.othis;
|
||||
http.post('toggle', { name: name, action: action })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg(status ? '已启用' : '已停用', { icon: 1 });
|
||||
clearMenuCache(); // 菜单可见性已变化,清掉侧栏菜单缓存(下次导航即刷新)
|
||||
} else {
|
||||
layer.msg(res.message || '操作失败', { icon: 2 });
|
||||
that.find('input').prop('checked', !status);
|
||||
form.render();
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
that.find('input').prop('checked', !status);
|
||||
form.render();
|
||||
});
|
||||
});
|
||||
|
||||
exports('addon', {}); // 输出模块接口
|
||||
});
|
||||
@@ -0,0 +1,410 @@
|
||||
layui.define(['http', 'layer', 'laydate', 'util', 'auth'], function (exports) {
|
||||
var $ = layui.$
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, layer = layui.layer
|
||||
, laydate = layui.laydate
|
||||
, util = layui.util
|
||||
, http = layui.http
|
||||
, laytpl = layui.laytpl; var auth = layui.auth;
|
||||
|
||||
// 使用登录时后端返回的真实权限(已存入 layui.data),并以当前控制器解析裸动作 token
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('admin');
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
, url: "index" // 后端数据接口
|
||||
, page: true
|
||||
, limit: 15
|
||||
//, toolbar: '#tableBar'
|
||||
// , defaultToolbar: auth.renderToolbar(tableActions)
|
||||
, cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' }
|
||||
, { field: 'id', title: 'ID', width: 72, align: 'center', sort: true, fixed: 'left' }
|
||||
, { field: 'account', title: '账户', width: 120, align: 'center', fixed: 'left' }
|
||||
, { field: 'nickname', title: '昵称', width: 100, align: 'center' }
|
||||
// , { field: 'role_id', title: '角色', width: 100, align: 'center', templet: '#roleTpl' }
|
||||
, { field: 'email', title: '邮箱', minWidth: 180, align: 'center' }
|
||||
, { field: 'mobile', title: '手机', width: 120, align: 'center' }
|
||||
, { field: 'login_info', title: '登录信息', width: 160, align: 'center', templet: '#loginInfoTpl' }
|
||||
, { field: 'status', title: '状态', width: 90, align: 'center', templet: '#statusTpl', unresize: true }
|
||||
, { field: 'create_at', title: '创建时间', width: 160, align: 'center', sort: true }
|
||||
, { title: '操作', width: 120, align: 'left', toolbar: '#dataBar', fixed: 'right', unresize: true }
|
||||
]],
|
||||
done: function (res, curr, count) {
|
||||
// 行内按钮按真实权限显隐(data-perm 为完整权限 key,如 admin:edit)
|
||||
$('#dataTable').next('.layui-table-view').find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) {
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 搜索
|
||||
form.on('submit(searchBtn)', function (data) {
|
||||
adminTable.reload({
|
||||
where: data.field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 状态开关
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var id = this.value;
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
layer.confirm('确定要' + (status ? '启用' : '禁用') + '该管理员账号吗?', function (index) {
|
||||
layui.request.post('update', { id: id, status: status }
|
||||
).then(function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.msg, { icon: 1 });
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
}, function () {
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
});
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate':
|
||||
active.dataCreate({ pid: 0, type: 1 });
|
||||
break;
|
||||
case 'dataDelete':
|
||||
var checkStatus = table.checkStatus('dataTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataDelete(ids);
|
||||
break;
|
||||
case 'dataRecybin':
|
||||
active.dataRecybin();
|
||||
break;
|
||||
};
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update':
|
||||
active.dataEdit(data);
|
||||
break;
|
||||
case 'delete':
|
||||
active.dataDelete([data.id]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data ? '编辑数据[' + data.account + ']' : '添加数据';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: data.id ? '编辑菜单' : (data.pid ? '添加子菜单' : '添加根菜单'),
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
btnAlign: "l",
|
||||
area: ['50% ', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
btn: ['确定', '取消'],
|
||||
success: function (layero, index) {
|
||||
callback(layero, index);
|
||||
form.render();
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem);
|
||||
layui.off('submit(wxapp-form)', 'from');
|
||||
return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
//事件
|
||||
var active = {
|
||||
dataDelete: function (ids, force = 0) {
|
||||
if (ids.length === 0) {
|
||||
return layer.msg('请选择数据');
|
||||
}
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '敏感操作,请验证口令'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
layer.confirm('确定删除吗?', function (index) {
|
||||
http.delete('delete', { ids: ids.join(','), force: force })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
dataCreate: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) { },
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.icon = 'layui-icon ' + field.icon;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('create', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataEdit: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) { },
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.icon = 'layui-icon ' + field.icon;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataRecybin: function (data = {}) {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: '资源回收站',
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
area: ['50%', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
layui.table.render({
|
||||
elem: '#dataRecybinTable',
|
||||
url: "recyclebin",
|
||||
height: 'full-100',
|
||||
defaultToolbar: [{
|
||||
title: '批量删除数据',
|
||||
layEvent: 'dataDelete',
|
||||
icon: 'layui-icon-delete',
|
||||
onClick: function (obj) {
|
||||
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
console.log(ids);
|
||||
}
|
||||
}, 'filter', 'exports', 'print'],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '名称', width: 180, fixed: 'left' },
|
||||
{ field: 'code', title: '代码', width: 180, fixed: 'left' },
|
||||
{ field: 'description', title: '描述', minWidth: 200, sort: true },
|
||||
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true,
|
||||
done: function (res, curr, count, origin) {
|
||||
console.log('表格渲染完成');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data = {}) {
|
||||
http.put("restore", { id: data.id })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg('恢复成功');
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '恢复失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 打开管理员表单
|
||||
function opendataForm(data) {
|
||||
var title = data ? '编辑管理员 [' + data.account + ']' : '添加管理员';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title,
|
||||
area: ['500px', '520px'],
|
||||
shadeClose: true,
|
||||
content: formHtml,
|
||||
success: function (layero, index) {
|
||||
// 显示/隐藏密码字段
|
||||
if (data) {
|
||||
$('#passwordGroup').hide();
|
||||
} else {
|
||||
$('#passwordGroup').show();
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
layui.form.verify({
|
||||
username: function (value) {
|
||||
if (!/^[\w\u4e00-\u9fa5]{2,20}$/.test(value)) {
|
||||
return '用户名必须2-20位字符,支持中文、字母、数字和下划线';
|
||||
}
|
||||
},
|
||||
pass: [
|
||||
/^[\S]{6,20}$/
|
||||
, '密码必须6到20位,且不能出现空格'
|
||||
]
|
||||
});
|
||||
|
||||
// 提交表单
|
||||
form.on('submit(adminFormSubmit)', function (formData) {
|
||||
var url = data ? "update" : "create";
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
data: formData.field,
|
||||
success: function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
|
||||
layer.close(index);
|
||||
adminTable.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('操作失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
form.render();
|
||||
},
|
||||
btn: ['保存', '取消'],
|
||||
yes: function (index, layero) {
|
||||
// 触发表单提交
|
||||
layero.find('form').find('button[lay-filter=adminFormSubmit]').click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 重置密码
|
||||
function resetPassword(data) {
|
||||
layer.confirm('确定要重置管理员 [' + data.username + '] 的密码吗?重置后密码将变为123456', {
|
||||
btn: ['确定', '取消'],
|
||||
title: '重置密码'
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: "resetPassword",
|
||||
type: 'POST',
|
||||
data: { id: data.id },
|
||||
success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('操作失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 删除管理员
|
||||
function deleteAdmin(data) {
|
||||
layer.confirm('确定要删除管理员 [' + data.username + '] 吗?此操作不可恢复!', {
|
||||
btn: ['确定', '取消'],
|
||||
title: '删除管理员',
|
||||
icon: 3
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: "delete",
|
||||
type: 'POST',
|
||||
data: { id: data.id },
|
||||
success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
|
||||
adminTable.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('操作失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
function batchDelete(data) {
|
||||
if (data.length === 0) {
|
||||
layer.msg('请先选择要删除的管理员', { icon: 3 });
|
||||
return;
|
||||
}
|
||||
var superAdmins = data.filter(function (item) {
|
||||
return item.is_super == 1;
|
||||
});
|
||||
if (superAdmins.length > 0) {
|
||||
layer.msg('不能删除超级管理员账号', { icon: 2 });
|
||||
return;
|
||||
}
|
||||
var ids = data.map(function (item) {
|
||||
return item.id;
|
||||
});
|
||||
layer.confirm('确定要删除选中的 ' + data.length + ' 个管理员吗?此操作不可恢复!', {
|
||||
btn: ['确定', '取消'],
|
||||
title: '批量删除',
|
||||
icon: 3
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: "batchDelete",
|
||||
type: 'POST',
|
||||
data: { ids: ids },
|
||||
success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
|
||||
adminTable.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('操作失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
exports('admin', {});
|
||||
});
|
||||
@@ -0,0 +1,281 @@
|
||||
layui.define(['http', 'setter', 'auth', 'form'], function (exports) {
|
||||
var $ = layui.$, layer = layui.layer, http = layui.http, auth = layui.auth, form = layui.form;
|
||||
var _perms = (layui.data('backend').permission) || [];
|
||||
auth.init(_perms);
|
||||
auth.setController('addon');
|
||||
|
||||
var isDemo = false;
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
|
||||
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c];
|
||||
});
|
||||
}
|
||||
|
||||
function priceText(p) {
|
||||
p = Number(p) || 0;
|
||||
return p > 0 ? '¥' + p : '免费';
|
||||
}
|
||||
|
||||
function cardHtml(item) {
|
||||
var logo = item.logo
|
||||
? '<img src="' + escapeHtml(item.logo) + '" class="m-logo">'
|
||||
: '<div class="m-logo m-logo-default">' + escapeHtml((item.title || '?').charAt(0)) + '</div>';
|
||||
var action;
|
||||
if (item.installed) {
|
||||
var btns = '<button class="layui-btn layui-btn-xs layui-btn-normal" data-act="manage" data-name="' + escapeHtml(item.name) + '">管理</button>';
|
||||
if (item.upgradable) {
|
||||
btns = '<button class="layui-btn layui-btn-xs layui-btn-warm" data-act="upgrade" data-name="' + escapeHtml(item.name) + '" data-version="' + escapeHtml(item.version) + '">升级 v' + escapeHtml(item.version) + '</button>' + btns;
|
||||
}
|
||||
if (Number(item.price) > 0) {
|
||||
btns += '<button class="layui-btn layui-btn-xs layui-btn-danger" data-act="refund" data-name="' + escapeHtml(item.name) + '">退款</button>';
|
||||
}
|
||||
action = '<button class="layui-btn layui-btn-xs layui-btn-disabled" disabled>已安装</button>' + btns;
|
||||
} else {
|
||||
var label = (Number(item.price) > 0 ? '¥' + item.price + ' 购买安装' : '安装');
|
||||
action = '<button class="layui-btn layui-btn-xs layui-btn-warm" data-act="install" data-name="' + escapeHtml(item.name) + '" data-version="' + escapeHtml(item.version) + '" data-price="' + Number(item.price || 0) + '">' + label + '</button>';
|
||||
}
|
||||
return '<div class="market-card">'
|
||||
+ '<div class="m-head">' + logo + '<div class="m-meta"><div class="m-title">' + escapeHtml(item.title) + '</div><div class="m-author">' + escapeHtml(item.author || '') + ' · v' + escapeHtml(item.version || '') + '</div></div></div>'
|
||||
+ '<div class="m-intro">' + escapeHtml(item.intro || '') + '</div>'
|
||||
+ '<div class="m-foot"><span class="m-price ' + (Number(item.price) > 0 ? 'paid' : 'free') + '">' + priceText(item.price) + '</span>' + action + '</div>'
|
||||
+ '</div>';
|
||||
}
|
||||
|
||||
function render(list) {
|
||||
var html = (list || []).map(cardHtml).join('');
|
||||
$('#marketList').html(html || '<div class="empty">暂无可安装的插件</div>');
|
||||
// 权限控制:无安装权限则隐藏安装按钮
|
||||
if (!auth.has('addon:install') && !auth.has('addon:*')) {
|
||||
$('[data-act="install"]').remove();
|
||||
}
|
||||
}
|
||||
|
||||
function load() {
|
||||
http.get('market', {})
|
||||
.then(function (res) {
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.message || '获取失败', { icon: 2 });
|
||||
return;
|
||||
}
|
||||
isDemo = !!res.data.demo;
|
||||
render(res.data.list || []);
|
||||
})
|
||||
.catch(function () {
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
});
|
||||
}
|
||||
|
||||
$('#marketList').on('click', '[data-act="install"]', function () {
|
||||
var $btn = $(this);
|
||||
var name = $btn.data('name');
|
||||
var version = $btn.data('version');
|
||||
var price = Number($btn.data('price')) || 0;
|
||||
var doInstall = function () {
|
||||
if (isDemo) {
|
||||
layer.msg('演示模式:已安装「' + name + '」', { icon: 1 });
|
||||
$btn.parent().html('<button class="layui-btn layui-btn-xs layui-btn-disabled" disabled>已安装</button><button class="layui-btn layui-btn-xs layui-btn-normal" data-act="manage" data-name="' + name + '">管理</button>');
|
||||
return;
|
||||
}
|
||||
var loading = layer.load();
|
||||
http.post('downloadInstall', { name: name, version: version })
|
||||
.then(function (res) {
|
||||
layer.close(loading);
|
||||
if (res.code === 0) {
|
||||
layer.msg('安装成功', { icon: 1 });
|
||||
load();
|
||||
} else {
|
||||
layer.msg(res.message || '安装失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
layer.close(loading);
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
});
|
||||
};
|
||||
if (price > 0) {
|
||||
layer.confirm('该付费插件授权绑定当前站点域名(' + location.host + '),换站点安装将被拒绝。确认在当前站点安装?', { title: '域名授权提示' }, function (idx) {
|
||||
layer.close(idx);
|
||||
doInstall();
|
||||
});
|
||||
} else {
|
||||
doInstall();
|
||||
}
|
||||
});
|
||||
|
||||
$('#marketList').on('click', '[data-act="refund"]', function () {
|
||||
var $btn = $(this);
|
||||
var name = $btn.data('name');
|
||||
layer.confirm('确认对插件「' + name + '」发起退款?退款后授权将被吊销,无法再下载或安装。', function (idx) {
|
||||
layer.close(idx);
|
||||
var loading = layer.load();
|
||||
http.post('refund', { name: name })
|
||||
.then(function (res) {
|
||||
layer.close(loading);
|
||||
if (res.code === 0) {
|
||||
layer.msg('退款成功,授权已吊销', { icon: 1 });
|
||||
load();
|
||||
} else {
|
||||
layer.msg(res.message || '退款失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
layer.close(loading);
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#marketList').on('click', '[data-act="upgrade"]', function () {
|
||||
var $btn = $(this);
|
||||
var name = $btn.data('name');
|
||||
var version = $btn.data('version');
|
||||
var loading = layer.load();
|
||||
http.post('upgrade', { name: name, version: version })
|
||||
.then(function (res) {
|
||||
layer.close(loading);
|
||||
if (res.code === 0) {
|
||||
layer.msg('升级成功', { icon: 1 });
|
||||
load();
|
||||
} else {
|
||||
layer.msg(res.message || '升级失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
layer.close(loading);
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
});
|
||||
});
|
||||
|
||||
$('#marketList').on('click', '[data-act="manage"]', function () {
|
||||
var name = $(this).data('name');
|
||||
if (isDemo) {
|
||||
layer.msg('演示:进入「' + name + '」后台', { icon: 0 });
|
||||
return;
|
||||
}
|
||||
// 真实模式:跳转到插件自己的后台(约定路径,可按实际调整)
|
||||
window.open('/' + name);
|
||||
});
|
||||
|
||||
// ===== 发布到本服务器(仅开发模式显示) =====
|
||||
var isDev = $('#appDebug').val() === '1';
|
||||
var installedList = [];
|
||||
if (isDev) {
|
||||
$('#btnPublish').show();
|
||||
}
|
||||
|
||||
function loadInstalled() {
|
||||
return http.get('index', { page: 1, limit: 9999 })
|
||||
.then(function (res) {
|
||||
if (res.code === 0 && Array.isArray(res.data)) {
|
||||
installedList = res.data;
|
||||
}
|
||||
return installedList;
|
||||
})
|
||||
.catch(function () { return []; });
|
||||
}
|
||||
|
||||
$('#btnPublish').on('click', function () {
|
||||
loadInstalled().then(function (list) {
|
||||
if (!list.length) {
|
||||
layer.msg('暂无已安装插件可发布', { icon: 2 });
|
||||
return;
|
||||
}
|
||||
var opts = list.map(function (it) {
|
||||
return '<option value="' + escapeHtml(it.name) + '">' + escapeHtml(it.title || it.name) + ' v' + escapeHtml(it.version || '') + '</option>';
|
||||
}).join('');
|
||||
var html =
|
||||
'<div style="padding:15px;"><div class="layui-form">'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">选择插件</label><div class="layui-input-block"><select id="pubName" class="layui-input">' + opts + '</select></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">标题</label><div class="layui-input-block"><input id="pubTitle" class="layui-input"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">作者</label><div class="layui-input-block"><input id="pubAuthor" class="layui-input"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">简介</label><div class="layui-input-block"><textarea id="pubDesc" class="layui-input" rows="3"></textarea></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">价格</label><div class="layui-input-block"><input id="pubPrice" type="number" step="0.01" value="0" class="layui-input"></div></div>'
|
||||
+ '<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn layui-btn-danger" id="pubSubmit">确认发布到本服务器</button></div></div>'
|
||||
+ '</div></div>';
|
||||
|
||||
layer.open({ type: 1, title: '发布到本服务器市场', area: ['520px', 'auto'], content: html });
|
||||
|
||||
// 关键:下拉是动态注入到 .layui-form 内的元素,必须显式 render 才会显示选项,
|
||||
// 否则 layui 增强后的 select 会显示为空(表现为「选择插件」没有任何内容)。
|
||||
form.render('select');
|
||||
|
||||
function fillMeta() {
|
||||
var name = $('#pubName').val();
|
||||
var it = list.filter(function (x) { return x.name === name; })[0] || {};
|
||||
$('#pubTitle').val(it.title || name);
|
||||
$('#pubAuthor').val(it.author || '');
|
||||
$('#pubDesc').val(it.description || it.intro || '');
|
||||
$('#pubPrice').val(it.price != null ? it.price : 0);
|
||||
}
|
||||
fillMeta();
|
||||
$('#pubName').on('change', fillMeta);
|
||||
|
||||
$('#pubSubmit').on('click', function () {
|
||||
var data = {
|
||||
name: $('#pubName').val(),
|
||||
title: $('#pubTitle').val(),
|
||||
author: $('#pubAuthor').val(),
|
||||
description: $('#pubDesc').val(),
|
||||
price: $('#pubPrice').val() || 0
|
||||
};
|
||||
var loading = layer.load();
|
||||
http.post('publish', data)
|
||||
.then(function (res) {
|
||||
layer.close(loading);
|
||||
if (res.code === 0) {
|
||||
layer.msg('发布成功', { icon: 1 });
|
||||
layer.closeAll();
|
||||
load();
|
||||
} else {
|
||||
layer.msg(res.message || '发布失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
layer.close(loading);
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ===== 发布到官方公共市场(需开发者令牌,服务端审核) =====
|
||||
$('#btnSubmitOfficial').on('click', function () {
|
||||
loadInstalled().then(function (list) {
|
||||
if (!list.length) {
|
||||
layer.msg('暂无已安装插件可发布', { icon: 2 });
|
||||
return;
|
||||
}
|
||||
var opts = list.map(function (it) {
|
||||
return '<option value="' + escapeHtml(it.name) + '">' + escapeHtml(it.title || it.name) + ' v' + escapeHtml(it.version || '') + '</option>';
|
||||
}).join('');
|
||||
var html =
|
||||
'<div style="padding:15px;"><div class="layui-form">'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">选择插件</label><div class="layui-input-block"><select id="offName" class="layui-input">' + opts + '</select></div></div>'
|
||||
+ '<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn layui-btn-normal" id="offSubmit">提交审核</button></div></div>'
|
||||
+ '</div></div>';
|
||||
layer.open({ type: 1, title: '发布到官方市场(需审核)', area: ['520px', 'auto'], content: html });
|
||||
form.render('select');
|
||||
$('#offSubmit').on('click', function () {
|
||||
var loading = layer.load();
|
||||
http.post('submitOfficial', { name: $('#offName').val() })
|
||||
.then(function (res) {
|
||||
layer.close(loading);
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.message || '提交成功,等待审核', { icon: 1 });
|
||||
layer.closeAll();
|
||||
} else {
|
||||
layer.msg(res.message || '提交失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
layer.close(loading);
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
load();
|
||||
exports('market', {});
|
||||
});
|
||||
@@ -0,0 +1,209 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('card');
|
||||
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'cardno', minWidth: 160, title: '卡号' },
|
||||
{ field: 'amount', width: 100, title: '面值', sort: true },
|
||||
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'user_name', width: 120, title: '兑换会员' },
|
||||
{ field: 'use_time_text', width: 180, title: '兑换时间' },
|
||||
{ field: 'sort', width: 100, title: '排序', sort: true },
|
||||
{ field: 'create_time', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { cardno: data.field.cardno, status: data.field.status } });
|
||||
return false;
|
||||
});
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name=\"cardno\"]').val('');
|
||||
$('select[name=\"status\"]').val('');
|
||||
form.render('select');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { cardno: '', status: '' } });
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate': active.dataCreate({}); break;
|
||||
case 'dataBatch': active.dataBatch(); break;
|
||||
case 'dataDelete':
|
||||
var check = table.checkStatus('dataTable').data;
|
||||
active.dataDelete(check.map(function (i) { return i.id; }));
|
||||
break;
|
||||
case 'dataRecybin': active.dataRecybin(); break;
|
||||
}
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update': active.dataEdit(data); break;
|
||||
case 'delete': active.dataDelete([data.id]); break;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.put('update', { id: this.value, status: status })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) { layer.msg('操作成功'); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
table.reload('dataTable', {}, true);
|
||||
})
|
||||
.catch(function () { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑充值卡密' : '添加充值卡密';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title, content: formHtml, anim: "slideLeft", offset: "r",
|
||||
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
|
||||
success: function (layero, index) { callback(layero, index); form.render(); },
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var active = {
|
||||
dataDelete: function (ids, force) {
|
||||
if (ids.length === 0) { return layer.msg('请选择数据'); }
|
||||
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
|
||||
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
|
||||
});
|
||||
},
|
||||
dataCreate: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
if (field.status === undefined) field.status = 0;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataEdit: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataBatch: function () {
|
||||
var formHtml = laytpl($('#batchFormTpl').html()).render({});
|
||||
layer.open({
|
||||
title: '批量生成卡密', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
btn: ['生成', '取消'],
|
||||
success: function () { form.render(); },
|
||||
yes: function (index, layero) {
|
||||
var field = layui.form.val('wxapp-batch-form');
|
||||
http.post('generate', field).then(function (res) {
|
||||
if (res.code === 0) {
|
||||
var resultHtml = laytpl($('#batchResultTpl').html()).render({ list: res.data.list, amount: field.amount });
|
||||
layer.open({
|
||||
title: '生成结果', content: resultHtml, area: ['600px', '70%'],
|
||||
shadeClose: true, btn: ['知道了'],
|
||||
yes: function (i2) { layer.close(i2); layer.close(index); table.reload('dataTable', {}, true); }
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg || '生成失败');
|
||||
}
|
||||
}).catch(function (e) { layer.msg('请求失败:' + e); });
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRecybin: function () {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
|
||||
layer.open({
|
||||
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
success: function () {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
|
||||
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'cardno', title: '卡号', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data) {
|
||||
http.put("restore", { ids: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '恢复失败'); }
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore': active.dataRestore(data); break;
|
||||
case 'forcedelete': active.dataForceDelete(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('card', {});
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
layui.define(['http', 'auth', 'table', 'layer'], function (exports) {
|
||||
var table = layui.table,
|
||||
layer = layui.layer,
|
||||
auth = layui.auth,
|
||||
http = layui.http;
|
||||
|
||||
// 权限控制器前缀:与后端 BackendPower.name(articles:backend:category:add 等)对齐
|
||||
auth.setController('articles:backend:category');
|
||||
auth.render();
|
||||
|
||||
var MODULE = 'articles/backend.category',
|
||||
FUNC = {
|
||||
index: MODULE + '/index',
|
||||
delete: MODULE + '/delete'
|
||||
};
|
||||
|
||||
var obj = {
|
||||
init: function () {
|
||||
this.render();
|
||||
this.events();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
table.render({
|
||||
elem: '#table',
|
||||
url: FUNC.index,
|
||||
toolbar: '#toolbar',
|
||||
defaultToolbar: ['filter', 'print', 'exports'],
|
||||
method: 'get',
|
||||
cols: [[
|
||||
{field: 'id', title: 'ID', width: 70, sort: true},
|
||||
{field: 'name', title: '名称', width: 150},
|
||||
{field: 'alias', title: '别名', width: 150},
|
||||
{field: 'description', title: '描述'},
|
||||
{field: 'sort', title: '排序', width: 80, sort: true},
|
||||
{field: 'status', title: '状态', width: 90, templet: '#statusTpl'},
|
||||
{field: 'create_at', title: '创建时间', width: 170, templet: function (d) {
|
||||
return d.create_at ? layui.util.toDateString(d.create_at * 1000, 'yyyy-MM-dd HH:mm:ss') : '';
|
||||
}},
|
||||
{title: '操作', width: 130, templet: '#action', fixed: 'right'}
|
||||
]],
|
||||
page: true,
|
||||
limit: 10,
|
||||
limits: [10, 20, 50, 100],
|
||||
response: {statusCode: 0},
|
||||
parseData: function (res) {
|
||||
return {
|
||||
code: res.code,
|
||||
msg: res.msg,
|
||||
count: res.count,
|
||||
data: res.data
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
events: function () {
|
||||
// 顶部工具条
|
||||
table.on('toolbar(table)', function (obj) {
|
||||
var event = obj.event;
|
||||
if (event === 'add') {
|
||||
if (!auth.has('add')) return layer.msg('无权限', {icon: 2});
|
||||
window.location.href = '/articles/backend.category/edit';
|
||||
}
|
||||
});
|
||||
|
||||
// 行内操作
|
||||
table.on('tool(table)', function (obj) {
|
||||
var data = obj.data,
|
||||
event = obj.event;
|
||||
if (event === 'edit') {
|
||||
if (!auth.has('edit')) return layer.msg('无权限', {icon: 2});
|
||||
window.location.href = '/articles/backend.category/edit/id/' + data.id;
|
||||
} else if (event === 'del') {
|
||||
if (!auth.has('delete')) return layer.msg('无权限', {icon: 2});
|
||||
layer.confirm('确定删除该分类吗?', {title: '提示'}, function (index) {
|
||||
http.delete(FUNC.delete, {id: data.id}, function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.msg || '删除成功', {icon: 1});
|
||||
table.reload('table');
|
||||
} else {
|
||||
layer.msg(res.msg || '删除失败', {icon: 2});
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
obj.init();
|
||||
exports('category', obj);
|
||||
});
|
||||
@@ -0,0 +1,170 @@
|
||||
|
||||
// 原始数据
|
||||
var formData = [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "site_name",
|
||||
"group": "basic",
|
||||
"title": "站点名称",
|
||||
"tip": "请填写站点名称",
|
||||
"type": "string",
|
||||
"value": "YFCMF-TP6",
|
||||
"content": "",
|
||||
"rule": "required",
|
||||
"extend": "",
|
||||
"setting": ""
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "beian",
|
||||
"group": "basic",
|
||||
"title": "备案号",
|
||||
"tip": "",
|
||||
"type": "string",
|
||||
"value": "",
|
||||
"content": "",
|
||||
"rule": "",
|
||||
"extend": "",
|
||||
"setting": ""
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "site_description",
|
||||
"group": "basic",
|
||||
"title": "站点描述",
|
||||
"tip": "请填写站点描述",
|
||||
"type": "textarea",
|
||||
"value": "这是一个基于TP6的CMS系统",
|
||||
"content": "",
|
||||
"rule": "",
|
||||
"extend": "",
|
||||
"setting": ""
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "site_status",
|
||||
"group": "advanced",
|
||||
"title": "站点状态",
|
||||
"tip": "选择站点是否开启",
|
||||
"type": "select",
|
||||
"value": "1",
|
||||
"content": "开启,关闭,维护中",
|
||||
"rule": "required",
|
||||
"extend": "",
|
||||
"setting": ""
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "allow_comment",
|
||||
"group": "advanced",
|
||||
"title": "允许评论",
|
||||
"tip": "是否允许访客评论",
|
||||
"type": "radio",
|
||||
"value": "1",
|
||||
"content": "是,否",
|
||||
"rule": "",
|
||||
"extend": "",
|
||||
"setting": ""
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "features",
|
||||
"group": "advanced",
|
||||
"title": "功能模块",
|
||||
"tip": "选择启用的功能模块",
|
||||
"type": "checkbox",
|
||||
"value": "文章,评论",
|
||||
"content": "文章,评论,用户,统计",
|
||||
"rule": "",
|
||||
"extend": "",
|
||||
"setting": ""
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "max_upload_size",
|
||||
"group": "upload",
|
||||
"title": "最大上传大小",
|
||||
"tip": "单位:MB",
|
||||
"type": "number",
|
||||
"value": "10",
|
||||
"content": "",
|
||||
"rule": "required",
|
||||
"extend": "",
|
||||
"setting": ""
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "upload_date",
|
||||
"group": "upload",
|
||||
"title": "上传日期限制",
|
||||
"tip": "选择可上传文件的日期范围",
|
||||
"type": "date",
|
||||
"value": "2024-01-01",
|
||||
"content": "",
|
||||
"rule": "",
|
||||
"extend": "",
|
||||
"setting": ""
|
||||
}
|
||||
];
|
||||
|
||||
// 处理数据:按group分组
|
||||
function processData(data) {
|
||||
var groups = {};
|
||||
var groupNames = [];
|
||||
|
||||
// 收集所有分组
|
||||
data.forEach(function (item) {
|
||||
if (!groups[item.group]) {
|
||||
groups[item.group] = [];
|
||||
groupNames.push(item.group);
|
||||
}
|
||||
groups[item.group].push(item);
|
||||
});
|
||||
|
||||
return {
|
||||
groups: groupNames,
|
||||
data: groups
|
||||
};
|
||||
}
|
||||
|
||||
// 初始化Layui
|
||||
layui.define(['laytpl', 'form', 'element', 'laydate', 'http'], function (exports) {
|
||||
var laytpl = layui.laytpl;
|
||||
var form = layui.form;
|
||||
var element = layui.element;
|
||||
var laydate = layui.laydate;
|
||||
var http = layui.http;
|
||||
http.get('index').then(respon => {
|
||||
let respona = processData(respon.data);
|
||||
var getTpl = document.getElementById('formTpl').innerHTML;
|
||||
var view = document.getElementById('formView');
|
||||
laytpl(getTpl).render(respona, function (html) {
|
||||
view.innerHTML = html;
|
||||
// 重新渲染表单元素
|
||||
form.render();
|
||||
element.render('tab');
|
||||
// 初始化日期选择器
|
||||
formData.forEach(function (item) {
|
||||
if (item.type === 'date') {
|
||||
laydate.render({
|
||||
elem: '#date-' + item.id,
|
||||
format: 'yyyy-MM-dd'
|
||||
});
|
||||
}
|
||||
});
|
||||
// 监听表单提交
|
||||
form.on('submit', function (data) {
|
||||
console.log('表单提交数据:', data.field);
|
||||
http.post('update', data.field).then(respon => {
|
||||
console.log(respon)
|
||||
});
|
||||
layer.msg('表单提交成功!已输出到控制台');
|
||||
return false;
|
||||
});
|
||||
});
|
||||
})
|
||||
// 处理数据
|
||||
var processedData = processData(formData);
|
||||
// 渲染模板
|
||||
exports('configure', {});
|
||||
});
|
||||
@@ -0,0 +1,295 @@
|
||||
/**
|
||||
* console - homepage demo
|
||||
*/
|
||||
|
||||
|
||||
layui.define('ywxapp',function (exports) {
|
||||
var ywxapp = layui.ywxapp;
|
||||
//区块轮播切换
|
||||
layui.use(['ywxapp', 'carousel'], function () {
|
||||
var $ = layui.$
|
||||
, ywxapp = layui.ywxapp
|
||||
, carousel = layui.carousel
|
||||
, element = layui.element
|
||||
, device = layui.device();
|
||||
|
||||
//轮播切换
|
||||
$('.layadmin-carousel').each(function () {
|
||||
var othis = $(this);
|
||||
carousel.render({
|
||||
elem: this
|
||||
, width: '100%'
|
||||
, arrow: 'none'
|
||||
, interval: othis.data('interval')
|
||||
, autoplay: othis.data('autoplay') === true
|
||||
, trigger: (device.ios || device.android) ? 'click' : 'hover'
|
||||
, anim: othis.data('anim')
|
||||
});
|
||||
});
|
||||
|
||||
element.render('progress');
|
||||
|
||||
});
|
||||
|
||||
//八卦新闻
|
||||
layui.use(['carousel', 'echarts'], function () {
|
||||
var $ = layui.$
|
||||
, carousel = layui.carousel
|
||||
, echarts = layui.echarts;
|
||||
|
||||
var echartsApp = [], options = [
|
||||
{
|
||||
title: {
|
||||
subtext: '完全实况球员数据',
|
||||
textStyle: {
|
||||
fontSize: 14
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
x: 'left',
|
||||
data: ['罗纳尔多', '舍普琴科']
|
||||
},
|
||||
polar: [
|
||||
{
|
||||
indicator: [
|
||||
{ text: '进攻', max: 100 },
|
||||
{ text: '防守', max: 100 },
|
||||
{ text: '体能', max: 100 },
|
||||
{ text: '速度', max: 100 },
|
||||
{ text: '力量', max: 100 },
|
||||
{ text: '技巧', max: 100 }
|
||||
],
|
||||
radius: 130
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: 'radar',
|
||||
center: ['50%', '50%'],
|
||||
itemStyle: {
|
||||
normal: {
|
||||
areaStyle: {
|
||||
type: 'default'
|
||||
}
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{ value: [97, 42, 88, 94, 90, 86], name: '舍普琴科' },
|
||||
{ value: [97, 32, 74, 95, 88, 92], name: '罗纳尔多' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
, elemDataView = $('#LAY-index-pageone').children('div')
|
||||
, renderDataView = function (index) {
|
||||
echartsApp[index] = echarts.init(elemDataView[index], layui.echartsTheme);
|
||||
echartsApp[index].setOption(options[index]);
|
||||
window.onresize = echartsApp[index].resize;
|
||||
};
|
||||
//没找到DOM,终止执行
|
||||
if (!elemDataView[0]) return;
|
||||
|
||||
renderDataView(0);
|
||||
});
|
||||
|
||||
//访问量
|
||||
layui.use(['carousel', 'echarts'], function () {
|
||||
var $ = layui.$
|
||||
, carousel = layui.carousel
|
||||
, echarts = layui.echarts;
|
||||
|
||||
var echartsApp = [], options = [
|
||||
{
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
calculable: true,
|
||||
legend: {
|
||||
data: ['访问量', '下载量', '平均访问量']
|
||||
},
|
||||
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '访问量',
|
||||
axisLabel: {
|
||||
formatter: '{value} 万'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '下载量',
|
||||
axisLabel: {
|
||||
formatter: '{value} 万'
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '访问量',
|
||||
type: 'line',
|
||||
data: [900, 850, 950, 1000, 1100, 1050, 1000, 1150, 1250, 1370, 1250, 1100]
|
||||
},
|
||||
{
|
||||
name: '下载量',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
data: [850, 850, 800, 950, 1000, 950, 950, 1150, 1100, 1240, 1000, 950]
|
||||
},
|
||||
{
|
||||
name: '平均访问量',
|
||||
type: 'line',
|
||||
data: [870, 850, 850, 950, 1050, 1000, 980, 1150, 1000, 1300, 1150, 1000]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
, elemDataView = $('#LAY-index-pagetwo').children('div')
|
||||
, renderDataView = function (index) {
|
||||
echartsApp[index] = echarts.init(elemDataView[index], layui.echartsTheme);
|
||||
echartsApp[index].setOption(options[index]);
|
||||
window.onresize = echartsApp[index].resize;
|
||||
};
|
||||
//没找到DOM,终止执行
|
||||
if (!elemDataView[0]) return;
|
||||
renderDataView(0);
|
||||
|
||||
});
|
||||
|
||||
//地图
|
||||
layui.use(['carousel', 'echarts'], function () {
|
||||
var $ = layui.$
|
||||
, carousel = layui.carousel
|
||||
, echarts = layui.echarts;
|
||||
|
||||
var echartsApp = [], options = [
|
||||
{
|
||||
title: {
|
||||
text: '访客地区分布',
|
||||
subtext: '不完全统计'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
dataRange: {
|
||||
orient: 'horizontal',
|
||||
min: 0,
|
||||
max: 60000,
|
||||
text: ['高', '低'],
|
||||
splitNumber: 0
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '访客地区分布',
|
||||
type: 'map',
|
||||
mapType: 'china',
|
||||
selectedMode: 'multiple',
|
||||
itemStyle: {
|
||||
normal: { label: { show: true } },
|
||||
emphasis: { label: { show: true } }
|
||||
},
|
||||
data: [
|
||||
{ name: '西藏', value: 60 },
|
||||
{ name: '青海', value: 167 },
|
||||
{ name: '宁夏', value: 210 },
|
||||
{ name: '海南', value: 252 },
|
||||
{ name: '甘肃', value: 502 },
|
||||
{ name: '贵州', value: 570 },
|
||||
{ name: '新疆', value: 661 },
|
||||
{ name: '云南', value: 8890 },
|
||||
{ name: '重庆', value: 10010 },
|
||||
{ name: '吉林', value: 5056 },
|
||||
{ name: '山西', value: 2123 },
|
||||
{ name: '天津', value: 9130 },
|
||||
{ name: '江西', value: 10170 },
|
||||
{ name: '广西', value: 6172 },
|
||||
{ name: '陕西', value: 9251 },
|
||||
{ name: '黑龙江', value: 5125 },
|
||||
{ name: '内蒙古', value: 1435 },
|
||||
{ name: '安徽', value: 9530 },
|
||||
{ name: '北京', value: 51919 },
|
||||
{ name: '福建', value: 3756 },
|
||||
{ name: '上海', value: 59190 },
|
||||
{ name: '湖北', value: 37109 },
|
||||
{ name: '湖南', value: 8966 },
|
||||
{ name: '四川', value: 31020 },
|
||||
{ name: '辽宁', value: 7222 },
|
||||
{ name: '河北', value: 3451 },
|
||||
{ name: '河南', value: 9693 },
|
||||
{ name: '浙江', value: 62310 },
|
||||
{ name: '山东', value: 39231 },
|
||||
{ name: '江苏', value: 35911 },
|
||||
{ name: '广东', value: 55891 }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
, elemDataView = $('#LAY-index-pagethree').children('div')
|
||||
, renderDataView = function (index) {
|
||||
echartsApp[index] = echarts.init(elemDataView[index], layui.echartsTheme);
|
||||
echartsApp[index].setOption(options[index]);
|
||||
window.onresize = echartsApp[index].resize;
|
||||
};
|
||||
//没找到DOM,终止执行
|
||||
if (!elemDataView[0]) return;
|
||||
|
||||
renderDataView(0);
|
||||
});
|
||||
|
||||
//项目进展
|
||||
layui.use('table', function () {
|
||||
var $ = layui.$
|
||||
, table = layui.table;
|
||||
|
||||
table.render({
|
||||
elem: '#LAY-index-prograss'
|
||||
, url: layui.setter.paths.base + 'json/console/prograss.js' //模拟接口
|
||||
, cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' }
|
||||
, { field: 'prograss', title: '任务' }
|
||||
, { field: 'time', title: '所需时间' }
|
||||
, {
|
||||
field: 'complete', title: '完成情况'
|
||||
, templet: function (d) {
|
||||
if (d.complete == '已完成') {
|
||||
return '<del style="color: #16b777;">' + d.complete + '</del>'
|
||||
} else if (d.complete == '进行中') {
|
||||
return '<span style="color: #FFB800;">' + d.complete + '</span>'
|
||||
} else {
|
||||
return '<span style="color: #FF5722;">' + d.complete + '</span>'
|
||||
}
|
||||
}
|
||||
}
|
||||
]]
|
||||
, skin: 'line'
|
||||
});
|
||||
});
|
||||
|
||||
console.log('进入控制台',layui.ywxapp);
|
||||
//回复留言
|
||||
ywxapp.events.replyNote = function (othis) {
|
||||
var nid = othis.data('id');
|
||||
layer.prompt({
|
||||
title: '回复留言 ID:' + nid
|
||||
, formType: 2
|
||||
}, function (value, index) {
|
||||
//这里可以请求 Ajax
|
||||
//…
|
||||
layer.msg('得到:' + value);
|
||||
layer.close(index);
|
||||
});
|
||||
};
|
||||
|
||||
exports('console', {})
|
||||
});
|
||||
@@ -0,0 +1,298 @@
|
||||
|
||||
layui.define(['http', 'auth'], function (exports) {
|
||||
var $ = layui.$, table = layui.table, form = layui.form, layer = layui.layer
|
||||
, laydate = layui.laydate, laytpl = layui.laytpl, tree = layui.tree, http = layui.http
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('group');
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
, url: 'index' // 后端数据接口
|
||||
, page: true
|
||||
, limit: 15
|
||||
, toolbar: '#tableBarTpl'
|
||||
, cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' }
|
||||
, { field: 'id', title: 'ID', width: 60, align: 'center', sort: true, fixed: 'left' }
|
||||
, { field: 'title', title: '名称', width: 150, align: 'center', fixed: 'left' }
|
||||
, { field: 'name', title: '代码', width: 150, align: 'center', fixed: 'left' }
|
||||
, { field: 'description', title: '描述', minWidth: 200, align: 'left' }
|
||||
, { field: 'status', title: '状态', width: 120, align: 'center', templet: '#statusTpl' }
|
||||
, { field: 'create_time', title: '创建时间', width: 160, align: 'center', sort: true }
|
||||
, { title: '操作', width: 160, align: 'left', toolbar: '#dataBarTpl', fixed: 'right', unresize: true }
|
||||
]]
|
||||
, done: function (res, curr, count) {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate':
|
||||
active.dataCreate({ pid: 0, type: 1 });
|
||||
break;
|
||||
case 'dataDelete':
|
||||
var checkStatus = table.checkStatus('dataTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataDelete(ids);
|
||||
break;
|
||||
case 'dataRecybin':
|
||||
active.dataRecybin();
|
||||
break;
|
||||
};
|
||||
});
|
||||
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update':
|
||||
active.dataEdit(data);
|
||||
break;
|
||||
case 'permission':
|
||||
openPermissionForm(data);
|
||||
break;
|
||||
case 'delete':
|
||||
active.dataDelete([data.id]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data ? '编辑数据[' + data.account + ']' : '添加数据';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: data.id ? '编辑菜单' : (data.pid ? '添加子菜单' : '添加根菜单'),
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
btnAlign: "l",
|
||||
area: ['50% ', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
btn: ['确定', '取消'],
|
||||
success: function (layero, index) {
|
||||
callback(layero, index);
|
||||
form.render();
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem);
|
||||
layui.off('submit(wxapp-form)', 'from');
|
||||
return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//事件
|
||||
var active = {
|
||||
dataDelete: function (ids, force = 0) {
|
||||
if (ids.length === 0) {
|
||||
return layer.msg('请选择数据');
|
||||
}
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '敏感操作,请验证口令'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
layer.confirm('确定删除吗?', function (index) {
|
||||
http.delete("delete", { ids: ids.join(','), force: force })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
dataCreate: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) { },
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
http.post('save', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataEdit: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) { },
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
http.put('update', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataRecybin: function (data = {}) {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: '资源回收站',
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
area: ['50%', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable',
|
||||
url: "recyclebin",
|
||||
defaultToolbar: [{
|
||||
title: '批量删除数据',
|
||||
layEvent: 'dataDelete',
|
||||
icon: 'layui-icon-delete',
|
||||
onClick: function (obj) {
|
||||
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
console.log(ids);
|
||||
}
|
||||
}, 'filter', 'exports', 'print'],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '名称', width: 180, fixed: 'left' },
|
||||
{ field: 'name', title: '代码', width: 180, fixed: 'left' },
|
||||
{ field: 'description', title: '描述', minWidth: 200, sort: true },
|
||||
{
|
||||
fixed: "right", title: "操作", width: 120, align: "center", templet: function (d) {
|
||||
return `<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm" title="恢复数据" lay-event="restore" > <i class="layui-icon layui-icon-edit"></i> </a >
|
||||
<a class="layui-btn layui-btn-sm" title="删除数据" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
</div >`;
|
||||
}
|
||||
}
|
||||
]],
|
||||
page: true,
|
||||
done: function () {
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore':
|
||||
active.dataRestore([data.id]);
|
||||
break;
|
||||
case 'delete':
|
||||
active.dataDelete([data.id], 1);
|
||||
break;
|
||||
}
|
||||
});
|
||||
table.on('toolbar(dataRecybinTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataDelete':
|
||||
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let idss = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataDelete(idss, 1);
|
||||
break;
|
||||
case 'dataRestore':
|
||||
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataRestore(ids);
|
||||
break;
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (ids) {
|
||||
if (ids.length === 0) {
|
||||
return layer.msg('请选择数据');
|
||||
}
|
||||
http.put("restore", { ids: ids.join(',') })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg('恢复成功');
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '恢复失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 打开权限分配表单
|
||||
function openPermissionForm(data) {
|
||||
var title = '分配权限 [' + data.name + ']';
|
||||
var formHtml = laytpl($('#permissionFormTpl').html()).render(data);
|
||||
var index = layer.open({
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
btnAlign: "l",
|
||||
area: ['50% ', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
content: formHtml,
|
||||
success: function (layero, index) {
|
||||
http.get("permission", { id: data.id })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
tree.render({
|
||||
elem: '#permissionTree',
|
||||
data: res.data,
|
||||
showCheckbox: true,
|
||||
id: 'permissionTree'
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg || '获取权限失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
},
|
||||
btn: ['保存', '取消'],
|
||||
yes: function (index, layero) {
|
||||
var checkedData = layui.tree.getChecked('permissionTree');
|
||||
var permissionIds = [];
|
||||
function getIds(data) {
|
||||
data.forEach(function (item) {
|
||||
permissionIds.push(item.id);
|
||||
if (item.children && item.children.length > 0) {
|
||||
getIds(item.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
getIds(checkedData);
|
||||
http.put("permission", {
|
||||
id: data.id,
|
||||
permissions: permissionIds
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.msg || '保存成功', { icon: 1, time: 1000 }, function () {
|
||||
layer.close(index);
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg || '保存失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
exports('group', {});
|
||||
});
|
||||
@@ -0,0 +1,179 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('help');
|
||||
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'title', minWidth: 160, title: '标题' },
|
||||
{ field: 'sort', width: 100, title: '排序', sort: true },
|
||||
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'create_time', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
|
||||
return false;
|
||||
});
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name=\"title\"]').val('');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate': active.dataCreate({}); break;
|
||||
case 'dataDelete':
|
||||
var check = table.checkStatus('dataTable').data;
|
||||
active.dataDelete(check.map(function (i) { return i.id; }));
|
||||
break;
|
||||
case 'dataRecybin': active.dataRecybin(); break;
|
||||
}
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update': active.dataEdit(data); break;
|
||||
case 'delete': active.dataDelete([data.id]); break;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.put('update', { id: this.value, status: status })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) { layer.msg('操作成功'); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
table.reload('dataTable', {}, true);
|
||||
})
|
||||
.catch(function () { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑站点帮助' : '添加站点帮助';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title, content: formHtml, anim: "slideLeft", offset: "r",
|
||||
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
|
||||
success: function (layero, index) { callback(layero, index); form.render(); },
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var active = {
|
||||
dataDelete: function (ids, force) {
|
||||
if (ids.length === 0) { return layer.msg('请选择数据'); }
|
||||
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
|
||||
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
|
||||
});
|
||||
},
|
||||
dataCreate: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
if (field.status === undefined) field.status = 0;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataEdit: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataRecybin: function () {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
|
||||
layer.open({
|
||||
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
success: function () {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
|
||||
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '标题', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data) {
|
||||
http.put("restore", { ids: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '恢复失败'); }
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore': active.dataRestore(data); break;
|
||||
case 'forcedelete': active.dataForceDelete(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('help', {});
|
||||
});
|
||||
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* Layui Admin Index Module - Theme v2.7.1
|
||||
* 功能:处理后台管理系统的标签页(Tabs)逻辑,包括打开新标签、切换标签、URL路由监听等。
|
||||
*/
|
||||
layui.define(["ywxapp", "http", "route"], function (exports) {
|
||||
|
||||
// 获取 Layui 核心模块引用
|
||||
var $ = layui.$;
|
||||
var element = layui.element;
|
||||
var ywxapp = layui.ywxapp;
|
||||
var http = layui.http;
|
||||
var route = layui.route;
|
||||
var setter = layui.setter;
|
||||
var view = layui.view;
|
||||
var util = layui.util;
|
||||
|
||||
// 状态与配置常量
|
||||
var tabsPageState = ywxapp.tabsPage; // 当前标签页状态
|
||||
var TABS_CONTAINER_ID = "layadmin-layout-tabs"; // 标签容器ID
|
||||
|
||||
/**
|
||||
* 核心函数:打开或切换标签页
|
||||
* @param {Object} options - 配置对象
|
||||
* @param {String} options.url - 页面URL
|
||||
* @param {String} options.title - 页面标题
|
||||
* @param {Boolean} options.escape - 是否转义标题(默认true)
|
||||
* @param {String} options.highlight - 标题高亮样式
|
||||
*/
|
||||
function openOrSwitchTab(options) {
|
||||
// 合并默认配置
|
||||
options = $.extend({
|
||||
url: "",
|
||||
escape: true
|
||||
}, options);
|
||||
|
||||
var isTabExists = false;
|
||||
var tabHeaders = $("#LAY_app_tabsheader > li");
|
||||
|
||||
// 提取用于匹配的唯一标识(去除协议头和查询参数)
|
||||
var matchKey = options.url.replace(/(^http(s*):)|(\?[\s\S]*$)/g, "");
|
||||
|
||||
// 1. 检查标签是否已存在
|
||||
tabHeaders.each(function (index) {
|
||||
if ($(this).attr("lay-id") === options.url) {
|
||||
isTabExists = true;
|
||||
tabsPageState.index = index; // 更新当前激活标签索引
|
||||
}
|
||||
});
|
||||
|
||||
// 设置默认标题
|
||||
if (!options.title) {
|
||||
options.title = (tabsPageState.index === 0) ? "" : "\u65b0\u6807\u7b7e\u9875"; // "新标签页"
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行标签切换动作
|
||||
*/
|
||||
function performTabChange() {
|
||||
element.tabChange(TABS_CONTAINER_ID, options.url);
|
||||
ywxapp.tabsBodyChange(tabsPageState.index, {
|
||||
url: options.url,
|
||||
title: options.title
|
||||
});
|
||||
}
|
||||
|
||||
// 2. 根据配置决定是新增标签还是刷新现有iframe
|
||||
if (setter.pageTabs) {
|
||||
// 如果开启了多标签模式
|
||||
if (!isTabExists) {
|
||||
// 延迟添加DOM,确保渲染顺序
|
||||
setTimeout(function () {
|
||||
var iframeHtml = [
|
||||
'<div class="layadmin-tabsbody-item layui-show">',
|
||||
'<iframe src="' + options.url + '" frameborder="0" class="layadmin-iframe"></iframe>',
|
||||
"</div>"
|
||||
].join("");
|
||||
|
||||
$("#LAY_app_body").append(iframeHtml);
|
||||
performTabChange();
|
||||
}, 10);
|
||||
|
||||
// 添加标签头
|
||||
var displayTitle = options.title;
|
||||
if (options.escape) {
|
||||
displayTitle = util.escape(displayTitle);
|
||||
}
|
||||
|
||||
// 处理标题高亮
|
||||
var titleHtml = displayTitle;
|
||||
if (options.highlight) {
|
||||
titleHtml = '<span style="' + options.highlight + '">' + displayTitle + "</span>";
|
||||
}
|
||||
|
||||
element.tabAdd(TABS_CONTAINER_ID, {
|
||||
title: "<span>" + titleHtml + "</span>",
|
||||
id: options.url,
|
||||
attr: matchKey
|
||||
});
|
||||
|
||||
// 更新索引为新添加的标签
|
||||
tabsPageState.index = tabHeaders.length;
|
||||
} else {
|
||||
// 标签已存在,直接切换
|
||||
performTabChange();
|
||||
}
|
||||
} else {
|
||||
// 如果未开启多标签模式,直接在当前iframe中跳转
|
||||
var currentIframe = ywxapp.tabsBody(ywxapp.tabsPage.index).find(".layadmin-iframe")[0];
|
||||
if (currentIframe && currentIframe.contentWindow) {
|
||||
currentIframe.contentWindow.location.href = options.url;
|
||||
}
|
||||
// 即使不新增标签,也可能需要更新内部状态
|
||||
performTabChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建侧边菜单的HTML结构
|
||||
* @param {Array} data
|
||||
* @returns
|
||||
*/
|
||||
/**
|
||||
* 递归构建侧边菜单 HTML(支持任意层级)
|
||||
* - 顶层用 <li>,嵌套层用 <dd>;有子项者为可展开目录,否则为可点击菜单。
|
||||
* @param {Array} data 当前层级菜单数组
|
||||
* @param {Boolean} isTop 是否为顶层(默认 true)
|
||||
* @returns {String}
|
||||
*/
|
||||
function buildSideMenu(data, isTop) {
|
||||
isTop = isTop !== false;
|
||||
var html = '';
|
||||
$.each(data || [], function (i, item) {
|
||||
var hasChild = item.child && item.child.length > 0;
|
||||
var tag = isTop ? 'li' : 'dd';
|
||||
var cls = isTop ? 'layui-nav-item' : '';
|
||||
if (item.spread) {
|
||||
cls += (cls ? ' ' : '') + 'layui-nav-itemed';
|
||||
}
|
||||
var clsAttr = cls ? ' class="' + cls + '"' : '';
|
||||
if (hasChild) {
|
||||
html += '<' + tag + ' data-name="' + item.name + '"' + clsAttr + '>';
|
||||
if (isTop) {
|
||||
html += ' <a href="javascript:;" lay-tips="' + item.title + '" lay-direction="2">';
|
||||
html += ' <i class="layui-icon ' + item.icon + '"></i>';
|
||||
html += ' <cite>' + item.title + '</cite>';
|
||||
html += ' </a>';
|
||||
} else {
|
||||
html += ' <a href="javascript:;">' + item.title + '</a>';
|
||||
}
|
||||
// 递归渲染子级,保证第 4 层及更深的菜单也能显示
|
||||
html += ' <dl class="layui-nav-child">' + buildSideMenu(item.child, false) + '</dl>';
|
||||
html += '</' + tag + '>';
|
||||
} else {
|
||||
html += '<' + tag + ' data-name="' + item.name + '"' + clsAttr + '>';
|
||||
if (isTop) {
|
||||
html += ' <a lay-href="' + item.route + '" lay-tips="' + item.title + '" lay-direction="2">';
|
||||
html += ' <i class="layui-icon ' + item.icon + '"></i>';
|
||||
html += ' <cite>' + item.title + '</cite>';
|
||||
html += ' </a>';
|
||||
} else {
|
||||
html += ' <a lay-href="' + item.route + '">' + item.title + '</a>';
|
||||
}
|
||||
html += '</' + tag + '>';
|
||||
}
|
||||
});
|
||||
return html;
|
||||
}
|
||||
|
||||
const menuApi = route.route('menu');
|
||||
|
||||
http.get(menuApi).then(function (res) {
|
||||
if (res.code === 0) {
|
||||
var html = buildSideMenu(res.data);
|
||||
$('#LAY-system-side-menu').html(html);
|
||||
} else {
|
||||
layer.msg('菜单加载失败: ' + res.msg, { icon: 2 });
|
||||
}
|
||||
element.init(); // 重新渲染导航
|
||||
}).catch(function (error) {
|
||||
layer.msg('菜单加载失败: ' + error, { icon: 2 });
|
||||
element.init();
|
||||
});
|
||||
/**
|
||||
* 初始化路由监听与自动渲染
|
||||
*/
|
||||
(function initRouter() {
|
||||
// 自动渲染视图
|
||||
view().autoRender();
|
||||
|
||||
// 监听 Hash 变化
|
||||
var hashObj = layui.url().hash;
|
||||
var recordConfig = setter.record || {};
|
||||
var path = hashObj.href.replace(/^\//, ""); // 去除开头的斜杠
|
||||
|
||||
// 尝试从本地存储获取标题
|
||||
var storedData = layui.data(setter.tableName).record || {};
|
||||
var savedTitle = storedData[path] || "";
|
||||
|
||||
// 如果配置了记录功能且路径有效
|
||||
if (recordConfig.url && path) {
|
||||
var cleanPath = $.trim(path);
|
||||
|
||||
// 安全检查:如果是外部链接且不属于当前域名,则通过 openOrSwitchTab 处理
|
||||
// 注意:原代码逻辑中,正则测试失败(即不是外部链接)或者属于当前域名时,可能不走这个分支,
|
||||
// 但原代码结构是:如果满足条件则调用 n (即 openOrSwitchTab)。
|
||||
// 原逻辑:/^(\w*:)*\/\/.+/.test(i) && -1 === i.indexOf(location.hostname)
|
||||
// 意思是:如果是绝对路径且域名不同,则作为新标签打开。
|
||||
if (/^(\w*:)*\/\/.+/.test(cleanPath) && cleanPath.indexOf(location.hostname) === -1) {
|
||||
openOrSwitchTab({
|
||||
url: cleanPath,
|
||||
title: savedTitle
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 延迟显示主体内容,避免闪烁
|
||||
setTimeout(function () { $("#" + setter.container).css("visibility", "visible"); }, 3000);
|
||||
})();
|
||||
|
||||
// 导出模块接口http://127.0.0.1/%7B__CTRL__%7D/menu”。
|
||||
var exportsData = {
|
||||
openTabsPage: openOrSwitchTab
|
||||
};
|
||||
|
||||
// 扩展 ywxapp 模块的功能
|
||||
$.extend(ywxapp, exportsData);
|
||||
|
||||
// 完成模块定义
|
||||
exports("index",{});
|
||||
});
|
||||
@@ -0,0 +1,285 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('links');
|
||||
|
||||
// 渲染表格
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return {
|
||||
code: res.code === 0 ? 0 : 1,
|
||||
msg: res.message || '',
|
||||
count: res.count || (res.data ? res.data.length : 0),
|
||||
data: res.data || []
|
||||
};
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'title', width: 200, title: '网站标题' },
|
||||
{
|
||||
field: 'url', title: '链接地址', minWidth: 200, templet: function (d) {
|
||||
return '<a href="' + d.url + '" target="_blank" style="color:#1E9FFF;">' + d.url + '</a>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'logo', width: 100, title: 'Logo', templet: function (d) {
|
||||
return d.logo ? '<img src="' + d.logo + '" style="width:30px;height:30px;border-radius:50%;">' : '无';
|
||||
}
|
||||
},
|
||||
{ field: 'sort', width: 100, title: '排序', sort: true },
|
||||
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'create_at', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function (res, curr, count) {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 搜索
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', {
|
||||
page: { curr: 1 },
|
||||
where: { title: data.field.title }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name="title"]').val('');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
|
||||
});
|
||||
|
||||
// 顶部工具条
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate':
|
||||
active.dataCreate({});
|
||||
break;
|
||||
case 'dataDelete':
|
||||
var checkStatus = table.checkStatus('dataTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item) => { return item.id; });
|
||||
active.dataDelete(ids);
|
||||
break;
|
||||
case 'dataRecybin':
|
||||
active.dataRecybin();
|
||||
break;
|
||||
};
|
||||
});
|
||||
|
||||
// 行工具
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update':
|
||||
active.dataEdit(data);
|
||||
break;
|
||||
case 'delete':
|
||||
active.dataDelete([data.id]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// 状态开关
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
var id = this.value;
|
||||
http.put('update', { id: id, status: status })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg('操作成功');
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
table.reload('dataTable', {}, true); // 还原界面状态
|
||||
}
|
||||
})
|
||||
.catch(() => { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
// 打开表单抽屉
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑友情链接' : '添加友情链接';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title,
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
btnAlign: "l",
|
||||
area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
btn: ['确定', '取消'],
|
||||
success: function (layero, index) {
|
||||
callback(layero, index);
|
||||
form.render();
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem);
|
||||
layui.off('submit(wxapp-form)', 'from');
|
||||
return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 事件
|
||||
var active = {
|
||||
dataDelete: function (ids, force = 0) {
|
||||
if (ids.length === 0) {
|
||||
return layer.msg('请选择数据');
|
||||
}
|
||||
layer.confirm('确定删除吗?' + (force ? '(将彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
dataCreate: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) { },
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataEdit: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) { },
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataRecybin: function (data = {}) {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: '资源回收站',
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
area: ['50%', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable',
|
||||
url: "recyclebin",
|
||||
height: 'full-120',
|
||||
parseData: function (res) {
|
||||
return {
|
||||
code: res.code === 0 ? 0 : 1,
|
||||
msg: res.message || '',
|
||||
count: res.count || (res.data ? res.data.length : 0),
|
||||
data: res.data || []
|
||||
};
|
||||
},
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '网站标题', width: 180, fixed: 'left' },
|
||||
{ field: 'url', title: '链接', minWidth: 200 },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 120, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data = {}) {
|
||||
http.put("restore", { ids: data.id })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg('恢复成功');
|
||||
table.reload('dataRecybinTable', {}, true);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '恢复失败');
|
||||
}
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data = {}) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg('已彻底删除');
|
||||
table.reload('dataRecybinTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 回收站行操作
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore':
|
||||
active.dataRestore(data);
|
||||
break;
|
||||
case 'forcedelete':
|
||||
active.dataForceDelete(data);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('links', {});
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
layui.define(['form', 'http'], function (exports) {
|
||||
var form = layui.form;
|
||||
function refreshVerifyCode() {
|
||||
const verifyImg = document.querySelector('[lay-filter="verifyCode"]');
|
||||
if (verifyImg) {
|
||||
verifyImg.style.opacity = '0.7';
|
||||
setTimeout(() => {
|
||||
const baseSrc = verifyImg.src.split('?')[0];
|
||||
verifyImg.src = baseSrc + '?' + Date.now();
|
||||
verifyImg.style.opacity = '1';
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
const verifyImg = document.querySelector('[lay-filter="verifyCode"]');
|
||||
if (verifyImg) {
|
||||
verifyImg.addEventListener('click', refreshVerifyCode);
|
||||
}
|
||||
form.on('submit(dataSubmit)', function (obj) {
|
||||
let data = obj.field;
|
||||
layui.http.post("save", data)
|
||||
.then(function (res) {
|
||||
console.log(res);
|
||||
if (res.code != 0) {
|
||||
layer.msg(res.message);
|
||||
refreshVerifyCode();
|
||||
} else {
|
||||
layui.setter.setMenus(res.data.menus);
|
||||
layui.setter.permissions(res.data.permissions);
|
||||
layer.alert('请稍后!', {
|
||||
time: 15000,
|
||||
end: function () {
|
||||
if (window.self !== window.top) {
|
||||
// 在 iframe 中,跳转顶级页面
|
||||
window.top.location.href = "/admin";
|
||||
} else {
|
||||
// 顶级窗口,直接跳转
|
||||
window.location.href = "/admin";
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
exports('login', {});
|
||||
})
|
||||
@@ -0,0 +1,204 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('medal');
|
||||
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'title', minWidth: 160, title: '勋章名称' },
|
||||
{ field: 'sort', width: 100, title: '排序', sort: true },
|
||||
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'create_time', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
|
||||
return false;
|
||||
});
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name=\"title\"]').val('');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate': active.dataCreate({}); break;
|
||||
case 'dataDelete':
|
||||
var check = table.checkStatus('dataTable').data;
|
||||
active.dataDelete(check.map(function (i) { return i.id; }));
|
||||
break;
|
||||
case 'dataRecybin': active.dataRecybin(); break;
|
||||
}
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update': active.dataEdit(data); break;
|
||||
case 'delete': active.dataDelete([data.id]); break;
|
||||
case 'grant': active.dataGrant(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.put('update', { id: this.value, status: status })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) { layer.msg('操作成功'); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
table.reload('dataTable', {}, true);
|
||||
})
|
||||
.catch(function () { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑勋章中心' : '添加勋章中心';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title, content: formHtml, anim: "slideLeft", offset: "r",
|
||||
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
|
||||
success: function (layero, index) { callback(layero, index); form.render(); },
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var active = {
|
||||
dataDelete: function (ids, force) {
|
||||
if (ids.length === 0) { return layer.msg('请选择数据'); }
|
||||
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
|
||||
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
|
||||
});
|
||||
},
|
||||
dataCreate: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
if (field.status === undefined) field.status = 0;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataEdit: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataGrant: function (data) {
|
||||
var formHtml = ''
|
||||
+ '<div class="layui-form" style="padding:20px 30px;">'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">勋章</label>'
|
||||
+ '<div class="layui-input-block"><input class="layui-input" value="' + (data.title || '') + '" disabled></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">用户ID</label>'
|
||||
+ '<div class="layui-input-block"><input class="layui-input" name="uid" id="grantUid" placeholder="输入要授予的用户UID" lay-verify="required"></div></div>'
|
||||
+ '<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" id="grantSubmit">确认授予</button></div></div>'
|
||||
+ '</div>';
|
||||
layer.open({
|
||||
title: '授予勋章', content: formHtml, anim: 'slideLeft', offset: 'r',
|
||||
area: ['420px', '320px'], shade: 0.1, shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
$('#grantSubmit').on('click', function () {
|
||||
var uid = parseInt($('#grantUid').val(), 10);
|
||||
if (!uid || uid <= 0) { return layer.msg('请输入有效的用户ID'); }
|
||||
http.post('grant', { uid: uid, medal_id: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); layer.msg(res.message || '授予成功', { icon: 1 }); }
|
||||
else { layer.msg(res.message || '授予失败', { icon: 2 }); }
|
||||
}).catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRecybin: function () {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
|
||||
layer.open({
|
||||
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
success: function () {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
|
||||
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '勋章名称', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data) {
|
||||
http.put("restore", { ids: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '恢复失败'); }
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore': active.dataRestore(data); break;
|
||||
case 'forcedelete': active.dataForceDelete(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('medal', {});
|
||||
});
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* @Author: YwxApp <ywx@ywxapp.cn>
|
||||
* @Description: 前台主导航菜单管理(后台)
|
||||
*/
|
||||
layui.define(['http', 'auth', 'table', 'treeTable'], function (exports) {
|
||||
var $ = layui.$,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
laytpl = layui.laytpl,
|
||||
http = layui.http,
|
||||
auth = layui.auth;
|
||||
|
||||
auth.init((layui.data('backend').permission) || []);
|
||||
|
||||
// 两级树拍平成单表,子项缩进展示
|
||||
function flatTree(list, level) {
|
||||
var rows = [];
|
||||
layui.each(list || [], function (i, item) {
|
||||
item._level = level;
|
||||
item._title = (level > 0 ? ' ├ ' : '') + item.title;
|
||||
rows.push(item);
|
||||
if (item.child && item.child.length) {
|
||||
rows = rows.concat(flatTree(item.child, level + 1));
|
||||
}
|
||||
});
|
||||
return rows;
|
||||
}
|
||||
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable',
|
||||
url: 'index',
|
||||
page: false,
|
||||
toolbar: '#tableBar',
|
||||
cols: [[
|
||||
{ field: 'id', title: 'ID', width: 70, align: 'center' },
|
||||
{ field: 'title', title: '菜单名称', minWidth: 180, templet: function (d) { return d._title || d.title; } },
|
||||
{ field: 'parent_id', title: '层级', width: 90, align: 'center', templet: '#parentTpl' },
|
||||
{ field: 'url', title: '链接', minWidth: 200 },
|
||||
{ field: 'sort', title: '排序', width: 80, align: 'center' },
|
||||
{ field: 'status', title: '状态', width: 110, align: 'center', templet: '#statusTpl' },
|
||||
{ title: '操作', width: 200, align: 'center', toolbar: '#dataBar', fixed: 'right' }
|
||||
]],
|
||||
response: { statusCode: 0 },
|
||||
parseData: function (res) {
|
||||
return { code: res.code, msg: res.msg, count: res.count || 0, data: flatTree(res.data, 0) };
|
||||
},
|
||||
done: function () {
|
||||
auth.render();
|
||||
}
|
||||
});
|
||||
|
||||
// 状态开关
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var id = obj.value;
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.post('status', { id: id, status: status }).then(function (res) {
|
||||
if (res.code !== 0) { layer.msg(res.msg || '操作失败'); dataTable.reload(); }
|
||||
});
|
||||
});
|
||||
|
||||
// 工具条(新建)
|
||||
table.on('toolbar(dataTable)', function (obj) {
|
||||
if (obj.event === 'dataCreate') { openForm({}); }
|
||||
});
|
||||
|
||||
// 行操作
|
||||
table.on('tool(dataTable)', function (obj) {
|
||||
var d = obj.data;
|
||||
if (obj.event === 'update') { openForm(d); }
|
||||
else if (obj.event === 'addChild') { openForm({ parent_id: d.id }); }
|
||||
else if (obj.event === 'delete') {
|
||||
layer.confirm('确定删除该菜单吗?', function (idx) {
|
||||
http.delete('delete', { id: d.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.close(idx); dataTable.reload(); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 表单弹窗:拉取一级菜单作为父级选项
|
||||
function openForm(data) {
|
||||
http.get('index').then(function (res) {
|
||||
var parents = [];
|
||||
layui.each((res.data || []), function (i, p) {
|
||||
if (p.parent_id == 0) parents.push(p);
|
||||
});
|
||||
var html = laytpl($('#dataFormTpl').html()).render($.extend({ parents: parents }, data));
|
||||
layer.open({
|
||||
type: 1, title: data.id ? '编辑菜单' : '新建菜单',
|
||||
area: ['480px', 'auto'], content: html,
|
||||
btn: ['保存', '取消'],
|
||||
success: function () { form.render(); },
|
||||
yes: function (idx, layero) {
|
||||
var field = form.val('wxapp-form-submit') || {};
|
||||
// 用表单序列化兜底
|
||||
var fd = {};
|
||||
$(layero).find('form').serializeArray().map(function (x) { fd[x.name] = x.value; });
|
||||
http.post(data.id ? 'update' : 'save', fd).then(function (r) {
|
||||
if (r.code === 0) { layer.close(idx); dataTable.reload(); }
|
||||
else { layer.msg(r.msg || '操作失败'); }
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
exports('navbar', {});
|
||||
});
|
||||
@@ -0,0 +1,202 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('notice');
|
||||
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'title', minWidth: 160, title: '标题' },
|
||||
{ field: 'type', width: 100, title: '类型', templet: '#typeTpl' },
|
||||
{ field: 'is_top', width: 80, title: '置顶', templet: '#topTpl' },
|
||||
{ field: 'sort', width: 90, title: '排序', sort: true },
|
||||
{ field: 'status', width: 90, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'start_time', width: 160, title: '开始时间', templet: '#startTpl' },
|
||||
{ field: 'end_time', width: 160, title: '结束时间', templet: '#endTpl' },
|
||||
{ field: 'view_count', width: 90, title: '浏览量' },
|
||||
{ field: 'create_time', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title, type: data.field.type } });
|
||||
return false;
|
||||
});
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name=\"title\"]').val('');
|
||||
$('select[name=\"type\"]').val('');
|
||||
form.render('select');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: '', type: '' } });
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate': active.dataCreate({}); break;
|
||||
case 'dataDelete':
|
||||
var check = table.checkStatus('dataTable').data;
|
||||
active.dataDelete(check.map(function (i) { return i.id; }));
|
||||
break;
|
||||
case 'dataRecybin': active.dataRecybin(); break;
|
||||
}
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update': active.dataEdit(data); break;
|
||||
case 'delete': active.dataDelete([data.id]); break;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.put('update', { id: this.value, status: status })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) { layer.msg('操作成功'); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
table.reload('dataTable', {}, true);
|
||||
})
|
||||
.catch(function () { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑站点公告' : '添加站点公告';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title, content: formHtml, anim: "slideLeft", offset: "r",
|
||||
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
|
||||
success: function (layero, index) {
|
||||
callback(layero, index);
|
||||
form.render();
|
||||
// 回填下拉/开关
|
||||
if (data.type) { layero.contents().find('select[name="type"]').val(String(data.type)); }
|
||||
if (data.is_top) { layero.contents().find('input[name="is_top"]').prop('checked', true); form.render('checkbox'); }
|
||||
// 有效期日期选择器
|
||||
layui.use(['laydate'], function () {
|
||||
var laydate = layui.laydate;
|
||||
laydate.render({ elem: layero.contents().find('#start_time')[0], type: 'datetime' });
|
||||
laydate.render({ elem: layero.contents().find('#end_time')[0], type: 'datetime' });
|
||||
});
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var active = {
|
||||
dataDelete: function (ids, force) {
|
||||
if (ids.length === 0) { return layer.msg('请选择数据'); }
|
||||
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
|
||||
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
|
||||
});
|
||||
},
|
||||
dataCreate: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
if (field.status === undefined) field.status = 0;
|
||||
field.status = field.status ? 1 : 0;
|
||||
field.is_top = field.is_top ? 1 : 0;
|
||||
field.type = field.type ? parseInt(field.type, 10) : 1;
|
||||
http.post('save', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataEdit: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
field.is_top = field.is_top ? 1 : 0;
|
||||
field.type = field.type ? parseInt(field.type, 10) : 1;
|
||||
http.put('update', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataRecybin: function () {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
|
||||
layer.open({
|
||||
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
success: function () {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
|
||||
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '标题', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data) {
|
||||
http.put("restore", { ids: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '恢复失败'); }
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore': active.dataRestore(data); break;
|
||||
case 'forcedelete': active.dataForceDelete(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('notice', {});
|
||||
});
|
||||
@@ -0,0 +1,327 @@
|
||||
layui.define(['layer', 'http', 'iconPicker', 'auth'], function (exports) {
|
||||
var $ = layui.$;
|
||||
var treeTable = layui.treeTable;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var laytpl = layui.laytpl;
|
||||
var iconPicker = layui.iconPicker;
|
||||
var http = layui.http;
|
||||
var auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('power');
|
||||
treeTable.render({
|
||||
elem: '#dataTable',
|
||||
url: 'index',
|
||||
parseData: function (res) { // 预处理返回数据
|
||||
console.log('原始数据:', res); // 调试输入
|
||||
return {
|
||||
code: res.code === 0 ? 0 : 1, // 0 标识成功
|
||||
data: res.data || [], // 数据数组
|
||||
msg: res.message || '' // 错误信息
|
||||
};
|
||||
},
|
||||
tree: {
|
||||
customName: {
|
||||
children: "children",
|
||||
isParent: "is_parent",
|
||||
name: "title",
|
||||
id: "id",
|
||||
pid: "pid",
|
||||
icon: "icon"
|
||||
},
|
||||
data: { isSimpleData: true, rootPid: 0 },
|
||||
view: {},
|
||||
async: {},
|
||||
callback: {}
|
||||
},
|
||||
height: 'full-100',
|
||||
toolbar: '#tableBarTpl',
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: 'title', width: 180, fixed: 'left' },
|
||||
{ field: 'name', title: 'name', width: 180, fixed: 'left' },
|
||||
{
|
||||
field: 'type', title: '类型', width: 80, templet: function (d) {
|
||||
if (d.type === 1) {
|
||||
return '<span class="layui-badge layui-bg-gray">目录</span>';
|
||||
} else if (d.type === 2) {
|
||||
return '<span class="layui-badge layui-bg-gray">菜单</span>';
|
||||
} else if (d.type === 3) {
|
||||
return '<span class="layui-badge layui-bg-gray">按钮</span>';
|
||||
} else if (d.type === 4) {
|
||||
return '<span class="layui-badge layui-bg-gray">API</span>';
|
||||
}
|
||||
}
|
||||
}, { field: 'route', title: '路由', minWidth: 200, sort: true },
|
||||
{
|
||||
field: 'icon', title: '图标', width: 80, sort: true, templet: function (d) {
|
||||
return '<i class="layui-icon ' + d.icon + '"></i> ';
|
||||
}
|
||||
},
|
||||
{ field: 'sort', title: '排序', width: 80, sort: true },
|
||||
{ field: 'status', title: '状态', width: 96, align: 'center', templet: '#statusTpl' },
|
||||
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#dataBarTpl" }
|
||||
]],
|
||||
page: true,
|
||||
done: function (res, curr, count, origin) {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
treeTable.on('toolbar(dataTable)', function (obj) {
|
||||
var options = obj.config;
|
||||
switch (obj.event) {
|
||||
case 'dataCreate':
|
||||
active.dataCreate({ pid: 0, type: 1 });
|
||||
break;
|
||||
case 'dataDelete':
|
||||
var checkStatus = treeTable.checkStatus('dataTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataDelete(ids);
|
||||
break;
|
||||
case 'dataRecybin':
|
||||
active.dataRecybin();
|
||||
break;
|
||||
};
|
||||
});
|
||||
treeTable.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update':
|
||||
active.dataEdit(data);
|
||||
break;
|
||||
case 'create':
|
||||
active.dataCreate({ pid: data.id });
|
||||
break;
|
||||
case 'delete':
|
||||
active.dataDelete([data.id]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// 状态开关
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var id = this.value;
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
layer.confirm('确定要' + (status ? '启用' : '禁用') + '该数据吗?', function (index) {
|
||||
layui.request.post('update', { id: id, status: status }).then(function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.msg, { icon: 1 });
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
}, function () {
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
});
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: data.id ? '编辑数据' : (data.pid ? '添加子数据' : '添加根数据'),
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
btnAlign: "l",
|
||||
area: ['520px', '98%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
btn: ['确定', '取消'],
|
||||
success: function (layero, index) {
|
||||
callback(layero, index);
|
||||
form.render();
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem);
|
||||
layui.off('submit(wxapp-form)', 'from');
|
||||
return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
//事件
|
||||
var active = {
|
||||
dataDelete: function (ids, force = 0) {
|
||||
if (ids.length === 0) {
|
||||
return layer.msg('请选择数据');
|
||||
}
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '敏感操作,请验证口令'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
layer.confirm('确定删除吗?', function (index) {
|
||||
http.delete('delete', { ids: ids.join(','), force: force })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
treeTable.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
layer.msg('已删除');
|
||||
treeTable.reload('dataTable', {}, true);
|
||||
});
|
||||
});
|
||||
},
|
||||
dataCreate: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) {
|
||||
iconPicker.render({
|
||||
elem: '#iconPicker',
|
||||
type: 'fontClass',
|
||||
search: true,
|
||||
page: false,
|
||||
});
|
||||
},
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.icon = 'layui-icon ' + field.icon;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
treeTable.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataEdit: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) {
|
||||
iconPicker.render({
|
||||
elem: '#iconPicker',
|
||||
type: 'fontClass',
|
||||
search: true,
|
||||
page: false,
|
||||
});
|
||||
},
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.icon = 'layui-icon ' + field.icon;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
treeTable.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataRecybin: function (data = {}) {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: '资源回收站',
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
area: ['60%', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
layui.table.render({
|
||||
elem: '#dataRecybinTable',
|
||||
url: 'recyclebin',
|
||||
height: 'full-100',
|
||||
defaultToolbar: [{
|
||||
title: '批量删除数据',
|
||||
layEvent: 'dataDelete',
|
||||
icon: 'layui-icon-delete',
|
||||
onClick: function (obj) {
|
||||
var checkStatus = treeTable.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
console.log(ids);
|
||||
}
|
||||
}, 'filter', 'exports', 'print'],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: 'title', width: 180, fixed: 'left' },
|
||||
{ field: 'name', title: 'name', width: 180, fixed: 'left' },
|
||||
{ field: 'route', title: '路由', minWidth: 200, sort: true },
|
||||
{
|
||||
fixed: "right", title: "操作", width: 120, align: "center", templet: function (d) {
|
||||
return `<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm" title="恢复数据" lay-event="restore" > <i class="layui-icon layui-icon-edit"></i> </a >
|
||||
<a class="layui-btn layui-btn-sm" title="删除数据" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
</div >`;
|
||||
}
|
||||
}
|
||||
]],
|
||||
page: true,
|
||||
done: function (res, curr, count, origin) {
|
||||
layui.table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore':
|
||||
active.dataRestore([data.id]);
|
||||
break;
|
||||
case 'delete':
|
||||
active.dataDelete([data.id], 1);
|
||||
break;
|
||||
}
|
||||
});
|
||||
layui.table.on('toolbar(dataRecybinTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataDelete':
|
||||
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let idss = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataDelete(idss, 1);
|
||||
break;
|
||||
case 'dataRestore':
|
||||
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataRestore(ids);
|
||||
break;
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (ids) {
|
||||
if (ids.length === 0) {
|
||||
return layer.msg('请选择数据');
|
||||
}
|
||||
http.put('restore', { ids: ids.join(',') })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg('恢复成功');
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '恢复失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
exports('power', {});
|
||||
});
|
||||
@@ -0,0 +1,179 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('prop');
|
||||
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'title', minWidth: 160, title: '道具名称' },
|
||||
{ field: 'sort', width: 100, title: '排序', sort: true },
|
||||
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'create_time', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
|
||||
return false;
|
||||
});
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name=\"title\"]').val('');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate': active.dataCreate({}); break;
|
||||
case 'dataDelete':
|
||||
var check = table.checkStatus('dataTable').data;
|
||||
active.dataDelete(check.map(function (i) { return i.id; }));
|
||||
break;
|
||||
case 'dataRecybin': active.dataRecybin(); break;
|
||||
}
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update': active.dataEdit(data); break;
|
||||
case 'delete': active.dataDelete([data.id]); break;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.put('update', { id: this.value, status: status })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) { layer.msg('操作成功'); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
table.reload('dataTable', {}, true);
|
||||
})
|
||||
.catch(function () { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑道具中心' : '添加道具中心';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title, content: formHtml, anim: "slideLeft", offset: "r",
|
||||
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
|
||||
success: function (layero, index) { callback(layero, index); form.render(); },
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var active = {
|
||||
dataDelete: function (ids, force) {
|
||||
if (ids.length === 0) { return layer.msg('请选择数据'); }
|
||||
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
|
||||
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
|
||||
});
|
||||
},
|
||||
dataCreate: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
if (field.status === undefined) field.status = 0;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataEdit: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataRecybin: function () {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
|
||||
layer.open({
|
||||
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
success: function () {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
|
||||
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '道具名称', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data) {
|
||||
http.put("restore", { ids: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '恢复失败'); }
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore': active.dataRestore(data); break;
|
||||
case 'forcedelete': active.dataForceDelete(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('prop', {});
|
||||
});
|
||||
@@ -0,0 +1,297 @@
|
||||
layui.define(['http', 'auth'], function (exports) {
|
||||
var $ = layui.$, table = layui.table, form = layui.form, layer = layui.layer
|
||||
, laydate = layui.laydate, laytpl = layui.laytpl, tree = layui.tree, http = layui.http
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('role');
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
, url: 'index' // 后端数据接口
|
||||
, page: true
|
||||
, limit: 15
|
||||
, toolbar: '#tableBarTpl'
|
||||
, cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' }
|
||||
, { field: 'id', title: 'ID', width: 60, align: 'center', sort: true, fixed: 'left' }
|
||||
, { field: 'title', title: '名称', width: 150, align: 'center', fixed: 'left' }
|
||||
, { field: 'name', title: '代码', width: 150, align: 'center', fixed: 'left' }
|
||||
, { field: 'description', title: '描述', minWidth: 200, align: 'left' }
|
||||
, { field: 'status', title: '状态', width: 120, align: 'center', templet: '#statusTpl' }
|
||||
, { field: 'create_at', title: '创建时间', width: 160, align: 'center', sort: true }
|
||||
, { title: '操作', width: 160, align: 'left', toolbar: '#dataBarTpl', fixed: 'right', unresize: true }
|
||||
]]
|
||||
, done: function (res, curr, count) {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate':
|
||||
active.dataCreate({ pid: 0, type: 1 });
|
||||
break;
|
||||
case 'dataDelete':
|
||||
var checkStatus = table.checkStatus('dataTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataDelete(ids);
|
||||
break;
|
||||
case 'dataRecybin':
|
||||
active.dataRecybin();
|
||||
break;
|
||||
};
|
||||
});
|
||||
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update':
|
||||
active.dataEdit(data);
|
||||
break;
|
||||
case 'permission':
|
||||
openPermissionForm(data);
|
||||
break;
|
||||
case 'delete':
|
||||
active.dataDelete([data.id]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data ? '编辑数据[' + data.account + ']' : '添加数据';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: data.id ? '编辑菜单' : (data.pid ? '添加子菜单' : '添加根菜单'),
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
btnAlign: "l",
|
||||
area: ['50% ', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
btn: ['确定', '取消'],
|
||||
success: function (layero, index) {
|
||||
callback(layero, index);
|
||||
form.render();
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem);
|
||||
layui.off('submit(wxapp-form)', 'from');
|
||||
return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//事件
|
||||
var active = {
|
||||
dataDelete: function (ids, force = 0) {
|
||||
if (ids.length === 0) {
|
||||
return layer.msg('请选择数据');
|
||||
}
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '敏感操作,请验证口令'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
layer.confirm('确定删除吗?', function (index) {
|
||||
http.delete("delete", { ids: ids.join(','), force: force })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
dataCreate: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) { },
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
http.post("save", field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataEdit: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) { },
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
http.put("update", field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataRecybin: function (data = {}) {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: '资源回收站',
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
area: ['50%', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable',
|
||||
url: 'recyclebin',
|
||||
defaultToolbar: [{
|
||||
title: '批量删除数据',
|
||||
layEvent: 'dataDelete',
|
||||
icon: 'layui-icon-delete',
|
||||
onClick: function (obj) {
|
||||
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
console.log(ids);
|
||||
}
|
||||
}, 'filter', 'exports', 'print'],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '名称', width: 180, fixed: 'left' },
|
||||
{ field: 'name', title: '代码', width: 180, fixed: 'left' },
|
||||
{ field: 'description', title: '描述', minWidth: 200, sort: true },
|
||||
{
|
||||
fixed: "right", title: "操作", width: 120, align: "center", templet: function (d) {
|
||||
return `<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm" title="恢复数据" lay-event="restore" > <i class="layui-icon layui-icon-edit"></i> </a >
|
||||
<a class="layui-btn layui-btn-sm" title="删除数据" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
</div >`;
|
||||
}
|
||||
}
|
||||
]],
|
||||
page: true,
|
||||
done: function () {
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore':
|
||||
active.dataRestore([data.id]);
|
||||
break;
|
||||
case 'delete':
|
||||
active.dataDelete([data.id], 1);
|
||||
break;
|
||||
}
|
||||
});
|
||||
table.on('toolbar(dataRecybinTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataDelete':
|
||||
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let idss = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataDelete(idss, 1);
|
||||
break;
|
||||
case 'dataRestore':
|
||||
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataRestore(ids);
|
||||
break;
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (ids) {
|
||||
if (ids.length === 0) {
|
||||
return layer.msg('请选择数据');
|
||||
}
|
||||
http.put("restore", { ids: ids.join(',') })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg('恢复成功');
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '恢复失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 打开权限分配表单
|
||||
function openPermissionForm(data) {
|
||||
var title = '分配权限 [' + data.name + ']';
|
||||
var formHtml = laytpl($('#permissionFormTpl').html()).render(data);
|
||||
var index = layer.open({
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
btnAlign: "l",
|
||||
area: ['50% ', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
content: formHtml,
|
||||
success: function (layero, index) {
|
||||
http.get("permission", { id: data.id })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
tree.render({
|
||||
elem: '#permissionTree',
|
||||
data: res.data,
|
||||
showCheckbox: true,
|
||||
id: 'permissionTree'
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg || '获取权限失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
},
|
||||
btn: ['保存', '取消'],
|
||||
yes: function (index, layero) {
|
||||
var checkedData = layui.tree.getChecked('permissionTree');
|
||||
var permissionIds = [];
|
||||
function getIds(data) {
|
||||
data.forEach(function (item) {
|
||||
permissionIds.push(item.id);
|
||||
if (item.children && item.children.length > 0) {
|
||||
getIds(item.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
getIds(checkedData);
|
||||
http.put("permission", {
|
||||
id: data.id,
|
||||
permissions: permissionIds
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.msg || '保存成功', { icon: 1, time: 1000 }, function () {
|
||||
layer.close(index);
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg || '保存失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
exports('role', {});
|
||||
});
|
||||
@@ -0,0 +1,277 @@
|
||||
layui.define(['layer', 'http', 'iconPicker', 'auth'], function (exports) {
|
||||
var $ = layui.$;
|
||||
var treeTable = layui.treeTable;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var laytpl = layui.laytpl;
|
||||
var iconPicker = layui.iconPicker;
|
||||
var http = layui.http;
|
||||
var auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('rule');
|
||||
treeTable.render({
|
||||
elem: '#dataTable',
|
||||
url: 'index',
|
||||
parseData: function (res) { // 预处理返回数据
|
||||
console.log('原始数据:', res); // 调试输入
|
||||
return {
|
||||
code: res.code === 0 ? 0 : 1, // 0 标识成功
|
||||
data: res.data || [], // 数据数组
|
||||
msg: res.message || '' // 错误信息
|
||||
};
|
||||
},
|
||||
tree: {
|
||||
customName: {
|
||||
isParent: "is_parent",
|
||||
name: "title",
|
||||
id: "id",
|
||||
pid: "pid",
|
||||
icon: "icon"
|
||||
},
|
||||
data: { isSimpleData: true, rootPid: 0 },
|
||||
view: { showIcon: true },
|
||||
},
|
||||
height: 'full-100',
|
||||
toolbar: '#tableBarTpl',
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, align: 'left' },
|
||||
{ field: 'title', title: 'title', width: 180, align: 'left' },
|
||||
{ field: 'name', title: 'name', width: 180, align: 'center' },
|
||||
{
|
||||
field: 'module', title: '模块', width: 100, templet: function (d) {
|
||||
if (d.module === 'frontend') {
|
||||
return '<span class="layui-badge layui-bg-gray">Frontend</span>';
|
||||
} else if (d.module === 'member') {
|
||||
return '<span class="layui-badge layui-bg-gray">Member</span>';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'type', title: '类型', width: 80, templet: function (d) {
|
||||
if (d.type === '1') {
|
||||
return '<span class="layui-badge layui-bg-gray">目录</span>';
|
||||
} else if (d.type === '2') {
|
||||
return '<span class="layui-badge layui-bg-gray">菜单</span>';
|
||||
} else {
|
||||
return '<span class="layui-badge layui-bg-gray">按钮</span>';
|
||||
}
|
||||
}
|
||||
}, { field: 'route', title: '路由', minWidth: 200, sort: true },
|
||||
{
|
||||
field: 'icon', title: '图标', width: 80, sort: true, templet: function (d) {
|
||||
return '<i class="layui-icon ' + d.icon + '"></i> ';
|
||||
}
|
||||
},
|
||||
{ field: 'sort', title: '排序', width: 80, sort: true },
|
||||
{ field: 'status', title: '状态' },
|
||||
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#dataBarTpl" }
|
||||
]],
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function (res, curr, count, origin) {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
treeTable.on('toolbar(dataTable)', function (obj) {
|
||||
var options = obj.config;
|
||||
switch (obj.event) {
|
||||
case 'dataCreate':
|
||||
active.dataCreate({ pid: 0, type: 1 });
|
||||
break;
|
||||
case 'dataDelete':
|
||||
var checkStatus = treeTable.checkStatus('dataTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
active.dataDelete(ids);
|
||||
break;
|
||||
case 'dataRecybin':
|
||||
active.dataRecybin();
|
||||
break;
|
||||
};
|
||||
});
|
||||
treeTable.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update':
|
||||
active.dataEdit(data);
|
||||
break;
|
||||
case 'create':
|
||||
active.dataCreate({ pid: data.id });
|
||||
break;
|
||||
case 'delete':
|
||||
active.dataDelete([data.id]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data ? '编辑管理员 [' + data.account + ']' : '添加管理员';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: data.id ? '编辑菜单' : (data.pid ? '添加子菜单' : '添加根菜单'),
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
btnAlign: "l",
|
||||
area: ['520px', '98%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
btn: ['确定', '取消'],
|
||||
success: function (layero, index) {
|
||||
callback(layero, index);
|
||||
form.render();
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem);
|
||||
layui.off('submit(wxapp-form)', 'from');
|
||||
return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
//事件
|
||||
var active = {
|
||||
dataDelete: function (ids, force = 0) {
|
||||
if (ids.length === 0) {
|
||||
return layer.msg('请选择数据');
|
||||
}
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '敏感操作,请验证口令'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
layer.confirm('确定删除吗?', function (index) {
|
||||
http.delete("delete", { ids: ids.join(','), force: force })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
treeTable.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
layer.msg('已删除');
|
||||
treeTable.reload('dataTable', {}, true);
|
||||
});
|
||||
});
|
||||
},
|
||||
dataCreate: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) {
|
||||
iconPicker.render({
|
||||
elem: '#iconPicker',
|
||||
type: 'fontClass',
|
||||
search: true,
|
||||
page: false,
|
||||
});
|
||||
},
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.icon = 'layui-icon ' + field.icon.indexOf("layui-icon ") == -1 ? field.icon : field.icon.replace('layui-icon ', '');
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
treeTable.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataEdit: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) {
|
||||
iconPicker.render({
|
||||
elem: '#iconPicker',
|
||||
type: 'fontClass',
|
||||
search: true,
|
||||
page: false,
|
||||
});
|
||||
},
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.icon = 'layui-icon ' + field.icon.indexOf("layui-icon ") == -1 ? field.icon : field.icon.replace('layui-icon ', '');
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
treeTable.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataRecybin: function (data = {}) {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: '资源回收站',
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
area: ['60%', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
layui.table.render({
|
||||
elem: '#dataRecybinTable',
|
||||
url: 'recyclebin',
|
||||
height: 'full-100',
|
||||
defaultToolbar: [{
|
||||
title: '批量删除数据',
|
||||
layEvent: 'dataDelete',
|
||||
icon: 'layui-icon-delete',
|
||||
onClick: function (obj) {
|
||||
var checkStatus = treeTable.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.id; });
|
||||
console.log(ids);
|
||||
}
|
||||
}, 'filter', 'exports', 'print'],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: 'title', width: 180, fixed: 'left' },
|
||||
{ field: 'name', title: 'name', width: 180, fixed: 'left' },
|
||||
{ field: 'route', title: '路由', minWidth: 200, sort: true },
|
||||
|
||||
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#databar" }
|
||||
]],
|
||||
page: true,
|
||||
done: function (res, curr, count, origin) {
|
||||
console.log('表格渲染完成');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data = {}) {
|
||||
http.put('restore', { id: data.id })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg('恢复成功');
|
||||
treeTable.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '恢复失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
exports('rule', {});
|
||||
});
|
||||
@@ -0,0 +1,184 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('score');
|
||||
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'name', minWidth: 160, title: '规则名称' },
|
||||
{ field: 'action', width: 160, title: '触发动作' },
|
||||
{ field: 'type_text', width: 90, title: '类型', templet: '#typeTpl' },
|
||||
{ field: 'value', width: 90, title: '变动值', sort: true },
|
||||
{ field: 'sort', width: 90, title: '排序', sort: true },
|
||||
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'create_time', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 120, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { name: data.field.name } });
|
||||
return false;
|
||||
});
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name="name"]').val('');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { name: '' } });
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate': active.dataCreate({}); break;
|
||||
case 'dataDelete':
|
||||
var check = table.checkStatus('dataTable').data;
|
||||
active.dataDelete(check.map(function (i) { return i.id; }));
|
||||
break;
|
||||
case 'dataRecybin': active.dataRecybin(); break;
|
||||
}
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update': active.dataEdit(data); break;
|
||||
case 'delete': active.dataDelete([data.id]); break;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.put('update', { id: this.value, status: status })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) { layer.msg('操作成功'); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
table.reload('dataTable', {}, true);
|
||||
})
|
||||
.catch(function () { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑积分规则' : '添加积分规则';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title, content: formHtml, anim: "slideLeft", offset: "r",
|
||||
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
|
||||
success: function (layero, index) { callback(layero, index); form.render(); },
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var active = {
|
||||
dataDelete: function (ids, force) {
|
||||
if (ids.length === 0) { return layer.msg('请选择数据'); }
|
||||
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
|
||||
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
|
||||
});
|
||||
},
|
||||
dataCreate: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
if (field.status === undefined) field.status = 0;
|
||||
field.status = field.status ? 1 : 0;
|
||||
field.value = parseInt(field.value, 10) || 0;
|
||||
http.post('save', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataEdit: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
field.value = parseInt(field.value, 10) || 0;
|
||||
http.put('update', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataRecybin: function () {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
|
||||
layer.open({
|
||||
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
success: function () {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
|
||||
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'name', title: '规则名称', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data) {
|
||||
http.put("restore", { ids: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '恢复失败'); }
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore': active.dataRestore(data); break;
|
||||
case 'forcedelete': active.dataForceDelete(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('score', {});
|
||||
});
|
||||
@@ -0,0 +1,179 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('shop');
|
||||
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'title', minWidth: 160, title: '商品名称' },
|
||||
{ field: 'sort', width: 100, title: '排序', sort: true },
|
||||
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'create_time', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
|
||||
return false;
|
||||
});
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name=\"title\"]').val('');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate': active.dataCreate({}); break;
|
||||
case 'dataDelete':
|
||||
var check = table.checkStatus('dataTable').data;
|
||||
active.dataDelete(check.map(function (i) { return i.id; }));
|
||||
break;
|
||||
case 'dataRecybin': active.dataRecybin(); break;
|
||||
}
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update': active.dataEdit(data); break;
|
||||
case 'delete': active.dataDelete([data.id]); break;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.put('update', { id: this.value, status: status })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) { layer.msg('操作成功'); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
table.reload('dataTable', {}, true);
|
||||
})
|
||||
.catch(function () { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑电子商务' : '添加电子商务';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title, content: formHtml, anim: "slideLeft", offset: "r",
|
||||
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
|
||||
success: function (layero, index) { callback(layero, index); form.render(); },
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var active = {
|
||||
dataDelete: function (ids, force) {
|
||||
if (ids.length === 0) { return layer.msg('请选择数据'); }
|
||||
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
|
||||
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
|
||||
});
|
||||
},
|
||||
dataCreate: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
if (field.status === undefined) field.status = 0;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataEdit: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataRecybin: function () {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
|
||||
layer.open({
|
||||
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
success: function () {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
|
||||
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '商品名称', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data) {
|
||||
http.put("restore", { ids: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '恢复失败'); }
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore': active.dataRestore(data); break;
|
||||
case 'forcedelete': active.dataForceDelete(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('shop', {});
|
||||
});
|
||||
@@ -0,0 +1,179 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('sms');
|
||||
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'title', minWidth: 160, title: '模板名称' },
|
||||
{ field: 'sort', width: 100, title: '排序', sort: true },
|
||||
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'create_time', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
|
||||
return false;
|
||||
});
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name=\"title\"]').val('');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate': active.dataCreate({}); break;
|
||||
case 'dataDelete':
|
||||
var check = table.checkStatus('dataTable').data;
|
||||
active.dataDelete(check.map(function (i) { return i.id; }));
|
||||
break;
|
||||
case 'dataRecybin': active.dataRecybin(); break;
|
||||
}
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update': active.dataEdit(data); break;
|
||||
case 'delete': active.dataDelete([data.id]); break;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.put('update', { id: this.value, status: status })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) { layer.msg('操作成功'); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
table.reload('dataTable', {}, true);
|
||||
})
|
||||
.catch(function () { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑短信服务' : '添加短信服务';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title, content: formHtml, anim: "slideLeft", offset: "r",
|
||||
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
|
||||
success: function (layero, index) { callback(layero, index); form.render(); },
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var active = {
|
||||
dataDelete: function (ids, force) {
|
||||
if (ids.length === 0) { return layer.msg('请选择数据'); }
|
||||
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
|
||||
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
|
||||
});
|
||||
},
|
||||
dataCreate: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
if (field.status === undefined) field.status = 0;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataEdit: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataRecybin: function () {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
|
||||
layer.open({
|
||||
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
success: function () {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
|
||||
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '模板名称', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data) {
|
||||
http.put("restore", { ids: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '恢复失败'); }
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore': active.dataRestore(data); break;
|
||||
case 'forcedelete': active.dataForceDelete(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('sms', {});
|
||||
});
|
||||
@@ -0,0 +1,115 @@
|
||||
layui.define(['form', 'table', 'http', 'auth', 'laydate'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http,
|
||||
laydate = layui.laydate,
|
||||
auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('spider');
|
||||
|
||||
// 日期选择
|
||||
laydate.render({ elem: '#dateInput' });
|
||||
|
||||
// 汇总 + 趋势(纯 CSS 迷你条形图,不依赖 echarts)
|
||||
http.get('stats').then(function (res) {
|
||||
if (res.code !== 0) { return; }
|
||||
var summary = (res.data && res.data.summary) || [];
|
||||
var trend = (res.data && res.data.trend) || { dates: [], series: [] };
|
||||
var $body = $('#summaryBody').empty();
|
||||
if (summary.length === 0) {
|
||||
$body.append('<tr><td colspan="6" style="text-align:center;color:#999;">暂无蜘蛛来访记录</td></tr>');
|
||||
}
|
||||
var seriesMap = {};
|
||||
(trend.series || []).forEach(function (s) { seriesMap[s.name] = s.data; });
|
||||
summary.forEach(function (row) {
|
||||
var line = seriesMap[row.label] || [];
|
||||
var max = Math.max.apply(null, line.concat([1]));
|
||||
var bars = line.map(function (v, i) {
|
||||
var h = v > 0 ? Math.max(2, Math.round(v / max * 28)) : 1;
|
||||
return '<span title="' + (trend.dates[i] || '') + ': ' + v + '" style="display:inline-block;width:5px;margin-right:1px;height:' + h + 'px;background:' + (v > 0 ? '#1E9FFF' : '#e2e2e2') + ';vertical-align:bottom;"></span>';
|
||||
}).join('');
|
||||
$body.append('<tr>'
|
||||
+ '<td>' + row.label + ' <span style="color:#999;">(' + row.spider + ')</span></td>'
|
||||
+ '<td>' + row.today + '</td>'
|
||||
+ '<td>' + row.week + '</td>'
|
||||
+ '<td>' + row.month + '</td>'
|
||||
+ '<td>' + row.total + '</td>'
|
||||
+ '<td><div style="height:30px;line-height:30px;">' + bars + '</div></td>'
|
||||
+ '</tr>');
|
||||
$('#spiderSelect').append('<option value="' + row.spider + '">' + row.label + '</option>');
|
||||
});
|
||||
form.render('select');
|
||||
});
|
||||
|
||||
// 明细表
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: 'index',
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return {
|
||||
code: res.code === 0 ? 0 : 1,
|
||||
msg: res.message || '',
|
||||
count: res.count || (res.data ? res.data.length : 0),
|
||||
data: res.data || []
|
||||
};
|
||||
},
|
||||
cols: [[
|
||||
{ field: 'id', width: 90, title: 'ID', sort: true },
|
||||
{ field: 'spider_text', width: 110, title: '蜘蛛' },
|
||||
{ field: 'url', title: '抓取URL', minWidth: 240 },
|
||||
{ field: 'ip', width: 140, title: '来源IP' },
|
||||
{ field: 'app', width: 100, title: '应用' },
|
||||
{ field: 'http_code', width: 90, title: '状态码' },
|
||||
{ field: 'time_text', width: 170, title: '抓取时间' }
|
||||
]],
|
||||
limits: [15, 30, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 搜索
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: data.field });
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name="ip"],input[name="url"],input[name="date"]').val('');
|
||||
$('#spiderSelect').val('');
|
||||
form.render('select');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { spider: '', ip: '', url: '', date: '' } });
|
||||
});
|
||||
|
||||
// 工具条:清理旧日志
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
if (elem.event === 'dataClear') {
|
||||
layer.prompt({ title: '保留最近多少天的明细?(聚合报表不受影响)', value: '30' }, function (value, index) {
|
||||
layer.close(index);
|
||||
var days = parseInt(value, 10) || 30;
|
||||
http.post('clear', { days: days }).then(function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.message || '清理完成');
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || res.message || '清理失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
exports('spider', {});
|
||||
});
|
||||
@@ -0,0 +1,211 @@
|
||||
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
|
||||
var $ = layui.jquery,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
http = layui.http, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('task');
|
||||
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "index",
|
||||
toolbar: '#tableBar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
parseData: function (res) {
|
||||
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
|
||||
},
|
||||
cols: [[
|
||||
{ type: "checkbox", width: 50 },
|
||||
{ field: 'id', width: 80, title: 'ID', sort: true },
|
||||
{ field: 'title', minWidth: 160, title: '任务标题' },
|
||||
{ field: 'reward_type', width: 110, title: '奖励类型', templet: '#rewardTypeTpl' },
|
||||
{ field: 'reward_num', width: 100, title: '奖励数量', sort: true },
|
||||
{ field: 'sort', width: 100, title: '排序', sort: true },
|
||||
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
|
||||
{ field: 'create_time', width: 180, title: '创建时间' },
|
||||
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
|
||||
]],
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
limit: 15,
|
||||
page: true,
|
||||
skin: 'line',
|
||||
done: function () {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(data-search-btn)', function (data) {
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
|
||||
return false;
|
||||
});
|
||||
$('#btn-reset').on('click', function () {
|
||||
$('input[name=\"title\"]').val('');
|
||||
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate': active.dataCreate({}); break;
|
||||
case 'dataDelete':
|
||||
var check = table.checkStatus('dataTable').data;
|
||||
active.dataDelete(check.map(function (i) { return i.id; }));
|
||||
break;
|
||||
case 'dataRecybin': active.dataRecybin(); break;
|
||||
}
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update': active.dataEdit(data); break;
|
||||
case 'delete': active.dataDelete([data.id]); break;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
http.put('update', { id: this.value, status: status })
|
||||
.then(function (res) {
|
||||
if (res.code === 0) { layer.msg('操作成功'); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
table.reload('dataTable', {}, true);
|
||||
})
|
||||
.catch(function () { table.reload('dataTable', {}, true); });
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data.id ? '编辑站点任务' : '添加站点任务';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title, content: formHtml, anim: "slideLeft", offset: "r",
|
||||
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
|
||||
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
|
||||
success: function (layero, index) {
|
||||
callback(layero, index);
|
||||
form.render();
|
||||
// 道具奖励动态表单切换
|
||||
var $box = $(layero);
|
||||
var numItem = $box.find('#rewardNumItem');
|
||||
var propItem = $box.find('#rewardPropItem');
|
||||
var propNumItem = $box.find('#propNumItem');
|
||||
var typeSelect = $box.find('select[name="reward_type"]');
|
||||
function toggleRewardType() {
|
||||
var t = parseInt(typeSelect.val(), 10);
|
||||
if (t === 3) {
|
||||
numItem.hide();
|
||||
propItem.show();
|
||||
propNumItem.show();
|
||||
} else {
|
||||
numItem.show();
|
||||
propItem.hide();
|
||||
propNumItem.hide();
|
||||
}
|
||||
}
|
||||
toggleRewardType();
|
||||
typeSelect.on('change', toggleRewardType);
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var active = {
|
||||
dataDelete: function (ids, force) {
|
||||
if (ids.length === 0) { return layer.msg('请选择数据'); }
|
||||
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
|
||||
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
|
||||
});
|
||||
},
|
||||
dataCreate: function (data) {
|
||||
dataFromFun(data, function () {}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
if (field.status === undefined) field.status = 0;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataEdit: function (data) {
|
||||
dataFromFun(data, function (layero, index) {
|
||||
var vals = { reward_type: data.reward_type };
|
||||
if (data.reward_type == 3) {
|
||||
vals.reward_num = data.reward_num; // 道具下拉选中
|
||||
vals.prop_num = data.prop_num || 1;
|
||||
}
|
||||
form.val('wxapp-form', vals);
|
||||
}, function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field).then(function (res) {
|
||||
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
},
|
||||
dataRecybin: function () {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
|
||||
layer.open({
|
||||
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
|
||||
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
|
||||
success: function () {
|
||||
table.render({
|
||||
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
|
||||
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '任务标题', minWidth: 160, fixed: 'left' },
|
||||
{ field: 'sort', title: '排序', width: 80 },
|
||||
{ field: 'delete_at', title: '删除时间', width: 160 },
|
||||
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data) {
|
||||
http.put("restore", { ids: data.id }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
|
||||
else { layer.msg(res.msg || '恢复失败'); }
|
||||
});
|
||||
},
|
||||
dataForceDelete: function (data) {
|
||||
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
|
||||
layer.close(index);
|
||||
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
|
||||
else { layer.msg(res.msg || '操作失败'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(dataRecybinTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'restore': active.dataRestore(data); break;
|
||||
case 'forcedelete': active.dataForceDelete(data); break;
|
||||
}
|
||||
});
|
||||
|
||||
exports('task', {});
|
||||
});
|
||||
@@ -0,0 +1,404 @@
|
||||
|
||||
layui.define(['http', 'layer', 'laydate', 'util', 'auth'], function (exports) {
|
||||
var $ = layui.$
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, layer = layui.layer
|
||||
, laydate = layui.laydate
|
||||
, util = layui.util
|
||||
, http = layui.http
|
||||
, laytpl = layui.laytpl
|
||||
, auth = layui.auth;
|
||||
var _savedPerms = (layui.data('backend').permission) || [];
|
||||
auth.init(_savedPerms);
|
||||
auth.setController('user');
|
||||
// 渲染表格
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
, url: 'index' // 后端数据接口
|
||||
, page: true
|
||||
, limit: 15
|
||||
, toolbar: '#tableBar'
|
||||
, cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' }
|
||||
, { field: 'uid', title: 'UID', width: 99, align: 'center', sort: true, fixed: 'left' }
|
||||
, { field: 'account', title: '账户', width: 120, align: 'center', fixed: 'left' }
|
||||
, { field: 'nickname', title: '昵称', width: 100, align: 'center' }
|
||||
// , { field: 'role_id', title: '角色', width: 100, align: 'center', templet: '#roleTpl' }
|
||||
, { field: 'email', title: '邮箱', minWidth: 180, align: 'center' }
|
||||
, { field: 'mobile', title: '手机', width: 120, align: 'center' }
|
||||
, { field: 'login_info', title: '登录信息', width: 160, align: 'center', templet: '#loginInfoTpl' }
|
||||
, { field: 'status', title: '状态', width: 90, align: 'center', templet: '#statusTpl', unresize: true }
|
||||
, { field: 'create_at', title: '创建时间', width: 160, align: 'center', sort: true }
|
||||
, { title: '操作', width: 120, align: 'right', toolbar: '#dataBar', fixed: 'right', unresize: true }
|
||||
]],
|
||||
done: function (res, curr, count) {
|
||||
var view = $('#dataTable').next('.layui-table-view');
|
||||
view.find('[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
$('.layui-btn[data-perm]').each(function () {
|
||||
var perm = $(this).attr('data-perm');
|
||||
if (perm && !auth.has(perm)) { $(this).remove(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
form.on('submit(searchBtn)', function (data) {
|
||||
adminTable.reload({
|
||||
where: data.field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
form.on('switch(statusSwitch)', function (obj) {
|
||||
var uid = this.value;
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
layer.confirm('确定要' + (status ? '启用' : '禁用') + '该管理员账号吗?', function (index) {
|
||||
layui.http.post('update', { uid: uid, status: status }).then(function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.msg, { icon: 1 });
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
}, function () {
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
});
|
||||
});
|
||||
|
||||
table.on('toolbar(dataTable)', function (elem) {
|
||||
switch (elem.event) {
|
||||
case 'dataCreate':
|
||||
active.dataCreate({ pid: 0, type: 1 });
|
||||
break;
|
||||
case 'dataDelete':
|
||||
var checkStatus = table.checkStatus('dataTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.uid; });
|
||||
active.dataDelete(ids);
|
||||
break;
|
||||
case 'dataRecybin':
|
||||
active.dataRecybin();
|
||||
break;
|
||||
};
|
||||
});
|
||||
table.on('tool(dataTable)', function (elem) {
|
||||
var data = elem.data;
|
||||
switch (elem.event) {
|
||||
case 'update':
|
||||
active.dataEdit(data);
|
||||
break;
|
||||
case 'delete':
|
||||
active.dataDelete([data.uid]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
var dataFromFun = function (data, callback, done) {
|
||||
var title = data ? '编辑数据[' + data.account + ']' : '添加数据';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: title,
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
btnAlign: "l",
|
||||
area: ['50% ', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
btn: ['确定', '取消'],
|
||||
success: function (layero, index) {
|
||||
callback(layero, index);
|
||||
form.render();
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
|
||||
done(layero, index, elem);
|
||||
layui.off('submit(wxapp-form)', 'from');
|
||||
return false;
|
||||
});
|
||||
layero.contents().find("#wxapp-form-submit").trigger('click');
|
||||
}
|
||||
});
|
||||
};
|
||||
//事件
|
||||
var active = {
|
||||
dataDelete: function (ids, force = 0) {
|
||||
if (ids.length === 0) {
|
||||
return layer.msg('请选择数据');
|
||||
}
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '敏感操作,请验证口令'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
layer.confirm('确定删除吗?', function (index) {
|
||||
http.delete('delete', { ids: ids.join(','), force: force })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
dataCreate: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) { },
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.icon = 'layui-icon ' + field.icon;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.post('save', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataEdit: function (data = {}) {
|
||||
dataFromFun(data,
|
||||
function (layero, index) { },
|
||||
function (layero, index, elem) {
|
||||
var field = elem.field;
|
||||
field.icon = 'layui-icon ' + field.icon;
|
||||
field.status = field.status ? 1 : 0;
|
||||
http.put('update', field)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
dataRecybin: function (data = {}) {
|
||||
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
title: '资源回收站',
|
||||
content: formHtml,
|
||||
anim: "slideLeft",
|
||||
offset: "r",
|
||||
area: ['50%', '99%'],
|
||||
shade: 0.1,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
layui.table.render({
|
||||
elem: '#dataRecybinTable',
|
||||
url: 'recyclebin',
|
||||
height: 'full-100',
|
||||
defaultToolbar: [{
|
||||
title: '批量删除数据',
|
||||
layEvent: 'dataDelete',
|
||||
icon: 'layui-icon-delete',
|
||||
onClick: function (obj) {
|
||||
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
|
||||
let ids = checkData.map((item, index, array) => { return item.uid; });
|
||||
console.log(ids);
|
||||
}
|
||||
}, 'filter', 'exports', 'print'],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: 'uid', title: 'UID', width: 80, sort: true, fixed: 'left' },
|
||||
{ field: 'title', title: '名称', width: 180, fixed: 'left' },
|
||||
{ field: 'code', title: '代码', width: 180, fixed: 'left' },
|
||||
{ field: 'description', title: '描述', minWidth: 200, sort: true },
|
||||
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#dataRecybinBarTpl" }
|
||||
]],
|
||||
page: true,
|
||||
done: function (res, curr, count, origin) {
|
||||
console.log('表格渲染完成');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
dataRestore: function (data = {}) {
|
||||
http.put('restore', { uid: data.uid })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
layer.msg('恢复成功');
|
||||
table.reload('dataTable', {}, true);
|
||||
} else {
|
||||
layer.msg(res.msg || '恢复失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 打开管理员表单
|
||||
function opendataForm(data) {
|
||||
var title = data ? '编辑管理员 [' + data.account + ']' : '添加管理员';
|
||||
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title,
|
||||
area: ['500px', '520px'],
|
||||
shadeClose: true,
|
||||
content: formHtml,
|
||||
success: function (layero, index) {
|
||||
// 显示/隐藏密码字段
|
||||
if (data) {
|
||||
$('#passwordGroup').hide();
|
||||
} else {
|
||||
$('#passwordGroup').show();
|
||||
}
|
||||
// 表单验证规则
|
||||
layui.form.verify({
|
||||
username: function (value) {
|
||||
if (!/^[\w\u4e00-\u9fa5]{2,20}$/.test(value)) {
|
||||
return '用户名必须2-20位字符,支持中文、字母、数字和下划线';
|
||||
}
|
||||
},
|
||||
pass: [
|
||||
/^[\S]{6,20}$/
|
||||
, '密码必须6到20位,且不能出现空格'
|
||||
]
|
||||
});
|
||||
// 提交表单
|
||||
form.on('submit(adminFormSubmit)', function (formData) {
|
||||
var url = data ? 'update' : 'create';
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
data: formData.field,
|
||||
success: function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
|
||||
layer.close(index);
|
||||
adminTable.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('操作失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
form.render();
|
||||
},
|
||||
btn: ['保存', '取消'],
|
||||
yes: function (index, layero) {
|
||||
// 触发表单提交
|
||||
layero.find('form').find('button[lay-filter=adminFormSubmit]').click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 重置密码
|
||||
function resetPassword(data) {
|
||||
layer.confirm('确定要重置管理员 [' + data.username + '] 的密码吗?重置后密码将变为123456', {
|
||||
btn: ['确定', '取消'],
|
||||
title: '重置密码'
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: 'resetPassword',
|
||||
type: 'POST',
|
||||
data: { id: data.uid },
|
||||
success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1 });
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('操作失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 删除管理员
|
||||
function deleteAdmin(data) {
|
||||
layer.confirm('确定要删除管理员 [' + data.username + '] 吗?此操作不可恢复!', {
|
||||
btn: ['确定', '取消'],
|
||||
title: '删除管理员',
|
||||
icon: 3
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: 'delete',
|
||||
type: 'POST',
|
||||
data: { uid: data.uid },
|
||||
success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
|
||||
adminTable.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('操作失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
function batchDelete(data) {
|
||||
if (data.length === 0) {
|
||||
layer.msg('请先选择要删除的管理员', { icon: 3 });
|
||||
return;
|
||||
}
|
||||
var superAdmins = data.filter(function (item) {
|
||||
return item.is_super == 1;
|
||||
});
|
||||
if (superAdmins.length > 0) {
|
||||
layer.msg('不能删除超级管理员账号', { icon: 2 });
|
||||
return;
|
||||
}
|
||||
var ids = data.map(function (item) {
|
||||
return item.uid;
|
||||
});
|
||||
layer.confirm('确定要删除选中的 ' + data.length + ' 个管理员吗?此操作不可恢复!', {
|
||||
btn: ['确定', '取消'],
|
||||
title: '批量删除',
|
||||
icon: 3
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: 'batchDelete',
|
||||
type: 'POST',
|
||||
data: { ids: ids },
|
||||
success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
|
||||
adminTable.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('操作失败', { icon: 2 });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
exports('user', {});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
<div class="layui-card-header">版本</div>
|
||||
<div class="layui-card-body layui-text layadmin-about">
|
||||
<blockquote class="layui-elem-quote" style="border: none;">
|
||||
<script type="text/html" template>
|
||||
<p>当前版本:v{{ layui.ywxapp.version }}</p>
|
||||
</script>
|
||||
</blockquote>
|
||||
</div>
|
||||
|
||||
<div class="layui-card-header">关于</div>
|
||||
<div class="layui-card-body layui-text layadmin-about">
|
||||
<blockquote class="layui-elem-quote" style="border: none;">
|
||||
一套纯静态的 HTML 网页界面模板,以开源免费的 Layui 基础组件和页面模板 Demo 为组成,没有任何后端程序及数据库存储等服务端代码。
|
||||
<br><br>开发者使用该网页模板,可省去前端的大量工作,从而更高效地开发 Web 应用系统。
|
||||
|
||||
</blockquote>
|
||||
</div>
|
||||
@@ -0,0 +1,84 @@
|
||||
<!-- 主题设置模板 -->
|
||||
<script type="text/html" template lay-done="layui.data.theme();">
|
||||
{{#
|
||||
var local = layui.data(layui.setter.tableName);
|
||||
var theme = local.theme || {};
|
||||
var color = theme.color || {};
|
||||
var themeColorIndex = parseInt((theme && theme.color) ? theme.color.index : 0) || 0;
|
||||
}}
|
||||
|
||||
<div class="layui-card-header">
|
||||
<strong>主题设置</strong>
|
||||
</div>
|
||||
<div class="layui-card-body layadmin-setTheme">
|
||||
<h5><strong>配色方案</strong></h5>
|
||||
<ul class="layadmin-setTheme-color">
|
||||
{{# layui.each(layui.setter.theme.color, function(index, item){ }}
|
||||
<li layadmin-event="setTheme" data-index="{{ index }}" data-alias="{{ item.alias }}"
|
||||
{{- index === themeColorIndex ? 'class="layui-this"' : '' }} title="{{ item.alias }}">
|
||||
<div class="layadmin-setTheme-header" style="background-color: {{ item.header }};"></div>
|
||||
<div class="layadmin-setTheme-side" style="background-color: {{ item.main }};">
|
||||
<div class="layadmin-setTheme-logo" style="background-color: {{ item.logo }};"></div>
|
||||
</div>
|
||||
</li>
|
||||
{{# }); }}
|
||||
</ul>
|
||||
<h5><strong>自定义配色</strong></h5>
|
||||
<ul class="layadmin-setTheme-custom">
|
||||
<li>主题色 <div class="set-custom-theme" data-name="main" lay-options="{color: '{{= color.main }}'}"></div></li>
|
||||
<li>选中色 <div class="set-custom-theme" data-name="selected" lay-options="{color: '{{= color.selected }}'}"></div></li>
|
||||
<li>LOGO 背景色 <div class="set-custom-theme" data-name="logo" lay-options="{color: '{{= color.logo }}'}"></div></li>
|
||||
<li>头部拦背景色 <div class="set-custom-theme" data-name="header" lay-options="{color: '{{= color.header }}'}"></div></li>
|
||||
<li>恢复默认主题 <div class="set-default-theme"><button class="layui-btn layui-btn-primary"><i class="layui-icon layui-icon-refresh-1"></i></button></div></li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.data.theme = function () {
|
||||
layui.use(['form', 'colorpicker'], function () {
|
||||
var $ = layui.$;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form
|
||||
var colorpicker = layui.colorpicker
|
||||
var ywxapp = layui.ywxapp;
|
||||
var view = layui.view;
|
||||
|
||||
|
||||
var local = layui.data(layui.setter.tableName);
|
||||
var theme = local.theme || {};
|
||||
var color = theme.color || {};
|
||||
|
||||
// 自定义配色
|
||||
colorpicker.render({
|
||||
elem: '.set-custom-theme',
|
||||
done: function (value) {
|
||||
var elem = this.elem;
|
||||
var NAME = elem.data('name');
|
||||
|
||||
color[NAME] = value;
|
||||
|
||||
ywxapp.theme({
|
||||
color: color
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 恢复默认主题
|
||||
$('.set-default-theme').on('click', function () {
|
||||
layer.confirm('确认恢复默认主题吗?', function (i) {
|
||||
layer.close(i);
|
||||
ywxapp.events.setTheme($('.layadmin-setTheme-color>li:eq(0)'));
|
||||
ywxapp.initTheme(0);
|
||||
view('LAY_adminPopupTheme').render('system/theme');
|
||||
})
|
||||
});
|
||||
|
||||
// 事件-隐藏开关
|
||||
form.on('switch(system-theme-sideicon)', function () {
|
||||
ywxapp.theme({
|
||||
hideSideIcon: this.checked
|
||||
})
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,874 @@
|
||||
/**
|
||||
|
||||
@Name: layuiQuietBlog - 静谧风格个人博客模板
|
||||
@Author: xuzhiwen
|
||||
@Copyright: layui.com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
body {
|
||||
background: url(../img/bg.jpg) no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.seach input::-webkit-input-placeholder { /*WebKit browsers*/
|
||||
|
||||
color: #d1aa56;
|
||||
|
||||
}
|
||||
|
||||
.seach input::-moz-input-placeholder { /*Mozilla Firefox*/
|
||||
|
||||
color: #d1aa56;
|
||||
|
||||
}
|
||||
|
||||
.seach input::-ms-input-placeholder { /*Internet Explorer*/
|
||||
|
||||
color: #d1aa56;
|
||||
|
||||
}
|
||||
|
||||
.main .layui-tab .layui-tab-title .layui-tab-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*搜索框*/
|
||||
.seach {
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
right: 109px;
|
||||
}
|
||||
|
||||
.seach-box {
|
||||
width: 380px;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.seach-box .layui-input-block {
|
||||
margin-left: 0;
|
||||
height: 42px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.seach-box .layui-input-block .layui-input {
|
||||
height: 42px;
|
||||
background: #141412;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
filter: Alpha(opacity=50);
|
||||
color: #d1aa56;
|
||||
border: 1px solid #242320;
|
||||
padding: 0 53px 0 23px;
|
||||
}
|
||||
|
||||
.seach-box .layui-input-block .layui-input:hover, .seach-box .layui-input-block .layui-input:focus {
|
||||
border-color: #242320 !important;
|
||||
}
|
||||
|
||||
.seach-box .layui-input-block .layui-btn {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
width: 53px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.seach-box .layui-input-block .layui-btn i {
|
||||
font-size: 20px;
|
||||
color: #d1aa56;
|
||||
}
|
||||
|
||||
.seach-box .layui-input-block .layui-btn:hover {
|
||||
opacity: 01;
|
||||
}
|
||||
|
||||
|
||||
/*侧边内容*/
|
||||
.sidebar-content {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-card {
|
||||
width: 210px;
|
||||
background-color: transparent;
|
||||
margin-bottom: 130px;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-card .layui-card-header {
|
||||
padding: 50px 0 0 0;
|
||||
height: auto;
|
||||
line-height: 52px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px dashed #5e5d5d;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-card .layui-card-header img {
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-card .layui-card-header span {
|
||||
font-size: 16px;
|
||||
color: #5e5f5e;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-card .layui-card-body {
|
||||
padding: 20px 0 0 0;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-card .layui-card-body ul {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-card .layui-card-body li {
|
||||
line-height: 21px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #bcbcbc;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-card .layui-card-body li.txt {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-card .layui-card-body li.visitors {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
|
||||
.sidebar-content .layui-nav {
|
||||
background-color: transparent;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-nav a {
|
||||
padding: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-nav .layui-nav-item a:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-nav .layui-nav-item {
|
||||
text-align: center;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-nav .layui-nav-item a:hover, .layui-nav .layui-this a {
|
||||
color: #dda354;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-nav .layui-nav-item.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-nav .layui-this:after {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-nav .layui-nav-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/*主要内容*/
|
||||
.main {
|
||||
width: 62.5%;
|
||||
height: 100%;
|
||||
padding-top: 178px;
|
||||
margin-left: 21%;
|
||||
}
|
||||
|
||||
.main .item {
|
||||
padding: 16px 50px;
|
||||
background: #fff;
|
||||
background: #141412;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
filter: Alpha(opacity=200);
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.main .item img {
|
||||
float: left;
|
||||
padding-right: 39px;
|
||||
}
|
||||
|
||||
.main .item-content {
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.main .item-content p.time {
|
||||
line-height: 40px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.main .item-content p.time i {
|
||||
margin-right: 17px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.main .item-content p.brief {
|
||||
line-height: 24px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.main .item-content p.praise span {
|
||||
cursor: pointer;
|
||||
margin-right: 76px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
display: inline-block;
|
||||
color: #d1aa56;
|
||||
}
|
||||
|
||||
.main .item-content p.praise i {
|
||||
font-size: 20px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
margin-right: 6px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#demo1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#demo1 a, #demo1 span {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
background: #000;
|
||||
filter: Alpha(opacity=200);
|
||||
margin-right: 10px;
|
||||
color: #fff;
|
||||
border: 1px solid #535655;
|
||||
}
|
||||
|
||||
#demo1 .layui-laypage .layui-laypage-curr .layui-laypage-em {
|
||||
background-color: #a58f59;
|
||||
}
|
||||
|
||||
|
||||
/*文章*/
|
||||
.article {
|
||||
width: 57%;
|
||||
padding-top: 160px;
|
||||
}
|
||||
|
||||
.article .item {
|
||||
padding: 40px 66px 32px 74px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.article .item .date-box {
|
||||
width: 76px;
|
||||
height: 76px;
|
||||
border: 2px solid #9f7e39;
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: -39px;
|
||||
}
|
||||
|
||||
.article .item .date-box .date {
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
background: #000;
|
||||
color: #bcbcbc;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: -10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.article .item .date-box .date h4 {
|
||||
font-size: 36px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.main .layui-tab-title li {
|
||||
color: #cca455;
|
||||
}
|
||||
|
||||
.main .layui-tab-title {
|
||||
border-color: #6a6a67;
|
||||
}
|
||||
|
||||
.main .layui-tab-brief > .layui-tab-title .layui-this {
|
||||
color: #cca455;
|
||||
}
|
||||
|
||||
.main .layui-tab-brief > .layui-tab-title .layui-this:after {
|
||||
border-color: #d1aa55;
|
||||
}
|
||||
|
||||
.article .item-content h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.Subtitle {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
background: #a58c56;
|
||||
margin: 10px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.article .item-content p {
|
||||
line-height: 28px;
|
||||
margin-bottom: 16px;
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2; /*显示行数*/
|
||||
}
|
||||
|
||||
.article .item-content button {
|
||||
width: 102px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border: 1px solid #706553;
|
||||
background-color: transparent;
|
||||
color: #b79b52;
|
||||
}
|
||||
|
||||
.article-right-content {
|
||||
width: 13.5%;
|
||||
position: absolute;
|
||||
right: 109px;
|
||||
top: 242px;
|
||||
box-sizing: border-box;
|
||||
padding: 25px;
|
||||
background: #141412;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
filter: Alpha(opacity=200);
|
||||
}
|
||||
|
||||
.article-right-content h3 {
|
||||
font-size: 16px;
|
||||
line-height: 30px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.article-right-content li {
|
||||
margin: 7px 5px 0 0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
|
||||
/*作品*/
|
||||
.works {
|
||||
padding-top: 160px;
|
||||
width: 67%;
|
||||
}
|
||||
|
||||
.works .item {
|
||||
padding: 44px 30px 0 30px;
|
||||
}
|
||||
|
||||
.works .img-text {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.works .img-text img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.works .img-text p {
|
||||
line-height: 46px;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.works .item img {
|
||||
float: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.works .item .layui-laypage {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
|
||||
/*关于*/
|
||||
.about {
|
||||
width: 62.5%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.about .item {
|
||||
padding: 80px 10px 90px 10px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.about .item img {
|
||||
float: none;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.about .item img.portrait {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.about h4 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #ab8560;
|
||||
}
|
||||
|
||||
.about h4.personal {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.about .Introduction {
|
||||
line-height: 36px;
|
||||
font-size: 16px;
|
||||
margin: 10px 0 56px 0;
|
||||
color: #d9dbda;
|
||||
}
|
||||
|
||||
.about .layui-progress {
|
||||
width: 34%;
|
||||
margin-left: 35%;
|
||||
position: relative;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.about .layui-progress span {
|
||||
color: #fff;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.about .layui-progress em {
|
||||
position: absolute;
|
||||
left: -60px;
|
||||
color: #fff;
|
||||
font-style: normal;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.about h4.contact {
|
||||
margin: 50px 0 28px 0;
|
||||
}
|
||||
|
||||
.about .item img.code {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.about p.qq-number {
|
||||
line-height: 22px;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
|
||||
/*留言*/
|
||||
.message .item {
|
||||
padding: 0;
|
||||
background: #141412;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
filter: Alpha(opacity=200);
|
||||
}
|
||||
|
||||
.message .item .layui-card {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-header {
|
||||
border-bottom-color: #666465;
|
||||
padding: 40px 50px 27px 50px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-header .layui-form-item, .message .item .layui-card .layui-card-header .layui-input-block {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-header .layui-textarea {
|
||||
padding: 19px 24px;
|
||||
margin-bottom: 28px;
|
||||
color: #545454;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-header button {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
background-color: #d0aa55;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-header .btn-box {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body {
|
||||
padding: 40px 50px 27px 50px;
|
||||
color: #d8d8d8;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .title span {
|
||||
margin-right: 28px;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .title em {
|
||||
color: #b3924d;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .list-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .list-item .list-txt {
|
||||
padding-left: 75px;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .list-item li {
|
||||
padding: 32px 0 30px 10px;
|
||||
border-bottom: 1px dashed #5e5d5d;
|
||||
table-layout: fixed;
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .list-item img {
|
||||
border-radius: 50%;
|
||||
padding-right: 0;
|
||||
margin-right: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .list-item .max-title {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .list-item .max-title .name {
|
||||
color: #b29547;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .list-item .max-title .time {
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
||||
/* 微语 */
|
||||
.mood {
|
||||
width: 42%;
|
||||
margin-left: 29%;
|
||||
}
|
||||
|
||||
.mood .item1 {
|
||||
padding: 16px 50px;
|
||||
background: #fff;
|
||||
background: #141412;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
filter: Alpha(opacity=200);
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.mood .item1 img {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.mood .item .item-content img {
|
||||
padding: 0;
|
||||
margin-bottom: 30px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mood .item-content p.time i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.mood .item-content p.time span {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.mood.mood-details .top_title {
|
||||
color: #9f9f9d;
|
||||
height: 58px;
|
||||
line-height: 58px;
|
||||
border-bottom: 1px solid #666666;
|
||||
background: #141412;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
filter: Alpha(opacity=200);
|
||||
padding-left: 50px;
|
||||
}
|
||||
|
||||
.mood .item1 img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.article1 {
|
||||
width: 62.5%;
|
||||
margin-left: 21%;
|
||||
}
|
||||
|
||||
.main.article1 .top_title {
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
.article1 .item1 {
|
||||
padding: 16px 40px;
|
||||
}
|
||||
|
||||
.article1 .item .layui-card .layui-card-header, .article1 .item .layui-card .layui-card-body {
|
||||
padding: 40px 40px 27px 40px;
|
||||
}
|
||||
|
||||
.article1 h3 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.article1 .Subtitle {
|
||||
margin-right: 50px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.article1 .label {
|
||||
color: #a58e58;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.article1 .tb {
|
||||
margin-right: 50px;
|
||||
}
|
||||
|
||||
.article1 .txt {
|
||||
line-height: 28px;
|
||||
text-indent: 28px;
|
||||
color: #b2b0b1;
|
||||
}
|
||||
|
||||
.article1 .item1 img {
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.article1 .item1 .img-box {
|
||||
text-align: center;
|
||||
margin: 28px 0 40px 0;
|
||||
}
|
||||
|
||||
.article1 .item1 .btn-box {
|
||||
text-align: center;
|
||||
margin: 50px 0;
|
||||
}
|
||||
|
||||
.article1 .item1 .btn-box .layui-btn {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 1800px) {
|
||||
.main .item img {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.seach {
|
||||
right: 5%;
|
||||
}
|
||||
|
||||
.main {
|
||||
margin-left: 30%;
|
||||
width: 65%;
|
||||
}
|
||||
|
||||
.article {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.article-right-content {
|
||||
width: 20.5%;
|
||||
right: 5%;
|
||||
}
|
||||
|
||||
.mood .item1 img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1600px) {
|
||||
.article .item img {
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1100px) {
|
||||
.article .item {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.article .item h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.article .item .date-box {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.seach {
|
||||
top: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1000px) {
|
||||
.sidebar-content .layui-nav {
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-nav a {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-nav .layui-nav-item {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.sidebar-content .layui-card {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.main {
|
||||
margin: 0 auto;
|
||||
width: 80%;
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.seach {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.article-right-content {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
right: 0;
|
||||
top: 0px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.article-right-content ul {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.article-right-content .layui-btn {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 569px) {
|
||||
.article .layui-tab .layui-tab-title li, .works .layui-tab .layui-tab-title li {
|
||||
min-width: 50px;
|
||||
padding: 0 7px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.main .item {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
.main .item img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.about .item img {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.about .Introduction {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.main .item-content p.praise span {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-header, .message .item .layui-card .layui-card-body {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .list-item img {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .list-item .max-title .time {
|
||||
display: block;
|
||||
float: none;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-body .list-item .list-txt {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-header button {
|
||||
line-height: 30px;
|
||||
height: 30px;
|
||||
width: 80px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-header {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.message .item .layui-card .layui-card-header .layui-textarea {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.message .item {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mood.mood-details .top_title {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.mood .item1 {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
.article1 .item .layui-card .layui-card-header, .article1 .item .layui-card .layui-card-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.about .layui-progress em {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
/* =========================================================
|
||||
* TP-Blog 前台统一主题样式(移动优先 / 响应式 / 主题色可配)
|
||||
* 主题色由 layout 注入的 --theme 变量驱动(默认 #2d6cdf)。
|
||||
* 衍生浅色背景使用 color-mix(现代浏览器)。
|
||||
* ========================================================= */
|
||||
:root{
|
||||
--theme:#2d6cdf;
|
||||
--theme-dark:#1f54b8;
|
||||
--bg:#f4f5f7;
|
||||
--card:#ffffff;
|
||||
--text:#333;
|
||||
--text-2:#666;
|
||||
--text-3:#999;
|
||||
--border:#eee;
|
||||
--radius:12px;
|
||||
--radius-sm:8px;
|
||||
--shadow:0 2px 12px rgba(0,0,0,.05);
|
||||
--shadow-hover:0 6px 20px rgba(0,0,0,.10);
|
||||
--maxw:1140px;
|
||||
--nav-h:56px;
|
||||
--tab-h:56px;
|
||||
}
|
||||
|
||||
*{box-sizing:border-box;}
|
||||
html,body{margin:0;padding:0;min-height:100%;}
|
||||
body{
|
||||
font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;
|
||||
background:var(--bg);
|
||||
color:var(--text);
|
||||
line-height:1.6;
|
||||
-webkit-font-smoothing:antialiased;
|
||||
/* 让 footer 始终贴底:主体撑满剩余空间 */
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
min-height:100vh;
|
||||
}
|
||||
a{text-decoration:none;color:inherit;}
|
||||
img{max-width:100%;display:block;}
|
||||
.container,.fb-wrap{max-width:var(--maxw);margin:0 auto;padding:0 14px;}
|
||||
|
||||
/* ---------- 顶部导航 ---------- */
|
||||
.fb-nav{
|
||||
position:sticky;top:0;z-index:200;
|
||||
height:var(--nav-h);
|
||||
background:var(--card);
|
||||
box-shadow:0 1px 10px rgba(0,0,0,.06);
|
||||
}
|
||||
.fb-nav .inner{
|
||||
max-width:var(--maxw);margin:0 auto;height:100%;
|
||||
padding:0 14px;display:flex;align-items:center;gap:14px;
|
||||
}
|
||||
.fb-nav .logo{font-size:19px;font-weight:800;color:var(--theme);white-space:nowrap;letter-spacing:.5px;}
|
||||
.fb-nav .logo img{height:30px;width:auto;}
|
||||
.fb-nav .menu{display:flex;gap:4px;margin-left:8px;}
|
||||
.fb-nav .menu a{
|
||||
padding:7px 14px;border-radius:var(--radius-sm);font-size:15px;color:var(--text-2);transition:.2s;
|
||||
}
|
||||
.fb-nav .menu a:hover,.fb-nav .menu a.active{background:color-mix(in srgb,var(--theme) 10%,#fff);color:var(--theme);}
|
||||
.fb-nav .search{margin-left:auto;display:flex;align-items:center;background:#f1f2f4;border-radius:20px;padding:4px 6px 4px 14px;max-width:240px;flex:1;}
|
||||
.fb-nav .search input{border:0;background:transparent;outline:none;width:100%;font-size:14px;color:var(--text);}
|
||||
.fb-nav .search button{border:0;background:var(--theme);color:#fff;width:32px;height:32px;border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
|
||||
.fb-nav .user{display:flex;align-items:center;gap:12px;margin-left:8px;white-space:nowrap;font-size:14px;}
|
||||
.fb-nav .user a{color:var(--theme);}
|
||||
.fb-nav .hamburger{display:none;margin-left:auto;width:40px;height:40px;border:0;background:transparent;font-size:22px;color:var(--text);cursor:pointer;}
|
||||
|
||||
/* 顶部下拉小菜单(移动端点击汉堡展开) */
|
||||
.fb-nav .drawer{display:none;position:absolute;left:0;right:0;top:var(--nav-h);background:var(--card);box-shadow:0 8px 20px rgba(0,0,0,.08);padding:8px 14px 14px;}
|
||||
.fb-nav .drawer.open{display:block;}
|
||||
.fb-nav .drawer a{display:block;padding:11px 8px;border-bottom:1px solid var(--border);font-size:15px;color:var(--text-2);}
|
||||
.fb-nav .drawer a:last-child{border-bottom:0;}
|
||||
.fb-nav .drawer .user{margin:10px 0 0;padding-top:10px;border-top:1px solid var(--border);}
|
||||
|
||||
/* ---------- 主体布局 ---------- */
|
||||
.fb-main{flex:1 0 auto;padding:18px 0 40px;}
|
||||
.fb-layout{display:grid;grid-template-columns:1fr 312px;gap:22px;align-items:start;}
|
||||
.fb-content{min-width:0;}
|
||||
.fb-section-title{display:flex;align-items:center;justify-content:space-between;margin:6px 0 16px;}
|
||||
.fb-section-title h2{font-size:19px;position:relative;padding-left:12px;margin:0;}
|
||||
.fb-section-title h2::before{content:"";position:absolute;left:0;top:3px;bottom:3px;width:4px;background:var(--theme);border-radius:2px;}
|
||||
.fb-empty{background:var(--card);border-radius:var(--radius);padding:50px;text-align:center;color:var(--text-3);box-shadow:var(--shadow);}
|
||||
|
||||
/* ---------- 卡片 / 文章列表卡 ---------- */
|
||||
.fb-card{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);padding:18px 20px;}
|
||||
.fb-post-list{display:flex;flex-direction:column;gap:16px;}
|
||||
.fb-post{display:flex;background:var(--card);border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow);transition:.25s;}
|
||||
.fb-post:hover{transform:translateY(-3px);box-shadow:var(--shadow-hover);}
|
||||
.fb-post .thumb{width:230px;flex-shrink:0;background:#eef0f3;}
|
||||
.fb-post .thumb img{width:100%;height:100%;min-height:168px;object-fit:cover;}
|
||||
.fb-post .body{flex:1;padding:16px 18px;display:flex;flex-direction:column;min-width:0;}
|
||||
.fb-post .cat{align-self:flex-start;font-size:12px;color:var(--theme);background:color-mix(in srgb,var(--theme) 12%,#fff);padding:2px 10px;border-radius:10px;margin-bottom:8px;}
|
||||
.fb-post h3{font-size:17px;margin:0 0 8px;line-height:1.4;}
|
||||
.fb-post h3 a:hover{color:var(--theme);}
|
||||
.fb-post .summary{color:var(--text-3);font-size:14px;flex:1;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;word-break:break-word;overflow-wrap:anywhere;margin:0 0 10px;}
|
||||
.fb-post .meta{display:flex;align-items:center;gap:14px;font-size:13px;color:var(--text-3);flex-wrap:wrap;}
|
||||
.fb-post .meta .author{display:flex;align-items:center;gap:6px;color:var(--text-2);}
|
||||
.fb-post .meta .author img{width:22px;height:22px;border-radius:50%;}
|
||||
.fb-post .meta .sp{margin-left:auto;}
|
||||
.fb-post .meta i.layui-icon{color:var(--theme);}
|
||||
|
||||
/* Hero 推荐 */
|
||||
.fb-hero{margin:4px 0 18px;}
|
||||
.fb-hero-grid{display:grid;grid-template-columns:2fr 1fr;gap:14px;height:300px;}
|
||||
.fb-hero-main,.fb-hero-sub-item{position:relative;border-radius:var(--radius);overflow:hidden;background:#ddd;display:block;}
|
||||
.fb-hero-main img,.fb-hero-sub-item img{width:100%;height:100%;object-fit:cover;transition:.4s;}
|
||||
.fb-hero-main:hover img,.fb-hero-sub-item:hover img{transform:scale(1.05);}
|
||||
.fb-hero-sub{display:grid;grid-template-rows:1fr 1fr;gap:14px;}
|
||||
.fb-hero-cap{position:absolute;left:0;right:0;bottom:0;padding:22px 18px 14px;background:linear-gradient(transparent,rgba(0,0,0,.72));color:#fff;}
|
||||
.fb-hero-cap .tag{display:inline-block;background:var(--theme);font-size:12px;padding:2px 10px;border-radius:12px;margin-bottom:8px;}
|
||||
.fb-hero-main .fb-hero-cap h2{font-size:21px;margin:0;}
|
||||
.fb-hero-sub-item .fb-hero-cap h3{font-size:15px;margin:0;}
|
||||
|
||||
/* ---------- 侧栏 widget ---------- */
|
||||
.fb-aside{display:flex;flex-direction:column;gap:18px;}
|
||||
.fb-widget{background:var(--card);border-radius:var(--radius);padding:16px 18px;box-shadow:var(--shadow);}
|
||||
.fb-widget h4{font-size:16px;margin:0 0 12px;padding-bottom:10px;border-bottom:1px solid var(--border);}
|
||||
.fb-stat{display:grid;grid-template-columns:repeat(3,1fr);text-align:center;}
|
||||
.fb-stat .num{font-size:20px;font-weight:700;color:var(--theme);}
|
||||
.fb-stat .lbl{font-size:12px;color:var(--text-3);}
|
||||
.fb-hot li{list-style:none;padding:9px 0;border-bottom:1px dashed #eee;display:flex;gap:10px;align-items:baseline;}
|
||||
.fb-hot li:last-child{border-bottom:0;}
|
||||
.fb-hot .rank{width:20px;height:20px;flex-shrink:0;text-align:center;line-height:20px;font-size:12px;border-radius:4px;background:#f0f0f0;color:var(--text-3);}
|
||||
.fb-hot li:nth-child(1) .rank{background:#ff4d4f;color:#fff;}
|
||||
.fb-hot li:nth-child(2) .rank{background:#ff7a45;color:#fff;}
|
||||
.fb-hot li:nth-child(3) .rank{background:#ffa940;color:#fff;}
|
||||
.fb-hot a{font-size:14px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
||||
.fb-hot a:hover{color:var(--theme);}
|
||||
.fb-catlist li{list-style:none;}
|
||||
.fb-catlist a{display:flex;justify-content:space-between;padding:9px 0;border-bottom:1px dashed #eee;font-size:14px;color:var(--text);}
|
||||
.fb-catlist li:last-child a{border-bottom:0;}
|
||||
.fb-catlist a:hover{color:var(--theme);}
|
||||
.fb-catlist .cnt{color:#bbb;font-size:12px;}
|
||||
.fb-tagcloud a{display:inline-block;padding:5px 12px;margin:0 8px 8px 0;background:#f2f3f5;border-radius:14px;font-size:13px;color:var(--text-2);transition:.2s;}
|
||||
.fb-tagcloud a:hover{background:var(--theme);color:#fff;}
|
||||
.fb-cmt li{list-style:none;padding:10px 0;border-bottom:1px dashed #eee;font-size:13px;}
|
||||
.fb-cmt li:last-child{border-bottom:0;}
|
||||
.fb-cmt .who{color:var(--theme);}
|
||||
.fb-cmt .txt{color:var(--text-2);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
|
||||
|
||||
/* ---------- 按钮 / 标签 ---------- */
|
||||
.fb-btn{display:inline-flex;align-items:center;gap:6px;border:0;background:var(--theme);color:#fff;padding:9px 18px;border-radius:var(--radius-sm);cursor:pointer;font-size:14px;transition:.2s;}
|
||||
.fb-btn:hover{background:var(--theme-dark);}
|
||||
.fb-btn.ghost{background:color-mix(in srgb,var(--theme) 12%,#fff);color:var(--theme);}
|
||||
.layui-btn{background:var(--theme);}
|
||||
.fb-pager{display:flex;justify-content:center;gap:6px;margin-top:22px;flex-wrap:wrap;}
|
||||
.fb-pager a,.fb-pager span,.fb-pager .layui-laypage a{padding:7px 13px;border-radius:var(--radius-sm);background:var(--card);color:var(--text-2);box-shadow:var(--shadow);}
|
||||
.fb-pager .active,.fb-pager .layui-laypage .layui-laypage-curr{background:var(--theme);color:#fff;}
|
||||
|
||||
/* ---------- 详情页 ---------- */
|
||||
.fb-article{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);padding:22px 24px;margin-bottom:18px;}
|
||||
.fb-article .crumb{font-size:13px;color:var(--text-3);margin-bottom:10px;}
|
||||
.fb-article .crumb a{color:var(--theme);}
|
||||
.fb-article h1{font-size:24px;margin:0 0 12px;line-height:1.4;}
|
||||
.fb-article .post-meta{display:flex;align-items:center;gap:14px;font-size:13px;color:var(--text-3);flex-wrap:wrap;padding-bottom:14px;border-bottom:1px solid var(--border);margin-bottom:16px;}
|
||||
.fb-article .post-meta .author{display:flex;align-items:center;gap:6px;color:var(--text-2);}
|
||||
.fb-article .post-meta .author img{width:24px;height:24px;border-radius:50%;}
|
||||
.fb-article .post-meta i.layui-icon{color:var(--theme);}
|
||||
.fb-article .cover{margin:0 0 16px;border-radius:var(--radius-sm);overflow:hidden;}
|
||||
.fb-article .content{font-size:15px;color:#444;line-height:1.85;}
|
||||
.fb-article .content img{max-width:100%;border-radius:var(--radius-sm);margin:10px 0;}
|
||||
.fb-article .content pre{background:#f6f8fa;padding:14px;border-radius:var(--radius-sm);overflow:auto;}
|
||||
.fb-article .action-bar{display:flex;gap:10px;margin-top:20px;flex-wrap:wrap;}
|
||||
.fb-article .action-bar .fb-btn i{font-size:16px;}
|
||||
|
||||
/* 评论区 */
|
||||
.fb-comments{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);padding:18px 20px;}
|
||||
.fb-comments .ct-title{font-size:16px;font-weight:700;margin:0 0 14px;}
|
||||
.fb-comments .ct-title em{color:var(--theme);font-style:normal;}
|
||||
.fb-cmt-form{margin-bottom:16px;}
|
||||
.fb-cmt-form textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px 12px;font-size:14px;resize:vertical;font-family:inherit;outline:none;}
|
||||
.fb-cmt-form textarea:focus{border-color:var(--theme);}
|
||||
.fb-cmt-item{display:flex;gap:12px;padding:14px 0;border-bottom:1px solid var(--border);}
|
||||
.fb-cmt-item:last-child{border-bottom:0;}
|
||||
.fb-cmt-item>img{width:40px;height:40px;border-radius:50%;flex-shrink:0;}
|
||||
.fb-cmt-item .ci-body{flex:1;min-width:0;}
|
||||
.fb-cmt-item .ci-name{color:var(--theme);font-weight:600;font-size:14px;}
|
||||
.fb-cmt-item .ci-time{color:var(--text-3);font-size:12px;margin-left:8px;}
|
||||
.fb-cmt-item .ci-text{margin:4px 0 0;color:var(--text);font-size:14px;word-break:break-word;}
|
||||
.fb-cmt-item .ci-reply{color:var(--theme);font-size:13px;margin-left:8px;cursor:pointer;}
|
||||
.fb-cmt-children{list-style:none;margin:12px 0 0 52px;padding:0 0 0 12px;border-left:2px solid color-mix(in srgb,var(--theme) 20%,#fff);}
|
||||
.fb-cmt-children li{display:flex;gap:10px;padding:10px 0;}
|
||||
.fb-cmt-children img{width:32px;height:32px;border-radius:50%;flex-shrink:0;}
|
||||
|
||||
/* ---------- 通用内容页(关于/联系) ---------- */
|
||||
.fb-page{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);padding:24px;}
|
||||
.fb-page h3{font-size:20px;margin:0 0 14px;color:var(--text);}
|
||||
.fb-page p{color:var(--text-2);margin:0 0 12px;}
|
||||
.fb-page .lead{font-size:15px;}
|
||||
|
||||
/* ---------- 底部 Tab 导航(移动端) ---------- */
|
||||
.fb-tabbar{display:none;position:fixed;left:0;right:0;bottom:0;z-index:200;height:var(--tab-h);
|
||||
background:var(--card);box-shadow:0 -2px 12px rgba(0,0,0,.06);border-top:1px solid var(--border);}
|
||||
.fb-tabbar a{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;font-size:11px;color:var(--text-3);}
|
||||
.fb-tabbar a i.layui-icon{font-size:22px;}
|
||||
.fb-tabbar a.active{color:var(--theme);}
|
||||
|
||||
/* ---------- 页脚 ---------- */
|
||||
.fb-footer{flex-shrink:0;background:#222;color:#aaa;text-align:center;padding:24px 16px;font-size:13px;margin-top:auto;}
|
||||
.fb-footer a{color:#ccc;}
|
||||
|
||||
/* =========================================================
|
||||
* 旧 class 兜底(尚未迁移的页面沿用,浅色化避免裸奔)
|
||||
* ========================================================= */
|
||||
.main.article,.main.about,.main.mood{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);padding:18px 20px;margin-bottom:18px;}
|
||||
.item{display:flex;gap:14px;padding:14px 0;border-bottom:1px solid var(--border);}
|
||||
.item:last-child{border-bottom:0;}
|
||||
.item>img{width:160px;height:120px;object-fit:cover;border-radius:var(--radius-sm);flex-shrink:0;background:#eee;}
|
||||
.item .item-content{flex:1;min-width:0;}
|
||||
.item .item-content h3{font-size:17px;margin:0 0 6px;}
|
||||
.item .item-content h3 a:hover{color:var(--theme);}
|
||||
.item .item-content .Subtitle{color:var(--theme);font-size:13px;margin-right:10px;}
|
||||
.item .item-content .author-link a{color:var(--text-2);font-size:13px;}
|
||||
.item .item-content p{color:var(--text-3);margin:6px 0;}
|
||||
.item .date-box{flex-shrink:0;text-align:center;color:var(--theme);}
|
||||
.item .date-box h4{font-size:20px;margin:0;}
|
||||
.item .date-box span{font-size:12px;color:var(--text-3);}
|
||||
.cat-list{list-style:none;padding:0;margin:0;}
|
||||
.cat-list a{display:flex;justify-content:space-between;padding:9px 0;border-bottom:1px dashed var(--border);color:var(--text);}
|
||||
.cat-list a:hover{color:var(--theme);}
|
||||
.tag-cloud a{display:inline-block;padding:5px 12px;margin:0 8px 8px 0;background:#f2f3f5;border-radius:14px;font-size:13px;color:var(--text-2);}
|
||||
.tag-cloud a:hover{background:var(--theme);color:#fff;}
|
||||
.top_title{font-size:14px;color:var(--text-3);margin-bottom:14px;}
|
||||
.item1 .item-content h3{font-size:22px;margin:0 0 10px;}
|
||||
.item1 .item-content .label span{margin-right:12px;font-size:13px;color:var(--text-3);}
|
||||
.item1 .item-content .label .Subtitle{color:var(--theme);}
|
||||
.item1 .img-box{margin:14px 0;}
|
||||
.item1 .txt{font-size:15px;color:#444;line-height:1.85;}
|
||||
.btn-box{margin-top:16px;}
|
||||
.txt .layui-btn,.item1 .layui-btn{margin-right:8px;}
|
||||
|
||||
/* =========================================================
|
||||
* 响应式断点
|
||||
* ========================================================= */
|
||||
@media (max-width:980px){
|
||||
.fb-layout{grid-template-columns:1fr;}
|
||||
.fb-hero-grid{grid-template-columns:1fr;height:auto;}
|
||||
.fb-hero-main{height:220px;}
|
||||
.fb-hero-sub{grid-template-rows:none;grid-template-columns:1fr 1fr;}
|
||||
.fb-hero-sub-item{height:150px;}
|
||||
}
|
||||
@media (max-width:860px){
|
||||
.fb-nav .menu,.fb-nav .search,.fb-nav .user{display:none;}
|
||||
.fb-nav .hamburger{display:block;}
|
||||
.fb-post{flex-direction:column;}
|
||||
.fb-post .thumb{width:100%;height:180px;}
|
||||
.fb-post .thumb img{min-height:0;}
|
||||
/* 移动端显示底部 Tab 导航 */
|
||||
.fb-tabbar{display:flex;}
|
||||
body.has-tab{padding-bottom:calc(var(--tab-h) + 8px);}
|
||||
.item>img{width:110px;height:84px;}
|
||||
.fb-article{padding:16px;}
|
||||
.fb-article h1{font-size:20px;}
|
||||
}
|
||||
@media (max-width:480px){
|
||||
.container,.fb-wrap{padding:0 10px;}
|
||||
.fb-post .body{padding:12px 14px;}
|
||||
.fb-cmt-children{margin-left:14px;}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 296 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
@@ -0,0 +1,490 @@
|
||||
/* ==========================================================================
|
||||
YwxApp 文档中心前台样式
|
||||
三栏布局:左侧目录树 / 中间正文 / 右侧本页锚点
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
--dc-primary: #2f6fed;
|
||||
--dc-primary-soft: #eaf1ff;
|
||||
--dc-text: #24292f;
|
||||
--dc-text-sub: #656d76;
|
||||
--dc-border: #e6e8eb;
|
||||
--dc-bg: #ffffff;
|
||||
--dc-bg-soft: #f7f8fa;
|
||||
--dc-code-bg: #f6f8fa;
|
||||
--dc-header-h: 60px;
|
||||
--dc-sidebar-w: 268px;
|
||||
--dc-toc-w: 220px;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
html { scroll-behavior: smooth; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--dc-bg);
|
||||
color: var(--dc-text);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
|
||||
"Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;
|
||||
font-size: 15px;
|
||||
line-height: 1.7;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
a { color: var(--dc-primary); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
|
||||
/* ---------------------------- 顶部导航 ---------------------------- */
|
||||
.dc-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
height: var(--dc-header-h);
|
||||
background: rgba(255, 255, 255, .92);
|
||||
backdrop-filter: saturate(180%) blur(8px);
|
||||
border-bottom: 1px solid var(--dc-border);
|
||||
}
|
||||
|
||||
.dc-header-inner {
|
||||
max-width: 1440px;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 0 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.dc-logo { display: flex; align-items: center; gap: 9px; flex-shrink: 0; }
|
||||
.dc-logo:hover { text-decoration: none; }
|
||||
|
||||
.dc-logo-mark {
|
||||
width: 30px; height: 30px;
|
||||
border-radius: 7px;
|
||||
background: linear-gradient(135deg, #2f6fed, #6c47ff);
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
|
||||
.dc-logo-text { font-size: 16px; font-weight: 600; color: var(--dc-text); }
|
||||
|
||||
.dc-nav { display: flex; align-items: center; gap: 20px; flex: 1; overflow: hidden; }
|
||||
.dc-nav a { color: var(--dc-text-sub); font-size: 14px; white-space: nowrap; }
|
||||
.dc-nav a:hover { color: var(--dc-primary); text-decoration: none; }
|
||||
|
||||
.dc-search { position: relative; flex-shrink: 0; }
|
||||
.dc-search input {
|
||||
width: 210px; height: 34px;
|
||||
padding: 0 34px 0 12px;
|
||||
border: 1px solid var(--dc-border);
|
||||
border-radius: 17px;
|
||||
background: var(--dc-bg-soft);
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
transition: all .2s;
|
||||
}
|
||||
.dc-search input:focus {
|
||||
width: 250px;
|
||||
border-color: var(--dc-primary);
|
||||
background: #fff;
|
||||
}
|
||||
.dc-search button {
|
||||
position: absolute; right: 4px; top: 3px;
|
||||
width: 28px; height: 28px;
|
||||
border: none; background: none;
|
||||
color: var(--dc-text-sub);
|
||||
cursor: pointer;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
|
||||
.dc-menu-toggle {
|
||||
display: none;
|
||||
width: 34px; height: 34px;
|
||||
border: 1px solid var(--dc-border);
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
flex-direction: column; align-items: center; justify-content: center; gap: 4px;
|
||||
}
|
||||
.dc-menu-toggle span { display: block; width: 16px; height: 2px; background: var(--dc-text); }
|
||||
|
||||
/* ---------------------------- 三栏骨架 ---------------------------- */
|
||||
.dc-layout {
|
||||
max-width: 1440px;
|
||||
margin: 0 auto;
|
||||
padding: 0 24px;
|
||||
display: grid;
|
||||
grid-template-columns: var(--dc-sidebar-w) minmax(0, 1fr) var(--dc-toc-w);
|
||||
gap: 36px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
/* ---------------------------- 左侧目录 ---------------------------- */
|
||||
.dc-sidebar {
|
||||
position: sticky;
|
||||
top: var(--dc-header-h);
|
||||
max-height: calc(100vh - var(--dc-header-h));
|
||||
overflow-y: auto;
|
||||
padding: 22px 8px 40px 0;
|
||||
border-right: 1px solid var(--dc-border);
|
||||
}
|
||||
|
||||
.dc-sidebar::-webkit-scrollbar { width: 6px; }
|
||||
.dc-sidebar::-webkit-scrollbar-thumb { background: #d8dce1; border-radius: 3px; }
|
||||
|
||||
.dc-sidebar-head { padding: 0 10px 14px; border-bottom: 1px solid var(--dc-border); margin-bottom: 12px; }
|
||||
.dc-project-title { font-size: 15px; font-weight: 600; margin-bottom: 8px; }
|
||||
|
||||
.dc-version-select {
|
||||
width: 100%; height: 30px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid var(--dc-border);
|
||||
border-radius: 6px;
|
||||
background: var(--dc-bg-soft);
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dc-tree ul { list-style: none; margin: 0; padding: 0; }
|
||||
.dc-tree > ul > li > .dc-tree-item > .dc-tree-link { font-weight: 600; color: var(--dc-text); }
|
||||
.dc-tree ul ul { padding-left: 14px; display: none; }
|
||||
.dc-tree li.is-open > ul { display: block; }
|
||||
|
||||
.dc-tree-item {
|
||||
display: flex; align-items: center;
|
||||
border-radius: 6px;
|
||||
margin: 1px 0;
|
||||
transition: background .15s;
|
||||
}
|
||||
.dc-tree-item:hover { background: var(--dc-bg-soft); }
|
||||
.dc-tree-item.is-active { background: var(--dc-primary-soft); }
|
||||
.dc-tree-item.is-active > .dc-tree-link { color: var(--dc-primary); font-weight: 600; }
|
||||
|
||||
.dc-tree-toggle {
|
||||
width: 18px; height: 28px;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.dc-tree-toggle::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 6px; top: 11px;
|
||||
width: 5px; height: 5px;
|
||||
border-right: 1.5px solid var(--dc-text-sub);
|
||||
border-bottom: 1.5px solid var(--dc-text-sub);
|
||||
transform: rotate(-45deg);
|
||||
transition: transform .18s;
|
||||
}
|
||||
li.is-open > .dc-tree-item > .dc-tree-toggle::before { transform: rotate(45deg); }
|
||||
|
||||
.dc-tree-link {
|
||||
flex: 1;
|
||||
padding: 5px 10px 5px 4px;
|
||||
font-size: 14px;
|
||||
color: var(--dc-text-sub);
|
||||
line-height: 1.5;
|
||||
word-break: break-word;
|
||||
}
|
||||
.dc-tree-link:hover { color: var(--dc-primary); text-decoration: none; }
|
||||
.dc-tree-link.is-dir { cursor: pointer; color: var(--dc-text); font-weight: 500; }
|
||||
|
||||
/* 没有折叠箭头的节点需要补齐缩进,保持文字左对齐 */
|
||||
.dc-tree-item > .dc-tree-link:first-child { padding-left: 22px; }
|
||||
|
||||
/* ---------------------------- 中间正文 ---------------------------- */
|
||||
.dc-main { min-width: 0; padding: 22px 0 60px; }
|
||||
|
||||
.dc-crumbs { font-size: 13px; color: var(--dc-text-sub); margin-bottom: 18px; }
|
||||
.dc-crumb-sep { margin: 0 7px; color: #c9ced4; }
|
||||
.dc-crumb-current { color: var(--dc-text); }
|
||||
|
||||
.dc-article-title {
|
||||
font-size: 30px;
|
||||
line-height: 1.35;
|
||||
margin: 0 0 12px;
|
||||
font-weight: 650;
|
||||
letter-spacing: -.3px;
|
||||
}
|
||||
|
||||
.dc-article-meta { font-size: 13px; color: var(--dc-text-sub); padding-bottom: 18px; border-bottom: 1px solid var(--dc-border); }
|
||||
.dc-dot { margin: 0 8px; }
|
||||
|
||||
/* 正文排版 */
|
||||
.dc-content { padding-top: 22px; }
|
||||
.dc-content h2 {
|
||||
font-size: 22px;
|
||||
margin: 34px 0 14px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid var(--dc-border);
|
||||
scroll-margin-top: calc(var(--dc-header-h) + 16px);
|
||||
}
|
||||
.dc-content h3 {
|
||||
font-size: 18px;
|
||||
margin: 26px 0 12px;
|
||||
scroll-margin-top: calc(var(--dc-header-h) + 16px);
|
||||
}
|
||||
.dc-content h4 { font-size: 16px; margin: 20px 0 10px; }
|
||||
.dc-content p { margin: 0 0 15px; }
|
||||
.dc-content ul, .dc-content ol { margin: 0 0 15px; padding-left: 26px; }
|
||||
.dc-content li { margin: 5px 0; }
|
||||
.dc-content img { max-width: 100%; border-radius: 6px; }
|
||||
|
||||
.dc-content blockquote {
|
||||
margin: 0 0 15px;
|
||||
padding: 10px 16px;
|
||||
border-left: 4px solid var(--dc-primary);
|
||||
background: var(--dc-primary-soft);
|
||||
border-radius: 0 6px 6px 0;
|
||||
color: var(--dc-text-sub);
|
||||
}
|
||||
.dc-content blockquote p:last-child { margin-bottom: 0; }
|
||||
|
||||
.dc-content code {
|
||||
padding: 2px 6px;
|
||||
background: var(--dc-code-bg);
|
||||
border-radius: 4px;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
|
||||
font-size: 13px;
|
||||
color: #d63384;
|
||||
}
|
||||
|
||||
.dc-content pre {
|
||||
position: relative;
|
||||
margin: 0 0 18px;
|
||||
padding: 16px;
|
||||
background: #1f2430;
|
||||
border-radius: 8px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.dc-content pre code {
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: #e6e6e6;
|
||||
font-size: 13px;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.dc-copy-btn {
|
||||
position: absolute;
|
||||
top: 8px; right: 8px;
|
||||
padding: 3px 10px;
|
||||
border: 1px solid rgba(255, 255, 255, .2);
|
||||
border-radius: 5px;
|
||||
background: rgba(255, 255, 255, .08);
|
||||
color: #cfd4dc;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity .18s;
|
||||
}
|
||||
.dc-content pre:hover .dc-copy-btn { opacity: 1; }
|
||||
.dc-copy-btn:hover { background: rgba(255, 255, 255, .18); color: #fff; }
|
||||
.dc-copy-btn.is-done { color: #7ee2a8; border-color: rgba(126, 226, 168, .4); }
|
||||
|
||||
.dc-content table {
|
||||
width: 100%;
|
||||
margin: 0 0 18px;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
}
|
||||
.dc-content th, .dc-content td { padding: 9px 12px; border: 1px solid var(--dc-border); text-align: left; }
|
||||
.dc-content th { background: var(--dc-bg-soft); font-weight: 600; }
|
||||
.dc-content tr:nth-child(even) td { background: #fbfcfd; }
|
||||
|
||||
.dc-content hr { margin: 28px 0; border: none; border-top: 1px solid var(--dc-border); }
|
||||
|
||||
/* 上下篇 */
|
||||
.dc-pager { display: flex; gap: 16px; margin-top: 44px; }
|
||||
.dc-pager-item {
|
||||
flex: 1;
|
||||
padding: 14px 18px;
|
||||
border: 1px solid var(--dc-border);
|
||||
border-radius: 8px;
|
||||
transition: all .18s;
|
||||
min-height: 66px;
|
||||
}
|
||||
a.dc-pager-item:hover { border-color: var(--dc-primary); background: var(--dc-primary-soft); text-decoration: none; }
|
||||
.dc-pager-item.is-disabled { border: none; background: none; }
|
||||
.dc-pager-next { text-align: right; }
|
||||
.dc-pager-label { display: block; font-size: 12px; color: var(--dc-text-sub); margin-bottom: 4px; }
|
||||
.dc-pager-title { display: block; font-size: 14px; font-weight: 500; color: var(--dc-text); }
|
||||
|
||||
/* ---------------------------- 右侧锚点 ---------------------------- */
|
||||
.dc-toc {
|
||||
position: sticky;
|
||||
top: var(--dc-header-h);
|
||||
max-height: calc(100vh - var(--dc-header-h));
|
||||
overflow-y: auto;
|
||||
padding: 30px 0 40px;
|
||||
}
|
||||
|
||||
.dc-toc-title { font-size: 12px; font-weight: 600; color: var(--dc-text-sub); letter-spacing: .5px; text-transform: uppercase; margin-bottom: 10px; }
|
||||
|
||||
.dc-toc-list { list-style: none; margin: 0; padding: 0; border-left: 2px solid var(--dc-border); }
|
||||
.dc-toc-list li a {
|
||||
display: block;
|
||||
padding: 4px 0 4px 12px;
|
||||
margin-left: -2px;
|
||||
border-left: 2px solid transparent;
|
||||
font-size: 13px;
|
||||
color: var(--dc-text-sub);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.dc-toc-list li a:hover { color: var(--dc-primary); text-decoration: none; }
|
||||
.dc-toc-list li a.is-active { color: var(--dc-primary); border-left-color: var(--dc-primary); font-weight: 500; }
|
||||
.dc-toc-h3 a { padding-left: 24px !important; font-size: 12.5px; }
|
||||
|
||||
/* ---------------------------- 首页 ---------------------------- */
|
||||
.dc-hero {
|
||||
padding: 66px 24px 54px;
|
||||
background: linear-gradient(160deg, #f4f7ff 0%, #ffffff 100%);
|
||||
border-bottom: 1px solid var(--dc-border);
|
||||
text-align: center;
|
||||
}
|
||||
.dc-hero-inner { max-width: 720px; margin: 0 auto; }
|
||||
.dc-hero h1 { font-size: 36px; margin: 0 0 12px; font-weight: 700; letter-spacing: -.5px; }
|
||||
.dc-hero p { color: var(--dc-text-sub); margin: 0 0 26px; font-size: 16px; }
|
||||
|
||||
.dc-hero-search { display: flex; gap: 10px; max-width: 520px; margin: 0 auto; }
|
||||
.dc-hero-search input {
|
||||
flex: 1; height: 44px;
|
||||
padding: 0 16px;
|
||||
border: 1px solid var(--dc-border);
|
||||
border-radius: 8px;
|
||||
font-size: 15px;
|
||||
outline: none;
|
||||
}
|
||||
.dc-hero-search input:focus { border-color: var(--dc-primary); }
|
||||
.dc-hero-search button {
|
||||
height: 44px; padding: 0 26px;
|
||||
border: none; border-radius: 8px;
|
||||
background: var(--dc-primary);
|
||||
color: #fff; font-size: 15px; cursor: pointer;
|
||||
}
|
||||
.dc-hero-search button:hover { background: #2560d8; }
|
||||
|
||||
.dc-projects { max-width: 1200px; margin: 0 auto; padding: 44px 24px 60px; }
|
||||
.dc-project-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 20px; }
|
||||
|
||||
.dc-project-card {
|
||||
padding: 22px;
|
||||
border: 1px solid var(--dc-border);
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
transition: all .2s;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
.dc-project-card:hover { border-color: var(--dc-primary); box-shadow: 0 6px 20px rgba(47, 111, 237, .1); transform: translateY(-2px); }
|
||||
|
||||
.dc-project-head { display: flex; gap: 14px; margin-bottom: 14px; }
|
||||
.dc-project-icon {
|
||||
width: 46px; height: 46px; flex-shrink: 0;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(135deg, #2f6fed, #6c47ff);
|
||||
color: #fff;
|
||||
font-size: 20px; font-weight: 700;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
.dc-project-icon img { width: 100%; height: 100%; object-fit: cover; }
|
||||
.dc-project-info h2 { font-size: 17px; margin: 0 0 5px; }
|
||||
.dc-project-info h2 a { color: var(--dc-text); }
|
||||
.dc-project-info p { margin: 0; font-size: 13px; color: var(--dc-text-sub); line-height: 1.6; }
|
||||
|
||||
.dc-project-meta { display: flex; gap: 10px; align-items: center; font-size: 12px; color: var(--dc-text-sub); margin-bottom: 14px; }
|
||||
.dc-tag { padding: 2px 8px; background: var(--dc-bg-soft); border-radius: 4px; }
|
||||
|
||||
.dc-project-recent { list-style: none; margin: 0 0 16px; padding: 12px 0 0; border-top: 1px dashed var(--dc-border); flex: 1; }
|
||||
.dc-project-recent li { margin: 6px 0; font-size: 13px; }
|
||||
.dc-project-recent li a { color: var(--dc-text-sub); }
|
||||
.dc-project-recent li a::before { content: '›'; margin-right: 6px; color: #c9ced4; }
|
||||
.dc-project-recent li a:hover { color: var(--dc-primary); text-decoration: none; }
|
||||
|
||||
.dc-project-enter { font-size: 13.5px; font-weight: 500; }
|
||||
|
||||
/* ---------------------------- 搜索页 ---------------------------- */
|
||||
.dc-search-page { max-width: 820px; margin: 0 auto; padding: 40px 24px 60px; }
|
||||
.dc-search-form { display: flex; gap: 10px; margin-bottom: 26px; }
|
||||
.dc-search-form input { flex: 1; height: 42px; padding: 0 14px; border: 1px solid var(--dc-border); border-radius: 8px; font-size: 15px; outline: none; }
|
||||
.dc-search-form input:focus { border-color: var(--dc-primary); }
|
||||
.dc-search-form select { height: 42px; padding: 0 10px; border: 1px solid var(--dc-border); border-radius: 8px; background: #fff; outline: none; cursor: pointer; }
|
||||
.dc-search-form button { height: 42px; padding: 0 24px; border: none; border-radius: 8px; background: var(--dc-primary); color: #fff; font-size: 15px; cursor: pointer; }
|
||||
|
||||
.dc-search-summary { font-size: 14px; color: var(--dc-text-sub); padding-bottom: 14px; border-bottom: 1px solid var(--dc-border); }
|
||||
.dc-search-list { list-style: none; margin: 0; padding: 0; }
|
||||
.dc-search-list li { padding: 18px 0; border-bottom: 1px solid var(--dc-border); }
|
||||
.dc-search-title { font-size: 17px; font-weight: 600; }
|
||||
.dc-search-path { font-size: 12px; color: var(--dc-text-sub); margin: 5px 0 7px; }
|
||||
.dc-search-snippet { margin: 0; font-size: 14px; color: var(--dc-text-sub); line-height: 1.7; }
|
||||
.dc-search-snippet mark { background: #fff3bf; color: inherit; padding: 0 2px; border-radius: 2px; }
|
||||
|
||||
/* ---------------------------- 空态与 404 ---------------------------- */
|
||||
.dc-empty { padding: 70px 20px; text-align: center; color: var(--dc-text-sub); }
|
||||
.dc-empty p { margin: 6px 0; }
|
||||
.dc-empty-tip { font-size: 13px; color: #9aa1a9; }
|
||||
|
||||
.dc-notfound { max-width: 560px; margin: 0 auto; padding: 90px 24px; text-align: center; }
|
||||
.dc-notfound-code { font-size: 84px; font-weight: 800; color: var(--dc-primary-soft); line-height: 1; }
|
||||
.dc-notfound h1 { font-size: 21px; margin: 12px 0 8px; }
|
||||
.dc-notfound p { color: var(--dc-text-sub); margin: 0 0 26px; }
|
||||
.dc-notfound-ops { display: flex; gap: 12px; justify-content: center; }
|
||||
|
||||
.dc-btn { display: inline-block; padding: 9px 22px; border: 1px solid var(--dc-border); border-radius: 7px; color: var(--dc-text); font-size: 14px; }
|
||||
.dc-btn:hover { text-decoration: none; border-color: var(--dc-primary); color: var(--dc-primary); }
|
||||
.dc-btn-primary { background: var(--dc-primary); border-color: var(--dc-primary); color: #fff; }
|
||||
.dc-btn-primary:hover { background: #2560d8; color: #fff; }
|
||||
|
||||
/* ---------------------------- 页脚 ---------------------------- */
|
||||
.dc-footer { padding: 26px 24px; border-top: 1px solid var(--dc-border); text-align: center; color: var(--dc-text-sub); font-size: 13px; }
|
||||
.dc-footer p { margin: 0; }
|
||||
|
||||
/* ---------------------------- 遮罩 ---------------------------- */
|
||||
.dc-mask {
|
||||
display: none;
|
||||
position: fixed; inset: 0;
|
||||
background: rgba(0, 0, 0, .4);
|
||||
z-index: 98;
|
||||
}
|
||||
.dc-mask.is-show { display: block; }
|
||||
|
||||
/* ---------------------------- 响应式 ---------------------------- */
|
||||
@media (max-width: 1180px) {
|
||||
.dc-layout { grid-template-columns: var(--dc-sidebar-w) minmax(0, 1fr); }
|
||||
.dc-toc { display: none; }
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.dc-nav { display: none; }
|
||||
.dc-menu-toggle { display: flex; }
|
||||
.dc-search input { width: 140px; }
|
||||
.dc-search input:focus { width: 170px; }
|
||||
|
||||
.dc-layout { grid-template-columns: minmax(0, 1fr); padding: 0 16px; }
|
||||
|
||||
.dc-sidebar {
|
||||
position: fixed;
|
||||
top: var(--dc-header-h);
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
width: 280px;
|
||||
height: calc(100vh - var(--dc-header-h));
|
||||
max-height: none;
|
||||
padding: 18px 14px 40px;
|
||||
background: #fff;
|
||||
border-right: 1px solid var(--dc-border);
|
||||
transform: translateX(-100%);
|
||||
transition: transform .25s;
|
||||
}
|
||||
.dc-sidebar.is-open { transform: translateX(0); }
|
||||
|
||||
.dc-article-title { font-size: 24px; }
|
||||
.dc-pager { flex-direction: column; }
|
||||
.dc-hero h1 { font-size: 27px; }
|
||||
.dc-project-grid { grid-template-columns: 1fr; }
|
||||
.dc-search-form { flex-wrap: wrap; }
|
||||
.dc-search-form input { flex: 1 1 100%; }
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* YwxApp 文档中心前台脚本
|
||||
*
|
||||
* 提供:目录折叠、移动端抽屉、代码复制、右侧锚点滚动高亮、版本切换。
|
||||
* 纯原生实现,不依赖任何库。
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
initTreeToggle();
|
||||
initMobileDrawer();
|
||||
initCodeCopy();
|
||||
initTocScrollSpy();
|
||||
initVersionSwitch();
|
||||
scrollActiveIntoView();
|
||||
});
|
||||
|
||||
/**
|
||||
* 侧边目录展开与折叠
|
||||
*/
|
||||
function initTreeToggle() {
|
||||
var tree = document.querySelector('.dc-tree');
|
||||
if (!tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
tree.addEventListener('click', function (e) {
|
||||
var toggle = e.target.closest('.dc-tree-toggle');
|
||||
var dirLink = e.target.closest('.dc-tree-link.is-dir');
|
||||
var trigger = toggle || dirLink;
|
||||
|
||||
if (!trigger) {
|
||||
return;
|
||||
}
|
||||
|
||||
var li = trigger.closest('li');
|
||||
if (li) {
|
||||
li.classList.toggle('is-open');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动端侧边栏抽屉
|
||||
*/
|
||||
function initMobileDrawer() {
|
||||
var btn = document.getElementById('dcMenuToggle');
|
||||
var sidebar = document.getElementById('dcSidebar');
|
||||
var mask = document.getElementById('dcMask');
|
||||
|
||||
if (!btn || !sidebar) {
|
||||
return;
|
||||
}
|
||||
|
||||
function close() {
|
||||
sidebar.classList.remove('is-open');
|
||||
if (mask) {
|
||||
mask.classList.remove('is-show');
|
||||
}
|
||||
}
|
||||
|
||||
btn.addEventListener('click', function () {
|
||||
sidebar.classList.toggle('is-open');
|
||||
if (mask) {
|
||||
mask.classList.toggle('is-show', sidebar.classList.contains('is-open'));
|
||||
}
|
||||
});
|
||||
|
||||
if (mask) {
|
||||
mask.addEventListener('click', close);
|
||||
}
|
||||
|
||||
// 点击目录项后自动收起抽屉
|
||||
sidebar.addEventListener('click', function (e) {
|
||||
if (e.target.closest('a.dc-tree-link') && window.innerWidth <= 860) {
|
||||
close();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('resize', function () {
|
||||
if (window.innerWidth > 860) {
|
||||
close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码块复制按钮
|
||||
*/
|
||||
function initCodeCopy() {
|
||||
var blocks = document.querySelectorAll('.dc-content pre');
|
||||
|
||||
Array.prototype.forEach.call(blocks, function (pre) {
|
||||
var btn = document.createElement('button');
|
||||
btn.className = 'dc-copy-btn';
|
||||
btn.type = 'button';
|
||||
btn.textContent = '复制';
|
||||
|
||||
btn.addEventListener('click', function () {
|
||||
var code = pre.querySelector('code');
|
||||
var text = code ? code.innerText : pre.innerText;
|
||||
|
||||
copyText(text, function (ok) {
|
||||
btn.textContent = ok ? '已复制' : '复制失败';
|
||||
btn.classList.toggle('is-done', ok);
|
||||
setTimeout(function () {
|
||||
btn.textContent = '复制';
|
||||
btn.classList.remove('is-done');
|
||||
}, 1600);
|
||||
});
|
||||
});
|
||||
|
||||
pre.appendChild(btn);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制文本到剪贴板,兼容不支持 Clipboard API 的环境
|
||||
*
|
||||
* @param {string} text 待复制文本
|
||||
* @param {Function} cb 回调,参数为是否成功
|
||||
*/
|
||||
function copyText(text, cb) {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
navigator.clipboard.writeText(text).then(function () {
|
||||
cb(true);
|
||||
}).catch(function () {
|
||||
cb(fallbackCopy(text));
|
||||
});
|
||||
return;
|
||||
}
|
||||
cb(fallbackCopy(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* 兜底复制方案
|
||||
*
|
||||
* @param {string} text 待复制文本
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function fallbackCopy(text) {
|
||||
var ta = document.createElement('textarea');
|
||||
ta.value = text;
|
||||
ta.style.position = 'fixed';
|
||||
ta.style.opacity = '0';
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
|
||||
var ok = false;
|
||||
try {
|
||||
ok = document.execCommand('copy');
|
||||
} catch (err) {
|
||||
ok = false;
|
||||
}
|
||||
|
||||
document.body.removeChild(ta);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* 右侧锚点滚动高亮
|
||||
*/
|
||||
function initTocScrollSpy() {
|
||||
var toc = document.getElementById('dcToc');
|
||||
var content = document.getElementById('dcContent');
|
||||
|
||||
if (!toc || !content) {
|
||||
return;
|
||||
}
|
||||
|
||||
var links = Array.prototype.slice.call(toc.querySelectorAll('a[data-anchor]'));
|
||||
if (!links.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var headings = links.map(function (link) {
|
||||
return document.getElementById(link.getAttribute('data-anchor'));
|
||||
}).filter(Boolean);
|
||||
|
||||
if (!headings.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var offset = 90;
|
||||
var ticking = false;
|
||||
|
||||
function update() {
|
||||
var current = 0;
|
||||
|
||||
for (var i = 0; i < headings.length; i++) {
|
||||
if (headings[i].getBoundingClientRect().top <= offset) {
|
||||
current = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
links.forEach(function (link, index) {
|
||||
link.classList.toggle('is-active', index === current);
|
||||
});
|
||||
|
||||
ticking = false;
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', function () {
|
||||
if (!ticking) {
|
||||
window.requestAnimationFrame(update);
|
||||
ticking = true;
|
||||
}
|
||||
}, { passive: true });
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本切换:保持当前文档路径,仅替换版本段
|
||||
*/
|
||||
function initVersionSwitch() {
|
||||
var select = document.getElementById('dcVersionSelect');
|
||||
if (!select) {
|
||||
return;
|
||||
}
|
||||
|
||||
select.addEventListener('change', function () {
|
||||
var opt = select.options[select.selectedIndex];
|
||||
var isDefault = opt.getAttribute('data-default') === '1';
|
||||
|
||||
// 地址形如 /docs/<项目>[/<版本>]/<文档>
|
||||
var parts = window.location.pathname.split('/').filter(Boolean);
|
||||
if (parts.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
var project = parts[1];
|
||||
var docName = parts[parts.length - 1];
|
||||
|
||||
// 只有项目段时说明还未进入具体文档
|
||||
if (parts.length === 2) {
|
||||
window.location.href = '/docs/' + project;
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = isDefault
|
||||
? '/docs/' + project + '/' + docName
|
||||
: '/docs/' + project + '/' + select.value + '/' + docName;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 让当前选中的目录项进入可视区域
|
||||
*/
|
||||
function scrollActiveIntoView() {
|
||||
var active = document.querySelector('.dc-tree-item.is-active');
|
||||
var sidebar = document.getElementById('dcSidebar');
|
||||
|
||||
if (!active || !sidebar) {
|
||||
return;
|
||||
}
|
||||
|
||||
var top = active.offsetTop - sidebar.clientHeight / 2;
|
||||
if (top > 0) {
|
||||
sidebar.scrollTop = top;
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,53 @@
|
||||
/*! 默认风格 */
|
||||
|
||||
html body{margin-top:0; margin-left: 136px;}
|
||||
html .fly-full{margin-top: 0;}
|
||||
|
||||
.main{width:auto; margin:15px 24px 15px 24px;}
|
||||
.content{margin-right: 360px;}
|
||||
.jie-row li .jie-title{max-width:70%;}
|
||||
|
||||
/* 头部 */
|
||||
.header{width:136px; height:100%;}
|
||||
.header .main{position: static; width:auto;}
|
||||
.logo{top:20px; left:50%; width:86px; height:74px; margin-left:-43px; background:url(../images/logo-1.png);}
|
||||
.nav{position:relative; left:0; top:110px; border-top:1px solid #282C35;}
|
||||
.nav a{display:block; height:50px; line-height:50px; padding:0; text-align:center;}
|
||||
.nav a:first-child{border-top:1px solid #424857;}
|
||||
.nav-user span{margin-top: 10px;}
|
||||
|
||||
.icon-touxiang{font-size: 60px;}
|
||||
|
||||
.nav-user{top: auto; bottom:20px; left:0; width:100%;}
|
||||
.nav-user span,
|
||||
.nav-user .unlogin,
|
||||
.out-login,
|
||||
.avatar,
|
||||
.avatar cite,
|
||||
.nav-user .nav{display:block; *display:block; text-align:center;}
|
||||
.nav-user span{top: 0;}
|
||||
.nav-user span a{padding:0 6px;}
|
||||
.nav-user .unlogin{margin-right: 0;}
|
||||
.out-login{margin-left:0; margin-top:20px;}
|
||||
.out-login a{ padding:0 5px;}
|
||||
.nav-user .nav{position:relative; margin-left: 0; margin-top: 15px;}
|
||||
|
||||
.avatar img{width:60px; height:60px;}
|
||||
.avatar cite{margin-left: 0; margin-top:10px; }
|
||||
.avatar i{margin-left: 0;}
|
||||
|
||||
.nav-message{left: auto; right: 10px;}
|
||||
|
||||
/* 适配 */
|
||||
@media screen and (max-width: 1024px) {
|
||||
html body{margin-left: 140px;}
|
||||
.main{margin: 15px 10px;}
|
||||
.content{margin: 0;}
|
||||
.edge{display:none}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 750px) {
|
||||
html body{margin-left:0;}
|
||||
.header{left:-140px;}
|
||||
.edge{display: block;}
|
||||
}
|
||||
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 8.1 KiB |