chore: 重写初始提交(清空历史,整理后全量提交)

This commit is contained in:
ywxapp
2026-08-16 16:54:14 +08:00
commit 6c1a106bc1
1808 changed files with 238144 additions and 0 deletions
+263
View File
@@ -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;}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

+214
View File
@@ -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)
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

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": "未完成"
}]
}
+196
View File
@@ -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', {});
});
+259
View File
@@ -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', {}); // 输出模块接口
});
+410
View File
@@ -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', {});
});
+281
View File
@@ -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 { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[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', {});
});
+209
View File
@@ -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', {});
});
+94
View File
@@ -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.namearticles: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);
});
+170
View File
@@ -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', {});
});
+295
View File
@@ -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', {})
});
+298
View File
@@ -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', {});
});
+179
View File
@@ -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', {});
});
+230
View File
@@ -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",{});
});
+285
View File
@@ -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', {});
});
+47
View File
@@ -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', {});
})
+204
View File
@@ -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', {});
});
+110
View File
@@ -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', {});
});
+202
View File
@@ -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', {});
});
+327
View File
@@ -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', {});
});
+179
View File
@@ -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', {});
});
+297
View File
@@ -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', {});
});
+277
View File
@@ -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', {});
});
+184
View File
@@ -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', {});
});
+179
View File
@@ -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', {});
});
+179
View File
@@ -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', {});
});
+115
View File
@@ -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', {});
});
+211
View File
@@ -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', {});
});
+404
View File
@@ -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', {});
});
+17
View File
@@ -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>
+84
View File
@@ -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>
+874
View File
@@ -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;
}
}
+257
View File
@@ -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;}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

+490
View File
@@ -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%; }
}
+266
View File
@@ -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;
}
}
})();
+53
View File
@@ -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;}
}
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Some files were not shown because too many files have changed in this diff Show More