fix(workflow): 移除 public 文件夹
1
.gitignore
vendored
@@ -71,3 +71,4 @@ __debug_bin
|
||||
# 前端工具链 #
|
||||
.sass-cache/*
|
||||
node_modules/
|
||||
/public
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,65 +0,0 @@
|
||||
<!--
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// _ooOoo_ //
|
||||
// o8888888o //
|
||||
// 88" . "88 //
|
||||
// (| ^_^ |) //
|
||||
// O\ = /O //
|
||||
// ____/`---'\____ //
|
||||
// .' \\| |// `. //
|
||||
// / \\||| : |||// \ //
|
||||
// / _||||| -:- |||||- \ //
|
||||
// | | \\\ - /// | | //
|
||||
// | \_| ''\---/'' | | //
|
||||
// \ .-\__ `-` ___/-. / //
|
||||
// ___`. .' /--.--\ `. . ___ //
|
||||
// ."" '< `.___\_<|>_/___.' >'"". //
|
||||
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
|
||||
// \ \ `-. \_ __\ /__ _/ .-` / / //
|
||||
// ========`-.____`-.___\_____/___.-`____.-'======== //
|
||||
// `=---=' //
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
|
||||
// 佛祖保佑 永无Bug 永不宕机 //
|
||||
// Name: 耗子Linux面板 Author: 耗子 Date: 2023-07-25 //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>加载中...</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdnjs.cdn.haozi.net/layui/2.8.11/css/layui.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="Panel_app"></div>
|
||||
<script src="https://cdnjs.cdn.haozi.net/layui/2.8.11/layui.min.js"></script>
|
||||
<script src="https://cdnjs.cdn.haozi.net/ace/1.6.1/ace.js"></script>
|
||||
<script src="https://cdnjs.cdn.haozi.net/echarts/5.4.2/echarts.min.js"></script>
|
||||
<script src="https://registry.npmmirror.com/xterm/5.2.1/files/lib/xterm.js"></script>
|
||||
<script src="https://registry.npmmirror.com/xterm-addon-fit/0.7.0/files/lib/xterm-addon-fit.js"></script>
|
||||
<script src="https://cdnjs.cdn.haozi.net/crypto-js/4.1.1/crypto-js.min.js"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: 'panel/', // 静态资源所在路径
|
||||
version: new Date().getTime()
|
||||
}).use(['index', 'setter'], function () {
|
||||
var admin = layui.admin
|
||||
var setter = layui.setter
|
||||
admin.req({
|
||||
url: '/api/panel/info/name',
|
||||
type: 'get',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
setter.name = res.data.name
|
||||
document.title = setter.name
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,182 +0,0 @@
|
||||
/**
|
||||
* admin.login.css
|
||||
*/
|
||||
|
||||
html, body, #Panel_app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.layui-layout-body {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#LAY-user-login,
|
||||
.layadmin-user-display-show {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.layadmin-user-login {
|
||||
position: relative;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 110px 0;
|
||||
min-height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.layadmin-user-login-main {
|
||||
width: 375px;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.layadmin-user-login-box {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.layadmin-user-login-header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.layadmin-user-login-header h2 {
|
||||
margin-bottom: 10px;
|
||||
font-weight: 300;
|
||||
font-size: 30px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.layadmin-user-login-header p {
|
||||
font-weight: 300;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.layadmin-user-login-body .layui-form-item {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layadmin-user-login-icon {
|
||||
position: absolute;
|
||||
left: 1px;
|
||||
top: 1px;
|
||||
width: 38px;
|
||||
line-height: 36px;
|
||||
text-align: center;
|
||||
color: #d2d2d2;
|
||||
}
|
||||
|
||||
.layadmin-user-login-body .layui-form-item .layui-input {
|
||||
padding-left: 38px;
|
||||
}
|
||||
|
||||
.layadmin-user-login-codeimg {
|
||||
max-height: 38px;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.layadmin-user-login-other {
|
||||
position: relative;
|
||||
font-size: 0;
|
||||
line-height: 38px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.layadmin-user-login-other > * {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-right: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.layadmin-user-login-other .layui-icon {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
.layadmin-user-login-other a:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.layadmin-user-jump-change {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.layadmin-user-login-footer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
line-height: 30px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
color: rgba(0, 0, 0, .5)
|
||||
}
|
||||
|
||||
.layadmin-user-login-footer span {
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.layadmin-user-login-footer a {
|
||||
padding: 0 5px;
|
||||
color: rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
.layadmin-user-login-footer a:hover {
|
||||
color: rgba(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/* 有背景图时 */
|
||||
.layadmin-user-login-main[bgimg] {
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 主题背景 */
|
||||
.ladmin-user-login-theme {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ladmin-user-login-theme ul {
|
||||
display: inline-block;
|
||||
padding: 5px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.ladmin-user-login-theme ul li {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 64px;
|
||||
height: 43px;
|
||||
cursor: pointer;
|
||||
transition: all .3s;
|
||||
-webkit-transition: all .3s;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
.ladmin-user-login-theme ul li:hover {
|
||||
opacity: 0.9
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.layadmin-user-login {
|
||||
padding-top: 60px;
|
||||
}
|
||||
|
||||
.layadmin-user-login-main {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.layadmin-user-login-box {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,890 +0,0 @@
|
||||
/**
|
||||
* 界面核心模块
|
||||
*/
|
||||
|
||||
layui.define('view', function (exports) {
|
||||
var $ = layui.jquery
|
||||
, laytpl = layui.laytpl
|
||||
, element = layui.element
|
||||
, table = layui.table
|
||||
, upload = layui.upload
|
||||
, setter = layui.setter
|
||||
, view = layui.view
|
||||
, device = layui.device()
|
||||
|
||||
, $win = $(window), $body = $('body')
|
||||
, container = $('#' + setter.container)
|
||||
|
||||
, SHOW = 'layui-show', HIDE = 'layui-hide', THIS = 'layui-this', DISABLED = 'layui-disabled', TEMP = 'template'
|
||||
, APP_BODY = '#Panel_app_body', APP_FLEXIBLE = 'Panel_app_flexible'
|
||||
, FILTER_TAB_TBAS = 'layadmin-layout-tabs'
|
||||
, APP_SPREAD_SM = 'layadmin-side-spread-sm', TABS_BODY = 'layadmin-tabsbody-item'
|
||||
, ICON_SHRINK = 'layui-icon-shrink-right', ICON_SPREAD = 'layui-icon-spread-left'
|
||||
, SIDE_SHRINK = 'layadmin-side-shrink', SIDE_MENU = 'LAY-system-side-menu'
|
||||
|
||||
//通用方法
|
||||
, admin = {
|
||||
v: '2.0.0'
|
||||
, mode: 'spa'
|
||||
|
||||
//数据的异步请求
|
||||
, req: view.req
|
||||
|
||||
//清除本地 token,并跳转到登入页
|
||||
, exit: view.exit
|
||||
|
||||
//xss 转义
|
||||
, escape: function (html) {
|
||||
return String(html || '').replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&')
|
||||
.replace(/</g, '<').replace(/>/g, '>')
|
||||
.replace(/'/g, ''').replace(/"/g, '"')
|
||||
}
|
||||
|
||||
//事件
|
||||
, on: function (events, callback) {
|
||||
return layui.onevent.call(this, setter.MOD_NAME, events, callback)
|
||||
}
|
||||
|
||||
//弹出面板
|
||||
, popup: view.popup
|
||||
|
||||
//右侧面板
|
||||
, popupRight: function (options) {
|
||||
//layer.close(admin.popup.index);
|
||||
return admin.popup.index = layer.open($.extend({
|
||||
type: 1
|
||||
, id: 'LAY_adminPopupR'
|
||||
, anim: -1
|
||||
, title: false
|
||||
, closeBtn: false
|
||||
, offset: 'r'
|
||||
, shade: 0.1
|
||||
, shadeClose: true
|
||||
, skin: 'layui-anim layui-anim-rl layui-layer-adminRight'
|
||||
, area: '300px'
|
||||
}, options))
|
||||
}
|
||||
|
||||
//发送验证码
|
||||
, sendAuthCode: function (options) {
|
||||
options = $.extend({
|
||||
seconds: 60
|
||||
, elemPhone: '#LAY_phone'
|
||||
, elemVercode: '#LAY_vercode'
|
||||
}, options)
|
||||
|
||||
var seconds = options.seconds
|
||||
, token = null
|
||||
, timer, countDown = function (loop) {
|
||||
var btn = $(options.elem)
|
||||
seconds--
|
||||
if (seconds < 0) {
|
||||
btn.removeClass(DISABLED).html('获取验证码')
|
||||
seconds = options.seconds
|
||||
clearInterval(timer)
|
||||
} else {
|
||||
btn.addClass(DISABLED).html(seconds + '秒后重获')
|
||||
}
|
||||
|
||||
if (!loop) {
|
||||
timer = setInterval(function () {
|
||||
countDown(true)
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
$body.off('click', options.elem).on('click', options.elem, function () {
|
||||
options.elemPhone = $(options.elemPhone)
|
||||
options.elemVercode = $(options.elemVercode)
|
||||
|
||||
var elemPhone = options.elemPhone
|
||||
, value = elemPhone.val()
|
||||
|
||||
if (seconds !== options.seconds || $(this).hasClass(DISABLED)) return
|
||||
|
||||
if (!/^1\d{10}$/.test(value)) {
|
||||
elemPhone.focus()
|
||||
return layer.msg('请输入正确的手机号')
|
||||
}
|
||||
|
||||
if (typeof options.ajax === 'object') {
|
||||
var success = options.ajax.success
|
||||
delete options.ajax.success
|
||||
}
|
||||
|
||||
admin.req($.extend(true, {
|
||||
url: '/auth/code'
|
||||
, type: 'get'
|
||||
, data: {
|
||||
phone: value
|
||||
}
|
||||
, success: function (res) {
|
||||
layer.msg('验证码已发送至你的手机,请注意查收', {
|
||||
icon: 1
|
||||
, shade: 0
|
||||
})
|
||||
options.elemVercode.focus()
|
||||
countDown()
|
||||
success && success(res)
|
||||
}
|
||||
}, options.ajax))
|
||||
})
|
||||
}
|
||||
|
||||
//屏幕类型
|
||||
, screen: function () {
|
||||
var width = $win.width()
|
||||
if (width > 1200) {
|
||||
return 3 //大屏幕
|
||||
} else if (width > 992) {
|
||||
return 2 //中屏幕
|
||||
} else if (width > 768) {
|
||||
return 1 //小屏幕
|
||||
} else {
|
||||
return 0 //超小屏幕
|
||||
}
|
||||
}
|
||||
|
||||
//侧边伸缩
|
||||
, sideFlexible: function (status) {
|
||||
var app = container
|
||||
, iconElem = $('#' + APP_FLEXIBLE)
|
||||
, screen = admin.screen()
|
||||
|
||||
//设置状态,PC:默认展开、移动:默认收缩
|
||||
if (status === 'spread') {
|
||||
//切换到展开状态的 icon,箭头:←
|
||||
iconElem.removeClass(ICON_SPREAD).addClass(ICON_SHRINK)
|
||||
|
||||
//移动:从左到右位移;PC:清除多余选择器恢复默认
|
||||
if (screen < 2) {
|
||||
app.addClass(APP_SPREAD_SM)
|
||||
} else {
|
||||
app.removeClass(APP_SPREAD_SM)
|
||||
}
|
||||
|
||||
app.removeClass(SIDE_SHRINK)
|
||||
} else {
|
||||
//切换到搜索状态的 icon,箭头:→
|
||||
iconElem.removeClass(ICON_SHRINK).addClass(ICON_SPREAD)
|
||||
|
||||
//移动:清除多余选择器恢复默认;PC:从右往左收缩
|
||||
if (screen < 2) {
|
||||
app.removeClass(SIDE_SHRINK)
|
||||
} else {
|
||||
app.addClass(SIDE_SHRINK)
|
||||
}
|
||||
|
||||
app.removeClass(APP_SPREAD_SM)
|
||||
}
|
||||
|
||||
layui.event.call(this, setter.MOD_NAME, 'side({*})', {
|
||||
status: status
|
||||
})
|
||||
}
|
||||
|
||||
//重置主体区域表格尺寸
|
||||
, resizeTable: function (delay) {
|
||||
var that = this, runResizeTable = function () {
|
||||
that.tabsBody(admin.tabsPage.index).find('.layui-table-view').each(function () {
|
||||
var tableID = $(this).attr('lay-id')
|
||||
layui.table.resize(tableID)
|
||||
})
|
||||
}
|
||||
if (!layui.table) return
|
||||
delay ? setTimeout(runResizeTable, delay) : runResizeTable()
|
||||
}
|
||||
|
||||
//主题设置
|
||||
, theme: function (options) {
|
||||
var theme = setter.theme
|
||||
, local = layui.data(setter.tableName)
|
||||
, id = 'LAY_layadmin_theme'
|
||||
, style = document.createElement('style')
|
||||
, styleText = laytpl([
|
||||
//主题色
|
||||
'.layui-side-menu,'
|
||||
, '.layui-layer-admin .layui-layer-title,'
|
||||
, '.layadmin-side-shrink .layui-side-menu .layui-nav>.layui-nav-item>.layui-nav-child'
|
||||
, '{background-color:{{d.color.main}} !important;}'
|
||||
|
||||
//背景选中色
|
||||
, '.layadmin-pagetabs .layui-tab-title li:after,'
|
||||
, '.layadmin-pagetabs .layui-tab-title li.layui-this:after,'
|
||||
, '.layui-nav-tree .layui-this,'
|
||||
, '.layui-nav-tree .layui-this>a,'
|
||||
, '.layui-nav-tree .layui-nav-child dd.layui-this,'
|
||||
, '.layui-nav-tree .layui-nav-child dd.layui-this a,'
|
||||
, '.layui-nav-tree .layui-nav-bar'
|
||||
, '{background-color:{{d.color.selected}} !important;}'
|
||||
|
||||
//logo
|
||||
, '.layui-layout-admin .layui-logo{background-color:{{d.color.logo || d.color.main}} !important;}'
|
||||
|
||||
//文字选中色
|
||||
, '.layadmin-pagetabs .layui-tab-title li:hover,'
|
||||
, '.layadmin-pagetabs .layui-tab-title li.layui-this'
|
||||
, '{color: {{d.color.selected}} !important;}'
|
||||
|
||||
//头部色
|
||||
, '{{# if(d.color.header){ }}'
|
||||
, '.layui-layout-admin .layui-header{background-color:{{ d.color.header }};}'
|
||||
, '.layui-layout-admin .layui-header a,'
|
||||
, '.layui-layout-admin .layui-header a cite{color: #f8f8f8;}'
|
||||
, '.layui-layout-admin .layui-header a:hover{color: #fff;}'
|
||||
, '.layui-layout-admin .layui-header .layui-nav .layui-nav-more{border-top-color: #fbfbfb;}'
|
||||
, '.layui-layout-admin .layui-header .layui-nav .layui-nav-mored{border-color: transparent; border-bottom-color: #fbfbfb;}'
|
||||
, '.layui-layout-admin .layui-header .layui-nav .layui-this:after, .layui-layout-admin .layui-header .layui-nav-bar{background-color: #fff; background-color: rgba(255,255,255,.5);}'
|
||||
, '.layadmin-pagetabs .layui-tab-title li:after{display: none;}'
|
||||
, '{{# } }}'
|
||||
].join('')).render(options = $.extend({}, local.theme, options))
|
||||
, styleElem = document.getElementById(id)
|
||||
|
||||
//添加主题样式
|
||||
if ('styleSheet' in style) {
|
||||
style.setAttribute('type', 'text/css')
|
||||
style.styleSheet.cssText = styleText
|
||||
} else {
|
||||
style.innerHTML = styleText
|
||||
}
|
||||
style.id = id
|
||||
|
||||
styleElem && $body[0].removeChild(styleElem)
|
||||
$body[0].appendChild(style)
|
||||
$body.attr('layadmin-themealias', options.color.alias)
|
||||
|
||||
//本地存储记录
|
||||
local.theme = local.theme || {}
|
||||
layui.each(options, function (key, value) {
|
||||
local.theme[key] = value
|
||||
})
|
||||
layui.data(setter.tableName, {
|
||||
key: 'theme'
|
||||
, value: local.theme
|
||||
})
|
||||
}
|
||||
|
||||
//初始化主题
|
||||
, initTheme: function (index) {
|
||||
var theme = setter.theme
|
||||
index = index || 0
|
||||
if (theme.color[index]) {
|
||||
theme.color[index].index = index
|
||||
admin.theme({
|
||||
color: theme.color[index]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//记录最近一次点击的页面标签数据
|
||||
, tabsPage: {}
|
||||
|
||||
//获取标签页的头元素
|
||||
, tabsHeader: function (index) {
|
||||
return $('#Panel_app_tabsheader').children('li').eq(index || 0)
|
||||
}
|
||||
|
||||
//获取页面标签主体元素
|
||||
, tabsBody: function (index) {
|
||||
return $(APP_BODY).find('.' + TABS_BODY).eq(index || 0)
|
||||
}
|
||||
|
||||
//切换页面标签主体
|
||||
, tabsBodyChange: function (index) {
|
||||
admin.tabsHeader(index).attr('lay-attr', layui.router().href)
|
||||
admin.tabsBody(index).addClass(SHOW).siblings().removeClass(SHOW)
|
||||
events.rollPage('auto', index)
|
||||
}
|
||||
|
||||
//resize事件管理
|
||||
, resize: function (fn) {
|
||||
var router = layui.router()
|
||||
, key = router.path.join('-')
|
||||
|
||||
if (admin.resizeFn[key]) {
|
||||
$win.off('resize', admin.resizeFn[key])
|
||||
delete admin.resizeFn[key]
|
||||
}
|
||||
|
||||
if (fn === 'off') return //如果是清除 resize 事件,则终止往下执行
|
||||
|
||||
fn(), admin.resizeFn[key] = fn
|
||||
$win.on('resize', admin.resizeFn[key])
|
||||
}
|
||||
, resizeFn: {}
|
||||
, runResize: function () {
|
||||
var router = layui.router()
|
||||
, key = router.path.join('-')
|
||||
admin.resizeFn[key] && admin.resizeFn[key]()
|
||||
}
|
||||
, delResize: function () {
|
||||
this.resize('off')
|
||||
}
|
||||
|
||||
//关闭当前 pageTabs
|
||||
, closeThisTabs: function () {
|
||||
if (!admin.tabsPage.index) return
|
||||
$(TABS_HEADER).eq(admin.tabsPage.index).find('.layui-tab-close').trigger('click')
|
||||
}
|
||||
|
||||
//全屏
|
||||
, fullScreen: function () {
|
||||
var ele = document.documentElement
|
||||
, reqFullScreen = ele.requestFullScreen || ele.webkitRequestFullScreen
|
||||
|| ele.mozRequestFullScreen || ele.msRequestFullscreen
|
||||
if (typeof reqFullScreen !== 'undefined' && reqFullScreen) {
|
||||
reqFullScreen.call(ele)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//退出全屏
|
||||
, exitScreen: function () {
|
||||
var ele = document.documentElement
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen()
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen()
|
||||
} else if (document.webkitCancelFullScreen) {
|
||||
document.webkitCancelFullScreen()
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen()
|
||||
}
|
||||
}
|
||||
|
||||
//纠正单页路由格式
|
||||
, correctRouter: function (href) {
|
||||
if (!/^\//.test(href)) href = '/' + href
|
||||
|
||||
//纠正首尾
|
||||
return href.replace(/^(\/+)/, '/')
|
||||
.replace(new RegExp('\/' + setter.entry + '$'), '/') //过滤路由最后的默认视图文件名(如:index)
|
||||
}
|
||||
|
||||
//……
|
||||
}
|
||||
|
||||
//事件
|
||||
var events = admin.events = {
|
||||
//伸缩
|
||||
flexible: function (othis) {
|
||||
var iconElem = othis.find('#' + APP_FLEXIBLE)
|
||||
, isSpread = iconElem.hasClass(ICON_SPREAD)
|
||||
admin.sideFlexible(isSpread ? 'spread' : null) //控制伸缩
|
||||
admin.resizeTable(350)
|
||||
}
|
||||
|
||||
//刷新
|
||||
, refresh: function () {
|
||||
admin.render()
|
||||
}
|
||||
|
||||
//输入框搜索
|
||||
, serach: function (othis) {
|
||||
othis.off('keypress').on('keypress', function (e) {
|
||||
if (!this.value.replace(/\s/g, '')) return
|
||||
//回车跳转
|
||||
if (e.keyCode === 13) {
|
||||
var href = othis.attr('lay-action')
|
||||
, text = othis.attr('lay-text') || '搜索'
|
||||
|
||||
href = href + this.value
|
||||
text = text + ' <span style="color: #FF5722;">' + admin.escape(this.value) + '</span>'
|
||||
|
||||
//打开标签页
|
||||
location.hash = admin.correctRouter(href)
|
||||
|
||||
//如果搜索关键词已经打开,则刷新页面即可
|
||||
events.serach.keys || (events.serach.keys = {})
|
||||
events.serach.keys[admin.tabsPage.index] = this.value
|
||||
if (this.value === events.serach.keys[admin.tabsPage.index]) {
|
||||
events.refresh(othis)
|
||||
}
|
||||
|
||||
//清空输入框
|
||||
this.value = ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//点击消息
|
||||
, message: function (othis) {
|
||||
othis.find('.layui-badge-dot').remove()
|
||||
}
|
||||
|
||||
//弹出主题面板
|
||||
, theme: function () {
|
||||
admin.popupRight({
|
||||
id: 'LAY_adminPopupTheme'
|
||||
, success: function () {
|
||||
view(this.id).render('ui/theme')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//便签
|
||||
, note: function (othis) {
|
||||
var mobile = admin.screen() < 2
|
||||
, note = layui.data(setter.tableName).note
|
||||
|
||||
events.note.index = admin.popup({
|
||||
title: '便签'
|
||||
, shade: 0
|
||||
, offset: [
|
||||
'41px'
|
||||
, (mobile ? null : (othis.offset().left - 250) + 'px')
|
||||
]
|
||||
, anim: -1
|
||||
, id: 'LAY_adminNote'
|
||||
, skin: 'layadmin-note layui-anim layui-anim-upbit'
|
||||
, content: '<textarea placeholder="内容"></textarea>'
|
||||
, resize: false
|
||||
, success: function (layero, index) {
|
||||
var textarea = layero.find('textarea')
|
||||
,
|
||||
value = note === undefined ? '便签中的内容会存储在本地,这样即便你关掉了浏览器,在下次打开时,依然会读取到上一次的记录。是个非常小巧实用的本地备忘录' : note
|
||||
|
||||
textarea.val(value).focus().on('keyup', function () {
|
||||
layui.data(setter.tableName, {
|
||||
key: 'note'
|
||||
, value: this.value
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//全屏
|
||||
, fullscreen: function (othis, opts) {
|
||||
var SCREEN_FULL = 'layui-icon-screen-full';
|
||||
var SCREEN_REST = 'layui-icon-screen-restore';
|
||||
var iconElem = othis.children("i");
|
||||
var hasFull = iconElem.hasClass(SCREEN_FULL);
|
||||
|
||||
// 设置图标状态
|
||||
var setIcon = function (status) {
|
||||
if (status) {
|
||||
iconElem.addClass(SCREEN_REST).removeClass(SCREEN_FULL);
|
||||
} else {
|
||||
iconElem.addClass(SCREEN_FULL).removeClass(SCREEN_REST);
|
||||
}
|
||||
};
|
||||
|
||||
// 设置全屏状态
|
||||
var setScreen = function (status) {
|
||||
status ? admin.fullScreen() : admin.exitScreen();
|
||||
};
|
||||
|
||||
// 仅设置图标状态
|
||||
if (opts) {
|
||||
return setIcon(opts.status);
|
||||
}
|
||||
|
||||
setIcon(hasFull);
|
||||
setScreen(hasFull);
|
||||
}
|
||||
|
||||
//弹出关于面板
|
||||
, about: function () {
|
||||
admin.popupRight({
|
||||
id: 'LAY_adminPopupAbout'
|
||||
, success: function () {
|
||||
view(this.id).render('system/about')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//弹出更多面板
|
||||
, more: function () {
|
||||
admin.popupRight({
|
||||
id: 'LAY_adminPopupMore'
|
||||
, success: function () {
|
||||
view(this.id).render('system/more')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//返回上一页
|
||||
, back: function () {
|
||||
history.back()
|
||||
}
|
||||
|
||||
//主题设置
|
||||
, setTheme: function (othis) {
|
||||
var index = othis.data('index')
|
||||
, nextIndex = othis.siblings('.layui-this').data('index')
|
||||
|
||||
if (othis.hasClass(THIS)) return
|
||||
|
||||
othis.addClass(THIS).siblings('.layui-this').removeClass(THIS)
|
||||
admin.initTheme(index)
|
||||
}
|
||||
|
||||
//左右滚动页面标签
|
||||
, rollPage: function (type, index) {
|
||||
var tabsHeader = $('#Panel_app_tabsheader')
|
||||
, liItem = tabsHeader.children('li')
|
||||
, scrollWidth = tabsHeader.prop('scrollWidth')
|
||||
, outerWidth = tabsHeader.outerWidth()
|
||||
, tabsLeft = parseFloat(tabsHeader.css('left'))
|
||||
|
||||
//右左往右
|
||||
if (type === 'left') {
|
||||
if (!tabsLeft && tabsLeft <= 0) return
|
||||
|
||||
//当前的left减去可视宽度,用于与上一轮的页标比较
|
||||
var prefLeft = -tabsLeft - outerWidth
|
||||
|
||||
liItem.each(function (index, item) {
|
||||
var li = $(item)
|
||||
, left = li.position().left
|
||||
|
||||
if (left >= prefLeft) {
|
||||
tabsHeader.css('left', -left)
|
||||
return false
|
||||
}
|
||||
})
|
||||
} else if (type === 'auto') { //自动滚动
|
||||
(function () {
|
||||
var thisLi = liItem.eq(index), thisLeft
|
||||
|
||||
if (!thisLi[0]) return
|
||||
thisLeft = thisLi.position().left
|
||||
|
||||
//当目标标签在可视区域左侧时
|
||||
if (thisLeft < -tabsLeft) {
|
||||
return tabsHeader.css('left', -thisLeft)
|
||||
}
|
||||
|
||||
//当目标标签在可视区域右侧时
|
||||
if (thisLeft + thisLi.outerWidth() >= outerWidth - tabsLeft) {
|
||||
var subLeft = thisLeft + thisLi.outerWidth() - (outerWidth - tabsLeft)
|
||||
liItem.each(function (i, item) {
|
||||
var li = $(item)
|
||||
, left = li.position().left
|
||||
|
||||
//从当前可视区域的最左第二个节点遍历,如果减去最左节点的差 > 目标在右侧不可见的宽度,则将该节点放置可视区域最左
|
||||
if (left + tabsLeft > 0) {
|
||||
if (left - tabsLeft > subLeft) {
|
||||
tabsHeader.css('left', -left)
|
||||
return false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}())
|
||||
} else {
|
||||
//默认向左滚动
|
||||
liItem.each(function (i, item) {
|
||||
var li = $(item)
|
||||
, left = li.position().left
|
||||
|
||||
if (left + li.outerWidth() >= outerWidth - tabsLeft) {
|
||||
tabsHeader.css('left', -left)
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//向右滚动页面标签
|
||||
, leftPage: function () {
|
||||
events.rollPage('left')
|
||||
}
|
||||
|
||||
//向左滚动页面标签
|
||||
, rightPage: function () {
|
||||
events.rollPage()
|
||||
}
|
||||
|
||||
//关闭当前标签页
|
||||
, closeThisTabs: function () {
|
||||
admin.closeThisTabs()
|
||||
}
|
||||
|
||||
//关闭其它标签页
|
||||
, closeOtherTabs: function (type) {
|
||||
var TABS_REMOVE = 'LAY-system-pagetabs-remove'
|
||||
if (type === 'all') {
|
||||
$(TABS_HEADER + ':gt(0)').remove()
|
||||
$(APP_BODY).find('.' + TABS_BODY + ':gt(0)').remove()
|
||||
} else {
|
||||
$(TABS_HEADER).each(function (index, item) {
|
||||
if (index && index != admin.tabsPage.index) {
|
||||
$(item).addClass(TABS_REMOVE)
|
||||
admin.tabsBody(index).addClass(TABS_REMOVE)
|
||||
}
|
||||
})
|
||||
$('.' + TABS_REMOVE).remove()
|
||||
}
|
||||
}
|
||||
|
||||
//关闭全部标签页
|
||||
, closeAllTabs: function () {
|
||||
events.closeOtherTabs('all')
|
||||
location.hash = ''
|
||||
}
|
||||
|
||||
//遮罩
|
||||
, shade: function () {
|
||||
admin.sideFlexible()
|
||||
}
|
||||
}
|
||||
|
||||
//初始
|
||||
!function () {
|
||||
//主题初始化,本地主题记录优先,其次为 initColorIndex
|
||||
var local = layui.data(setter.tableName)
|
||||
if (local.theme) {
|
||||
admin.theme(local.theme)
|
||||
} else if (setter.theme) {
|
||||
admin.initTheme(setter.theme.initColorIndex)
|
||||
}
|
||||
|
||||
//禁止水平滚动
|
||||
$body.addClass('layui-layout-body')
|
||||
|
||||
//移动端强制不开启页面标签功能
|
||||
if (admin.screen() < 1) {
|
||||
delete setter.pageTabs
|
||||
}
|
||||
|
||||
//不开启页面标签时
|
||||
if (!setter.pageTabs) {
|
||||
container.addClass('layadmin-tabspage-none')
|
||||
}
|
||||
|
||||
//低版本IE提示
|
||||
if (device.ie && device.ie < 10) {
|
||||
view.error('IE' + device.ie + '下访问可能不佳,推荐使用:Chrome / Firefox / Edge 等高级浏览器', {
|
||||
offset: 'auto'
|
||||
, id: 'LAY_errorIE'
|
||||
})
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
//admin.prevRouter = {}; //上一个路由
|
||||
|
||||
// hash 改变侧边状态
|
||||
admin.on('hash(side)', function (router) {
|
||||
var path = router.path, getData = function (item) {
|
||||
return {
|
||||
list: item.children('.layui-nav-child')
|
||||
, name: item.data('name')
|
||||
, jump: item.data('jump')
|
||||
}
|
||||
}
|
||||
, sideMenu = $('#' + SIDE_MENU)
|
||||
, SIDE_NAV_ITEMD = 'layui-nav-itemed'
|
||||
|
||||
//捕获对应菜单
|
||||
, matchMenu = function (list) {
|
||||
var pathURL = admin.correctRouter(path.join('/'))
|
||||
list.each(function (index1, item1) {
|
||||
var othis1 = $(item1)
|
||||
, data1 = getData(othis1)
|
||||
, listChildren1 = data1.list.children('dd')
|
||||
, matched1 = path[0] == data1.name || (index1 === 0 && !path[0])
|
||||
|| (data1.jump && pathURL == admin.correctRouter(data1.jump))
|
||||
|
||||
listChildren1.each(function (index2, item2) {
|
||||
var othis2 = $(item2)
|
||||
, data2 = getData(othis2)
|
||||
, listChildren2 = data2.list.children('dd')
|
||||
, matched2 = (path[0] == data1.name && path[1] == data2.name)
|
||||
|| (data2.jump && pathURL == admin.correctRouter(data2.jump))
|
||||
|
||||
listChildren2.each(function (index3, item3) {
|
||||
var othis3 = $(item3)
|
||||
, data3 = getData(othis3)
|
||||
, matched3 = (path[0] == data1.name && path[1] == data2.name && path[2] == data3.name)
|
||||
|| (data3.jump && pathURL == admin.correctRouter(data3.jump))
|
||||
|
||||
if (matched3) {
|
||||
var selected = data3.list[0] ? SIDE_NAV_ITEMD : THIS
|
||||
othis3.addClass(selected).siblings().removeClass(selected) //标记选择器
|
||||
return false
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
if (matched2) {
|
||||
var selected = data2.list[0] ? SIDE_NAV_ITEMD : THIS
|
||||
othis2.addClass(selected).siblings().removeClass(selected) //标记选择器
|
||||
return false
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
if (matched1) {
|
||||
var selected = data1.list[0] ? SIDE_NAV_ITEMD : THIS
|
||||
othis1.addClass(selected).siblings().removeClass(selected) //标记选择器
|
||||
return false
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
//重置状态
|
||||
sideMenu.find('.' + THIS).removeClass(THIS)
|
||||
|
||||
//移动端点击菜单时自动收缩
|
||||
if (admin.screen() < 2) admin.sideFlexible()
|
||||
|
||||
//开始捕获
|
||||
matchMenu(sideMenu.children('li'))
|
||||
})
|
||||
|
||||
//侧边导航点击事件
|
||||
element.on('nav(layadmin-system-side-menu)', function (elem) {
|
||||
if (elem.siblings('.layui-nav-child')[0] && container.hasClass(SIDE_SHRINK)) {
|
||||
admin.sideFlexible('spread')
|
||||
layer.close(elem.data('index'))
|
||||
}
|
||||
|
||||
admin.tabsPage.type = 'nav'
|
||||
})
|
||||
|
||||
//选项卡的更多操作
|
||||
element.on('nav(layadmin-pagetabs-nav)', function (elem) {
|
||||
var dd = elem.parent()
|
||||
dd.removeClass(THIS)
|
||||
dd.parent().removeClass(SHOW)
|
||||
})
|
||||
|
||||
//同步路由
|
||||
var setThisRouter = function (othis) {
|
||||
var layid = othis.attr('lay-id')
|
||||
, attr = othis.attr('lay-attr')
|
||||
, index = othis.index()
|
||||
|
||||
location.hash = layid === setter.entry ? '/' : (attr || '/')
|
||||
admin.tabsBodyChange(index)
|
||||
}
|
||||
, TABS_HEADER = '#Panel_app_tabsheader>li'
|
||||
|
||||
//页面标签点击
|
||||
$body.on('click', TABS_HEADER, function () {
|
||||
var othis = $(this)
|
||||
, index = othis.index()
|
||||
|
||||
admin.tabsPage.type = 'tab'
|
||||
admin.tabsPage.index = index
|
||||
|
||||
//如果是iframe类型的标签页
|
||||
if (othis.attr('lay-attr') === 'iframe') {
|
||||
return admin.tabsBodyChange(index)
|
||||
}
|
||||
|
||||
setThisRouter(othis) //同步路由
|
||||
admin.runResize() //执行resize事件,如果存在的话
|
||||
admin.resizeTable() //重置当前主体区域的表格尺寸
|
||||
})
|
||||
|
||||
// tabspage 删除
|
||||
element.on('tabDelete(layadmin-layout-tabs)', function (obj) {
|
||||
var othis = $(TABS_HEADER + '.layui-this')
|
||||
|
||||
obj.index && admin.tabsBody(obj.index).remove()
|
||||
setThisRouter(othis)
|
||||
|
||||
//移除resize事件
|
||||
admin.delResize()
|
||||
})
|
||||
|
||||
// 页面跳转
|
||||
$body.on('click', '*[lay-href]', function () {
|
||||
var othis = $(this)
|
||||
var href = othis.attr('lay-href')
|
||||
var router = layui.router()
|
||||
|
||||
admin.tabsPage.elem = othis
|
||||
// admin.prevRouter[router.path[0]] = router.href; //记录上一次各菜单的路由信息
|
||||
|
||||
// 执行跳转
|
||||
location.hash = admin.correctRouter(href)
|
||||
|
||||
// 如果为当前页,则执行刷新
|
||||
if (setter.refreshCurrPage) {
|
||||
if (admin.correctRouter(href) === router.href) {
|
||||
admin.events.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
// 清理所有定时器
|
||||
var highestTimeoutId = setTimeout(';')
|
||||
for (var i = 0; i < highestTimeoutId; i++) {
|
||||
clearTimeout(i)
|
||||
}
|
||||
})
|
||||
|
||||
//点击事件
|
||||
$body.on('click', '*[layadmin-event]', function () {
|
||||
var othis = $(this)
|
||||
, attrEvent = othis.attr('layadmin-event')
|
||||
events[attrEvent] && events[attrEvent].call(this, othis)
|
||||
})
|
||||
|
||||
//tips
|
||||
$body.on('mouseenter', '*[lay-tips]', function () {
|
||||
var othis = $(this)
|
||||
|
||||
if (othis.parent().hasClass('layui-nav-item') && !container.hasClass(SIDE_SHRINK)) return
|
||||
|
||||
var tips = othis.attr('lay-tips')
|
||||
, offset = othis.attr('lay-offset')
|
||||
, direction = othis.attr('lay-direction')
|
||||
, index = layer.tips(tips, this, {
|
||||
tips: direction || 1
|
||||
, time: -1
|
||||
, success: function (layero, index) {
|
||||
if (offset) {
|
||||
layero.css('margin-left', offset + 'px')
|
||||
}
|
||||
}
|
||||
})
|
||||
othis.data('index', index)
|
||||
}).on('mouseleave', '*[lay-tips]', function () {
|
||||
layer.close($(this).data('index'))
|
||||
})
|
||||
|
||||
//窗口resize事件
|
||||
var resizeSystem = layui.data.resizeSystem = function () {
|
||||
//layer.close(events.note.index);
|
||||
layer.closeAll('tips')
|
||||
|
||||
if (!resizeSystem.lock) {
|
||||
setTimeout(function () {
|
||||
admin.sideFlexible(admin.screen() < 2 ? '' : 'spread')
|
||||
delete resizeSystem.lock
|
||||
}, 100)
|
||||
}
|
||||
|
||||
resizeSystem.lock = true
|
||||
}
|
||||
$win.on('resize', layui.data.resizeSystem)
|
||||
|
||||
//设置组件全局 token
|
||||
!function () {
|
||||
var request = setter.request
|
||||
if (request.tokenName) {
|
||||
var obj = {}
|
||||
obj[request.tokenName] = layui.data(setter.tableName)[request.tokenName] || ''
|
||||
|
||||
//table
|
||||
table.set({
|
||||
headers: obj, //通过 request 头传递
|
||||
where: obj //通过参数传递
|
||||
})
|
||||
//upload
|
||||
upload.set({
|
||||
headers: obj, //通过 request 头传递
|
||||
data: obj //通过参数传递
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
//接口输出
|
||||
exports('admin', admin)
|
||||
})
|
||||
@@ -1,198 +0,0 @@
|
||||
/**
|
||||
* 界面入口模块
|
||||
*/
|
||||
|
||||
layui.define('admin', function (exports) {
|
||||
var setter = layui.setter
|
||||
var element = layui.element
|
||||
var admin = layui.admin
|
||||
var tabsPage = admin.tabsPage
|
||||
var view = layui.view
|
||||
|
||||
//根据路由渲染页面
|
||||
var renderPage = function () {
|
||||
var router = layui.router()
|
||||
, path = router.path
|
||||
, pathURL = admin.correctRouter(router.path.join('/'))
|
||||
|
||||
//默认读取主页
|
||||
if (!path.length) path = ['']
|
||||
|
||||
//如果最后一项为空字符,则读取默认文件
|
||||
if (path[path.length - 1] === '') {
|
||||
path[path.length - 1] = setter.entry
|
||||
}
|
||||
|
||||
//重置状态
|
||||
var reset = function (type) {
|
||||
//renderPage.haveInit && layer.closeAll();
|
||||
if (renderPage.haveInit) {
|
||||
$('.layui-layer').each(function () {
|
||||
var othis = $(this),
|
||||
index = othis.attr('times')
|
||||
if (!(othis.hasClass('layui-layim') || othis.hasClass('layui-layim-chat'))) {
|
||||
layer.close(index)
|
||||
}
|
||||
})
|
||||
}
|
||||
renderPage.haveInit = true
|
||||
|
||||
$(APP_BODY).scrollTop(0)
|
||||
delete tabsPage.type //重置页面标签的来源类型
|
||||
}
|
||||
|
||||
//如果路由来自于 tab 切换,则不重新请求视图
|
||||
if (tabsPage.type === 'tab') {
|
||||
//切换到非主页、或者切换到主页且主页必须有内容。方可阻止请求
|
||||
if (pathURL !== '/' || (pathURL === '/' && admin.tabsBody().html())) {
|
||||
admin.tabsBodyChange(tabsPage.index)
|
||||
return reset(tabsPage.type)
|
||||
}
|
||||
}
|
||||
|
||||
//请求视图渲染
|
||||
view().render(path.join('/')).then(function (res) {
|
||||
|
||||
//遍历页签选项卡
|
||||
var matchTo
|
||||
, tabs = $('#Panel_app_tabsheader>li')
|
||||
|
||||
tabs.each(function (index) {
|
||||
var li = $(this)
|
||||
, layid = li.attr('lay-id')
|
||||
|
||||
if (layid === pathURL) {
|
||||
matchTo = true
|
||||
tabsPage.index = index
|
||||
}
|
||||
})
|
||||
|
||||
//如果未在选项卡中匹配到,则追加选项卡
|
||||
if (setter.pageTabs && pathURL !== '/') {
|
||||
if (!matchTo) {
|
||||
$(APP_BODY).append('<div class="layadmin-tabsbody-item layui-show"></div>')
|
||||
tabsPage.index = tabs.length
|
||||
element.tabAdd(FILTER_TAB_TBAS, {
|
||||
title: '<span>' + (res.title || '新标签页') + '</span>'
|
||||
, id: pathURL
|
||||
, attr: router.href
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.container = admin.tabsBody(tabsPage.index)
|
||||
setter.pageTabs || this.container.scrollTop(0) //如果不开启标签页,则跳转时重置滚动条
|
||||
|
||||
//定位当前tabs
|
||||
element.tabChange(FILTER_TAB_TBAS, pathURL)
|
||||
admin.tabsBodyChange(tabsPage.index)
|
||||
|
||||
}).done(function () {
|
||||
layui.use('common', layui.cache.callback.common)
|
||||
$win.on('resize', layui.data.resize)
|
||||
|
||||
element.render('breadcrumb', 'breadcrumb')
|
||||
|
||||
//容器 scroll 事件,剔除吸附层
|
||||
admin.tabsBody(tabsPage.index).on('scroll', function () {
|
||||
var othis = $(this)
|
||||
, elemDate = $('.layui-laydate')
|
||||
, layerOpen = $('.layui-layer')[0]
|
||||
|
||||
//关闭 layDate
|
||||
if (elemDate[0]) {
|
||||
elemDate.each(function () {
|
||||
var thisElemDate = $(this)
|
||||
thisElemDate.hasClass('layui-laydate-static') || thisElemDate.remove()
|
||||
})
|
||||
othis.find('input').blur()
|
||||
}
|
||||
|
||||
//关闭 Tips 层
|
||||
layerOpen && layer.closeAll('tips')
|
||||
})
|
||||
})
|
||||
|
||||
reset()
|
||||
}
|
||||
|
||||
//入口页面
|
||||
var entryPage = function (fn) {
|
||||
var router = layui.router()
|
||||
, container = view(setter.container)
|
||||
, pathURL = admin.correctRouter(router.path.join('/'))
|
||||
, isIndPage
|
||||
|
||||
//检查是否属于独立页面
|
||||
layui.each(setter.indPage, function (index, item) {
|
||||
if (pathURL === item) {
|
||||
return isIndPage = true
|
||||
}
|
||||
})
|
||||
|
||||
//将模块根路径设置为 modules 目录
|
||||
layui.config({
|
||||
base: setter.paths.base + 'modules/'
|
||||
})
|
||||
|
||||
//独立页面
|
||||
if (isIndPage) {
|
||||
container.render(router.path.join('/')).done(function () {
|
||||
admin.pageType = 'alone'
|
||||
})
|
||||
} else { //后台框架页面
|
||||
|
||||
//强制拦截未登入
|
||||
if (setter.interceptor) {
|
||||
var local = layui.data(setter.tableName)
|
||||
if (!local[setter.request.tokenName]) {
|
||||
return location.hash = '/login/redirect=' + encodeURIComponent(pathURL) //跳转到登入页
|
||||
}
|
||||
}
|
||||
|
||||
//渲染后台结构
|
||||
if (admin.pageType === 'console') { //后台主体页
|
||||
renderPage()
|
||||
} else { //初始控制台结构
|
||||
container.render('ui/layout').done(function () {
|
||||
renderPage()
|
||||
layui.element.render()
|
||||
|
||||
if (admin.screen() < 2) {
|
||||
admin.sideFlexible()
|
||||
}
|
||||
admin.pageType = 'console'
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var APP_BODY = '#Panel_app_body'
|
||||
var FILTER_TAB_TBAS = 'layadmin-layout-tabs'
|
||||
var $ = layui.$, $win = $(window)
|
||||
|
||||
//初始主体结构
|
||||
layui.link(
|
||||
setter.paths.core + 'css/admin.css?v=' + admin.v
|
||||
, function () {
|
||||
entryPage()
|
||||
}
|
||||
, 'layuiAdmin'
|
||||
)
|
||||
|
||||
//Hash改变
|
||||
window.onhashchange = function () {
|
||||
entryPage()
|
||||
//执行 {setter.MOD_NAME}.hash 下的事件
|
||||
layui.event.call(this, setter.MOD_NAME, 'hash({*})', layui.router())
|
||||
}
|
||||
|
||||
// 对外输出
|
||||
var adminuiIndex = {
|
||||
render: renderPage
|
||||
}
|
||||
|
||||
$.extend(admin, adminuiIndex)
|
||||
exports('adminIndex', adminuiIndex)
|
||||
})
|
||||
@@ -1,325 +0,0 @@
|
||||
/**
|
||||
* 界面视图模块
|
||||
*/
|
||||
|
||||
layui.define(['laytpl', 'layer'], function (exports) {
|
||||
var $ = layui.jquery, laytpl = layui.laytpl, layer = layui.layer, setter = layui.setter, device = layui.device(),
|
||||
hint = layui.hint()
|
||||
|
||||
//对外接口
|
||||
, view = function (id) {
|
||||
return new Class(id)
|
||||
}
|
||||
|
||||
, SHOW = 'layui-show', LAY_BODY = 'Panel_app_body'
|
||||
|
||||
//构造器
|
||||
, Class = function (id) {
|
||||
this.id = id
|
||||
this.container = $('#' + (id || LAY_BODY))
|
||||
}
|
||||
|
||||
//加载中
|
||||
view.loading = function (elem) {
|
||||
elem.append(this.elemLoad = $('<i class="layui-anim layui-anim-rotate layui-anim-loop layui-icon layui-icon-loading layadmin-loading"></i>'))
|
||||
}
|
||||
|
||||
//移除加载
|
||||
view.removeLoad = function () {
|
||||
this.elemLoad && this.elemLoad.remove()
|
||||
}
|
||||
|
||||
//清除 token,并跳转到登入页
|
||||
view.exit = function () {
|
||||
//清空本地记录的 token
|
||||
layui.data(setter.tableName, {
|
||||
key: setter.request.tokenName, remove: true
|
||||
})
|
||||
|
||||
//跳转到登入页
|
||||
location.hash = '/login'
|
||||
}
|
||||
|
||||
//Ajax请求
|
||||
view.req = function (options) {
|
||||
var that = this, success = options.success, error = options.error, request = setter.request,
|
||||
response = setter.response, debug = function () {
|
||||
return setter.debug ? '<br><cite>URL:</cite>' + options.url : ''
|
||||
}
|
||||
|
||||
options.data = options.data || {}
|
||||
options.headers = options.headers || {}
|
||||
|
||||
if (request.tokenName) {
|
||||
var sendData = typeof options.data === 'string' ? JSON.parse(options.data) : options.data
|
||||
|
||||
//自动给参数传入默认 token
|
||||
options.data[request.tokenName] = request.tokenName in sendData ? options.data[request.tokenName] : (layui.data(setter.tableName)[request.tokenName] || '')
|
||||
|
||||
//自动给 Request Headers 传入 token
|
||||
options.headers[request.tokenName] = request.tokenName in options.headers ? options.headers[request.tokenName] : (layui.data(setter.tableName)[request.tokenName] || '')
|
||||
}
|
||||
|
||||
delete options.success
|
||||
delete options.error
|
||||
|
||||
if (options.type === 'post' || options.type === 'put' || options.type === 'delete' || options.type === 'patch' || options.type === 'POST' || options.type === 'PUT' || options.type === 'DELETE' || options.type === 'PATCH') {
|
||||
options.contentType = 'application/json'
|
||||
options.data = JSON.stringify(options.data)
|
||||
}
|
||||
|
||||
return $.ajax($.extend({
|
||||
type: 'get', dataType: 'json', success: function (res) {
|
||||
var statusCode = response.statusCode
|
||||
|
||||
//只有 response 的 code 一切正常才执行 done
|
||||
if (res[response.statusName] == statusCode.ok) {
|
||||
typeof options.done === 'function' && options.done(res)
|
||||
}
|
||||
|
||||
//登录状态失效,清除本地 access_token,并强制跳转到登入页
|
||||
else if (res[response.statusName] == statusCode.logout) {
|
||||
view.exit()
|
||||
}
|
||||
|
||||
//其它异常
|
||||
else {
|
||||
var errorText = ['<cite>Error:</cite> ' + (res[response.msgName] || '返回状态码异常'), debug()].join('')
|
||||
view.error(errorText)
|
||||
}
|
||||
|
||||
//只要 http 状态码正常,无论 response 的 code 是否正常都执行 success
|
||||
typeof success === 'function' && success(res)
|
||||
}, error: function (e, code) {
|
||||
console.log('面板响应异常: ' + e.responseText)
|
||||
if (e.status === 422) {
|
||||
var errorText = ''
|
||||
var res = e.responseText
|
||||
try {
|
||||
res = JSON.parse(res)
|
||||
} catch (e) {
|
||||
res = {}
|
||||
}
|
||||
if (typeof res.message === 'object' && res.message !== null) {
|
||||
for (let key in res.message) {
|
||||
if (res.message.hasOwnProperty(key)) {
|
||||
for (let subKey in res.message[key]) {
|
||||
if (res.message[key].hasOwnProperty(subKey)) {
|
||||
errorText += '<cite>Error:</cite> ' + res.message[key][subKey] + '<br>'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errorText = res.message
|
||||
}
|
||||
|
||||
view.error(errorText)
|
||||
return false
|
||||
}
|
||||
var errorText = ['请求异常,请重试<br><cite>错误信息:</cite>' + code, debug()].join('')
|
||||
view.error(errorText)
|
||||
|
||||
typeof error === 'function' && error.apply(this, arguments)
|
||||
}
|
||||
}, options))
|
||||
}
|
||||
|
||||
//弹窗
|
||||
view.popup = function (options) {
|
||||
var success = options.success, skin = options.skin
|
||||
|
||||
delete options.success
|
||||
delete options.skin
|
||||
|
||||
return layer.open($.extend({
|
||||
type: 1,
|
||||
title: '提示',
|
||||
content: '',
|
||||
id: 'LAY-system-view-popup',
|
||||
skin: 'layui-layer-admin' + (skin ? ' ' + skin : ''),
|
||||
shadeClose: true,
|
||||
closeBtn: false,
|
||||
success: function (layero, index) {
|
||||
var elemClose = $('<i class="layui-icon" close>ဆ</i>')
|
||||
layero.append(elemClose)
|
||||
elemClose.on('click', function () {
|
||||
layer.close(index)
|
||||
})
|
||||
typeof success === 'function' && success.apply(this, arguments)
|
||||
}
|
||||
}, options))
|
||||
}
|
||||
|
||||
//异常提示
|
||||
view.error = function (content, options) {
|
||||
return view.popup($.extend({
|
||||
content: content, maxWidth: 300
|
||||
//,shade: 0.01
|
||||
, offset: 't', anim: 6, id: 'LAY_adminError'
|
||||
}, options))
|
||||
}
|
||||
|
||||
//请求模板文件渲染
|
||||
Class.prototype.render = function (views, params) {
|
||||
var that = this, router = layui.router()
|
||||
views = (setter.paths && setter.paths.views ? setter.paths.views : setter.views) + views + setter.engine
|
||||
|
||||
$('#' + LAY_BODY).children('.layadmin-loading').remove()
|
||||
view.loading(that.container) //loading
|
||||
|
||||
//请求模板
|
||||
$.ajax({
|
||||
url: views, type: 'get', dataType: 'html', data: {
|
||||
v: layui.cache.version
|
||||
}, success: function (html) {
|
||||
html = '<div>' + html + '</div>'
|
||||
|
||||
var elemTitle = $(html).find('title'),
|
||||
title = elemTitle.text() || (html.match(/\<title\>([\s\S]*)\<\/title>/) || [])[1]
|
||||
|
||||
var res = {
|
||||
title: title, body: html
|
||||
}
|
||||
|
||||
elemTitle.remove()
|
||||
that.params = params || {} //获取参数
|
||||
|
||||
if (that.then) {
|
||||
that.then(res)
|
||||
delete that.then
|
||||
}
|
||||
|
||||
that.parse(html)
|
||||
view.removeLoad()
|
||||
|
||||
if (that.done) {
|
||||
that.done(res)
|
||||
delete that.done
|
||||
}
|
||||
|
||||
}, error: function (e) {
|
||||
view.removeLoad()
|
||||
|
||||
if (that.render.isError) {
|
||||
return view.error('请求视图文件异常,状态:' + e.status)
|
||||
}
|
||||
|
||||
if (e.status === 404) {
|
||||
that.render('ui/404')
|
||||
} else {
|
||||
that.render('ui/error')
|
||||
}
|
||||
|
||||
that.render.isError = true
|
||||
}
|
||||
})
|
||||
return that
|
||||
}
|
||||
|
||||
//解析模板
|
||||
Class.prototype.parse = function (html, refresh, callback) {
|
||||
var that = this, isScriptTpl = typeof html === 'object' //是否模板元素
|
||||
, elem = isScriptTpl ? html : $(html), elemTemp = isScriptTpl ? html : elem.find('*[template]'),
|
||||
fn = function (options) {
|
||||
var tpl = laytpl(options.dataElem.html()), res = $.extend({
|
||||
params: router.params
|
||||
}, options.res)
|
||||
|
||||
options.dataElem.after(tpl.render(res))
|
||||
typeof callback === 'function' && callback()
|
||||
|
||||
try {
|
||||
options.done && new Function('d', options.done)(res)
|
||||
} catch (e) {
|
||||
console.error(options.dataElem[0], '\n存在错误回调脚本\n\n', e)
|
||||
}
|
||||
}, router = layui.router()
|
||||
|
||||
elem.find('title').remove()
|
||||
that.container[refresh ? 'after' : 'html'](elem.children())
|
||||
|
||||
router.params = that.params || {}
|
||||
|
||||
//遍历模板区块
|
||||
for (var i = elemTemp.length; i > 0; i--) {
|
||||
(function () {
|
||||
var dataElem = elemTemp.eq(i - 1), layDone = dataElem.attr('lay-done') || dataElem.attr('lay-then') //获取回调
|
||||
, url = laytpl(dataElem.attr('lay-url') || '').render(router) //接口 url
|
||||
, data = laytpl(dataElem.attr('lay-data') || '').render(router) //接口参数
|
||||
, headers = laytpl(dataElem.attr('lay-headers') || '').render(router) //接口请求的头信息
|
||||
|
||||
try {
|
||||
data = new Function('return ' + data + ';')()
|
||||
} catch (e) {
|
||||
hint.error('lay-data: ' + e.message)
|
||||
data = {}
|
||||
}
|
||||
|
||||
try {
|
||||
headers = new Function('return ' + headers + ';')()
|
||||
} catch (e) {
|
||||
hint.error('lay-headers: ' + e.message)
|
||||
headers = headers || {}
|
||||
}
|
||||
|
||||
if (url) {
|
||||
view.req({
|
||||
type: dataElem.attr('lay-type') || 'get',
|
||||
url: url,
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
headers: headers,
|
||||
success: function (res) {
|
||||
fn({
|
||||
dataElem: dataElem, res: res, done: layDone
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
fn({
|
||||
dataElem: dataElem, done: layDone
|
||||
})
|
||||
}
|
||||
}())
|
||||
}
|
||||
|
||||
return that
|
||||
}
|
||||
|
||||
//直接渲染字符
|
||||
Class.prototype.send = function (views, data) {
|
||||
var tpl = laytpl(views || this.container.html()).render(data || {})
|
||||
this.container.html(tpl)
|
||||
return this
|
||||
}
|
||||
|
||||
//局部刷新模板
|
||||
Class.prototype.refresh = function (callback) {
|
||||
var that = this, next = that.container.next(), templateid = next.attr('lay-templateid')
|
||||
|
||||
if (that.id != templateid) return that
|
||||
|
||||
that.parse(that.container, 'refresh', function () {
|
||||
that.container.siblings('[lay-templateid="' + that.id + '"]:last').remove()
|
||||
typeof callback === 'function' && callback()
|
||||
})
|
||||
|
||||
return that
|
||||
}
|
||||
|
||||
//视图请求成功后的回调
|
||||
Class.prototype.then = function (callback) {
|
||||
this.then = callback
|
||||
return this
|
||||
}
|
||||
|
||||
//视图渲染完毕后的回调
|
||||
Class.prototype.done = function (callback) {
|
||||
this.done = callback
|
||||
return this
|
||||
}
|
||||
|
||||
//对外接口
|
||||
exports('view', view)
|
||||
})
|
||||
@@ -1,99 +0,0 @@
|
||||
/**
|
||||
* setter
|
||||
*/
|
||||
|
||||
// 初始化配置
|
||||
layui.define(['all'], function (exports) {
|
||||
exports('setter', {
|
||||
paths: { // v1.9.0 及以上版本的写法
|
||||
core: layui.cache.base + 'adminui/src/', // 核心库所在目录
|
||||
views: layui.cache.base + 'views/', // 业务视图所在目录
|
||||
modules: layui.cache.base + 'modules/', // 业务模块所在目录
|
||||
base: layui.cache.base // 记录静态资源所在基础目录
|
||||
},
|
||||
|
||||
container: 'Panel_app', // 容器ID
|
||||
entry: 'index', // 默认视图文件名
|
||||
engine: '.html', // 视图文件后缀名
|
||||
pageTabs: true, // 是否开启页面选项卡功能。单页版不推荐开启
|
||||
refreshCurrPage: true, // 当跳转页面 url 与当前页 url 相同时,是否自动执行刷新
|
||||
|
||||
name: '耗子Linux面板', tableName: 'HaoZiPanel', // 本地存储表名
|
||||
MOD_NAME: 'admin', // 模块事件名
|
||||
|
||||
debug: true, // 是否开启调试模式。如开启,接口异常时会抛出异常 URL 等信息
|
||||
interceptor: true, // 是否开启未登入拦截
|
||||
|
||||
// 自定义请求字段
|
||||
request: {
|
||||
tokenName: 'access_token' // 自动携带 token 的字段名。可设置 false 不携带。
|
||||
},
|
||||
|
||||
// 自定义响应字段
|
||||
response: {
|
||||
statusName: 'code', // 数据状态的字段名称
|
||||
statusCode: {
|
||||
ok: 0, // 数据状态一切正常的状态码
|
||||
logout: 401 // 登录状态失效的状态码
|
||||
}, msgName: 'message', // 状态信息的字段名称
|
||||
dataName: 'data' // 数据详情的字段名称
|
||||
},
|
||||
|
||||
// 独立页面路由,可随意添加(无需写参数)
|
||||
indPage: [
|
||||
'/login',
|
||||
'/logout',
|
||||
],
|
||||
|
||||
// 配置业务模块目录中的特殊模块
|
||||
extend: {},
|
||||
|
||||
// 主题配置
|
||||
theme: {
|
||||
// 内置主题配色方案
|
||||
color: [{
|
||||
main: '#20222A', // 主题色
|
||||
selected: '#16baaa', // 选中色
|
||||
alias: 'default' // 默认别名
|
||||
}, {
|
||||
main: '#03152A', selected: '#3B91FF', alias: 'dark-blue' // 藏蓝
|
||||
}, {
|
||||
main: '#2E241B', selected: '#A48566', alias: 'coffee' // 咖啡
|
||||
}, {
|
||||
main: '#50314F', selected: '#7A4D7B', alias: 'purple-red' // 紫红
|
||||
}, {
|
||||
main: '#344058', logo: '#1E9FFF', selected: '#1E9FFF', alias: 'ocean' // 海洋
|
||||
}, {
|
||||
main: '#3A3D49', logo: '#2F9688', selected: '#16b777', alias: 'green' // 墨绿
|
||||
}, {
|
||||
main: '#20222A', logo: '#F78400', selected: '#F78400', alias: 'red' // 橙色
|
||||
}, {
|
||||
main: '#28333E', logo: '#AA3130', selected: '#AA3130', alias: 'fashion-red' // 时尚红
|
||||
}, {
|
||||
main: '#24262F', logo: '#3A3D49', selected: '#16baaa', alias: 'classic-black' // 经典黑
|
||||
}, {
|
||||
logo: '#226A62', header: '#2F9688', alias: 'green-header' // 墨绿头
|
||||
}, {
|
||||
main: '#344058', logo: '#0085E8', selected: '#1E9FFF', header: '#1E9FFF', alias: 'ocean-header' // 海洋头
|
||||
}, {
|
||||
header: '#393D49', alias: 'classic-black-header' // 经典黑
|
||||
}, {
|
||||
main: '#50314F', logo: '#50314F', selected: '#7A4D7B', header: '#50314F', alias: 'purple-red-header' // 紫红头
|
||||
}, {
|
||||
main: '#28333E', logo: '#28333E', selected: '#AA3130', header: '#AA3130', alias: 'fashion-red-header' // 时尚红头
|
||||
}, {
|
||||
main: '#28333E', logo: '#16baaa', selected: '#16baaa', header: '#16baaa', alias: 'green-header' // 墨绿头
|
||||
}, {
|
||||
main: '#393D49', logo: '#393D49', selected: '#16baaa', header: '#23262E', alias: 'Classic-style1' // 经典风格1
|
||||
}, {
|
||||
main: '#001529', logo: '#001529', selected: '#1890FF', header: '#1890FF', alias: 'Classic-style2' // 经典风格2
|
||||
}, {
|
||||
main: '#25282A', logo: '#25282A', selected: '#35BDB2', header: '#35BDB2', alias: 'Classic-style3' // 经典风格3
|
||||
}],
|
||||
|
||||
// 初始的颜色索引,对应上面的配色方案数组索引
|
||||
// 如果本地已经有主题色记录,则以本地记录为优先,除非请求本地数据(localStorage)
|
||||
initColorIndex: 0
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* 初始化主题入口模块
|
||||
*/
|
||||
|
||||
layui.extend({
|
||||
setter: 'config' // 将 config.js 扩展到 layui 模块
|
||||
}).define(['setter'], function (exports) {
|
||||
var setter = layui.setter
|
||||
|
||||
// 将核心库扩展到 layui 模块
|
||||
layui.each({
|
||||
admin: 'admin',
|
||||
view: 'view',
|
||||
adminIndex: 'index'
|
||||
}, function (modName, fileName) {
|
||||
var libs = {}
|
||||
libs[modName] = '{/}' + setter.paths.core + '/modules/' + fileName
|
||||
layui.extend(libs)
|
||||
})
|
||||
|
||||
// 指定业务模块基础目录
|
||||
layui.config({
|
||||
base: setter.paths.modules
|
||||
})
|
||||
|
||||
// 将业务模块中的特殊模块扩展到 layui 模块
|
||||
layui.each(setter.extend, function (key, value) {
|
||||
var mods = {}
|
||||
mods[key] = '{/}' + layui.cache.base + value
|
||||
layui.extend(mods)
|
||||
})
|
||||
|
||||
// 加载主题核心库入口模块
|
||||
layui.use('adminIndex', function () {
|
||||
layui.use('common') // 加载公共业务模块,如不需要可剔除
|
||||
|
||||
// 输出模块 / 模块加载完毕标志
|
||||
exports('index', layui.admin)
|
||||
})
|
||||
})
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* common
|
||||
*/
|
||||
|
||||
layui.define(function (exports) {
|
||||
var $ = layui.$
|
||||
, layer = layui.layer
|
||||
, laytpl = layui.laytpl
|
||||
, setter = layui.setter
|
||||
, view = layui.view
|
||||
, admin = layui.admin
|
||||
|
||||
//公共业务的逻辑处理可以写在此处,切换任何页面都会执行
|
||||
//……
|
||||
|
||||
//退出
|
||||
admin.events.logout = function () {
|
||||
//执行退出接口
|
||||
admin.req({
|
||||
url: './res/json/user/logout.js'
|
||||
, type: 'get'
|
||||
, data: {}
|
||||
, done: function (res) { //这里要说明一下:done 是只有 response 的 code 正常才会执行。而 succese 则是只要 http 为 200 就会执行
|
||||
|
||||
//清空本地记录的 token,并跳转到登入页
|
||||
admin.exit()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//对外暴露的接口
|
||||
exports('common', {})
|
||||
})
|
||||
@@ -1,194 +0,0 @@
|
||||
|
||||
/* 样式加载完毕的标识 */
|
||||
html #layuicss-cron {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 1989px;
|
||||
}
|
||||
|
||||
|
||||
/* 主体结构 */
|
||||
.layui-cron {
|
||||
width: 550px;
|
||||
position: absolute;
|
||||
z-index: 99999999;
|
||||
margin: 5px 0;
|
||||
border-radius: 2px;
|
||||
font-size: 14px;
|
||||
-webkit-animation-duration: 0.3s;
|
||||
animation-duration: 0.3s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
background-color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 5px 0px;
|
||||
-webkit-animation-name: cron-upbit;
|
||||
animation-name: cron-upbit;
|
||||
border: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.layui-cron-main ul {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
@-webkit-keyframes cron-upbit {
|
||||
|
||||
/* 微微往上滑入 */
|
||||
from {
|
||||
-webkit-transform: translate3d(0, 20px, 0);
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes cron-upbit {
|
||||
from {
|
||||
transform: translate3d(0, 20px, 0);
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* tabs */
|
||||
.layui-cron>.layui-tab {
|
||||
margin: 0;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* 行 */
|
||||
.cron-row {
|
||||
padding-left: 13px;
|
||||
}
|
||||
/* 格 */
|
||||
.cron-grid {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
/* 表达式 */
|
||||
.cron-title {
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
margin: 10px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.cron-box {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.cron-box+.cron-box {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* 按钮 */
|
||||
.cron-footer-btns {
|
||||
text-align: right;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.cron-footer-btns span {
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
margin: 0 0 0 -1px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid #C9C9C9;
|
||||
background-color: #fff;
|
||||
white-space: nowrap;
|
||||
vertical-align: top;
|
||||
border-radius: 2px;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
box-sizing: border-box;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.cron-footer-btns span:hover {
|
||||
color: #5FB878;
|
||||
}
|
||||
|
||||
|
||||
/* 表单 */
|
||||
.layui-cron .layui-form-radio {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.cron-form {
|
||||
line-height: 28px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.cron-input-mid {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-top: 6px;
|
||||
background-color: #e5e5e5;
|
||||
padding: 0 12px;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cron-input {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-top: 6px;
|
||||
padding: 0 8px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
box-sizing: border-box;
|
||||
width: 80px;
|
||||
-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
.cron-input:focus {
|
||||
outline: 0;
|
||||
border: 1px solid #01AAED;
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 4px 0px #01AAED;
|
||||
translate: 1s;
|
||||
}
|
||||
|
||||
.layui-cron .layui-form-checkbox[lay-skin="primary"] span {
|
||||
padding-right: 10px;
|
||||
min-width: 16px;
|
||||
}
|
||||
|
||||
.layui-cron .layui-form-checkbox[lay-skin="primary"] {
|
||||
padding-left: 22px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.layui-cron input[type=number] {
|
||||
-moz-appearance:textfield;
|
||||
}
|
||||
.layui-cron input[type=number]::-webkit-inner-spin-button,
|
||||
.layui-cron input[type=number]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
.cron-tips{
|
||||
color: grey;
|
||||
line-height: 28px;
|
||||
height: 28px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-top: 8px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
@@ -1,970 +0,0 @@
|
||||
/**
|
||||
@ Name:layui.cron Cron表达式解析器
|
||||
@ Author:贝哥哥
|
||||
@ License:MIT
|
||||
*/
|
||||
|
||||
layui.define(['lay', 'element', 'form'], function (exports) { //假如该组件依赖 layui.form
|
||||
var $ = layui.$, layer = layui.layer, lay = layui.lay, element = layui.element, form = layui.form
|
||||
|
||||
|
||||
//字符常量
|
||||
, MOD_NAME = 'cron', ELEM = '.layui-cron', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide'
|
||||
|
||||
, ELEM_STATIC = 'layui-cron-static', ELEM_FOOTER = 'layui-cron-footer', ELEM_CONFIRM = '.cron-btns-confirm',
|
||||
ELEM_HINT = 'layui-cron-hint'
|
||||
|
||||
, ELEM_RUN_HINT = 'layui-cron-run-hint'
|
||||
|
||||
//外部接口
|
||||
, cron = {
|
||||
v: '2.0.0' // cron 组件当前版本
|
||||
, index: layui.cron ? (layui.cron.index + 10000) : 0 // corn 实例标识
|
||||
|
||||
//设置全局项
|
||||
, set: function (options) {
|
||||
var that = this;
|
||||
that.config = $.extend({}, that.config, options);
|
||||
return that;
|
||||
}
|
||||
|
||||
//事件监听
|
||||
, on: function (events, callback) {
|
||||
return layui.onevent.call(this, MOD_NAME, events, callback);
|
||||
}
|
||||
|
||||
//主体CSS等待事件
|
||||
, ready: function (fn) {
|
||||
var cssPath = layui.cache.base + "cron.css?v=" + cron.v;
|
||||
layui.link(cssPath, fn, "cron"); //此处的“cron”要对应 cron.css 中的样式: html #layuicss-cron{}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
//操作当前实例
|
||||
, thisIns = function () {
|
||||
var that = this, options = that.config, id = options.id || options.index;
|
||||
|
||||
return {
|
||||
//提示框
|
||||
hint: function (content) {
|
||||
that.hint.call(that, content);
|
||||
}, config: options
|
||||
}
|
||||
}
|
||||
|
||||
//构造器,创建实例
|
||||
, Class = function (options) {
|
||||
var that = this;
|
||||
that.index = ++cron.index;
|
||||
that.config = $.extend({}, that.config, cron.config, options);
|
||||
cron.ready(function () {
|
||||
that.init();
|
||||
});
|
||||
};
|
||||
|
||||
//默认配置
|
||||
Class.prototype.config = {
|
||||
value: null // 当前表达式值,每秒执行一次
|
||||
,
|
||||
isInitValue: true //用于控制是否自动向元素填充初始值(需配合 value 参数使用)
|
||||
,
|
||||
lang: "cn" //语言,只支持cn/en,即中文和英文
|
||||
,
|
||||
tabs: [{key: 'minutes', range: '0-59'}, {
|
||||
key: 'hours', range: '0-23'
|
||||
}, {key: 'days', range: '1-31'}, {key: 'months', range: '1-12'}, {key: 'weeks', range: '1-7'}],
|
||||
defaultCron: {minutes: "*", hours: "*", days: "*", months: "*", weeks: "*"},
|
||||
trigger: "click" //呼出控件的事件
|
||||
,
|
||||
btns: ['run', 'confirm'] //右下角显示的按钮,会按照数组顺序排列
|
||||
,
|
||||
position: null //控件定位方式定位, 默认absolute,支持:fixed/absolute/static
|
||||
,
|
||||
zIndex: null //控件层叠顺序
|
||||
,
|
||||
show: false //是否直接显示,如果设置 true,则默认直接显示控件
|
||||
,
|
||||
showBottom: true //是否显示底部栏
|
||||
,
|
||||
done: null //控件选择完毕后的回调,点击运行/确定也均会触发
|
||||
,
|
||||
run: null // 最近运行时间接口
|
||||
};
|
||||
|
||||
//多语言
|
||||
Class.prototype.lang = function () {
|
||||
var that = this, options = that.config, text = {
|
||||
cn: {
|
||||
tabs: [{title: "分"}, {title: "时"}, {title: "日"}, {title: "月"}, {
|
||||
title: "周",
|
||||
rateBegin: "第",
|
||||
rateMid: "周的星期",
|
||||
rateEnd: ""
|
||||
}],
|
||||
every: "每",
|
||||
unspecified: "不指定",
|
||||
period: "周期",
|
||||
periodFrom: "从",
|
||||
rate: "按照",
|
||||
rateBegin: "从",
|
||||
rateMid: "开始,每",
|
||||
rateEnd: "执行一次",
|
||||
weekday: "工作日",
|
||||
weekdayPrefix: "每月",
|
||||
weekdaySuffix: "号最近的那个工作日",
|
||||
lastday: "本月最后一日",
|
||||
lastweek: "本月最后一个星期",
|
||||
custom: "指定",
|
||||
tools: {
|
||||
confirm: '确定', run: '运行'
|
||||
},
|
||||
formatError: ['Cron格式不合法', '<br>已为你重置']
|
||||
}, en: {
|
||||
tabs: [{title: "Minutes"}, {title: "Hours"}, {title: "Days"}, {title: "Months"}, {title: "Weeks"}],
|
||||
every: "Every ",
|
||||
unspecified: "Unspecified",
|
||||
period: "Period",
|
||||
periodFrom: "From",
|
||||
rate: "According to",
|
||||
rateBegin: "begin at",
|
||||
rateMid: ", every",
|
||||
rateEnd: " execute once",
|
||||
weekday: "Weekday",
|
||||
weekdayPrefix: "Every month at ",
|
||||
weekdaySuffix: "号最近的那个工作日",
|
||||
lastday: "Last day of the month",
|
||||
lastweek: "本月最后一个星期",
|
||||
custom: "Custom",
|
||||
tools: {
|
||||
confirm: 'Confirm', run: 'Run'
|
||||
},
|
||||
formatError: ['The cron format error', '<br>It has been reset']
|
||||
}
|
||||
};
|
||||
return text[options.lang] || text['cn'];
|
||||
};
|
||||
|
||||
//初始准备
|
||||
Class.prototype.init = function () {
|
||||
var that = this, options = that.config, isStatic = options.position === 'static';
|
||||
|
||||
options.elem = lay(options.elem);
|
||||
|
||||
options.eventElem = lay(options.eventElem);
|
||||
|
||||
if (!options.elem[0]) return;
|
||||
|
||||
//如果不是input|textarea元素,则默认采用click事件
|
||||
if (!that.isInput(options.elem[0])) {
|
||||
if (options.trigger === 'focus') {
|
||||
options.trigger = 'click';
|
||||
}
|
||||
}
|
||||
|
||||
// 设置渲染所绑定元素的唯一KEY
|
||||
if (!options.elem.attr('lay-key')) {
|
||||
options.elem.attr('lay-key', that.index);
|
||||
options.eventElem.attr('lay-key', that.index);
|
||||
}
|
||||
|
||||
// 当前实例主面板ID
|
||||
that.elemID = 'layui-icon' + options.elem.attr('lay-key');
|
||||
|
||||
//默认赋值
|
||||
if (options.value && options.isInitValue) {
|
||||
that.setValue(options.value);
|
||||
}
|
||||
if (!options.value) {
|
||||
options.value = options.elem[0].value || '';
|
||||
}
|
||||
var cronArr = options.value.split(' ');
|
||||
if (cronArr.length >= 6) {
|
||||
options.cron = {
|
||||
minutes: cronArr[0],
|
||||
hours: cronArr[1],
|
||||
days: cronArr[2],
|
||||
months: cronArr[3],
|
||||
weeks: cronArr[4],
|
||||
};
|
||||
} else {
|
||||
options.cron = lay.extend({}, options.defaultCron);
|
||||
}
|
||||
|
||||
|
||||
if (options.show || isStatic) that.render();
|
||||
isStatic || that.events();
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
// 控件主体渲染
|
||||
Class.prototype.render = function () {
|
||||
var that = this, options = that.config, lang = that.lang(), isStatic = options.position === 'static',
|
||||
tabFilter = 'cron-tab' + options.elem.attr('lay-key')
|
||||
//主面板
|
||||
, elem = that.elem = lay.elem('div', {
|
||||
id: that.elemID, 'class': ['layui-cron', isStatic ? (' ' + ELEM_STATIC) : ''].join('')
|
||||
})
|
||||
|
||||
// tab 内容区域
|
||||
, elemTab = that.elemTab = lay.elem('div', {
|
||||
'class': 'layui-tab layui-tab-card', 'lay-filter': tabFilter
|
||||
}), tabHead = lay.elem('ul', {
|
||||
'class': 'layui-tab-title'
|
||||
}), tabContent = lay.elem('div', {
|
||||
'class': 'layui-tab-content'
|
||||
})
|
||||
|
||||
//底部区域
|
||||
, divFooter = that.footer = lay.elem('div', {
|
||||
'class': ELEM_FOOTER
|
||||
});
|
||||
|
||||
if (options.zIndex) elem.style.zIndex = options.zIndex;
|
||||
|
||||
// 生成tab 内容区域
|
||||
elemTab.appendChild(tabHead);
|
||||
elemTab.appendChild(tabContent);
|
||||
lay.each(lang.tabs, function (i, item) {
|
||||
// 表头
|
||||
var li = lay.elem('li', {
|
||||
'class': i === 0 ? THIS : "", 'lay-id': i
|
||||
});
|
||||
li.innerHTML = item.title;
|
||||
tabHead.appendChild(li);
|
||||
|
||||
// 表体
|
||||
tabContent.appendChild(that.getTabContentChildElem(i));
|
||||
});
|
||||
|
||||
// 主区域
|
||||
elemMain = that.elemMain = lay.elem('div', {
|
||||
'class': 'layui-cron-main'
|
||||
});
|
||||
elemMain.appendChild(elemTab);
|
||||
|
||||
//生成底部栏
|
||||
lay(divFooter).html(function () {
|
||||
var html = [], btns = [];
|
||||
lay.each(options.btns, function (i, item) {
|
||||
var title = lang.tools[item] || 'btn';
|
||||
btns.push('<span lay-type="' + item + '" class="cron-btns-' + item + '">' + title + '</span>');
|
||||
});
|
||||
html.push('<div class="cron-footer-btns">' + btns.join('') + '</div>');
|
||||
return html.join('');
|
||||
}());
|
||||
|
||||
//插入到主区域
|
||||
elem.appendChild(elemMain);
|
||||
|
||||
options.showBottom && elem.appendChild(divFooter);
|
||||
|
||||
|
||||
//移除上一个控件
|
||||
that.remove(Class.thisElemCron);
|
||||
|
||||
//如果是静态定位,则插入到指定的容器中,否则,插入到body
|
||||
isStatic ? options.elem.append(elem) : (document.body.appendChild(elem)
|
||||
, that.position());
|
||||
|
||||
|
||||
that.checkCron();
|
||||
|
||||
that.elemEvent(); // 主面板事件
|
||||
|
||||
Class.thisElemCron = that.elemID;
|
||||
|
||||
form.render();
|
||||
|
||||
}
|
||||
|
||||
// 渲染 tab 子控件
|
||||
Class.prototype.getTabContentChildElem = function (index) {
|
||||
var that = this, options = that.config, tabItem = options.tabs[index], tabItemKey = tabItem.key,
|
||||
lang = that.lang(), tabItemLang = lang.tabs[index], cron = options.cron,
|
||||
formFilter = 'cronForm' + tabItemKey + options.elem.attr('lay-key'), data = function () {
|
||||
if (cron[tabItemKey].indexOf('-') != -1) {
|
||||
// 周期数据
|
||||
var arr = cron[tabItemKey].split('-');
|
||||
return {
|
||||
type: 'range', start: arr[0], end: arr[1]
|
||||
};
|
||||
}
|
||||
if (cron[tabItemKey].indexOf('/') != -1) {
|
||||
// 频率数据
|
||||
var arr = cron[tabItemKey].split('/');
|
||||
return {
|
||||
type: 'rate', begin: arr[0], rate: arr[1]
|
||||
};
|
||||
}
|
||||
if (cron[tabItemKey].indexOf(',') != -1 || /^\+?[0-9][0-9]*$/.test(cron[tabItemKey])) {
|
||||
// 按照指定执行
|
||||
var arr = cron[tabItemKey].split(',').map(Number);
|
||||
return {
|
||||
type: 'custom', values: arr
|
||||
};
|
||||
}
|
||||
if (cron[tabItemKey].indexOf('W') != -1) {
|
||||
// 最近的工作日
|
||||
var value = cron[tabItemKey].replace('W', '');
|
||||
return {
|
||||
type: 'weekday', value: value
|
||||
};
|
||||
}
|
||||
if (index === 2 && cron[tabItemKey] === 'L') {
|
||||
// 本月最后一日
|
||||
return {
|
||||
type: 'lastday', value: 'L'
|
||||
};
|
||||
}
|
||||
if (index === 4 && cron[tabItemKey].indexOf('L') != -1) {
|
||||
// 本月最后一个周 value
|
||||
var value = cron[tabItemKey].replace('L', '');
|
||||
return {
|
||||
type: 'lastweek', value: value
|
||||
};
|
||||
}
|
||||
if (cron[tabItemKey] === '*') {
|
||||
// 每次
|
||||
return {
|
||||
type: 'every', value: '*'
|
||||
};
|
||||
}
|
||||
if (cron[tabItemKey] === '?' || cron[tabItemKey] === undefined || cron[tabItemKey] === '') {
|
||||
// 不指定
|
||||
return {
|
||||
//type: 'unspecified', value: cron[tabItemKey]
|
||||
type: 'every', value: '*'
|
||||
};
|
||||
}
|
||||
}(), rangeData = function () {
|
||||
if (tabItem.range) {
|
||||
var arr = tabItem.range.split('-');
|
||||
return {
|
||||
min: parseInt(arr[0]), max: parseInt(arr[1])
|
||||
};
|
||||
}
|
||||
}();
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'layui-tab-item layui-form ' + (index === 0 ? SHOW : ""), 'lay-filter': formFilter
|
||||
});
|
||||
|
||||
// 每次
|
||||
elem.appendChild(function () {
|
||||
var everyRadio = lay.elem('input', {
|
||||
'name': tabItemKey + '[type]',
|
||||
'type': 'radio',
|
||||
'value': 'every',
|
||||
'title': lang.every + tabItemLang.title
|
||||
});
|
||||
if (data.type === 'every') {
|
||||
lay(everyRadio).attr('checked', true);
|
||||
}
|
||||
var everyDiv = lay.elem('div', {
|
||||
'class': 'cron-row'
|
||||
});
|
||||
everyDiv.appendChild(everyRadio);
|
||||
return everyDiv;
|
||||
}());
|
||||
|
||||
// 不指定,从日开始
|
||||
/*if (index >= 2) {
|
||||
elem.appendChild(function () {
|
||||
var unspecifiedRadio = lay.elem('input', {
|
||||
'name': tabItemKey + '[type]', 'type': 'radio', 'value': 'unspecified', 'title': lang.unspecified
|
||||
});
|
||||
if (data.type === 'unspecified') {
|
||||
lay(unspecifiedRadio).attr('checked', true);
|
||||
}
|
||||
var unspecifiedDiv = lay.elem('div', {
|
||||
'class': 'cron-row'
|
||||
});
|
||||
unspecifiedDiv.appendChild(unspecifiedRadio);
|
||||
return unspecifiedDiv;
|
||||
}());
|
||||
}*/
|
||||
|
||||
// 周期
|
||||
var rangeChild = [function () {
|
||||
var rangeRadio = lay.elem('input', {
|
||||
'name': tabItemKey + '[type]', 'type': 'radio', 'value': 'range', 'title': lang.period
|
||||
});
|
||||
if (data.type === 'range') {
|
||||
lay(rangeRadio).attr('checked', true);
|
||||
}
|
||||
return rangeRadio;
|
||||
}(), function () {
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'cron-input-mid'
|
||||
});
|
||||
elem.innerHTML = lang.periodFrom;
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('input', {
|
||||
'class': 'cron-input', 'type': 'number', 'name': 'rangeStart', 'value': data.start || ''
|
||||
});
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'cron-input-mid'
|
||||
});
|
||||
elem.innerHTML = '-';
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('input', {
|
||||
'class': 'cron-input', 'type': 'number', 'name': 'rangeEnd', 'value': data.end || ''
|
||||
});
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'cron-input-mid'
|
||||
});
|
||||
elem.innerHTML = tabItemLang.title;
|
||||
return elem;
|
||||
}()]
|
||||
|
||||
, rangeDiv = lay.elem('div', {
|
||||
'class': 'cron-row'
|
||||
});
|
||||
lay.each(rangeChild, function (i, item) {
|
||||
rangeDiv.appendChild(item);
|
||||
});
|
||||
if (tabItem.range) {
|
||||
var rangeTip = lay.elem('div', {
|
||||
'class': 'cron-tips'
|
||||
});
|
||||
rangeTip.innerHTML = ['(', tabItem.range, ')'].join('');
|
||||
rangeDiv.appendChild(rangeTip);
|
||||
}
|
||||
elem.appendChild(rangeDiv);
|
||||
|
||||
// 频率,年没有
|
||||
if (index < 6) {
|
||||
var rateChild = [function () {
|
||||
var rateRadio = lay.elem('input', {
|
||||
'name': tabItemKey + '[type]', 'type': 'radio', 'value': 'rate', 'title': lang.rate
|
||||
});
|
||||
if (data.type === 'rate') {
|
||||
lay(rateRadio).attr('checked', true);
|
||||
}
|
||||
return rateRadio;
|
||||
}(), function () {
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'cron-input-mid'
|
||||
});
|
||||
elem.innerHTML = tabItemLang.rateBegin || lang.rateBegin;
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('input', {
|
||||
'class': 'cron-input', 'type': 'number', 'name': 'begin', 'value': data.begin || ''
|
||||
});
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'cron-input-mid'
|
||||
});
|
||||
elem.innerHTML = tabItemLang.rateMid || (tabItemLang.title + lang.rateMid);
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('input', {
|
||||
'class': 'cron-input', 'type': 'number', 'name': 'rate', 'value': data.rate || ''
|
||||
});
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'cron-input-mid'
|
||||
});
|
||||
elem.innerHTML = undefined != tabItemLang.rateEnd ? tabItemLang.rateEnd : (tabItemLang.title + lang.rateEnd);
|
||||
if (undefined != tabItemLang.rateEnd && tabItemLang.rateEnd === '') {
|
||||
lay(elem).addClass(HIDE);
|
||||
}
|
||||
return elem;
|
||||
}()]
|
||||
|
||||
, rateDiv = lay.elem('div', {
|
||||
'class': 'cron-row'
|
||||
});
|
||||
lay.each(rateChild, function (i, item) {
|
||||
rateDiv.appendChild(item);
|
||||
});
|
||||
if (tabItem.range) {
|
||||
var rateTip = lay.elem('div', {
|
||||
'class': 'cron-tips'
|
||||
});
|
||||
if (index === 4) {
|
||||
// 周
|
||||
rateTip.innerHTML = '(1-4/1-7)';
|
||||
} else {
|
||||
rateTip.innerHTML = ['(', rangeData.min, '/', (rangeData.max + (index <= 1 ? 1 : 0)), ')'].join('');
|
||||
}
|
||||
rateDiv.appendChild(rateTip);
|
||||
}
|
||||
elem.appendChild(rateDiv);
|
||||
}
|
||||
|
||||
// 特殊:日(最近的工作日、最后一日),周(最后一周)
|
||||
/*if (index === 2) {
|
||||
// 日
|
||||
// 最近的工作日
|
||||
var weekChild = [function () {
|
||||
var weekRadio = lay.elem('input', {
|
||||
'name': tabItemKey + '[type]', 'type': 'radio', 'value': 'weekday', 'title': lang.weekday
|
||||
});
|
||||
if (data.type === 'weekday') {
|
||||
lay(weekRadio).attr('checked', true);
|
||||
}
|
||||
return weekRadio;
|
||||
}(), function () {
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'cron-input-mid'
|
||||
});
|
||||
elem.innerHTML = lang.weekdayPrefix;
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('input', {
|
||||
'class': 'cron-input', 'type': 'number', 'name': 'weekday', 'value': data.value || ''
|
||||
});
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'cron-input-mid'
|
||||
});
|
||||
elem.innerHTML = lang.weekdaySuffix;
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'cron-tips'
|
||||
});
|
||||
elem.innerHTML = ['(', tabItem.range, ')'].join('');
|
||||
return elem;
|
||||
}()]
|
||||
|
||||
, weekDiv = lay.elem('div', {
|
||||
'class': 'cron-row'
|
||||
});
|
||||
lay.each(weekChild, function (i, item) {
|
||||
weekDiv.appendChild(item);
|
||||
});
|
||||
elem.appendChild(weekDiv);
|
||||
|
||||
// 本月最后一日
|
||||
elem.appendChild(function () {
|
||||
var lastRadio = lay.elem('input', {
|
||||
'name': tabItemKey + '[type]', 'type': 'radio', 'value': 'lastday', 'title': lang.lastday
|
||||
});
|
||||
if (data.type === 'lastday') {
|
||||
lay(lastRadio).attr('checked', true);
|
||||
}
|
||||
var lastDiv = lay.elem('div', {
|
||||
'class': 'cron-row'
|
||||
});
|
||||
lastDiv.appendChild(lastRadio);
|
||||
return lastDiv;
|
||||
}());
|
||||
|
||||
}
|
||||
|
||||
if (index === 4) {
|
||||
// 本月最后一个周几
|
||||
var lastWeekChild = [function () {
|
||||
var lastWeekRadio = lay.elem('input', {
|
||||
'name': tabItemKey + '[type]', 'type': 'radio', 'value': 'lastweek', 'title': lang.lastweek
|
||||
});
|
||||
if (data.type === 'lastweek') {
|
||||
lay(lastWeekRadio).attr('checked', true);
|
||||
}
|
||||
return lastWeekRadio;
|
||||
}(), function () {
|
||||
var elem = lay.elem('input', {
|
||||
'class': 'cron-input', 'type': 'number', 'name': 'lastweek', 'value': data.value || ''
|
||||
});
|
||||
return elem;
|
||||
}(), function () {
|
||||
var elem = lay.elem('div', {
|
||||
'class': 'cron-tips'
|
||||
});
|
||||
elem.innerHTML = ['(', tabItem.range, ')'].join('');
|
||||
return elem;
|
||||
}()]
|
||||
|
||||
, lastWeekDiv = lay.elem('div', {
|
||||
'class': 'cron-row'
|
||||
});
|
||||
lay.each(lastWeekChild, function (i, item) {
|
||||
lastWeekDiv.appendChild(item);
|
||||
});
|
||||
elem.appendChild(lastWeekDiv);
|
||||
|
||||
}*/
|
||||
|
||||
// 指定
|
||||
if (index <= 4) {
|
||||
elem.appendChild(function () {
|
||||
var customRadio = lay.elem('input', {
|
||||
'name': tabItemKey + '[type]', 'type': 'radio', 'value': 'custom', 'title': lang.custom
|
||||
});
|
||||
if (data.type === 'custom') {
|
||||
lay(customRadio).attr('checked', true);
|
||||
}
|
||||
var customDiv = lay.elem('div', {
|
||||
'class': 'cron-row'
|
||||
});
|
||||
customDiv.appendChild(customRadio);
|
||||
return customDiv;
|
||||
}());
|
||||
|
||||
// 指定数值,时分秒显示两位数,自动补零
|
||||
elem.appendChild(function () {
|
||||
var customGrid = lay.elem('div', {
|
||||
'class': 'cron-grid'
|
||||
});
|
||||
var i = rangeData.min;
|
||||
while (i <= rangeData.max) {
|
||||
// 时分秒显示两位数,自动补零
|
||||
var gridItemValue = index <= 1 ? lay.digit(i, 2) : i;
|
||||
var gridItem = lay.elem('input', {
|
||||
'type': 'checkbox',
|
||||
'title': gridItemValue,
|
||||
'lay-skin': 'primary',
|
||||
'name': tabItemKey + '[custom]',
|
||||
'value': i
|
||||
});
|
||||
if (data.values && data.values.includes(i)) {
|
||||
lay(gridItem).attr('checked', true);
|
||||
}
|
||||
customGrid.appendChild(gridItem);
|
||||
i++;
|
||||
}
|
||||
return customGrid;
|
||||
}());
|
||||
}
|
||||
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
//是否输入框
|
||||
Class.prototype.isInput = function (elem) {
|
||||
return /input|textarea/.test(elem.tagName.toLocaleLowerCase());
|
||||
};
|
||||
|
||||
// 绑定的元素事件处理
|
||||
Class.prototype.events = function () {
|
||||
var that = this, options = that.config
|
||||
|
||||
//绑定呼出控件事件
|
||||
, showEvent = function (elem, bind) {
|
||||
elem.on(options.trigger, function () {
|
||||
bind && (that.bindElem = this);
|
||||
that.render();
|
||||
});
|
||||
};
|
||||
|
||||
if (!options.elem[0] || options.elem[0].eventHandler) return;
|
||||
|
||||
showEvent(options.elem, 'bind');
|
||||
showEvent(options.eventElem);
|
||||
|
||||
//绑定关闭控件事件
|
||||
lay(document).on('click', function (e) {
|
||||
if (e.target === options.elem[0] || e.target === options.eventElem[0] || e.target === lay(options.closeStop)[0]) {
|
||||
return;
|
||||
}
|
||||
that.remove();
|
||||
}).on('keydown', function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
if (lay('#' + that.elemID)[0] && that.elemID === Class.thisElemDate) {
|
||||
e.preventDefault();
|
||||
lay(that.footer).find(ELEM_CONFIRM)[0].click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//自适应定位
|
||||
lay(window).on('resize', function () {
|
||||
if (!that.elem || !lay(ELEM)[0]) {
|
||||
return false;
|
||||
}
|
||||
that.position();
|
||||
});
|
||||
|
||||
options.elem[0].eventHandler = true;
|
||||
};
|
||||
|
||||
// 主面板事件
|
||||
Class.prototype.elemEvent = function () {
|
||||
var that = this, options = that.config, tabFilter = 'cron-tab' + options.elem.attr('lay-key');
|
||||
|
||||
// 阻止主面板点击冒泡,避免因触发文档事件而关闭主面
|
||||
lay(that.elem).on('click', function (e) {
|
||||
lay.stope(e);
|
||||
});
|
||||
|
||||
// tab选项卡切换
|
||||
var lis = lay(that.elemTab).find('li');
|
||||
lis.on('click', function () {
|
||||
var layid = lay(this).attr('lay-id');
|
||||
if (undefined === layid) {
|
||||
return;
|
||||
}
|
||||
element.tabChange(tabFilter, layid);
|
||||
});
|
||||
|
||||
// cron选项点击
|
||||
form.on('radio', function (data) {
|
||||
var $parent = data.othis.parent();
|
||||
var formFilter = $parent.parent().attr('lay-filter');
|
||||
var formData = form.val(formFilter);
|
||||
var radioType = data.value;
|
||||
if ('range' === radioType) {
|
||||
// 范围
|
||||
form.val(formFilter, {
|
||||
rangeStart: formData.rangeStart || 0, rangeEnd: formData.rangeEnd || 2
|
||||
});
|
||||
}
|
||||
if ('rate' === radioType) {
|
||||
// 频率
|
||||
form.val(formFilter, {
|
||||
begin: formData.begin || 0, rate: formData.rate || 2
|
||||
});
|
||||
}
|
||||
if ('custom' === radioType) {
|
||||
// custom
|
||||
var $grid = $parent.next();
|
||||
if ($grid.find(':checkbox:checked').length <= 0) {
|
||||
$grid.children(':checkbox:first').next().click()
|
||||
}
|
||||
}
|
||||
if ('weekday' === radioType) {
|
||||
// weekday
|
||||
form.val(formFilter, {
|
||||
weekday: formData.weekday || 1
|
||||
});
|
||||
}
|
||||
if ('lastweek' === radioType) {
|
||||
// lastweek
|
||||
form.val(formFilter, {
|
||||
lastweek: formData.lastweek || 1
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//gird checkbox点击时,自动选中radio
|
||||
form.on('checkbox', function (data) {
|
||||
//触发选项的点击事件
|
||||
var $parent = data.othis.parent().parent();
|
||||
//循环父级,找到子级的子级找到value="custom"的radio
|
||||
var $radio = $parent.children().find('input[value="custom"]');
|
||||
//触发radio的点击事件
|
||||
$radio.next().click();
|
||||
});
|
||||
|
||||
//点击底部按钮
|
||||
lay(that.footer).find('span').on('click', function () {
|
||||
var type = lay(this).attr('lay-type');
|
||||
that.tool(this, type);
|
||||
});
|
||||
};
|
||||
|
||||
//底部按钮点击事件
|
||||
Class.prototype.tool = function (btn, type) {
|
||||
var that = this, options = that.config, lang = that.lang(), isStatic = options.position === 'static', active = {
|
||||
//运行
|
||||
run: function () {
|
||||
var value = that.parse();
|
||||
var loading = layer.load();
|
||||
$.get(options.run, {cron: value}, function (res) {
|
||||
layer.close(loading);
|
||||
if (res.code !== 0) {
|
||||
return that.hint(res.msg);
|
||||
}
|
||||
that.runHint(res.data);
|
||||
}, 'json').fail(function () {
|
||||
layer.close(loading);
|
||||
that.hint('服务器异常!');
|
||||
});
|
||||
}
|
||||
|
||||
//确定
|
||||
, confirm: function () {
|
||||
var value = that.parse();
|
||||
that.done([value]);
|
||||
that.setValue(value).remove()
|
||||
}
|
||||
};
|
||||
active[type] && active[type]();
|
||||
};
|
||||
|
||||
//执行 done/change 回调
|
||||
Class.prototype.done = function (param, type) {
|
||||
var that = this, options = that.config;
|
||||
|
||||
param = param || [that.parse()];
|
||||
typeof options[type || 'done'] === 'function' && options[type || 'done'].apply(options, param);
|
||||
|
||||
return that;
|
||||
};
|
||||
|
||||
// 解析cron表达式
|
||||
Class.prototype.parse = function () {
|
||||
var that = this, options = that.config, valueArr = [];
|
||||
|
||||
lay.each(options.tabs, function (index, item) {
|
||||
var key = item.key;
|
||||
var formFilter = 'cronForm' + key + options.elem.attr('lay-key');
|
||||
var formData = form.val(formFilter);
|
||||
var radioType = (key + '[type]');
|
||||
var current = "";
|
||||
if (formData[radioType] === 'every') {
|
||||
// 每次
|
||||
current = "*";
|
||||
}
|
||||
if (formData[radioType] === 'range') {
|
||||
// 范围
|
||||
current = formData.rangeStart + "-" + formData.rangeEnd;
|
||||
}
|
||||
if (formData[radioType] === 'rate') {
|
||||
// 频率
|
||||
current = formData.begin + "/" + formData.rate;
|
||||
}
|
||||
if (formData[radioType] === 'custom') {
|
||||
// 指定
|
||||
var checkboxName = (item.key + '[custom]');
|
||||
var customArr = [];
|
||||
$('input[name="' + checkboxName + '"]:checked').each(function () {
|
||||
customArr.push($(this).val());
|
||||
});
|
||||
current = customArr.join(',');
|
||||
}
|
||||
if (formData[radioType] === 'weekday') {
|
||||
// 每月 formData.weekday 号最近的那个工作日
|
||||
current = formData.weekday + "W";
|
||||
}
|
||||
if (formData[radioType] === 'lastday') {
|
||||
// 本月最后一日
|
||||
current = "L";
|
||||
}
|
||||
if (formData[radioType] === 'lastweek') {
|
||||
// 本月最后星期
|
||||
current = formData.lastweek + "L";
|
||||
}
|
||||
|
||||
if (formData[radioType] === 'unspecified' && index != 6) {
|
||||
// 不指定
|
||||
current = "?";
|
||||
}
|
||||
if (current !== "") {
|
||||
valueArr.push(current);
|
||||
options.cron[key] = current;
|
||||
}
|
||||
});
|
||||
return valueArr.join(' ');
|
||||
};
|
||||
|
||||
//控件移除
|
||||
Class.prototype.remove = function (prev) {
|
||||
var that = this, options = that.config, elem = lay('#' + (prev || that.elemID));
|
||||
if (!elem[0]) return that;
|
||||
|
||||
if (!elem.hasClass(ELEM_STATIC)) {
|
||||
that.checkCron(function () {
|
||||
elem.remove();
|
||||
});
|
||||
}
|
||||
return that;
|
||||
};
|
||||
|
||||
//定位算法
|
||||
Class.prototype.position = function () {
|
||||
var that = this, options = that.config;
|
||||
lay.position(that.bindElem || options.elem[0], that.elem, {
|
||||
position: options.position
|
||||
});
|
||||
return that;
|
||||
};
|
||||
|
||||
//提示
|
||||
Class.prototype.hint = function (content) {
|
||||
var that = this, options = that.config, div = lay.elem('div', {
|
||||
'class': ELEM_HINT
|
||||
});
|
||||
|
||||
if (!that.elem) return;
|
||||
|
||||
div.innerHTML = content || '';
|
||||
lay(that.elem).find('.' + ELEM_HINT).remove();
|
||||
that.elem.appendChild(div);
|
||||
|
||||
clearTimeout(that.hinTimer);
|
||||
that.hinTimer = setTimeout(function () {
|
||||
lay(that.elem).find('.' + ELEM_HINT).remove();
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
//运行提示
|
||||
Class.prototype.runHint = function (runList) {
|
||||
var that = this, options = that.config, div = lay.elem('div', {
|
||||
'class': ELEM_RUN_HINT
|
||||
});
|
||||
// debugger;
|
||||
if (!that.elem || !runList || !runList.length) return;
|
||||
|
||||
|
||||
lay(div).html(function () {
|
||||
var html = [];
|
||||
lay.each(runList, function (i, item) {
|
||||
html.push('<div class="cron-run-list">' + item + '</div>');
|
||||
});
|
||||
return html.join('');
|
||||
}());
|
||||
|
||||
lay(that.elem).find('.' + ELEM_RUN_HINT).remove();
|
||||
that.elem.appendChild(div);
|
||||
};
|
||||
|
||||
//赋值
|
||||
Class.prototype.setValue = function (value = '') {
|
||||
var that = this, options = that.config, elem = that.bindElem || options.elem[0],
|
||||
valType = that.isInput(elem) ? 'val' : 'html'
|
||||
|
||||
options.position === 'static' || lay(elem)[valType](value || '');
|
||||
elem.textContent = '生成';
|
||||
return this;
|
||||
};
|
||||
|
||||
//cron校验
|
||||
Class.prototype.checkCron = function (fn) {
|
||||
var that = this, options = that.config, lang = that.lang(), elem = that.bindElem || options.elem[0],
|
||||
value = that.isInput(elem) ? elem.value : (options.position === 'static' ? '' : elem.innerHTML)
|
||||
|
||||
, checkValid = function (value = "") {
|
||||
|
||||
};
|
||||
|
||||
// cron 值,多个空格替换为一个空格,去掉首尾空格
|
||||
value = value || options.value;
|
||||
if (typeof value === 'string') {
|
||||
value = value.replace(/\s+/g, ' ').replace(/^\s|\s$/g, '');
|
||||
}
|
||||
|
||||
if (fn === 'init') return checkValid(value), that;
|
||||
|
||||
value = that.parse();
|
||||
if (value) {
|
||||
that.setValue(value);
|
||||
}
|
||||
fn && fn();
|
||||
return that;
|
||||
};
|
||||
|
||||
//核心入口
|
||||
cron.render = function (options) {
|
||||
var ins = new Class(options);
|
||||
return thisIns.call(ins);
|
||||
};
|
||||
|
||||
exports('cron', cron);
|
||||
});
|
||||
@@ -1,261 +0,0 @@
|
||||
/**
|
||||
* Set echarts theme
|
||||
*/
|
||||
|
||||
layui.define(function (exports) {
|
||||
exports('echartsTheme', {
|
||||
// 默认色板
|
||||
color: [
|
||||
'#16baaa', '#1E9FFF', '#16b777', '#FFB980', '#D87A80',
|
||||
'#8d98b3', '#e5cf0d', '#97b552', '#95706d', '#dc69aa',
|
||||
'#07a2a4', '#9a7fd1', '#588dd5', '#f5994e', '#c05050',
|
||||
'#59678c', '#c9ab00', '#7eb00a', '#6f5553', '#c14089'
|
||||
],
|
||||
|
||||
// 图表标题
|
||||
title: {
|
||||
textStyle: {
|
||||
fontWeight: 'normal',
|
||||
color: '#5F5F5F' // 主标题文字颜色
|
||||
}
|
||||
},
|
||||
|
||||
// 值域
|
||||
dataRange: {
|
||||
itemWidth: 15,
|
||||
color: ['#16baaa', '#e0ffff']
|
||||
},
|
||||
|
||||
// 工具箱
|
||||
toolbox: {
|
||||
color: ['#1e90ff', '#1e90ff', '#1e90ff', '#1e90ff'],
|
||||
effectiveColor: '#ff4500'
|
||||
},
|
||||
|
||||
// 提示框
|
||||
tooltip: {
|
||||
backgroundColor: 'rgba(50,50,50,0.5)', // 提示背景颜色,默认为透明度为0.7的黑色
|
||||
axisPointer: { // 坐标轴指示器,坐标轴触发有效
|
||||
type: 'line', // 默认为直线,可选为:'line' | 'shadow'
|
||||
lineStyle: { // 直线指示器样式设置
|
||||
color: '#16baaa'
|
||||
},
|
||||
crossStyle: {
|
||||
color: '#008acd'
|
||||
},
|
||||
shadowStyle: { // 阴影指示器样式设置
|
||||
color: 'rgba(200,200,200,0.2)'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 区域缩放控制器
|
||||
dataZoom: {
|
||||
dataBackgroundColor: '#efefff', // 数据背景颜色
|
||||
fillerColor: 'rgba(182,162,222,0.2)', // 填充颜色
|
||||
handleColor: '#008acd' // 手柄颜色
|
||||
},
|
||||
|
||||
// 网格
|
||||
grid: {
|
||||
borderColor: '#eee'
|
||||
},
|
||||
|
||||
// 类目轴 - X轴
|
||||
categoryAxis: {
|
||||
axisLine: { // 坐标轴线
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: '#16baaa'
|
||||
}
|
||||
},
|
||||
axisTick: { //小标记
|
||||
show: false
|
||||
},
|
||||
splitLine: { // 分隔线
|
||||
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
|
||||
color: ['#eee']
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 数值型坐标轴默认参数 - Y轴
|
||||
valueAxis: {
|
||||
axisLine: { // 坐标轴线
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: '#16baaa'
|
||||
}
|
||||
},
|
||||
splitArea: {
|
||||
show: true,
|
||||
areaStyle: {
|
||||
color: ['rgba(250,250,250,0.1)', 'rgba(200,200,200,0.1)']
|
||||
}
|
||||
},
|
||||
splitLine: { // 分隔线
|
||||
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
|
||||
color: ['#eee']
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
polar: {
|
||||
axisLine: { // 坐标轴线
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: '#ddd'
|
||||
}
|
||||
},
|
||||
splitArea: {
|
||||
show: true,
|
||||
areaStyle: {
|
||||
color: ['rgba(250,250,250,0.2)', 'rgba(200,200,200,0.2)']
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#ddd'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
timeline: {
|
||||
lineStyle: {
|
||||
color: '#16baaa'
|
||||
},
|
||||
controlStyle: {
|
||||
normal: { color: '#16baaa' },
|
||||
emphasis: { color: '#16baaa' }
|
||||
},
|
||||
symbol: 'emptyCircle',
|
||||
symbolSize: 3
|
||||
},
|
||||
|
||||
// 柱形图默认参数
|
||||
bar: {
|
||||
itemStyle: {
|
||||
normal: {
|
||||
barBorderRadius: 2
|
||||
},
|
||||
emphasis: {
|
||||
barBorderRadius: 2
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 折线图默认参数
|
||||
line: {
|
||||
smooth: true,
|
||||
symbol: 'emptyCircle', // 拐点图形类型
|
||||
symbolSize: 3 // 拐点图形大小
|
||||
},
|
||||
|
||||
// K线图默认参数
|
||||
k: {
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: '#d87a80', // 阳线填充颜色
|
||||
color0: '#2ec7c9', // 阴线填充颜色
|
||||
lineStyle: {
|
||||
color: '#d87a80', // 阳线边框颜色
|
||||
color0: '#2ec7c9' // 阴线边框颜色
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 散点图默认参数
|
||||
scatter: {
|
||||
symbol: 'circle', // 图形类型
|
||||
symbolSize: 4 // 图形大小,半宽(半径)参数,当图形为方向或菱形则总宽度为symbolSize * 2
|
||||
},
|
||||
|
||||
// 雷达图默认参数
|
||||
radar: {
|
||||
symbol: 'emptyCircle', // 图形类型
|
||||
symbolSize: 3
|
||||
//symbol: null, // 拐点图形类型
|
||||
//symbolRotate : null, // 图形旋转控制
|
||||
},
|
||||
|
||||
map: {
|
||||
itemStyle: {
|
||||
normal: {
|
||||
areaStyle: {
|
||||
color: '#ddd'
|
||||
},
|
||||
label: {
|
||||
textStyle: {
|
||||
color: '#d87a80'
|
||||
}
|
||||
}
|
||||
},
|
||||
emphasis: { // 也是选中样式
|
||||
areaStyle: {
|
||||
color: '#fe994e'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
force: {
|
||||
itemStyle: {
|
||||
normal: {
|
||||
linkStyle: {
|
||||
color: '#1e90ff'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
chord: {
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(128, 128, 128, 0.5)',
|
||||
chordStyle: {
|
||||
lineStyle: {
|
||||
color: 'rgba(128, 128, 128, 0.5)'
|
||||
}
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(128, 128, 128, 0.5)',
|
||||
chordStyle: {
|
||||
lineStyle: {
|
||||
color: 'rgba(128, 128, 128, 0.5)'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
gauge: {
|
||||
axisLine: { // 坐标轴线
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: [[0.2, '#2ec7c9'], [0.8, '#5ab1ef'], [1, '#d87a80']],
|
||||
width: 10
|
||||
}
|
||||
},
|
||||
axisTick: { // 坐标轴小标记
|
||||
splitNumber: 10, // 每份split细分多少段
|
||||
length: 15, // 属性length控制线长
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: 'auto'
|
||||
}
|
||||
},
|
||||
splitLine: { // 分隔线
|
||||
length: 22, // 属性length控制线长
|
||||
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
|
||||
color: 'auto'
|
||||
}
|
||||
},
|
||||
pointer: {
|
||||
width: 5
|
||||
}
|
||||
},
|
||||
|
||||
textStyle: {
|
||||
fontFamily: '微软雅黑, Arial, Verdana, sans-serif'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
Before Width: | Height: | Size: 832 B |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 455 B |
|
Before Width: | Height: | Size: 457 B |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
@@ -1,762 +0,0 @@
|
||||
/**
|
||||
* admin.templte.css
|
||||
*/
|
||||
|
||||
/********************************
|
||||
|
||||
模板开始
|
||||
|
||||
*******************************/
|
||||
|
||||
|
||||
/* 产品版本选择面板 */
|
||||
.layadmin-panel-selection {
|
||||
width: 768px;
|
||||
margin: 30px auto;
|
||||
}
|
||||
|
||||
.layadmin-panel-selection .layui-panel-window {
|
||||
padding: 30px 50px;
|
||||
border-top-color: #ddd;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.layadmin-panel-selection .layui-panel-window h2 {
|
||||
padding-bottom: 15px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.layadmin-panel-selection .layui-panel-window ul {
|
||||
margin-top: 15px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.layadmin-panel-selection .layui-btn-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.layadmin-panel-selection .layui-btn-container .layui-btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 通讯录面板 */
|
||||
.layadmin-maillist-fluid .layadmin-contact-box {
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #e7eaec;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layadmin-maillist-fluid .layadmin-text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.layadmin-maillist-fluid .layadmin-text-center img {
|
||||
max-width: 80%;
|
||||
border-radius: 50%;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.layadmin-maillist-fluid .layadmin-font-blod {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.layadmin-maillist-fluid .layadmin-maillist-img {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.layadmin-maillist-fluid .layadmin-title {
|
||||
margin: 5px 0 10px 0;
|
||||
}
|
||||
|
||||
.layadmin-maillist-fluid .layadmin-textimg {
|
||||
line-height: 25px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.layadmin-maillist-fluid .layadmin-address {
|
||||
line-height: 1.5;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.layadmin-maillist-fluid .layadmin-padding-left20 {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
/* 个人主页 */
|
||||
.layadmin-homepage-shadow {
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.17);
|
||||
border-radius: 0;
|
||||
border: 1px solid #e7ecf3;
|
||||
}
|
||||
|
||||
.layadmin-homepage-panel {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-panel .text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.layadmin-homepage-information {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
}
|
||||
|
||||
.layadmin-homepage-pad-ver {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-pad-img {
|
||||
box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.layadmin-homepage-font {
|
||||
font-weight: 600;
|
||||
color: #2b425b;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.layadmin-homepage-min-font {
|
||||
margin: 5px 0 10px 0;
|
||||
font-size: 0.9em;
|
||||
color: #afb9c3;
|
||||
}
|
||||
|
||||
.layadmin-homepage-pad-ver a {
|
||||
line-height: 1.1em;
|
||||
font-size: 1.3em;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-pad-ver a:hover {
|
||||
background: #16b777;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.layadmin-homepage-about {
|
||||
padding: 15px;
|
||||
font-weight: 600;
|
||||
color: #2b425b;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-group {
|
||||
font-size: 0.9em;
|
||||
line-height: 1.25;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-group li {
|
||||
padding: 5px 15px;
|
||||
border: 1px solid #ddd;
|
||||
margin-bottom: -1px;
|
||||
border-width: 1px 0;
|
||||
border-radius: 0;
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-group li i {
|
||||
font-size: 1.333em;
|
||||
line-height: 1.095em;
|
||||
vertical-align: middle;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-group li a.color {
|
||||
color: #337ab7;
|
||||
}
|
||||
|
||||
.layadmin-homepage-pad-hor {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
border-bottom: 15px;
|
||||
color: #758697;
|
||||
text-indent: 20px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-inline {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
padding-bottom: 20px
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-inline a {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-inline .layui-btn {
|
||||
font-size: .9em;
|
||||
line-height: 1.42857;
|
||||
vertical-align: middle;
|
||||
height: auto;
|
||||
padding: 4px 7px;
|
||||
margin-left: 0px;
|
||||
margin: 0 10px 10px 0;
|
||||
}
|
||||
|
||||
/* 左侧个人信息区域 */
|
||||
.layadmin-homepage-text-center {
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-padding15 {
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-padding8 {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-paddingmb {
|
||||
margin-bottom: 15px;
|
||||
margin: 0 -7.5px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-content {
|
||||
margin-left: 15px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.layadmin-homepage-content .new-section-xs {
|
||||
margin: 12px 0;
|
||||
color: inherit;
|
||||
border: 0 !important;
|
||||
height: 0px;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.layadmin-homepage-content .h4 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #2b425b;
|
||||
}
|
||||
|
||||
.layadmin-homepage-content small {
|
||||
color: #afb9c3
|
||||
}
|
||||
|
||||
.layadmin-homepage-text-center .layui-icon {
|
||||
color: #FFB800;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-padding15 .layui-col-sm5 a {
|
||||
font-size: 11px;
|
||||
height: auto;
|
||||
line-height: 1.5;
|
||||
padding: 5px 10px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.layadmin-homepage-padding15 .layui-btn-normal {
|
||||
margin: 0 15px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .layui-col-sm10, .layadmin-homepage-list-imgtxt .layui-col-sm2 {
|
||||
background: none
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .panel-body {
|
||||
padding: 15px 20px 25px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .panel-body .media-left {
|
||||
display: block;
|
||||
float: left;
|
||||
vertical-align: top;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .panel-body .media-left img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body {
|
||||
width: auto;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .pad-btm {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .pad-btm p:first-child {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .min-font {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .min-font .layui-breadcrumb a {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.layui-breadcrumb span[lay-separator] {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .pad-btm .fontColor a {
|
||||
font-weight: 600;
|
||||
color: #337ab7;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .pad-btm .fontColor span {
|
||||
color: #758697;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .h-img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .img-xs {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media {
|
||||
margin-top: 15px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media .media-right {
|
||||
float: right;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media .media-right .list-inline {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media .list-inline li {
|
||||
padding: 0 5px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media .media-right .list-inline li span {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media .media-left {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media .media-left .font-blod {
|
||||
font-weight: 700;
|
||||
color: #758697;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media-list {
|
||||
padding-top: 15px;
|
||||
margin-top: 15px;
|
||||
border-top: 1px solid #e9e9e9;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media-list .media-item {
|
||||
padding-bottom: 15px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media-list .media-item-left {
|
||||
display: inline-block;
|
||||
padding-right: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media-list .media-item-left img {
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media-list .media-text {
|
||||
overflow: hidden;
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media-list .media-text a {
|
||||
margin-right: 10px;
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media-list .media-text div:nth-child(2) {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media-list .layui-btn {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
padding: 0 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.layadmin-homepage-list-imgtxt .media-body .media-list .layui-btn {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
padding: 0 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* 个人内容区域 */
|
||||
|
||||
.homepage-top .layui-card-body img {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.homepage-top .layui-card-body .margin-top10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.homepage-top .layui-card-body .layui-btn {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.homepage-top {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.layadmin-privateletterlist-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.homepage-bottom .layui-card-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.homepage-bottom .layui-card-body img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.homepage-bottom .layui-card-body .meida-left {
|
||||
display: table-cell;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.homepage-bottom .layui-card-body .meida-right {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.homepage-bottom .layui-card-body a:hover {
|
||||
background: #F2F2F2;
|
||||
}
|
||||
|
||||
.homepage-bottom .layui-card-body {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.layui-card-header .panel-title .layui-icon {
|
||||
position: relative;
|
||||
left: 0;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
/* 右侧信息栏 */
|
||||
.layadmin-cmdlist-fluid {
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
.cmdlist-container {
|
||||
background: #fff;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.cmdlist-container:hover {
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.cmdlist-container img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cmdlist-text {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.cmdlist-text .info {
|
||||
height: 40px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
color: #5F5F5F;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.cmdlist-text .price {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.cmdlist-text .price b {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.cmdlist-text .price p {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.cmdlist-text .flow {
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#demo0 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 商品列表 */
|
||||
.layadmin-message-fluid .layui-col-md12 {
|
||||
background: #fff;
|
||||
height: auto;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.layadmin-message-fluid .layui-input-block {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.layadmin-message-fluid .layui-form {
|
||||
padding: 45px 40px 0 40px;
|
||||
}
|
||||
|
||||
.layadmin-message-fluid .layui-form-label {
|
||||
text-align: left;
|
||||
font-size: 18px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.layadmin-message-fluid .layui-textarea {
|
||||
min-height: 100px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.layadmin-message-fluid .layui-input-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.layadmin-messag-icon {
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.layadmin-messag-icon .layui-icon {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
margin-right: 15px;
|
||||
color: #C4CBCF;
|
||||
}
|
||||
|
||||
.layadmin-messag-icon {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
.message-content .media-body {
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.message-content .media-body .pad-btm {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.message-content .media-left {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.message-content .media-left img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.message-content-btn {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.message-content .layui-btn {
|
||||
height: auto;
|
||||
line-height: 26px;
|
||||
padding: 5px 30px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 搜索结果页面 */
|
||||
.layadmin-serach-main .layui-card-header {
|
||||
height: auto;
|
||||
line-height: 24px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.layadmin-serach-list {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #f6f6f6;
|
||||
}
|
||||
|
||||
.layadmin-serach-list h3 {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.layadmin-serach-list h3 .layui-badge {
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.layadmin-serach-list p {
|
||||
color: #5F5F5F;
|
||||
}
|
||||
|
||||
.layadmin-serach-list li {
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.layui-serachlist-cover {
|
||||
float: left;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.layui-serachlist-cover img {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
|
||||
|
||||
/* 用户列表开始 */
|
||||
.layadmin-caller {
|
||||
background: #fff;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.layadmin-caller em {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-fl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-fr {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-seach {
|
||||
position: relative;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-seach .caller-icon {
|
||||
font-size: 18px;
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-seach-icon {
|
||||
left: 6px;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-dump-icon {
|
||||
right: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-pl32 {
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-tab {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar .caller-item {
|
||||
padding: 25px 0;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar .caller-item .caller-main {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar .caller-item .caller-main p {
|
||||
line-height: 100%;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar .caller-item .caller-main p:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar .caller-item .caller-main em {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar .caller-item .caller-main .caller-adds i {
|
||||
padding-right: 5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar .caller-item .caller-main .caller-adds {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar .caller-iconset i {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar .caller-iconset i:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar button {
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.layadmin-caller .caller-contar .caller-img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
/****** 模板结束 ******/
|
||||
@@ -1,406 +0,0 @@
|
||||
<!--
|
||||
Name: 计划任务
|
||||
Author: 耗子
|
||||
Date: 2023-07-21
|
||||
-->
|
||||
<title>计划任务</title>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">添加计划任务</div>
|
||||
<div class="layui-card-body">
|
||||
<blockquote class="layui-elem-quote">
|
||||
<p>面板的计划任务均基于脚本运行,若任务类型满足不了需求,可自行修改对应的脚本。</p>
|
||||
</blockquote>
|
||||
<form class="layui-form" action="" lay-filter="cron-add-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务类型</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="type" lay-verify="required" lay-filter="cron-type">
|
||||
<option value="shell">运行脚本</option>
|
||||
<option value="backup">备份数据</option>
|
||||
<option value="cutoff">切割日志</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">请选择任务类型</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="cron-add-name-input">
|
||||
<label class="layui-form-label">任务名</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="name" lay-verify="required" placeholder="请输入任务名称"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">请填写任务名称</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="cron-add-backup-type-input" style="display: none;">
|
||||
<label class="layui-form-label">备份类型</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" lay-filter="cron-add-backup-type-radio" name="backup_type" value="website"
|
||||
title="网站目录" checked="">
|
||||
<input type="radio" lay-filter="cron-add-backup-type-radio" name="backup_type" value="mysql"
|
||||
title="MySQL数据库">
|
||||
<input type="radio" lay-filter="cron-add-backup-type-radio" name="backup_type"
|
||||
value="postgresql"
|
||||
title="PostgreSQL数据库">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="cron-add-website-input" style="display: none;">
|
||||
<label class="layui-form-label">网站</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template lay-url="/api/panel/website/list?page=1&limit=10000">
|
||||
<select name="website" lay-filter="cron-add-website">
|
||||
{{# layui.each(d.data.items, function(index, item){ }}
|
||||
{{# if(index == 0){ }}
|
||||
<option value="{{ item.name }}" selected="">{{ item.name }}</option>
|
||||
{{# }else{ }}
|
||||
<option value="{{ item.name }}">{{ item.name }}</option>
|
||||
{{# } }}
|
||||
{{# }); }}
|
||||
</select>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">请选择网站</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="cron-add-backup-database-input" style="display: none;">
|
||||
<label class="layui-form-label">数据库名</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="backup_database" placeholder="请输入数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">请填写数据库名</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="cron-add-backup-path-input" style="display: none;">
|
||||
<label class="layui-form-label">保存目录</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="backup_path" placeholder=""
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
目录可以为对象存储挂载目录,不填则默认为面板设置的备份目录
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="cron-add-save-input" style="display: none;">
|
||||
<label class="layui-form-label">保留份数</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="save" placeholder="10"
|
||||
autocomplete="off" class="layui-input" min="0" step="1" lay-affix="number">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">请填写保留份数,会自动清理过剩的副本</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">执行周期</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="time" id="cron-add-time"
|
||||
lay-verify="required" placeholder="请选择或输入cron表达式" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">请务必正确填写执行周期</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text" id="cron-add-shell">
|
||||
<label class="layui-form-label">脚本内容</label>
|
||||
<div class="layui-input-block">
|
||||
<div id="cron-add-script-editor"
|
||||
style="height: 250px;"># 在此输入你要执行的脚本内容</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="cron-add-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">计划任务列表</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="panel-cron" lay-filter="panel-cron"></table>
|
||||
<!-- 操作按钮模板 -->
|
||||
<script type="text/html" id="cron-table-edit">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="log">日志</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<!-- 任务类型 -->
|
||||
<script type="text/html" id="cron-table-type">
|
||||
{{# if(d.type == 'shell'){ }}
|
||||
运行脚本
|
||||
{{# }else if(d.type == 'backup'){ }}
|
||||
备份数据
|
||||
{{# }else if(d.type == 'cutoff'){ }}
|
||||
切割日志
|
||||
{{# } }}
|
||||
</script>
|
||||
<!-- 运行开关 -->
|
||||
<script type="text/html" id="cron-table-status">
|
||||
<input type="checkbox" name="cron-status" lay-skin="switch" lay-text="ON|OFF"
|
||||
lay-filter="cron-status"
|
||||
value="{{ d.status }}" data-id="{{ d.id }}"
|
||||
{{ d.status ? 'checked' : '' }}>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var cronAddScriptEditor = ace.edit("cron-add-script-editor", {
|
||||
mode: "ace/mode/sh",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
var cronEditScriptEditor;
|
||||
layui.use(['admin', 'table', 'jquery', 'cron'], function () {
|
||||
var $ = layui.$
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
, admin = layui.admin
|
||||
, cron = layui.cron;
|
||||
|
||||
cron.render({
|
||||
elem: "#cron-add-time",
|
||||
btns: ['confirm'],
|
||||
show: false,
|
||||
done: function (value) {
|
||||
$('#cron-add-time').val(value);
|
||||
}
|
||||
});
|
||||
|
||||
form.render();
|
||||
|
||||
table.render({
|
||||
elem: '#panel-cron'
|
||||
, url: '/api/panel/cron/list'
|
||||
, cols: [[
|
||||
{field: 'id', hide: true, title: 'ID'}
|
||||
, {field: 'name', width: 250, title: '任务名', sort: true}
|
||||
, {field: 'type', width: 150, title: '任务类型', templet: '#cron-table-type', sort: true}
|
||||
, {field: 'status', title: '启用', width: 100, templet: '#cron-table-status', unresize: true}
|
||||
, {field: 'time', width: 200, title: '任务周期(cron表达式)'}
|
||||
, {field: 'created_at', title: '创建时间'}
|
||||
, {field: 'updated_at', title: '最后更新时间'}
|
||||
, {
|
||||
field: 'edit',
|
||||
width: 180,
|
||||
title: '操作',
|
||||
templet: '#cron-table-edit',
|
||||
fixed: 'right',
|
||||
align: 'left'
|
||||
}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '暂无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
table.on('tool(panel-cron)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'log') {
|
||||
// 打开日志弹窗
|
||||
admin.popup({
|
||||
title: '日志 - ' + data.name
|
||||
,
|
||||
area: ['80%', '80%']
|
||||
,
|
||||
id: 'cron-log'
|
||||
,
|
||||
content: '<pre id="cron-log-view" style="overflow: auto; height: 95%;border: 0 none; line-height:23px; padding: 15px; margin: 0; white-space: pre-wrap; background-color: rgb(51,51,51); color:#f1f1f1; border-radius:0;"></pre>'
|
||||
,
|
||||
success: function (layero, index) {
|
||||
index2 = layer.msg('正在获取日志...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: '/api/panel/cron/log?id=' + data.id
|
||||
, type: 'GET'
|
||||
, success: function (res) {
|
||||
layer.close(index2);
|
||||
if (res.code === 0) {
|
||||
$('#cron-log-view').html(res.data);
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
} else if (obj.event === 'edit') {
|
||||
// 打开编辑弹窗
|
||||
admin.req({
|
||||
url: '/api/panel/cron/script?id=' + data.id
|
||||
, type: 'GET'
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
admin.popup({
|
||||
title: '编辑 - ' + data.name
|
||||
,
|
||||
area: ['80%', '80%']
|
||||
,
|
||||
id: 'cron-log'
|
||||
,
|
||||
content: '任务名 <div class="layui-input-inline" style="width: 190px;"><input type="text" name="cron-edit-name" placeholder="请输入任务名称" autocomplete="off" class="layui-input" value="' + data.name + '"></div> 执行周期 <div class="layui-input-inline" style="width: 190px;"><input id="cron-edit-time-' + data.id + '" type="text" name="cron-edit-time" placeholder="请输入执行周期" autocomplete="off" class="layui-input" value="' + data.time + '"/></div><hr><div id="cron-edit-script-editor" style="height: 80%;">' + res.data + '</div><br><button id="cron-edit-' + data.id + '" class="layui-btn">保存</button>'
|
||||
,
|
||||
success: function (layero, index) {
|
||||
cronEditScriptEditor = ace.edit("cron-edit-script-editor", {
|
||||
mode: "ace/mode/sh",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
cron.render({
|
||||
elem: "#cron-edit-time-" + data.id,
|
||||
btns: ['confirm'],
|
||||
show: false,
|
||||
done: function (value) {
|
||||
$('#cron-add-time').val(value);
|
||||
}
|
||||
});
|
||||
$('#cron-edit-' + data.id).click(function () {
|
||||
index2 = layer.msg('正在保存...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: '/api/panel/cron/update'
|
||||
, type: 'POST'
|
||||
, data: {
|
||||
id: data.id,
|
||||
name: $('input[name="cron-edit-name"]').val(),
|
||||
time: $('input[name="cron-edit-time"]').val(),
|
||||
script: cronEditScriptEditor.getValue()
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('保存成功', {icon: 1, time: 1000});
|
||||
table.reload('panel-cron');
|
||||
layer.close(index2);
|
||||
layer.close(index);
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除计划任务' + data.name + '吗?', function (index) {
|
||||
layer.close(index);
|
||||
admin.req({
|
||||
url: '/api/panel/cron/delete',
|
||||
type: 'POST',
|
||||
data: {
|
||||
id: data.id
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
table.reload('panel-cron');
|
||||
layer.msg('计划任务:' + data.name + ' 已删除', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on('select(cron-type)', function (data) {
|
||||
if (data.value === 'shell') {
|
||||
$("#cron-add-backup-type-input").hide();
|
||||
$("#cron-add-save-input").hide();
|
||||
$('#cron-add-website-input').hide();
|
||||
$('#cron-add-backup-database-input').hide();
|
||||
$('#cron-add-backup-path-input').hide();
|
||||
$("#cron-add-shell").show();
|
||||
} else if (data.value === 'backup') {
|
||||
let selectedType = $('input[name="backup_type"]:checked').val();
|
||||
if (selectedType === 'website') {
|
||||
$('#cron-add-website-input').show();
|
||||
$('#cron-add-backup-database-input').hide();
|
||||
} else {
|
||||
$('#cron-add-website-input').hide();
|
||||
$('#cron-add-backup-database-input').show();
|
||||
}
|
||||
$("#cron-add-backup-type-input").show();
|
||||
$('#cron-add-backup-path-input').show();
|
||||
$("#cron-add-save-input").show();
|
||||
$("#cron-add-shell").hide();
|
||||
} else if (data.value === 'cutoff') {
|
||||
$('#cron-add-website-input').show();
|
||||
$('#cron-add-save-input').show();
|
||||
$("#cron-add-shell").hide();
|
||||
$('#cron-add-backup-database-input').hide();
|
||||
$("#cron-add-backup-type-input").hide();
|
||||
$('#cron-add-backup-path-input').hide();
|
||||
}
|
||||
form.render();
|
||||
});
|
||||
form.on('radio(cron-add-backup-type-radio)', function (data) {
|
||||
if (data.value == 'website') {
|
||||
$('#cron-add-website-input').show();
|
||||
$('#cron-add-backup-database-input').hide();
|
||||
} else {
|
||||
$('#cron-add-website-input').hide();
|
||||
$('#cron-add-backup-database-input').show();
|
||||
}
|
||||
form.render();
|
||||
});
|
||||
|
||||
form.on('switch(cron-status)', function (obj) {
|
||||
let $ = layui.$;
|
||||
let id = $(this).data('id');
|
||||
let status = obj.elem.checked;
|
||||
|
||||
admin.req({
|
||||
url: '/api/panel/cron/status',
|
||||
type: 'POST',
|
||||
data: {
|
||||
id: id,
|
||||
status: status
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('设置成功', {icon: 1, time: 1000});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
form.on('submit(cron-add-submit)', function (data) {
|
||||
data.field.script = cronAddScriptEditor.getValue();
|
||||
admin.req({
|
||||
url: "/api/panel/cron/add"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
layer.msg('计划任务添加失败!')
|
||||
return false;
|
||||
}
|
||||
table.reload('panel-cron');
|
||||
layer.alert('计划任务添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,359 +0,0 @@
|
||||
<!--
|
||||
Name: 主页模板
|
||||
Author: 耗子
|
||||
Date: 2023-06-22
|
||||
-->
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div id="ad1" class="layui-col-md12">
|
||||
<div style="background: #fff;" class="layui-colla-content layui-show">
|
||||
<div id="ad1-carousel" class="layui-carousel"
|
||||
style="overflow: hidden;background: #fff;">
|
||||
<div carousel-item>
|
||||
<a style="background: #fff;" href="https://hzbk.net"
|
||||
title="耗子博客" target="_blank"><i class="layui-icon layui-icon-release"></i> 耗子博客</a>
|
||||
<a style="background: #fff;" href="https://weavatar.com"
|
||||
title="WeAvatar" target="_blank"><i class="layui-icon layui-icon-release"></i>
|
||||
WeAvatar - 互联网公共头像服务</a>
|
||||
<a style="background: #fff;" href="https://wepublish.cn"
|
||||
title="WePublish" target="_blank"><i class="layui-icon layui-icon-release"></i>
|
||||
WePublish - WordPress 本土化平台</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="monitor1" class="layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">资源使用</div>
|
||||
<div class="layui-card-body layadmin-takerates">
|
||||
<div class="layui-progress" lay-showPercent="yes" lay-filter="home_cpu">
|
||||
<h3 id="home_cpu">CPU信息加载中</h3>
|
||||
<div class="layui-progress-bar" lay-percent="0%"></div>
|
||||
</div>
|
||||
<div class="layui-progress" lay-showPercent="yes" lay-filter="home_mem">
|
||||
<h3 id="home_mem">内存信息加载中</h3>
|
||||
<div class="layui-progress-bar layui-bg-red" lay-percent="0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="monitor2" class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">系统负载</div>
|
||||
<div class="layui-card-body layadmin-takerates">
|
||||
<div class="layui-progress" lay-showPercent="yes" lay-filter="uptime_1">
|
||||
<h3>近1分钟</h3>
|
||||
<div class="layui-progress-bar" lay-percent="0%"></div>
|
||||
</div>
|
||||
<div class="layui-progress" lay-showPercent="yes" lay-filter="uptime_5">
|
||||
<h3>近5分钟</h3>
|
||||
<div class="layui-progress-bar layui-bg-red" lay-percent="0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
实时流量
|
||||
<span class="layui-badge layui-bg-blue layuiadmin-badge">发送 / 接收</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p style="text-align: center;"><b id="home_net_now">获取中...</b></p>
|
||||
</div>
|
||||
<div class="layui-card-header">
|
||||
累计流量
|
||||
<span class="layui-badge layui-bg-blue layuiadmin-badge">发送 / 接收</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p style="text-align: center;"><b id="home_net_total">获取中...</b></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md8">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">应用</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-carousel layadmin-carousel layadmin-shortcut" lay-anim="">
|
||||
<div carousel-item="">
|
||||
<ul class="layui-row layui-col-space10 layui-this">
|
||||
<script type="text/html" template lay-url="/api/panel/info/homePlugins">
|
||||
{{# layui.each(d.data, function(index, item){ }}
|
||||
<li class="layui-col-xs4 layui-col-md2 layui-col-sm4">
|
||||
<a lay-href="/plugins/{{ item.slug }}">
|
||||
<i class="layui-icon layui-icon-engine"></i>
|
||||
<cite>{{ item.name }}</cite>
|
||||
</a>
|
||||
</li>
|
||||
{{# }); }}
|
||||
{{# if(d.data == null){ }}
|
||||
这里好像啥也没有,去插件中心看看吧!
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">基本信息</div>
|
||||
<div class="layui-card-body layui-text layadmin-version">
|
||||
<table class="layui-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>系统信息</td>
|
||||
<td id="home_os_name">
|
||||
获取中...
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>面板版本</td>
|
||||
<td id="home_panel_version">
|
||||
获取中...
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>运行时间</td>
|
||||
<td id="home_uptime">
|
||||
获取中...
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>操作</td>
|
||||
<td>
|
||||
<button id="update_panel" class="layui-btn layui-btn-xs">更新</button>
|
||||
<button id="restart_panel" class="layui-btn layui-btn-xs">重启</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md8">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
磁盘信息
|
||||
<i class="layui-icon layui-icon-tips" lay-tips="磁盘信息显示" lay-offset="5"></i>
|
||||
</div>
|
||||
<div class="layui-card-body layadmin-takerates">
|
||||
<script type="text/html" template lay-url="/api/panel/info/nowMonitor">
|
||||
{{# layui.each(d.data.disk_usage, function(index, item){ }}
|
||||
{{# item.usedPercent = Number(item.usedPercent).toFixed(2) }}
|
||||
<div class="layui-progress" lay-showPercent="yes">
|
||||
<h3>{{index}}</h3>
|
||||
<div class="layui-progress-bar" lay-percent="{{item.usedPercent}}%"></div>
|
||||
</div>
|
||||
{{# }); }}
|
||||
{{# if(d.data.length === 0){ }}
|
||||
这里好像啥也没有...
|
||||
{{# } }}
|
||||
{{# layui.element.render('collapse') }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
关于面板
|
||||
<i class="layui-icon layui-icon-tips" lay-tips="你干嘛,哎哟!" lay-offset="5"></i>
|
||||
</div>
|
||||
<div class="layui-card-body layui-text layadmin-text">
|
||||
<blockquote class="layui-elem-quote">
|
||||
<p style="color: red;">开发组祝大家2023中秋国庆快乐!永无Bug,永不宕机!</p>
|
||||
</blockquote>
|
||||
<blockquote class="layui-elem-quote">
|
||||
<p>欢迎您使用耗子Linux面板。如遇到问题/Bug,可通过 <a
|
||||
href="https://jq.qq.com/?_wv=1027&k=I1oJKSTH">Q群12370907</a> / <a
|
||||
target="_blank" href="https://pd.qq.com/s/fyol46wfy">QQ频道</a> 寻求帮助</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var uptime_1 = '获取中', uptime_5 = '获取中', uptime_15 = '获取中'
|
||||
var net_send = 0, net_recv = 0, net_send_last = 0, net_recv_last = 0
|
||||
|
||||
function formatBytes(size) {
|
||||
size = Number(size)
|
||||
var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||
var i = 0
|
||||
|
||||
while (size >= 1024 && i < units.length) {
|
||||
size /= 1024
|
||||
i++
|
||||
}
|
||||
|
||||
return size.toFixed(2) + ' ' + units[i]
|
||||
}
|
||||
|
||||
function formatPercentage(num) {
|
||||
num = Number(num)
|
||||
return num.toFixed(2) + '%'
|
||||
}
|
||||
|
||||
function refresh_home_info(first = false) {
|
||||
layui.use(['index', 'jquery', 'admin'], function () {
|
||||
let $ = layui.jquery
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
|
||||
let cpu_info
|
||||
admin.req({
|
||||
url: '/api/panel/info/nowMonitor'
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
layer.msg('系统资源获取失败,请刷新重试!')
|
||||
return false
|
||||
}
|
||||
element.progress('home_cpu', formatPercentage(result.data.percent[0]))
|
||||
element.progress('home_mem', formatPercentage(result.data.mem.usedPercent))
|
||||
|
||||
// 计算核心数
|
||||
let cores = 0
|
||||
for (let i = 0; i < result.data.cpus.length; i++) {
|
||||
cores += result.data.cpus[i].cores
|
||||
}
|
||||
|
||||
// 计算负载百分比
|
||||
uptime_1 = formatPercentage(result.data.load.load1 / cores * 100)
|
||||
uptime_5 = formatPercentage(result.data.load.load5 / cores * 100)
|
||||
uptime_15 = formatPercentage(result.data.load.load15 / cores * 100)
|
||||
element.progress('uptime_1', uptime_1)
|
||||
element.progress('uptime_5', uptime_5)
|
||||
|
||||
// 计算网卡流量
|
||||
for (let i = 0; i < result.data.net.length; i++) {
|
||||
if (result.data.net[i].name === 'lo') {
|
||||
continue
|
||||
}
|
||||
net_send += result.data.net[i].bytesSent
|
||||
net_recv += result.data.net[i].bytesRecv
|
||||
}
|
||||
if (first) {
|
||||
net_send_last = net_send
|
||||
net_recv_last = net_recv
|
||||
}
|
||||
$('#home_net_now').html(formatBytes((net_send - net_send_last) / 3) + '/s / ' + formatBytes((net_recv - net_recv_last) / 3) + '/s')
|
||||
$('#home_net_total').html(formatBytes(net_send) + ' / ' + formatBytes(net_recv))
|
||||
net_send_last = net_send
|
||||
net_recv_last = net_recv
|
||||
net_send = 0
|
||||
net_recv = 0
|
||||
|
||||
cpu_info = result.data.cpus[0].modelName + ' ' + cores + '线程'
|
||||
$('#home_cpu').text(cpu_info)
|
||||
$('#home_mem').text('使用 ' + formatBytes(result.data.mem.used) + ' / ' + '总计 ' + formatBytes(result.data.mem.total))
|
||||
element.render('progress')
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
refresh_home_info(true)
|
||||
setInterval(refresh_home_info, 3000)
|
||||
// 获取系统信息,这部分信息无需更新。
|
||||
layui.use(['index', 'jquery', 'admin', 'carousel'], function () {
|
||||
let $ = layui.jquery
|
||||
, admin = layui.admin
|
||||
, carousel = layui.carousel
|
||||
carousel.render({
|
||||
elem: '#ad1-carousel'
|
||||
, width: '100%'
|
||||
, height: '22px'
|
||||
, anim: 'fade'
|
||||
, arrow: 'none'
|
||||
, indicator: 'none'
|
||||
})
|
||||
admin.req({
|
||||
url: '/api/panel/info/systemInfo'
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:系统信息获取失败,接口返回' + result)
|
||||
layer.msg('系统信息获取失败,请刷新重试!')
|
||||
return false
|
||||
}
|
||||
$('#home_os_name').text(result.data.os_name)
|
||||
$('#home_panel_version').text(result.data.panel_version)
|
||||
$('#home_uptime').text('已不间断运行 ' + result.data.uptime + ' 天')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
layui.use(['jquery', 'layer'], function () {
|
||||
let $ = layui.jquery
|
||||
, layer = layui.layer
|
||||
, admin = layui.admin
|
||||
// 监听鼠标悬停到uptime上的事件
|
||||
// 用于显示1分钟、5分钟、15分钟的负载
|
||||
$('#monitor2').hover(function () {
|
||||
layer.tips('1分钟负载:' + uptime_1 + '<br>5分钟负载:' + uptime_5 + '<br>15分钟负载:' + uptime_15, '#monitor2', {
|
||||
tips: 1,
|
||||
time: 0
|
||||
})
|
||||
}, function () {
|
||||
layer.closeAll('tips')
|
||||
})
|
||||
|
||||
$('#update_panel').click(function () {
|
||||
index = layer.msg('正在获取版本信息...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
})
|
||||
admin.req(
|
||||
{
|
||||
url: '/api/panel/info/checkUpdate'
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
layer.msg('获取版本信息失败,请刷新重试!')
|
||||
return false
|
||||
}
|
||||
if (result.data.update) {
|
||||
layer.confirm('更新日期: <br>' + new Date(result.data.date).toLocaleString() + '<br>更新日志: <pre>' + result.data.body + '</pre>', {
|
||||
title: '最新版本: ' + result.data.version + ' ,是否更新?',
|
||||
btn: ['更新', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('更新中(出现请求错误为正常情况),稍后请手动刷新...', {
|
||||
icon: 16,
|
||||
time: 0,
|
||||
shade: 0.3
|
||||
})
|
||||
admin.req({
|
||||
url: '/api/panel/info/update'
|
||||
, type: 'post'
|
||||
})
|
||||
})
|
||||
} else {
|
||||
layer.msg('当前已是最新版本!')
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
$('#restart_panel').click(function () {
|
||||
layer.confirm('真的要重启吗?', {
|
||||
btn: ['是', '否']
|
||||
}, function () {
|
||||
index = layer.msg('重启中(出现请求错误为正常情况),稍后请手动刷新...', {icon: 16, time: 0, shade: 0.3})
|
||||
admin.req({
|
||||
url: '/api/panel/info/restart'
|
||||
, type: 'post'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@@ -1,100 +0,0 @@
|
||||
<script type="text/html" template>
|
||||
<link rel="stylesheet" href="panel/adminui/src/css/login.css?v={{ layui.admin.v }}" media="all">
|
||||
</script>
|
||||
|
||||
|
||||
<div class="layadmin-user-login layadmin-user-display-show" id="LAY-user-login" style="display: none;">
|
||||
|
||||
<div class="layadmin-user-login-main">
|
||||
<div class="layadmin-user-login-box layadmin-user-login-header">
|
||||
<h2 id="panel-login-name">加载中...</h2>
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="layadmin-user-login-box layadmin-user-login-body layui-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-username"
|
||||
for="username"></label>
|
||||
<input type="text" name="username" id="username" lay-verify="required" placeholder="用户名"
|
||||
class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-password"
|
||||
for="password"></label>
|
||||
<input type="password" name="password" id="password" lay-verify="required"
|
||||
placeholder="密码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom: 20px;">
|
||||
<a target="_blank" href="https://jq.qq.com/?_wv=1027&k=I1oJKSTH"
|
||||
class="layadmin-user-jump-change layadmin-link"
|
||||
style="margin-top: 7px;">忘记密码?</a>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button class="layui-btn layui-btn-fluid" lay-submit lay-filter="panel-login-submit">登 入</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-trans layadmin-user-login-footer">
|
||||
|
||||
<p>耗子Linux面板 © 耗子 All Rights Reserved</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form'], function () {
|
||||
let $ = layui.$
|
||||
, setter = layui.setter
|
||||
, admin = layui.admin
|
||||
, form = layui.form
|
||||
, router = layui.router()
|
||||
, search = router.search;
|
||||
|
||||
// 判断是否已登录
|
||||
if (layui.data(setter.tableName)[setter.request.tokenName]) {
|
||||
location.hash = search.redirect ? decodeURIComponent(search.redirect) : '/';
|
||||
}
|
||||
|
||||
// 设置面板名称
|
||||
$('#panel-login-name').text(setter.name);
|
||||
|
||||
form.render();
|
||||
|
||||
//提交
|
||||
form.on('submit(panel-login-submit)', function (obj) {
|
||||
|
||||
// 判断obj.field.remember是否存在
|
||||
if (obj.field.remember) {
|
||||
obj.field.remember = 1;
|
||||
} else {
|
||||
obj.field.remember = 0;
|
||||
}
|
||||
admin.req({
|
||||
url: '/api/panel/user/login'
|
||||
, data: obj.field
|
||||
, type: 'post'
|
||||
, done: function (res) {
|
||||
// 请求成功后,写入 access_token
|
||||
layui.data(setter.tableName, {
|
||||
key: setter.request.tokenName
|
||||
, value: res.data.access_token
|
||||
});
|
||||
|
||||
// 登入成功的提示与跳转
|
||||
layer.msg('登录成功', {
|
||||
offset: '15px'
|
||||
, icon: 1
|
||||
, time: 1000
|
||||
}, function () {
|
||||
/**
|
||||
* 可能是LayuiAdmin的bug,如果直接跳转到主页,会出现表格无法获取access_token的问题
|
||||
* 所以这里强制刷新一次页面
|
||||
*/
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,29 +0,0 @@
|
||||
<script type="text/html" template>
|
||||
<link rel="stylesheet" href="panel/adminui/src/css/login.css?v={{ layui.admin.v }}" media="all">
|
||||
</script>
|
||||
|
||||
|
||||
<div class="layadmin-user-login layadmin-user-display-show" id="LAY-user-login" style="display: none;">
|
||||
|
||||
<div class="layadmin-user-login-main">
|
||||
<div class="layadmin-user-login-box layadmin-user-login-header">
|
||||
<h2>已退出登录</h2>
|
||||
<p>页面即将自动跳转</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-trans layadmin-user-login-footer">
|
||||
|
||||
<p>耗子Linux面板 © 耗子 All Rights Reserved</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin'], function () {
|
||||
let admin = layui.admin
|
||||
setTimeout(function () {
|
||||
admin.exit()
|
||||
location.hash = '/login'
|
||||
}, 3000)
|
||||
})
|
||||
</script>
|
||||
@@ -1,404 +0,0 @@
|
||||
<!--
|
||||
Name: 资源监控
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<title>资源监控</title>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-form layui-card-body" style="overflow: hidden;">
|
||||
<div class="layui-inline">
|
||||
<span style="margin-right: 10px;">开启监控</span><input type="checkbox" id="monitor-switch"
|
||||
lay-filter="monitor" lay-skin="switch"
|
||||
lay-text="ON|OFF">
|
||||
<span style="margin-left: 40px; margin-right: 10px;">保存天数</span>
|
||||
<div class="layui-input-inline"><input type="number" name="monitor-save-days" class="layui-input"
|
||||
style="height: 30px; margin-top: 5px;" min=0 max=30 disabled>
|
||||
</div>
|
||||
<div class="layui-input-inline">
|
||||
<button id="save_monitor_date" class="layui-btn layui-btn-sm" style="margin-left: 10px;">确定
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline" style="float: right;">
|
||||
<span style="margin-right: 10px;">时间选择</span>
|
||||
<div id="monitor-date" class="layui-input-inline">
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" autocomplete="off" id="monitor-startDate"
|
||||
class="layui-input"
|
||||
placeholder="开始时间">
|
||||
</div>
|
||||
-
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" autocomplete="off" id="monitor-endDate"
|
||||
class="layui-input"
|
||||
placeholder="结束时间">
|
||||
</div>
|
||||
</div>
|
||||
<span style="margin-left: 40px;"></span>
|
||||
<button id="clear_monitor_record" class="layui-btn layui-btn-sm layui-btn-danger">清空监控记录
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-row layui-col-space10">
|
||||
<div class="layui-col-xs12 layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<span>负载</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div id="load_monitor" style="width: 100%;height: 400px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-col-xs12 layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<span>CPU</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div id="cpu_monitor" style="width: 100%;height: 400px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-row layui-col-space10">
|
||||
<div class="layui-col-xs12 layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<span>内存</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div id="memory_monitor" style="width: 100%;height: 400px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs12 layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<span>网络</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div id="network_monitor" style="width: 100%;height: 400px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
layui.use(['admin', 'view', 'form', 'element', 'carousel'], function () {
|
||||
var admin = layui.admin;
|
||||
var $ = layui.jquery;
|
||||
var form = layui.form;
|
||||
var laydate = layui.laydate;
|
||||
|
||||
// 默认开始时间为今天0点,结束时间为当前时间
|
||||
var startDate = new Date(new Date().setHours(0, 0, 0, 0));
|
||||
var endDate = new Date();
|
||||
// 拼接时间字符串
|
||||
var startStr = startDate.getFullYear() + '-' + startDate.getMonth() + '-' + startDate.getDate() + ' ' + startDate.getHours() + ':' + startDate.getMinutes() + ':' + startDate.getSeconds();
|
||||
var endStr = endDate.getFullYear() + '-' + endDate.getMonth() + '-' + endDate.getDate() + ' ' + endDate.getHours() + ':' + endDate.getMinutes() + ':' + endDate.getSeconds();
|
||||
laydate.render({
|
||||
elem: '#monitor-date'
|
||||
, type: 'datetime'
|
||||
, range: ['#monitor-startDate', '#monitor-endDate']
|
||||
, value: startStr + ' - ' + endStr
|
||||
, calendar: true
|
||||
, done: function (value, date, endDate) {
|
||||
let start_date,
|
||||
end_date;
|
||||
// 初始化时间日期对象
|
||||
start_date = new Date(date.year, date.month, date.date, date.hours, date.minutes, date.seconds);
|
||||
end_date = new Date(endDate.year, endDate.month, endDate.date, endDate.hours, endDate.minutes, endDate.seconds);
|
||||
getMonitorData(start_date.getTime(), end_date.getTime());
|
||||
}
|
||||
});
|
||||
|
||||
// 获取监控开关和保存天数
|
||||
admin.req({
|
||||
url: '/api/panel/monitor/switchAndDays',
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
if (res.data.switch) {
|
||||
$('#monitor-switch').attr('checked', true);
|
||||
} else {
|
||||
$('#monitor-switch').attr('checked', false);
|
||||
}
|
||||
$('input[name="monitor-save-days"]').val(res.data.days);
|
||||
$('input[name="monitor-save-days"]').removeAttr('disabled');
|
||||
form.render();
|
||||
}
|
||||
}
|
||||
});
|
||||
form.on('switch(monitor)', function (data) {
|
||||
admin.req({
|
||||
url: '/api/panel/monitor/switch',
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: {switch: data.elem.checked},
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('修改成功', {icon: 1});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#save_monitor_date').click(function () {
|
||||
var days = $('input[name="monitor-save-days"]').val();
|
||||
if (days == '') {
|
||||
layer.msg('请输入保存天数', {icon: 2});
|
||||
return false;
|
||||
}
|
||||
admin.req({
|
||||
url: '/api/panel/monitor/saveDays',
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: {days: days},
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('修改成功', {icon: 1});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#clear_monitor_record').click(function () {
|
||||
layer.confirm('确定要清除监控数据吗?', function (index) {
|
||||
admin.req({
|
||||
url: '/api/panel/monitor/clear',
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('清除成功', {icon: 1});
|
||||
setTimeout(function () {
|
||||
admin.render();
|
||||
}, 1000);
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
});
|
||||
|
||||
getMonitorData(startDate.getTime(), endDate.getTime());
|
||||
});
|
||||
|
||||
// 获取监控数据
|
||||
function getMonitorData(startDate, endDate) {
|
||||
layui.use(['admin'], function () {
|
||||
let admin = layui.admin;
|
||||
admin.req({
|
||||
url: '/api/panel/monitor/list?start=' + startDate + '&end=' + endDate,
|
||||
type: 'get',
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.3});
|
||||
return false;
|
||||
}
|
||||
let loadChart = renderEcharts('load_monitor', '负载', {
|
||||
x: 'left',
|
||||
data: ["1分钟", "5分钟", "15分钟"]
|
||||
}, res.data.times, [{
|
||||
name: '1分钟',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: res.data.load.load1,
|
||||
markPoint: {
|
||||
data: [{type: 'max', name: '最大值'}, {type: 'min', name: '最小值'}]
|
||||
},
|
||||
markLine: {
|
||||
data: [{type: 'average', name: '平均值'}]
|
||||
}
|
||||
}, {
|
||||
name: '5分钟',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: res.data.load.load5,
|
||||
markPoint: {
|
||||
data: [{type: 'max', name: '最大值'}, {type: 'min', name: '最小值'}]
|
||||
},
|
||||
markLine: {
|
||||
data: [{type: 'average', name: '平均值'}]
|
||||
}
|
||||
}, {
|
||||
name: '15分钟',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: res.data.load.load15,
|
||||
markPoint: {
|
||||
data: [{type: 'max', name: '最大值'}, {type: 'min', name: '最小值'}]
|
||||
},
|
||||
markLine: {
|
||||
data: [{type: 'average', name: '平均值'}]
|
||||
}
|
||||
}], [{
|
||||
type: 'value',
|
||||
}]);
|
||||
let cpuChart = renderEcharts('cpu_monitor', 'CPU', undefined, res.data.times, [{
|
||||
name: '使用率',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: res.data.cpu.percent,
|
||||
markPoint: {
|
||||
data: [{type: 'max', name: '最大值'}, {type: 'min', name: '最小值'}]
|
||||
},
|
||||
markLine: {
|
||||
data: [{type: 'average', name: '平均值'}]
|
||||
}
|
||||
}], [{
|
||||
name: '单位 %',
|
||||
min: 0,
|
||||
max: 100,
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value} %'
|
||||
}
|
||||
}]);
|
||||
let memoryChart = renderEcharts('memory_monitor', '内存', {
|
||||
x: 'left',
|
||||
data: ["内存", "Swap"]
|
||||
}, res.data.times, [{
|
||||
name: '内存',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: res.data.mem.used,
|
||||
markPoint: {
|
||||
data: [{type: 'max', name: '最大值'}, {type: 'min', name: '最小值'}]
|
||||
},
|
||||
markLine: {
|
||||
data: [{type: 'average', name: '平均值'}]
|
||||
}
|
||||
}, {
|
||||
name: 'Swap',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: res.data.swap.used,
|
||||
markPoint: {
|
||||
data: [{type: 'max', name: '最大值'}, {type: 'min', name: '最小值'}]
|
||||
},
|
||||
markLine: {
|
||||
data: [{type: 'average', name: '平均值'}]
|
||||
}
|
||||
}], [{
|
||||
name: '单位 MB',
|
||||
min: 0,
|
||||
max: res.data.mem.total,
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value} M'
|
||||
}
|
||||
}]);
|
||||
let networkChart = renderEcharts('network_monitor', '网络', {
|
||||
x: 'left',
|
||||
data: ["总计出", "总计入", "每秒出", "每秒入"]
|
||||
}, res.data.times, [{
|
||||
name: '总计出',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: res.data.net.sent,
|
||||
markPoint: {
|
||||
data: [{type: 'max', name: '最大值'}, {type: 'min', name: '最小值'}]
|
||||
},
|
||||
markLine: {
|
||||
data: [{type: 'average', name: '平均值'}]
|
||||
}
|
||||
}, {
|
||||
name: '总计入',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: res.data.net.recv,
|
||||
markPoint: {
|
||||
data: [{type: 'max', name: '最大值'}, {type: 'min', name: '最小值'}]
|
||||
},
|
||||
markLine: {
|
||||
data: [{type: 'average', name: '平均值'}]
|
||||
}
|
||||
}, {
|
||||
name: '每秒出',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: res.data.net.tx,
|
||||
markPoint: {
|
||||
data: [{type: 'max', name: '最大值'}, {type: 'min', name: '最小值'}]
|
||||
},
|
||||
markLine: {
|
||||
data: [{type: 'average', name: '平均值'}]
|
||||
}
|
||||
}, {
|
||||
name: '每秒入',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: res.data.net.rx,
|
||||
markPoint: {
|
||||
data: [{type: 'max', name: '最大值'}, {type: 'min', name: '最小值'}]
|
||||
},
|
||||
markLine: {
|
||||
data: [{type: 'average', name: '平均值'}]
|
||||
}
|
||||
}], [{
|
||||
name: '单位 Mb',
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value} Mb'
|
||||
}
|
||||
}]);
|
||||
|
||||
// 在窗口大小改变时,重置图表大小
|
||||
window.addEventListener("resize", function () {
|
||||
loadChart.resize();
|
||||
cpuChart.resize();
|
||||
memoryChart.resize();
|
||||
networkChart.resize();
|
||||
});
|
||||
}, error: function (xhr, status, error) {
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 渲染图表
|
||||
function renderEcharts(element_id, title, legend = undefined, data_xAxis, series, yAxis = undefined) {
|
||||
var Chart = echarts.init(document.getElementById(element_id), layui.echartsTheme);
|
||||
var option = {
|
||||
title: {text: title, x: 'center', textStyle: {fontSize: 20}},
|
||||
tooltip: {trigger: 'axis'},
|
||||
legend: legend,
|
||||
xAxis: [{type: 'category', boundaryGap: false, data: data_xAxis}],
|
||||
yAxis: yAxis,
|
||||
dataZoom: {
|
||||
show: true,
|
||||
realtime: true,
|
||||
start: 0,
|
||||
end: 100
|
||||
},
|
||||
series: series
|
||||
};
|
||||
|
||||
Chart.setOption(option);
|
||||
return Chart;
|
||||
}
|
||||
</script>
|
||||
@@ -1,185 +0,0 @@
|
||||
<title>插件中心</title>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
按钮点击一次即可,请勿重复点击以免重复操作,任务中心在右上方!
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="panel-plugin" lay-filter="panel-plugin"></table>
|
||||
<!-- 操作按钮模板 -->
|
||||
<script type="text/html" id="panel-plugin-control">
|
||||
{{# if(d.installed && d.installed_version != d.version){ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update">更新</a>
|
||||
{{# } }}
|
||||
{{# if(d.installed && d.installed_version == d.version){ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="open">管理</a>
|
||||
{{# } }}
|
||||
{{# if(d.installed && d.installed_version == d.version){ }}
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="uninstall">卸载</a>
|
||||
{{# } }}
|
||||
{{# if(!d.installed){ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="install">安装</a>
|
||||
{{# } }}
|
||||
</script>
|
||||
<!-- 首页显示开关 -->
|
||||
<script type="text/html" id="plugin-show">
|
||||
<input type="checkbox" name="plugin-show-home" lay-skin="switch" lay-text="ON|OFF"
|
||||
lay-filter="plugin-show-home"
|
||||
value="{{ d.show }}" data-plugin-slug="{{ d.slug }}"
|
||||
{{ d.show==
|
||||
1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'jquery'], function () {
|
||||
var $ = layui.$
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
, admin = layui.admin
|
||||
|
||||
table.render({
|
||||
elem: '#panel-plugin'
|
||||
, url: '/api/panel/plugin/list'
|
||||
, cols: [[
|
||||
{field: 'slug', hide: true, title: 'Slug'}
|
||||
, {field: 'name', width: 150, title: '插件名', sort: true}
|
||||
, {field: 'description', title: '描述'}
|
||||
, {field: 'installed_version', width: 140, title: '已装版本'}
|
||||
, {field: 'version', width: 140, title: '最新版本'}
|
||||
, {field: 'show', title: '首页显示', width: 90, templet: '#plugin-show', unresize: true}
|
||||
, {
|
||||
field: 'control',
|
||||
width: 180,
|
||||
title: '操作',
|
||||
templet: '#panel-plugin-control',
|
||||
fixed: 'right',
|
||||
align: 'left'
|
||||
}
|
||||
]]
|
||||
, page: false
|
||||
, text: {
|
||||
none: '无数据'
|
||||
}
|
||||
, done: function () {
|
||||
//element.render('progress');
|
||||
}
|
||||
})
|
||||
|
||||
// 工具条
|
||||
table.on('tool(panel-plugin)', function (obj) {
|
||||
let data = obj.data
|
||||
if (obj.event === 'open') {
|
||||
location.hash = '/plugins/' + data.slug
|
||||
} else if (obj.event === 'install') {
|
||||
layer.confirm('确定安装该插件吗?', function (index) {
|
||||
layer.close(index)
|
||||
admin.req({
|
||||
url: '/api/panel/plugin/install',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
table.reload('panel-plugin')
|
||||
layer.msg('安装:' + data.name + ' 成功加入任务队列', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
})
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
} else if (obj.event === 'uninstall') {
|
||||
layer.confirm('确定卸载该插件吗?', function (index) {
|
||||
layer.close(index)
|
||||
admin.req({
|
||||
url: '/api/panel/plugin/uninstall',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
table.reload('panel-plugin')
|
||||
layer.msg('卸载:' + data.name + ' 成功加入任务队列', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
})
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
} else if (obj.event === 'update') {
|
||||
layer.confirm('确定升级该插件吗?', function (index) {
|
||||
layer.close(index)
|
||||
admin.req({
|
||||
url: '/api/panel/plugin/update',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
table.reload('panel-plugin')
|
||||
layer.msg('升级:' + data.name + ' 成功加入任务队列', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
})
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
form.on('switch(plugin-show-home)', function (obj) {
|
||||
let $ = layui.$
|
||||
let plugin_slug = $(this).data('plugin-slug')
|
||||
let show = obj.elem.checked ? 1 : 0
|
||||
|
||||
admin.req({
|
||||
url: '/api/panel/plugin/updateShow',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: plugin_slug,
|
||||
show: show
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('设置成功', {icon: 1, time: 1000})
|
||||
} else {
|
||||
// 还原开关状态
|
||||
obj.elem.checked = !obj.elem.checked
|
||||
form.render('checkbox')
|
||||
layer.msg(res.message, {icon: 2, time: 1000})
|
||||
}
|
||||
}
|
||||
, error: function (xhr, status, error) {
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error)
|
||||
}
|
||||
})
|
||||
})
|
||||
/*form.render(null, 'plugin-form');
|
||||
|
||||
//搜索
|
||||
form.on('submit(plugin-search-submit)', function (data) {
|
||||
var field = data.field;
|
||||
|
||||
//执行重载
|
||||
table.reload('plugin-search-submit', {
|
||||
where: field
|
||||
});
|
||||
});*/
|
||||
})
|
||||
</script>
|
||||
@@ -1,335 +0,0 @@
|
||||
<!--
|
||||
Name: Fail2ban管理器
|
||||
Author: 耗子
|
||||
Date: 2023-07-30
|
||||
-->
|
||||
<title>Fail2ban</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">Fail2ban 运行状态</div>
|
||||
<div class="layui-card-body">
|
||||
<blockquote id="fail2ban-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="fail2ban-start" class="layui-btn">启动</button>
|
||||
<button id="fail2ban-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="fail2ban-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="fail2ban-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>基本设置</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form" lay-filter="fail2ban_setting">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">IP白名单</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="fail2ban_white_list" value="获取中ing..." class="layui-input"
|
||||
disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">IP白名单,以英文逗号,分隔</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit lay-filter="fail2ban_setting_submit">
|
||||
确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">Fail2ban 规则列表</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="fail2ban-rule-list" lay-filter="fail2ban-rule-list"></table>
|
||||
<!-- 顶部工具栏 -->
|
||||
<script type="text/html" id="fail2ban-rule-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_rule">新建规则</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 右侧管理 -->
|
||||
<script type="text/html" id="fail2ban-rule-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="view">查看</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['index', 'form', 'table', 'view'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view;
|
||||
|
||||
// 获取运行状态并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#fail2ban-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#fail2ban-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 获取白名单并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/whiteList"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('input[name=fail2ban_white_list]').val(result.data);
|
||||
$('input').attr('disabled', false);
|
||||
form.render();
|
||||
}
|
||||
});
|
||||
|
||||
// 监听提交
|
||||
form.on('submit(fail2ban_setting_submit)', function (data) {
|
||||
data.field.ip = $('input[name=fail2ban_white_list]').val();
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/whiteList"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.msg('设置成功', {icon: 1});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
let websiteList = [];
|
||||
admin.req({
|
||||
url: '/api/panel/website/list?page=1&limit=10000'
|
||||
, type: 'get'
|
||||
, async: false
|
||||
, success: function (res) {
|
||||
websiteList = res.data.items;
|
||||
}
|
||||
});
|
||||
|
||||
// 获取规则列表
|
||||
table.render({
|
||||
elem: '#fail2ban-rule-list'
|
||||
, url: '/api/plugins/fail2ban/list'
|
||||
, toolbar: '#fail2ban-rule-list-bar'
|
||||
, title: 'Fail2ban 规则列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '规则名', fixed: 'left', unresize: true, sort: true}
|
||||
, {
|
||||
field: 'enabled', title: '状态', templet: function (d) {
|
||||
if (d.enabled) {
|
||||
return '<span class="layui-badge layui-bg-green">启用</span>';
|
||||
} else {
|
||||
return '<span class="layui-badge layui-bg-gray">禁用</span>';
|
||||
}
|
||||
}, sort: true
|
||||
}
|
||||
, {field: 'max_retry', title: '最大尝试次数', sort: true}
|
||||
, {field: 'ban_time', title: '封禁时间', sort: true}
|
||||
, {field: 'find_time', title: '查找时间', sort: true}
|
||||
, {field: 'log_path', title: '日志路径'}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#fail2ban-rule-list-control', width: 150}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(fail2ban-rule-list)', function (obj) {
|
||||
if (obj.event === 'add_rule') {
|
||||
index = layer.msg('加载中...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.popup({
|
||||
title: '新建Fail2ban规则'
|
||||
, area: ['600px', '600px']
|
||||
, id: 'LAY-popup-fail2ban-rule-add'
|
||||
, success: function () {
|
||||
layer.close(index);
|
||||
view(this.id).render('plugins/fail2ban/add_rule', {
|
||||
websiteList: websiteList
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-fail2ban-rule-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(fail2ban-rule-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/delete"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert(data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'view') {
|
||||
index = layer.msg('加载中...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/ban?name=" + data.name
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.popup({
|
||||
title: '查看Fail2ban规则'
|
||||
, area: ['600px', '600px']
|
||||
, id: 'LAY-popup-fail2ban-rule-view'
|
||||
, success: function () {
|
||||
layer.close(index);
|
||||
view(this.id).render('plugins/fail2ban/view_rule', {
|
||||
data: data
|
||||
, banList: result.data
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-fail2ban-rule-view');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#fail2ban-start').click(function () {
|
||||
layer.confirm('确定要启动Fail2ban吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Fail2ban启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#fail2ban-stop').click(function () {
|
||||
layer.confirm('停止Fail2ban将导致Fail2ban防护失效,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Fail2ban停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#fail2ban-restart').click(function () {
|
||||
layer.confirm('确定要重启Fail2ban吗?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Fail2ban重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#fail2ban-reload').click(function () {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('Fail2ban重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,170 +0,0 @@
|
||||
<!--
|
||||
Name: Fail2ban管理器 - 新建规则
|
||||
Author: 耗子
|
||||
Date: 2023-07-30
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-pure-ftpd-user-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类型</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" lay-filter="add-fail2ban-rule-type-radio" name="type" value="website"
|
||||
title="网站" checked="">
|
||||
<input type="radio" lay-filter="add-fail2ban-rule-type-radio" name="type" value="service"
|
||||
title="服务">
|
||||
</div>
|
||||
</div>
|
||||
<div id="add-fail2ban-rule-website-input" class="layui-form-item">
|
||||
<label class="layui-form-label">网站</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="website" lay-filter="add-fail2ban-rule-website">
|
||||
{{# layui.each(d.params.websiteList, function(index, item){ }}
|
||||
{{# if(index == 0){ }}
|
||||
<option value="{{ item.name }}" selected="">{{ item.name }}</option>
|
||||
{{# }else{ }}
|
||||
<option value="{{ item.name }}">{{ item.name }}</option>
|
||||
{{# } }}
|
||||
{{# }); }}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="add-fail2ban-rule-service-input" class="layui-form-item">
|
||||
<label class="layui-form-label">服务</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="service" lay-filter="add-fail2ban-rule-service">
|
||||
<option value="ssh" selected="">ssh</option>
|
||||
<option value="mysql">mysql</option>
|
||||
<option value="pure-ftpd">pure-ftpd</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="add-fail2ban-rule-website-mode-input" class="layui-form-item">
|
||||
<label class="layui-form-label">网站模式</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" lay-filter="add-fail2ban-rule-website-mode-radio" name="website_mode" value="cc"
|
||||
title="CC" checked="">
|
||||
<input type="radio" lay-filter="add-fail2ban-rule-website-mode-radio" name="website_mode" value="path"
|
||||
title="目录">
|
||||
</div>
|
||||
</div>
|
||||
<div id="add-fail2ban-rule-website-path-input" class="layui-form-item">
|
||||
<label class="layui-form-label">网站目录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="website_path"
|
||||
lay-verify="required" placeholder="输入一个禁止访问的目录" class="layui-input"
|
||||
value="/admin">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">最大重试</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="maxretry"
|
||||
lay-verify="required" placeholder="单位:次" class="layui-input"
|
||||
value="30">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">周期</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="findtime"
|
||||
lay-verify="required" placeholder="单位:秒" class="layui-input"
|
||||
value="300">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">禁止时间</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="bantime"
|
||||
lay-verify="required" placeholder="单位:秒" class="layui-input"
|
||||
value="600">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
在设置周期内(秒)有超过最大重试(次)的IP访问,将禁止该IP禁止时间(秒)
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
<span style="color: red;">防护端口自动获取,如果修改了规则项对应的端口,请删除重新添加,否则防护可能不会生效</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-fail2ban-rule-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'jquery', 'table'], function () {
|
||||
var $ = layui.jquery
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table;
|
||||
|
||||
form.render();
|
||||
|
||||
// 监听类型选择
|
||||
$('#add-fail2ban-rule-service-input').hide();
|
||||
form.on('radio(add-fail2ban-rule-type-radio)', function (data) {
|
||||
if (data.value == 'website') {
|
||||
$('#add-fail2ban-rule-website-input').show();
|
||||
$('#add-fail2ban-rule-website-mode-input').show();
|
||||
$('#add-fail2ban-rule-service-input').hide();
|
||||
if ($('input[name="website_mode"]:checked').val() == 'cc') {
|
||||
$('#add-fail2ban-rule-website-path-input').hide();
|
||||
} else {
|
||||
$('#add-fail2ban-rule-website-path-input').show();
|
||||
}
|
||||
} else if (data.value == 'service') {
|
||||
$('#add-fail2ban-rule-website-input').hide();
|
||||
$('#add-fail2ban-rule-website-mode-input').hide();
|
||||
$('#add-fail2ban-rule-service-input').show();
|
||||
$('#add-fail2ban-rule-website-path-input').hide();
|
||||
}
|
||||
});
|
||||
// 监听网站模式选择
|
||||
$('#add-fail2ban-rule-website-path-input').hide();
|
||||
form.on('radio(add-fail2ban-rule-website-mode-radio)', function (data) {
|
||||
if (data.value == 'cc') {
|
||||
$('#add-fail2ban-rule-website-path-input').hide();
|
||||
} else if (data.value == 'path') {
|
||||
$('#add-fail2ban-rule-website-path-input').show();
|
||||
}
|
||||
});
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-fail2ban-rule-submit)', function (data) {
|
||||
if (data.field.type === 'website') {
|
||||
data.field.name = data.field.website;
|
||||
} else if (data.field.type === 'service') {
|
||||
data.field.name = data.field.service;
|
||||
}
|
||||
index = layer.msg('提交中...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/add"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
table.reload('fail2ban-rule-list');
|
||||
layer.alert('Fail2ban规则添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,101 +0,0 @@
|
||||
<!--
|
||||
Name: Fail2ban管理器 - 查看规则
|
||||
Author: 耗子
|
||||
Date: 2023-07-30
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
{{# console.log(d.params) }}
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-sm6 layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p class="layuiadmin-big-font">{{ d.params.banList.currentlyBan }}</p>
|
||||
<p>当前封禁IP数</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm6 layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p class="layuiadmin-big-font">{{ d.params.banList.totalBan }}</p>
|
||||
<p>累计封禁IP数</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-sm12 layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<table class="layui-table" id="fail2ban-view-rule-table"
|
||||
lay-filter="fail2ban-view-rule-table"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="fail2ban-view-rule-ip-control">
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="unBan">解封</a>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
if (params.banList.bannedIpList === null) {
|
||||
params.banList.bannedIpList = [];
|
||||
}
|
||||
|
||||
layui.use(['admin', 'jquery'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, table = layui.table;
|
||||
|
||||
table.render({
|
||||
elem: '#fail2ban-view-rule-table'
|
||||
, cols: [[
|
||||
{field: 'name', title: '规则名', unresize: true, hide: true}
|
||||
, {field: 'ip', title: 'IP', unresize: true, sort: true}
|
||||
, {
|
||||
fixed: 'right',
|
||||
title: '操作',
|
||||
width: 150,
|
||||
unresize: true,
|
||||
toolbar: '#fail2ban-view-rule-ip-control'
|
||||
}
|
||||
]]
|
||||
, data: params.banList.bannedIpList
|
||||
, page: true
|
||||
, text: {
|
||||
none: '无数据'
|
||||
}
|
||||
});
|
||||
|
||||
// 监听工具条
|
||||
table.on('tool(fail2ban-view-rule-table)', function (obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event === 'unBan') {
|
||||
layer.confirm('确定要解封 <b style="color: red;">' + data.ip + '</b> 吗?', function (index) {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/fail2ban/unban"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert(data.ip + '解封成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,576 +0,0 @@
|
||||
<!--
|
||||
Name: MySQL管理器
|
||||
Author: 耗子
|
||||
Date: 2022-07-22
|
||||
-->
|
||||
<title>MySQL</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">MySQL管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">基本信息</li>
|
||||
<li>管理</li>
|
||||
<li>配置修改</li>
|
||||
<li>负载状态</li>
|
||||
<li>错误日志</li>
|
||||
<li>慢查询日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>运行状态</legend>
|
||||
</fieldset>
|
||||
<blockquote id="mysql-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="mysql-start" class="layui-btn">启动</button>
|
||||
<button id="mysql-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="mysql-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="mysql-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>基本设置</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form" lay-filter="mysql_setting">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">root 密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="mysql_root_password" value="获取中ing..."
|
||||
class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">查看/修改MySQL的root密码</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="mysql_setting_submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">面板仅集成了部分常用功能,如需更多功能,建议安装
|
||||
phpMyAdmin 使用。
|
||||
</blockquote>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>数据库列表</legend>
|
||||
</fieldset>
|
||||
<table class="layui-hide" id="mysql-database-list"
|
||||
lay-filter="mysql-database-list"></table>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>用户列表</legend>
|
||||
</fieldset>
|
||||
<table class="layui-hide" id="mysql-user-list" lay-filter="mysql-user-list"></table>
|
||||
<!-- 数据库顶部工具栏 -->
|
||||
<script type="text/html" id="mysql-database-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_database">新建数据库
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 用户顶部工具栏 -->
|
||||
<script type="text/html" id="mysql-user-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_user">新建用户</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 数据库右侧管理 -->
|
||||
<script type="text/html" id="mysql-database-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="backup">备份</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<!-- 用户右侧管理 -->
|
||||
<script type="text/html" id="mysql-user-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs"
|
||||
lay-event="change_password">改密</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是MySQL主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="mysql-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="mysql-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="mysql-load-status"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="mysql-clean-error-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="mysql-error-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="mysql-clean-slow-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="mysql-slow-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let mysql_config_editor;// 定义mysql配置编辑器的全局变量
|
||||
layui.use(['index', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, code = layui.code
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view;
|
||||
|
||||
// 渲染表单
|
||||
form.render();
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/rootPassword"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:系统信息获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
form.val("mysql_setting", {
|
||||
"mysql_root_password": result.data
|
||||
});
|
||||
$('input').attr('disabled', false);
|
||||
}
|
||||
});
|
||||
// 提交修改
|
||||
form.on('submit(mysql_setting_submit)', function (data) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/rootPassword"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL设置保存失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
layer.msg('修改成功!')
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 获取mysql运行状态并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL运行状态获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#mysql-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#mysql-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据库列表
|
||||
table.render({
|
||||
elem: '#mysql-database-list'
|
||||
, url: '/api/plugins/mysql57/database'
|
||||
, toolbar: '#mysql-database-list-bar'
|
||||
, title: '数据库列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '库名', fixed: 'left', unresize: true, sort: true}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#mysql-database-list-control', width: 150}
|
||||
]]
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
, page: true
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(mysql-database-list)', function (obj) {
|
||||
if (obj.event === 'add_database') {
|
||||
admin.popup({
|
||||
title: '新建数据库'
|
||||
, area: ['600px', '300px']
|
||||
, id: 'LAY-popup-mysql-database-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/mysql57/add_database', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-mysql-database-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(mysql-database-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('高风险操作,确定要删除数据库 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/deleteDatabase"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
database: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:数据库删除失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('数据库' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'backup') {
|
||||
// 打开备份页面
|
||||
admin.popup({
|
||||
title: '备份管理 - ' + data.name
|
||||
, area: ['70%', '80%']
|
||||
, id: 'LAY-popup-mysql-backup'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('plugins/mysql57/backup', {
|
||||
data: data
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-mysql-backup');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据库用户列表
|
||||
table.render({
|
||||
elem: '#mysql-user-list'
|
||||
, url: '/api/plugins/mysql57/user'
|
||||
, toolbar: '#mysql-user-list-bar'
|
||||
, title: '用户列表'
|
||||
, cols: [[
|
||||
{field: 'user', title: '用户名', fixed: 'left', width: 300, sort: true}
|
||||
, {field: 'host', title: '主机', width: 250, sort: true}
|
||||
, {field: 'grants', title: '权限'}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#mysql-user-list-control', width: 150}
|
||||
]]
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
, page: true
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(mysql-user-list)', function (obj) {
|
||||
if (obj.event === 'add_user') {
|
||||
admin.popup({
|
||||
title: '新建用户'
|
||||
, area: ['600px', '300px']
|
||||
, id: 'LAY-popup-mysql-user-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/mysql57/add_user', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-mysql-user-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(mysql-user-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('高风险操作,确定要删除用户 <b style="color: red;">' + data.user + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/deleteUser"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:用户删除失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('用户' + data.user + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'change_password') {
|
||||
// 弹出输入密码框
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '请输入新密码(8位以上大小写数字特殊符号混合)'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0});
|
||||
// 发送请求
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/userPassword"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
user: data.user,
|
||||
password: value
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:密码修改失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
layer.alert('用户' + data.user + '密码修改成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取mysql错误日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/errorLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL错误日志获取失败,接口返回' + result);
|
||||
$('#mysql-error-log').text('MySQL错误日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#mysql-error-log'
|
||||
, title: 'error.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#mysql-error-log').text(result.data);
|
||||
code({
|
||||
elem: '#mysql-error-log'
|
||||
, title: 'error.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取mysql慢查询日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/slowLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL慢查询日志获取失败,接口返回' + result);
|
||||
$('#mysql-slow-log').text('MySQL慢查询日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#mysql-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#mysql-slow-log').text(result.data);
|
||||
code({
|
||||
elem: '#mysql-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取mysql配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL主配置获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
$('#mysql-config-editor').text(result.data);
|
||||
mysql_config_editor = ace.edit("mysql-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取mysql负载状态并渲染
|
||||
table.render({
|
||||
elem: '#mysql-load-status'
|
||||
, url: '/api/plugins/mysql57/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '80%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 事件监听
|
||||
$('#mysql-start').click(function () {
|
||||
layer.confirm('确定要启动MySQL吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在启动MySQL...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL启动失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('MySQL启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#mysql-stop').click(function () {
|
||||
layer.confirm('停止MySQL将导致使用MySQL的网站无法访问,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止MySQL...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL停止失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('MySQL停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#mysql-restart').click(function () {
|
||||
layer.confirm('重启MySQL将导致使用MySQL的网站短时间无法访问,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启MySQL...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL重启失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('MySQL重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#mysql-reload').click(function () {
|
||||
index = layer.msg('正在重载MySQL...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL重载失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('MySQL重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#mysql-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: mysql_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL配置保存失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
layer.alert('MySQL配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#mysql-clean-error-log').click(function () {
|
||||
index = layer.msg('正在清空错误日志...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/clearErrorLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL错误日志清空失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
layer.msg('MySQL错误日志已清空!');
|
||||
setTimeout(function () {
|
||||
admin.events.refresh();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#mysql-clean-slow-log').click(function () {
|
||||
index = layer.msg('正在清空慢查询日志...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/clearSlowLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL慢查询日志清空失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
layer.msg('MySQL慢查询日志已清空!');
|
||||
setTimeout(function () {
|
||||
admin.events.refresh();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,80 +0,0 @@
|
||||
<!--
|
||||
Name: MySQL管理器 - 添加数据库
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-mysql-database-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数据库名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="database" lay-verify="required" placeholder="请输入数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" lay-verify="required" placeholder="请输入密码(8位以上大小写数字特殊符号混合)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-mysql-database-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-mysql-database-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/addDatabase"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:数据库添加失败,接口返回' + result);
|
||||
layer.msg('数据库添加失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
table.reload('mysql-database-list');
|
||||
table.reload('mysql-user-list');
|
||||
layer.alert('数据库添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,80 +0,0 @@
|
||||
<!--
|
||||
Name: MySQL管理器 - 添加用户
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-mysql-user-form">
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" lay-verify="required" placeholder="请输入密码(8位以上大小写数字特殊符号混合)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数据库</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="database" lay-verify="required" placeholder="输入授权给该用户的数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-mysql-user-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-mysql-user-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/addUser"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:用户添加失败,接口返回' + result);
|
||||
layer.msg('用户添加失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
table.reload('mysql-database-list');
|
||||
table.reload('mysql-user-list');
|
||||
layer.alert('用户添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,145 +0,0 @@
|
||||
<!--
|
||||
Name: MySQL管理器 - 数据库备份
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs12 layui-col-sm12 layui-col-md12">
|
||||
<table class="layui-hide" id="mysql-backup-list" lay-filter="mysql-backup-list"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份顶部工具栏 -->
|
||||
<script type="text/html" id="mysql-database-backup-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="backup_database">备份数据库</button>
|
||||
<button class="layui-btn layui-btn-sm" id="upload_mysql_backup">上传备份</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份右侧管理 -->
|
||||
<script type="text/html" id="mysql-database-backup-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'laydate', 'code'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, table = layui.table
|
||||
, upload = layui.upload;
|
||||
|
||||
// 渲染表格
|
||||
table.render({
|
||||
elem: '#mysql-backup-list'
|
||||
, url: '/api/plugins/mysql57/backup'
|
||||
, toolbar: '#mysql-database-backup-bar'
|
||||
, title: '备份列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '备份名称', width: 500}
|
||||
, {field: 'size', title: '文件大小'}
|
||||
, {field: 'right', title: '操作', width: 150, toolbar: '#mysql-database-backup-control'}
|
||||
]]
|
||||
, text: {
|
||||
none: '无备份数据'
|
||||
}
|
||||
, done: function (res, curr, count) {
|
||||
upload.render({
|
||||
elem: '#upload_mysql_backup'
|
||||
, url: '/api/plugins/mysql57/uploadBackup'
|
||||
, accept: 'file'
|
||||
, ext: 'sql|zip|rar|tar|gz|bz2'
|
||||
, before: function (obj) {
|
||||
index = layer.msg('正在上传备份文件,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
}
|
||||
, done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg('上传成功!', {icon: 1});
|
||||
table.reload('mysql-backup-list');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(mysql-backup-list)', function (obj) {
|
||||
if (obj.event === 'backup_database') {
|
||||
index = layer.msg('正在备份数据库,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: '/api/plugins/mysql57/createBackup'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
database: params.data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:备份数据库失败,接口返回' + result);
|
||||
layer.alert('备份失败!');
|
||||
return false;
|
||||
}
|
||||
table.reload('mysql-backup-list');
|
||||
layer.msg('备份成功!', {icon: 1});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(mysql-backup-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除数据库备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除数据库备份,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/deleteBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:数据库备份删除失败,接口返回' + result);
|
||||
layer.msg('数据库备份删除失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('数据库备份' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'restore') {
|
||||
layer.confirm('高风险操作,确定要恢复数据库备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在恢复数据库备份,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
data.database = params.data.name;
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql57/restoreBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:数据库恢复失败,接口返回' + result);
|
||||
layer.msg('数据库备份恢复失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.alert('数据库备份' + data.name + '恢复成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,576 +0,0 @@
|
||||
<!--
|
||||
Name: MySQL管理器
|
||||
Author: 耗子
|
||||
Date: 2022-07-22
|
||||
-->
|
||||
<title>MySQL</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">MySQL管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">基本信息</li>
|
||||
<li>管理</li>
|
||||
<li>配置修改</li>
|
||||
<li>负载状态</li>
|
||||
<li>错误日志</li>
|
||||
<li>慢查询日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>运行状态</legend>
|
||||
</fieldset>
|
||||
<blockquote id="mysql-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="mysql-start" class="layui-btn">启动</button>
|
||||
<button id="mysql-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="mysql-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="mysql-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>基本设置</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form" lay-filter="mysql_setting">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">root 密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="mysql_root_password" value="获取中ing..."
|
||||
class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">查看/修改MySQL的root密码</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="mysql_setting_submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">面板仅集成了部分常用功能,如需更多功能,建议安装
|
||||
phpMyAdmin 使用。
|
||||
</blockquote>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>数据库列表</legend>
|
||||
</fieldset>
|
||||
<table class="layui-hide" id="mysql-database-list"
|
||||
lay-filter="mysql-database-list"></table>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>用户列表</legend>
|
||||
</fieldset>
|
||||
<table class="layui-hide" id="mysql-user-list" lay-filter="mysql-user-list"></table>
|
||||
<!-- 数据库顶部工具栏 -->
|
||||
<script type="text/html" id="mysql-database-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_database">新建数据库
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 用户顶部工具栏 -->
|
||||
<script type="text/html" id="mysql-user-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_user">新建用户</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 数据库右侧管理 -->
|
||||
<script type="text/html" id="mysql-database-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="backup">备份</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<!-- 用户右侧管理 -->
|
||||
<script type="text/html" id="mysql-user-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs"
|
||||
lay-event="change_password">改密</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是MySQL主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="mysql-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="mysql-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="mysql-load-status"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="mysql-clean-error-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="mysql-error-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="mysql-clean-slow-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="mysql-slow-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let mysql_config_editor;// 定义mysql配置编辑器的全局变量
|
||||
layui.use(['index', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, code = layui.code
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view;
|
||||
|
||||
// 渲染表单
|
||||
form.render();
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/rootPassword"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:系统信息获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
form.val("mysql_setting", {
|
||||
"mysql_root_password": result.data
|
||||
});
|
||||
$('input').attr('disabled', false);
|
||||
}
|
||||
});
|
||||
// 提交修改
|
||||
form.on('submit(mysql_setting_submit)', function (data) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/rootPassword"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL设置保存失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
layer.msg('修改成功!')
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 获取mysql运行状态并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL运行状态获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#mysql-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#mysql-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据库列表
|
||||
table.render({
|
||||
elem: '#mysql-database-list'
|
||||
, url: '/api/plugins/mysql80/database'
|
||||
, toolbar: '#mysql-database-list-bar'
|
||||
, title: '数据库列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '库名', fixed: 'left', unresize: true, sort: true}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#mysql-database-list-control', width: 150}
|
||||
]]
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
, page: true
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(mysql-database-list)', function (obj) {
|
||||
if (obj.event === 'add_database') {
|
||||
admin.popup({
|
||||
title: '新建数据库'
|
||||
, area: ['600px', '300px']
|
||||
, id: 'LAY-popup-mysql-database-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/mysql80/add_database', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-mysql-database-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(mysql-database-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('高风险操作,确定要删除数据库 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/deleteDatabase"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
database: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:数据库删除失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('数据库' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'backup') {
|
||||
// 打开备份页面
|
||||
admin.popup({
|
||||
title: '备份管理 - ' + data.name
|
||||
, area: ['70%', '80%']
|
||||
, id: 'LAY-popup-mysql-backup'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('plugins/mysql80/backup', {
|
||||
data: data
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-mysql-backup');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据库用户列表
|
||||
table.render({
|
||||
elem: '#mysql-user-list'
|
||||
, url: '/api/plugins/mysql80/user'
|
||||
, toolbar: '#mysql-user-list-bar'
|
||||
, title: '用户列表'
|
||||
, cols: [[
|
||||
{field: 'user', title: '用户名', fixed: 'left', width: 300, sort: true}
|
||||
, {field: 'host', title: '主机', width: 250, sort: true}
|
||||
, {field: 'grants', title: '权限'}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#mysql-user-list-control', width: 150}
|
||||
]]
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
, page: true
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(mysql-user-list)', function (obj) {
|
||||
if (obj.event === 'add_user') {
|
||||
admin.popup({
|
||||
title: '新建用户'
|
||||
, area: ['600px', '300px']
|
||||
, id: 'LAY-popup-mysql-user-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/mysql80/add_user', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-mysql-user-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(mysql-user-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('高风险操作,确定要删除用户 <b style="color: red;">' + data.user + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/deleteUser"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:用户删除失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('用户' + data.user + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'change_password') {
|
||||
// 弹出输入密码框
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '请输入新密码(8位以上大小写数字特殊符号混合)'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0});
|
||||
// 发送请求
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/userPassword"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
user: data.user,
|
||||
password: value
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:密码修改失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
layer.alert('用户' + data.user + '密码修改成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取mysql错误日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/errorLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL错误日志获取失败,接口返回' + result);
|
||||
$('#mysql-error-log').text('MySQL错误日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#mysql-error-log'
|
||||
, title: 'error.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#mysql-error-log').text(result.data);
|
||||
code({
|
||||
elem: '#mysql-error-log'
|
||||
, title: 'error.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取mysql慢查询日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/slowLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL慢查询日志获取失败,接口返回' + result);
|
||||
$('#mysql-slow-log').text('MySQL慢查询日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#mysql-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#mysql-slow-log').text(result.data);
|
||||
code({
|
||||
elem: '#mysql-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取mysql配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL主配置获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
$('#mysql-config-editor').text(result.data);
|
||||
mysql_config_editor = ace.edit("mysql-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取mysql负载状态并渲染
|
||||
table.render({
|
||||
elem: '#mysql-load-status'
|
||||
, url: '/api/plugins/mysql80/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '80%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 事件监听
|
||||
$('#mysql-start').click(function () {
|
||||
layer.confirm('确定要启动MySQL吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在启动MySQL...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL启动失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('MySQL启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#mysql-stop').click(function () {
|
||||
layer.confirm('停止MySQL将导致使用MySQL的网站无法访问,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止MySQL...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL停止失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('MySQL停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#mysql-restart').click(function () {
|
||||
layer.confirm('重启MySQL将导致使用MySQL的网站短时间无法访问,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启MySQL...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL重启失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('MySQL重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#mysql-reload').click(function () {
|
||||
index = layer.msg('正在重载MySQL...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL重载失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('MySQL重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#mysql-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: mysql_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL配置保存失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
layer.alert('MySQL配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#mysql-clean-error-log').click(function () {
|
||||
index = layer.msg('正在清空错误日志...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/clearErrorLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL错误日志清空失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
layer.msg('MySQL错误日志已清空!');
|
||||
setTimeout(function () {
|
||||
admin.events.refresh();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#mysql-clean-slow-log').click(function () {
|
||||
index = layer.msg('正在清空慢查询日志...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/clearSlowLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:MySQL慢查询日志清空失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
layer.msg('MySQL慢查询日志已清空!');
|
||||
setTimeout(function () {
|
||||
admin.events.refresh();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,80 +0,0 @@
|
||||
<!--
|
||||
Name: MySQL管理器 - 添加数据库
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-mysql-database-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数据库名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="database" lay-verify="required" placeholder="请输入数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" lay-verify="required" placeholder="请输入密码(8位以上大小写数字特殊符号混合)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-mysql-database-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-mysql-database-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/addDatabase"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:数据库添加失败,接口返回' + result);
|
||||
layer.msg('数据库添加失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
table.reload('mysql-database-list');
|
||||
table.reload('mysql-user-list');
|
||||
layer.alert('数据库添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,80 +0,0 @@
|
||||
<!--
|
||||
Name: MySQL管理器 - 添加用户
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-mysql-user-form">
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" lay-verify="required" placeholder="请输入密码(8位以上大小写数字特殊符号混合)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数据库</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="database" lay-verify="required" placeholder="输入授权给该用户的数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-mysql-user-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-mysql-user-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/addUser"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:用户添加失败,接口返回' + result);
|
||||
layer.msg('用户添加失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
table.reload('mysql-database-list');
|
||||
table.reload('mysql-user-list');
|
||||
layer.alert('用户添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,145 +0,0 @@
|
||||
<!--
|
||||
Name: MySQL管理器 - 数据库备份
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs12 layui-col-sm12 layui-col-md12">
|
||||
<table class="layui-hide" id="mysql-backup-list" lay-filter="mysql-backup-list"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份顶部工具栏 -->
|
||||
<script type="text/html" id="mysql-database-backup-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="backup_database">备份数据库</button>
|
||||
<button class="layui-btn layui-btn-sm" id="upload_mysql_backup">上传备份</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份右侧管理 -->
|
||||
<script type="text/html" id="mysql-database-backup-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'laydate', 'code'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, table = layui.table
|
||||
, upload = layui.upload;
|
||||
|
||||
// 渲染表格
|
||||
table.render({
|
||||
elem: '#mysql-backup-list'
|
||||
, url: '/api/plugins/mysql80/backup'
|
||||
, toolbar: '#mysql-database-backup-bar'
|
||||
, title: '备份列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '备份名称', width: 500}
|
||||
, {field: 'size', title: '文件大小'}
|
||||
, {field: 'right', title: '操作', width: 150, toolbar: '#mysql-database-backup-control'}
|
||||
]]
|
||||
, text: {
|
||||
none: '无备份数据'
|
||||
}
|
||||
, done: function (res, curr, count) {
|
||||
upload.render({
|
||||
elem: '#upload_mysql_backup'
|
||||
, url: '/api/plugins/mysql80/uploadBackup'
|
||||
, accept: 'file'
|
||||
, ext: 'sql|zip|rar|tar|gz|bz2'
|
||||
, before: function (obj) {
|
||||
index = layer.msg('正在上传备份文件,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
}
|
||||
, done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg('上传成功!', {icon: 1});
|
||||
table.reload('mysql-backup-list');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(mysql-backup-list)', function (obj) {
|
||||
if (obj.event === 'backup_database') {
|
||||
index = layer.msg('正在备份数据库,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: '/api/plugins/mysql80/createBackup'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
database: params.data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:备份数据库失败,接口返回' + result);
|
||||
layer.alert('备份失败!');
|
||||
return false;
|
||||
}
|
||||
table.reload('mysql-backup-list');
|
||||
layer.msg('备份成功!', {icon: 1});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(mysql-backup-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除数据库备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除数据库备份,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/deleteBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:数据库备份删除失败,接口返回' + result);
|
||||
layer.msg('数据库备份删除失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('数据库备份' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'restore') {
|
||||
layer.confirm('高风险操作,确定要恢复数据库备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在恢复数据库备份,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
data.database = params.data.name;
|
||||
admin.req({
|
||||
url: "/api/plugins/mysql80/restoreBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:数据库恢复失败,接口返回' + result);
|
||||
layer.msg('数据库备份恢复失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.alert('数据库备份' + data.name + '恢复成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,245 +0,0 @@
|
||||
<!--
|
||||
Name: Openresty管理器
|
||||
Author: 耗子
|
||||
Date: 2023-06-24
|
||||
-->
|
||||
<title>OpenResty</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">OpenResty管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">运行状态</li>
|
||||
<li>配置修改</li>
|
||||
<li>负载状态</li>
|
||||
<li>错误日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<blockquote id="openresty-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="openresty-start" class="layui-btn">启动</button>
|
||||
<button id="openresty-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="openresty-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="openresty-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是OpenResty主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="openresty-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="openresty-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="openresty-load-status"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="openresty-clear-error-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="openresty-error-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let openresty_config_editor
|
||||
layui.use(['index', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, code = layui.code
|
||||
, table = layui.table
|
||||
|
||||
admin.req({
|
||||
url: '/api/plugins/openresty/status'
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:OpenResty运行状态获取失败,接口返回' + result)
|
||||
return false
|
||||
}
|
||||
if (result.data) {
|
||||
$('#openresty-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>')
|
||||
} else {
|
||||
$('#openresty-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>')
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
// 获取openresty错误日志并渲染
|
||||
admin.req({
|
||||
url: '/api/plugins/openresty/errorLog'
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:OpenResty错误日志获取失败,接口返回' + result)
|
||||
$('#openresty-error-log').text('OpenResty错误日志获取失败,请刷新重试!')
|
||||
code({
|
||||
elem: '#openresty-error-log'
|
||||
, title: 'error.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
})
|
||||
return false
|
||||
}
|
||||
$('#openresty-error-log').text(result.data)
|
||||
code({
|
||||
elem: '#openresty-error-log'
|
||||
, title: 'error.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 获取openresty配置并渲染
|
||||
admin.req({
|
||||
url: '/api/plugins/openresty/config'
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:OpenResty主配置获取失败,接口返回' + result)
|
||||
return false
|
||||
}
|
||||
$('#openresty-config-editor').text(result.data)
|
||||
openresty_config_editor = ace.edit('openresty-config-editor', {
|
||||
mode: 'ace/mode/nginx',
|
||||
selectionStyle: 'text'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 获取openresty负载状态并渲染
|
||||
table.render({
|
||||
elem: '#openresty-load-status'
|
||||
, url: '/api/plugins/openresty/load'
|
||||
, cols: [[
|
||||
{ field: 'name', width: '80%', title: '属性', }
|
||||
, { field: 'value', width: '20%', title: '当前值' }
|
||||
]]
|
||||
})
|
||||
element.render()
|
||||
|
||||
// 事件监听
|
||||
$('#openresty-start').click(function () {
|
||||
index = layer.msg('正在启动OpenResty...', { icon: 16, time: 0, shade: 0.3 })
|
||||
admin.req({
|
||||
url: '/api/plugins/openresty/start'
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false
|
||||
}
|
||||
admin.events.refresh()
|
||||
layer.alert('OpenResty启动成功!')
|
||||
}
|
||||
})
|
||||
})
|
||||
$('#openresty-stop').click(function () {
|
||||
layer.confirm('停止OpenResty将导致网站无法访问,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止OpenResty...', { icon: 16, time: 0, shade: 0.3 })
|
||||
admin.req({
|
||||
url: '/api/plugins/openresty/stop'
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false
|
||||
}
|
||||
admin.events.refresh()
|
||||
layer.alert('OpenResty停止成功!')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
$('#openresty-restart').click(function () {
|
||||
layer.confirm('重启OpenResty将导致网站短时间无法访问,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启OpenResty...', { icon: 16, time: 0, shade: 0.3 })
|
||||
admin.req({
|
||||
url: '/api/plugins/openresty/restart'
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false
|
||||
}
|
||||
admin.events.refresh()
|
||||
layer.alert('OpenResty重启成功!')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
$('#openresty-reload').click(function () {
|
||||
index = layer.msg('正在重载OpenResty...', { icon: 16, time: 0, shade: 0.3 })
|
||||
admin.req({
|
||||
url: '/api/plugins/openresty/reload'
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false
|
||||
}
|
||||
admin.events.refresh()
|
||||
layer.alert('OpenResty重载成功!')
|
||||
}
|
||||
})
|
||||
})
|
||||
$('#openresty-config-save').click(function () {
|
||||
index = layer.msg('正在保存OpenResty主配置...', { icon: 16, time: 0, shade: 0.3 })
|
||||
admin.req({
|
||||
url: '/api/plugins/openresty/config'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: openresty_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false
|
||||
}
|
||||
layer.alert('OpenResty配置保存成功!')
|
||||
}
|
||||
})
|
||||
})
|
||||
$('#openresty-clear-error-log').click(function () {
|
||||
index = layer.msg('正在清空OpenResty错误日志...', { icon: 16, time: 0, shade: 0.3 })
|
||||
admin.req({
|
||||
url: '/api/plugins/openresty/clearErrorLog'
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:OpenResty错误日志清空失败,接口返回' + result)
|
||||
return false
|
||||
}
|
||||
admin.events.refresh()
|
||||
layer.msg('OpenResty错误日志已清空!')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@@ -1,381 +0,0 @@
|
||||
<!--
|
||||
Name: PHP管理器
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<title>PHP-7.4</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">PHP-7.4管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">运行状态</li>
|
||||
<li>拓展管理</li>
|
||||
<li>配置修改</li>
|
||||
<li>负载状态</li>
|
||||
<li>运行日志</li>
|
||||
<li>慢日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<blockquote id="php74-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="php74-start" class="layui-btn">启动</button>
|
||||
<button id="php74-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="php74-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="php74-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table id="php74-extension" lay-filter="php74-extension"></table>
|
||||
<!-- 操作按钮模板 -->
|
||||
<script type="text/html" id="php74-extension-control">
|
||||
{{# if(d.installed == true){ }}
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="uninstall">卸载</a>
|
||||
{{# } else{ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="install">安装</a>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是PHP主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="php74-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="php74-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="php74-load-status"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="php74-clean-error-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="php74-error-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="php74-clean-slow-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="php74-slow-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let php74_config_editor;
|
||||
layui.use(['index', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, code = layui.code
|
||||
, table = layui.table;
|
||||
|
||||
// 获取php74运行状态并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:PHP运行状态获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#php74-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#php74-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php74错误日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/errorLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#php74-error-log').text('PHP日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#php74-error-log'
|
||||
, title: 'php-fpm.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#php74-error-log').text(result.data);
|
||||
code({
|
||||
elem: '#php74-error-log'
|
||||
, title: 'php-fpm.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php74慢日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/slowLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#php74-slow-log').text('PHP慢日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#php74-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#php74-slow-log').text(result.data);
|
||||
code({
|
||||
elem: '#php74-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php74配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:PHP主配置获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
$('#php74-config-editor').text(result.data);
|
||||
php74_config_editor = ace.edit("php74-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php74负载状态并渲染
|
||||
table.render({
|
||||
elem: '#php74-load-status'
|
||||
, url: '/api/plugins/php74/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '80%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 获取php74扩展并渲染
|
||||
table.render({
|
||||
elem: '#php74-extension'
|
||||
, url: '/api/plugins/php74/extensions'
|
||||
, cols: [[
|
||||
{field: 'slug', hide: true, title: 'Slug', sort: true}
|
||||
, {field: 'name', width: '20%', title: '拓展名'}
|
||||
, {field: 'description', width: '70%', title: '描述'}
|
||||
, {
|
||||
field: 'control',
|
||||
title: '操作',
|
||||
templet: '#php74-extension-control',
|
||||
fixed: 'right',
|
||||
align: 'left'
|
||||
}
|
||||
]]
|
||||
, page: false
|
||||
, text: {
|
||||
none: '暂无拓展'
|
||||
}
|
||||
});
|
||||
// 工具条
|
||||
table.on('tool(php74-extension)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'install') {
|
||||
layer.confirm('确定安装该拓展吗?', function (index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: '/api/plugins/php74/installExtension',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('php74-extension');
|
||||
layer.msg('安装:' + data.name + ' 成功加入任务队列', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'uninstall') {
|
||||
layer.confirm('确定卸载该拓展吗?', function (index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: '/api/plugins/php74/uninstallExtension',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
table.reload('php74-extension');
|
||||
layer.msg('卸载:' + data.name + ' 成功加入任务队列', {icon: 1, time: 1000});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 事件监听
|
||||
$('#php74-start').click(function () {
|
||||
index = layer.msg('正在启动PHP,请稍后...', {icon: 16, time: 0});
|
||||
layer.confirm('确定要启动PHP吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php74-stop').click(function () {
|
||||
layer.confirm('停止PHP将导致使用PHP的网站无法访问,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php74-restart').click(function () {
|
||||
layer.confirm('重启PHP将导致使用PHP的网站短时间无法访问,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php74-reload').click(function () {
|
||||
index = layer.msg('正在重载PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PHP重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php74-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: php74_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PHP配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php74-clean-error-log').click(function () {
|
||||
index = layer.msg('正在清空错误日志,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/clearErrorLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.msg('PHP日志已清空!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php74-clean-slow-log').click(function () {
|
||||
index = layer.msg('正在清空慢日志,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php74/clearSlowLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.msg('PHP慢日志已清空!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,381 +0,0 @@
|
||||
<!--
|
||||
Name: PHP管理器
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<title>PHP-8.0</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">PHP-8.0管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">运行状态</li>
|
||||
<li>拓展管理</li>
|
||||
<li>配置修改</li>
|
||||
<li>负载状态</li>
|
||||
<li>运行日志</li>
|
||||
<li>慢日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<blockquote id="php80-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="php80-start" class="layui-btn">启动</button>
|
||||
<button id="php80-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="php80-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="php80-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table id="php80-extension" lay-filter="php80-extension"></table>
|
||||
<!-- 操作按钮模板 -->
|
||||
<script type="text/html" id="php80-extension-control">
|
||||
{{# if(d.installed == true){ }}
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="uninstall">卸载</a>
|
||||
{{# } else{ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="install">安装</a>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是PHP主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="php80-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="php80-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="php80-load-status"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="php80-clean-error-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="php80-error-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="php80-clean-slow-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="php80-slow-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let php80_config_editor;
|
||||
layui.use(['index', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, code = layui.code
|
||||
, table = layui.table;
|
||||
|
||||
// 获取php80运行状态并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:PHP运行状态获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#php80-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#php80-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php80错误日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/errorLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#php80-error-log').text('PHP日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#php80-error-log'
|
||||
, title: 'php-fpm.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#php80-error-log').text(result.data);
|
||||
code({
|
||||
elem: '#php80-error-log'
|
||||
, title: 'php-fpm.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php80慢日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/slowLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#php80-slow-log').text('PHP慢日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#php80-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#php80-slow-log').text(result.data);
|
||||
code({
|
||||
elem: '#php80-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php80配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:PHP主配置获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
$('#php80-config-editor').text(result.data);
|
||||
php80_config_editor = ace.edit("php80-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php80负载状态并渲染
|
||||
table.render({
|
||||
elem: '#php80-load-status'
|
||||
, url: '/api/plugins/php80/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '80%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 获取php80扩展并渲染
|
||||
table.render({
|
||||
elem: '#php80-extension'
|
||||
, url: '/api/plugins/php80/extensions'
|
||||
, cols: [[
|
||||
{field: 'slug', hide: true, title: 'Slug', sort: true}
|
||||
, {field: 'name', width: '20%', title: '拓展名'}
|
||||
, {field: 'description', width: '70%', title: '描述'}
|
||||
, {
|
||||
field: 'control',
|
||||
title: '操作',
|
||||
templet: '#php80-extension-control',
|
||||
fixed: 'right',
|
||||
align: 'left'
|
||||
}
|
||||
]]
|
||||
, page: false
|
||||
, text: {
|
||||
none: '暂无拓展'
|
||||
}
|
||||
});
|
||||
// 工具条
|
||||
table.on('tool(php80-extension)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'install') {
|
||||
layer.confirm('确定安装该拓展吗?', function (index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: '/api/plugins/php80/installExtension',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('php80-extension');
|
||||
layer.msg('安装:' + data.name + ' 成功加入任务队列', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'uninstall') {
|
||||
layer.confirm('确定卸载该拓展吗?', function (index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: '/api/plugins/php80/uninstallExtension',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
table.reload('php80-extension');
|
||||
layer.msg('卸载:' + data.name + ' 成功加入任务队列', {icon: 1, time: 1000});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 事件监听
|
||||
$('#php80-start').click(function () {
|
||||
index = layer.msg('正在启动PHP,请稍后...', {icon: 16, time: 0});
|
||||
layer.confirm('确定要启动PHP吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php80-stop').click(function () {
|
||||
layer.confirm('停止PHP将导致使用PHP的网站无法访问,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php80-restart').click(function () {
|
||||
layer.confirm('重启PHP将导致使用PHP的网站短时间无法访问,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php80-reload').click(function () {
|
||||
index = layer.msg('正在重载PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PHP重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php80-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: php80_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PHP配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php80-clean-error-log').click(function () {
|
||||
index = layer.msg('正在清空错误日志,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/clearErrorLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.msg('PHP日志已清空!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php80-clean-slow-log').click(function () {
|
||||
index = layer.msg('正在清空慢日志,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php80/clearSlowLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.msg('PHP慢日志已清空!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,381 +0,0 @@
|
||||
<!--
|
||||
Name: PHP管理器
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<title>PHP-8.1</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">PHP-8.1管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">运行状态</li>
|
||||
<li>拓展管理</li>
|
||||
<li>配置修改</li>
|
||||
<li>负载状态</li>
|
||||
<li>运行日志</li>
|
||||
<li>慢日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<blockquote id="php81-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="php81-start" class="layui-btn">启动</button>
|
||||
<button id="php81-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="php81-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="php81-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table id="php81-extension" lay-filter="php81-extension"></table>
|
||||
<!-- 操作按钮模板 -->
|
||||
<script type="text/html" id="php81-extension-control">
|
||||
{{# if(d.installed == true){ }}
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="uninstall">卸载</a>
|
||||
{{# } else{ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="install">安装</a>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是PHP主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="php81-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="php81-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="php81-load-status"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="php81-clean-error-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="php81-error-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="php81-clean-slow-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="php81-slow-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let php81_config_editor;
|
||||
layui.use(['index', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, code = layui.code
|
||||
, table = layui.table;
|
||||
|
||||
// 获取php81运行状态并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:PHP运行状态获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#php81-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#php81-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php81错误日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/errorLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#php81-error-log').text('PHP日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#php81-error-log'
|
||||
, title: 'php-fpm.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#php81-error-log').text(result.data);
|
||||
code({
|
||||
elem: '#php81-error-log'
|
||||
, title: 'php-fpm.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php81慢日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/slowLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#php81-slow-log').text('PHP慢日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#php81-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#php81-slow-log').text(result.data);
|
||||
code({
|
||||
elem: '#php81-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php81配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:PHP主配置获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
$('#php81-config-editor').text(result.data);
|
||||
php81_config_editor = ace.edit("php81-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php81负载状态并渲染
|
||||
table.render({
|
||||
elem: '#php81-load-status'
|
||||
, url: '/api/plugins/php81/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '81%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 获取php81扩展并渲染
|
||||
table.render({
|
||||
elem: '#php81-extension'
|
||||
, url: '/api/plugins/php81/extensions'
|
||||
, cols: [[
|
||||
{field: 'slug', hide: true, title: 'Slug', sort: true}
|
||||
, {field: 'name', width: '20%', title: '拓展名'}
|
||||
, {field: 'description', width: '70%', title: '描述'}
|
||||
, {
|
||||
field: 'control',
|
||||
title: '操作',
|
||||
templet: '#php81-extension-control',
|
||||
fixed: 'right',
|
||||
align: 'left'
|
||||
}
|
||||
]]
|
||||
, page: false
|
||||
, text: {
|
||||
none: '暂无拓展'
|
||||
}
|
||||
});
|
||||
// 工具条
|
||||
table.on('tool(php81-extension)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'install') {
|
||||
layer.confirm('确定安装该拓展吗?', function (index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: '/api/plugins/php81/installExtension',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('php81-extension');
|
||||
layer.msg('安装:' + data.name + ' 成功加入任务队列', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'uninstall') {
|
||||
layer.confirm('确定卸载该拓展吗?', function (index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: '/api/plugins/php81/uninstallExtension',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
table.reload('php81-extension');
|
||||
layer.msg('卸载:' + data.name + ' 成功加入任务队列', {icon: 1, time: 1000});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 事件监听
|
||||
$('#php81-start').click(function () {
|
||||
index = layer.msg('正在启动PHP,请稍后...', {icon: 16, time: 0});
|
||||
layer.confirm('确定要启动PHP吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php81-stop').click(function () {
|
||||
layer.confirm('停止PHP将导致使用PHP的网站无法访问,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php81-restart').click(function () {
|
||||
layer.confirm('重启PHP将导致使用PHP的网站短时间无法访问,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php81-reload').click(function () {
|
||||
index = layer.msg('正在重载PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PHP重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php81-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: php81_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PHP配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php81-clean-error-log').click(function () {
|
||||
index = layer.msg('正在清空错误日志,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/clearErrorLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.msg('PHP日志已清空!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php81-clean-slow-log').click(function () {
|
||||
index = layer.msg('正在清空慢日志,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php81/clearSlowLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.msg('PHP慢日志已清空!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,381 +0,0 @@
|
||||
<!--
|
||||
Name: PHP管理器
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<title>PHP-8.2</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">PHP-8.2管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">运行状态</li>
|
||||
<li>拓展管理</li>
|
||||
<li>配置修改</li>
|
||||
<li>负载状态</li>
|
||||
<li>运行日志</li>
|
||||
<li>慢日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<blockquote id="php82-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="php82-start" class="layui-btn">启动</button>
|
||||
<button id="php82-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="php82-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="php82-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table id="php82-extension" lay-filter="php82-extension"></table>
|
||||
<!-- 操作按钮模板 -->
|
||||
<script type="text/html" id="php82-extension-control">
|
||||
{{# if(d.installed == true){ }}
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="uninstall">卸载</a>
|
||||
{{# } else{ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="install">安装</a>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是PHP主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="php82-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="php82-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="php82-load-status"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="php82-clean-error-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="php82-error-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="php82-clean-slow-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="php82-slow-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let php82_config_editor;
|
||||
layui.use(['index', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, code = layui.code
|
||||
, table = layui.table;
|
||||
|
||||
// 获取php82运行状态并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:PHP运行状态获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#php82-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#php82-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php82错误日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/errorLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#php82-error-log').text('PHP日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#php82-error-log'
|
||||
, title: 'php-fpm.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#php82-error-log').text(result.data);
|
||||
code({
|
||||
elem: '#php82-error-log'
|
||||
, title: 'php-fpm.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php82慢日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/slowLog"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#php82-slow-log').text('PHP慢日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#php82-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#php82-slow-log').text(result.data);
|
||||
code({
|
||||
elem: '#php82-slow-log'
|
||||
, title: 'slow.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php82配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:PHP主配置获取失败,接口返回' + result);
|
||||
return false;
|
||||
}
|
||||
$('#php82-config-editor').text(result.data);
|
||||
php82_config_editor = ace.edit("php82-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取php82负载状态并渲染
|
||||
table.render({
|
||||
elem: '#php82-load-status'
|
||||
, url: '/api/plugins/php82/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '82%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 获取php82扩展并渲染
|
||||
table.render({
|
||||
elem: '#php82-extension'
|
||||
, url: '/api/plugins/php82/extensions'
|
||||
, cols: [[
|
||||
{field: 'slug', hide: true, title: 'Slug', sort: true}
|
||||
, {field: 'name', width: '20%', title: '拓展名'}
|
||||
, {field: 'description', width: '70%', title: '描述'}
|
||||
, {
|
||||
field: 'control',
|
||||
title: '操作',
|
||||
templet: '#php82-extension-control',
|
||||
fixed: 'right',
|
||||
align: 'left'
|
||||
}
|
||||
]]
|
||||
, page: false
|
||||
, text: {
|
||||
none: '暂无拓展'
|
||||
}
|
||||
});
|
||||
// 工具条
|
||||
table.on('tool(php82-extension)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'install') {
|
||||
layer.confirm('确定安装该拓展吗?', function (index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: '/api/plugins/php82/installExtension',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
table.reload('php82-extension');
|
||||
layer.msg('安装:' + data.name + ' 成功加入任务队列', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'uninstall') {
|
||||
layer.confirm('确定卸载该拓展吗?', function (index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: '/api/plugins/php82/uninstallExtension',
|
||||
type: 'POST',
|
||||
data: {
|
||||
slug: data.slug
|
||||
}
|
||||
, success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
table.reload('php82-extension');
|
||||
layer.msg('卸载:' + data.name + ' 成功加入任务队列', {icon: 1, time: 1000});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 事件监听
|
||||
$('#php82-start').click(function () {
|
||||
index = layer.msg('正在启动PHP,请稍后...', {icon: 16, time: 0});
|
||||
layer.confirm('确定要启动PHP吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php82-stop').click(function () {
|
||||
layer.confirm('停止PHP将导致使用PHP的网站无法访问,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php82-restart').click(function () {
|
||||
layer.confirm('重启PHP将导致使用PHP的网站短时间无法访问,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PHP重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#php82-reload').click(function () {
|
||||
index = layer.msg('正在重载PHP,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PHP重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php82-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: php82_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PHP配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php82-clean-error-log').click(function () {
|
||||
index = layer.msg('正在清空错误日志,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/clearErrorLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.msg('PHP日志已清空!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#php82-clean-slow-log').click(function () {
|
||||
index = layer.msg('正在清空慢日志,请稍后...', {icon: 16, time: 0});
|
||||
admin.req({
|
||||
url: "/api/plugins/php82/clearSlowLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.msg('PHP慢日志已清空!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,92 +0,0 @@
|
||||
<!--
|
||||
Name: phpMyAdmin 管理器
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
<title>phpMyAdmin</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">phpMyAdmin 信息</div>
|
||||
<div class="layui-card-body">
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">访问地址:<span
|
||||
id="phpmyadmin-info">获取中...</span></blockquote>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>基本设置</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form" lay-filter="phpmyadmin_setting">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">访问端口</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="phpmyadmin_port" value="获取中ing..." class="layui-input"
|
||||
disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">查看 / 修改 phpMyAdmin 访问端口</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="phpmyadmin_setting_submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['index', 'code', 'table', 'form'], function () {
|
||||
let $ = layui.$
|
||||
, form = layui.form
|
||||
, admin = layui.admin;
|
||||
|
||||
// 获取phpmyadmin信息
|
||||
admin.req({
|
||||
url: "/api/plugins/phpmyadmin/info"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
layer.alert('phpMyAdmin 信息获取失败,可能已损坏!', {
|
||||
icon: 2
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// 获取当前域名
|
||||
let hostname = window.location.hostname;
|
||||
// 拼接phpmyadmin访问地址
|
||||
let phpmyadmin_url = 'http://' + hostname + ':' + result.data.port + '/' + result.data.phpmyadmin;
|
||||
$('#phpmyadmin-info').html('<a href="' + phpmyadmin_url + '" target="_blank">' + phpmyadmin_url + '</a>');
|
||||
$('input[name=phpmyadmin_port]').val(result.data.port);
|
||||
$('input').attr('disabled', false);
|
||||
form.render();
|
||||
}
|
||||
});
|
||||
|
||||
// 监听phpmyadmin设置提交
|
||||
form.on('submit(phpmyadmin_setting_submit)', function (data) {
|
||||
data.field.port = data.field.phpmyadmin_port;
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/phpmyadmin/port"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.alert('phpMyAdmin设置失败,可能已损坏!', {
|
||||
icon: 2
|
||||
});
|
||||
return false;
|
||||
}
|
||||
layer.msg('设置成功', {
|
||||
icon: 1
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,524 +0,0 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<title>PostgreSQL</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">PostgreSQL管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">基本信息</li>
|
||||
<li>管理</li>
|
||||
<li>主配置</li>
|
||||
<li>用户配置</li>
|
||||
<li>负载状态</li>
|
||||
<li>日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>运行状态</legend>
|
||||
</fieldset>
|
||||
<blockquote id="postgresql-status" class="layui-elem-quote layui-quote-nm">
|
||||
当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="postgresql-start" class="layui-btn">启动</button>
|
||||
<button id="postgresql-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="postgresql-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="postgresql-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">面板仅集成了部分常用功能,如需更多功能,请使用
|
||||
pgAdmin 客户端。
|
||||
</blockquote>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>数据库列表</legend>
|
||||
</fieldset>
|
||||
<table class="layui-hide" id="postgresql-database-list"
|
||||
lay-filter="postgresql-database-list"></table>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>用户列表</legend>
|
||||
</fieldset>
|
||||
<table class="layui-hide" id="postgresql-user-list"
|
||||
lay-filter="postgresql-user-list"></table>
|
||||
<!-- 数据库顶部工具栏 -->
|
||||
<script type="text/html" id="postgresql-database-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_database">新建数据库
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 用户顶部工具栏 -->
|
||||
<script type="text/html" id="postgresql-user-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_user">新建用户</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 数据库右侧管理 -->
|
||||
<script type="text/html" id="postgresql-database-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="backup">备份</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<!-- 用户右侧管理 -->
|
||||
<script type="text/html" id="postgresql-user-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs"
|
||||
lay-event="change_password">改密</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是PostgreSQL主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="postgresql-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="postgresql-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是PostgreSQL用户配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="postgresql-user-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="postgresql-user-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="postgresql-load-status"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<pre id="postgresql-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let postgresql_config_editor;
|
||||
let postgresql_user_config_editor;
|
||||
layui.use(['index', 'admin', 'element', 'form', 'view', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, code = layui.code
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view;
|
||||
|
||||
form.render();
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#postgresql-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#postgresql-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据库列表
|
||||
table.render({
|
||||
elem: '#postgresql-database-list'
|
||||
, url: '/api/plugins/postgresql15/database'
|
||||
, toolbar: '#postgresql-database-list-bar'
|
||||
, title: '数据库列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '库名', fixed: 'left', unresize: true, sort: true}
|
||||
, {field: 'owner', title: '所有者', unresize: true, sort: true}
|
||||
, {field: 'encoding', title: '编码', unresize: true, sort: true}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#postgresql-database-list-control', width: 150}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '暂无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(postgresql-database-list)', function (obj) {
|
||||
if (obj.event === 'add_database') {
|
||||
admin.popup({
|
||||
title: '新建数据库'
|
||||
, area: ['600px', '300px']
|
||||
, id: 'LAY-popup-postgresql-database-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/postgresql15/add_database', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-postgresql-database-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(postgresql-database-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('高风险操作,确定要删除数据库 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除数据库 <b style="color: red;">' + data.name + '</b> ...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/deleteDatabase"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
database: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('数据库' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'backup') {
|
||||
// 打开备份页面
|
||||
admin.popup({
|
||||
title: '备份管理 - ' + data.name
|
||||
, area: ['70%', '80%']
|
||||
, id: 'LAY-popup-postgresql-backup'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('plugins/postgresql15/backup', {
|
||||
data: data
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-postgresql-backup');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据库用户列表
|
||||
table.render({
|
||||
elem: '#postgresql-user-list'
|
||||
, url: '/api/plugins/postgresql15/user'
|
||||
, toolbar: '#postgresql-user-list-bar'
|
||||
, title: '用户列表'
|
||||
, cols: [[
|
||||
{field: 'user', title: '用户名', fixed: 'left', width: 300, sort: true}
|
||||
, {field: 'role', title: '权限'}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#postgresql-user-list-control', width: 150}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '暂无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(postgresql-user-list)', function (obj) {
|
||||
if (obj.event === 'add_user') {
|
||||
admin.popup({
|
||||
title: '新建用户'
|
||||
, area: ['600px', '300px']
|
||||
, id: 'LAY-popup-postgresql-user-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/postgresql15/add_user', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-postgresql-user-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(postgresql-user-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('高风险操作,确定要删除用户 <b style="color: red;">' + data.user + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除用户 <b style="color: red;">' + data.user + '</b> ...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/deleteUser"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('用户' + data.user + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'change_password') {
|
||||
// 弹出输入密码框
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '请输入新密码(建议8位以上大小写数字特殊符号混合)'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
layer.msg('正在修改密码 ...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
// 发送请求
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/changePassword"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
user: data.user,
|
||||
password: value
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('用户' + data.user + '密码修改成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/log"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#postgresql-log').text('PostgreSQL日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#postgresql-log'
|
||||
, title: 'error.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#postgresql-log').text(result.data);
|
||||
code({
|
||||
elem: '#postgresql-log'
|
||||
, title: 'postgresql.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#postgresql-config-editor').text(result.data);
|
||||
postgresql_config_editor = ace.edit("postgresql-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql用户配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/userConfig"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#postgresql-user-config-editor').text(result.data);
|
||||
postgresql_user_config_editor = ace.edit("postgresql-user-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql负载状态并渲染
|
||||
table.render({
|
||||
elem: '#postgresql-load-status'
|
||||
, url: '/api/plugins/postgresql15/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '80%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 事件监听
|
||||
$('#postgresql-start').click(function () {
|
||||
layer.confirm('确定要启动PostgreSQL吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在启动PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#postgresql-stop').click(function () {
|
||||
layer.confirm('停止PostgreSQL将导致使用PostgreSQL的网站无法访问,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#postgresql-restart').click(function () {
|
||||
layer.confirm('重启PostgreSQL将导致使用PostgreSQL的网站短时间无法访问,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#postgresql-reload').click(function () {
|
||||
index = layer.msg('正在重载PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#postgresql-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: postgresql_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PostgreSQL配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#postgresql-user-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/userConfig"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: postgresql_user_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PostgreSQL用户配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,77 +0,0 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器 - 添加数据库
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-postgresql-database-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数据库名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="database" lay-verify="required" placeholder="请输入数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" lay-verify="required" placeholder="请输入密码(8位以上大小写数字特殊符号混合)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-postgresql-database-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'table'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-postgresql-database-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/addDatabase"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
table.reload('postgresql-database-list');
|
||||
table.reload('postgresql-user-list');
|
||||
layer.alert('数据库添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,79 +0,0 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器 - 添加用户
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-postgresql-user-form">
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" lay-verify="required"
|
||||
placeholder="请输入密码(8位以上大小写数字特殊符号混合)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数据库</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="database" lay-verify="required" placeholder="输入授权给该用户的数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-postgresql-user-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'table'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-postgresql-user-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/addUser"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
table.reload('postgresql-database-list');
|
||||
table.reload('postgresql-user-list');
|
||||
layer.alert('用户添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,141 +0,0 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器 - 数据库备份
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs12 layui-col-sm12 layui-col-md12">
|
||||
<table class="layui-hide" id="postgresql-backup-list" lay-filter="postgresql-backup-list"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份顶部工具栏 -->
|
||||
<script type="text/html" id="postgresql-database-backup-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="backup_database">备份数据库</button>
|
||||
<button class="layui-btn layui-btn-sm" id="upload_postgresql_backup">上传备份</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份右侧管理 -->
|
||||
<script type="text/html" id="postgresql-database-backup-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'laydate', 'code'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, table = layui.table
|
||||
, upload = layui.upload;
|
||||
|
||||
// 渲染表格
|
||||
table.render({
|
||||
elem: '#postgresql-backup-list'
|
||||
, url: '/api/plugins/postgresql15/backup'
|
||||
, toolbar: '#postgresql-database-backup-bar'
|
||||
, title: '备份列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '备份名称', width: 500}
|
||||
, {field: 'size', title: '文件大小'}
|
||||
, {field: 'right', title: '操作', width: 150, toolbar: '#postgresql-database-backup-control'}
|
||||
]]
|
||||
, text: {
|
||||
none: '无备份数据'
|
||||
}
|
||||
, done: function (res, curr, count) {
|
||||
upload.render({
|
||||
elem: '#upload_postgresql_backup'
|
||||
, url: '/api/plugins/postgresql15/uploadBackup'
|
||||
, accept: 'file'
|
||||
, ext: 'sql|zip|rar|tar|gz|bz2'
|
||||
, before: function (obj) {
|
||||
index = layer.msg('正在上传备份文件,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
}
|
||||
, done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg('上传成功!', {icon: 1});
|
||||
table.reload('postgresql-backup-list');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(postgresql-backup-list)', function (obj) {
|
||||
if (obj.event === 'backup_database') {
|
||||
index = layer.msg('正在备份数据库,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: '/api/plugins/postgresql15/createBackup'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
database: params.data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.alert('备份失败!');
|
||||
return false;
|
||||
}
|
||||
table.reload('postgresql-backup-list');
|
||||
layer.msg('备份成功!', {icon: 1});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(postgresql-backup-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除数据库备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除数据库备份,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/deleteBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('数据库备份删除失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('数据库备份' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'restore') {
|
||||
layer.confirm('高风险操作,确定要恢复数据库备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在恢复数据库备份,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
data.database = params.data.name;
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/restoreBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('数据库备份恢复失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.alert('数据库备份' + data.name + '恢复成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,524 +0,0 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<title>PostgreSQL</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">PostgreSQL管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">基本信息</li>
|
||||
<li>管理</li>
|
||||
<li>主配置</li>
|
||||
<li>用户配置</li>
|
||||
<li>负载状态</li>
|
||||
<li>日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>运行状态</legend>
|
||||
</fieldset>
|
||||
<blockquote id="postgresql-status" class="layui-elem-quote layui-quote-nm">
|
||||
当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="postgresql-start" class="layui-btn">启动</button>
|
||||
<button id="postgresql-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="postgresql-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="postgresql-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">面板仅集成了部分常用功能,如需更多功能,请使用
|
||||
pgAdmin 客户端。
|
||||
</blockquote>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>数据库列表</legend>
|
||||
</fieldset>
|
||||
<table class="layui-hide" id="postgresql-database-list"
|
||||
lay-filter="postgresql-database-list"></table>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>用户列表</legend>
|
||||
</fieldset>
|
||||
<table class="layui-hide" id="postgresql-user-list"
|
||||
lay-filter="postgresql-user-list"></table>
|
||||
<!-- 数据库顶部工具栏 -->
|
||||
<script type="text/html" id="postgresql-database-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_database">新建数据库
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 用户顶部工具栏 -->
|
||||
<script type="text/html" id="postgresql-user-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_user">新建用户</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 数据库右侧管理 -->
|
||||
<script type="text/html" id="postgresql-database-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="backup">备份</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<!-- 用户右侧管理 -->
|
||||
<script type="text/html" id="postgresql-user-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs"
|
||||
lay-event="change_password">改密</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是PostgreSQL主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="postgresql-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="postgresql-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是PostgreSQL用户配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="postgresql-user-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="postgresql-user-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="postgresql-load-status"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<pre id="postgresql-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let postgresql_config_editor;
|
||||
let postgresql_user_config_editor;
|
||||
layui.use(['index', 'admin', 'element', 'form', 'view', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, code = layui.code
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view;
|
||||
|
||||
form.render();
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#postgresql-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#postgresql-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据库列表
|
||||
table.render({
|
||||
elem: '#postgresql-database-list'
|
||||
, url: '/api/plugins/postgresql16/database'
|
||||
, toolbar: '#postgresql-database-list-bar'
|
||||
, title: '数据库列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '库名', fixed: 'left', unresize: true, sort: true}
|
||||
, {field: 'owner', title: '所有者', unresize: true, sort: true}
|
||||
, {field: 'encoding', title: '编码', unresize: true, sort: true}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#postgresql-database-list-control', width: 150}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '暂无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(postgresql-database-list)', function (obj) {
|
||||
if (obj.event === 'add_database') {
|
||||
admin.popup({
|
||||
title: '新建数据库'
|
||||
, area: ['600px', '300px']
|
||||
, id: 'LAY-popup-postgresql-database-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/postgresql16/add_database', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-postgresql-database-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(postgresql-database-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('高风险操作,确定要删除数据库 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除数据库 <b style="color: red;">' + data.name + '</b> ...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/deleteDatabase"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
database: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('数据库' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'backup') {
|
||||
// 打开备份页面
|
||||
admin.popup({
|
||||
title: '备份管理 - ' + data.name
|
||||
, area: ['70%', '80%']
|
||||
, id: 'LAY-popup-postgresql-backup'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('plugins/postgresql16/backup', {
|
||||
data: data
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-postgresql-backup');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据库用户列表
|
||||
table.render({
|
||||
elem: '#postgresql-user-list'
|
||||
, url: '/api/plugins/postgresql16/user'
|
||||
, toolbar: '#postgresql-user-list-bar'
|
||||
, title: '用户列表'
|
||||
, cols: [[
|
||||
{field: 'user', title: '用户名', fixed: 'left', width: 300, sort: true}
|
||||
, {field: 'role', title: '权限'}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#postgresql-user-list-control', width: 150}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '暂无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(postgresql-user-list)', function (obj) {
|
||||
if (obj.event === 'add_user') {
|
||||
admin.popup({
|
||||
title: '新建用户'
|
||||
, area: ['600px', '300px']
|
||||
, id: 'LAY-popup-postgresql-user-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/postgresql16/add_user', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-postgresql-user-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(postgresql-user-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('高风险操作,确定要删除用户 <b style="color: red;">' + data.user + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除用户 <b style="color: red;">' + data.user + '</b> ...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/deleteUser"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('用户' + data.user + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'change_password') {
|
||||
// 弹出输入密码框
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '请输入新密码(建议8位以上大小写数字特殊符号混合)'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
layer.msg('正在修改密码 ...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
// 发送请求
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/changePassword"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
user: data.user,
|
||||
password: value
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('用户' + data.user + '密码修改成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/log"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#postgresql-log').text('PostgreSQL日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#postgresql-log'
|
||||
, title: 'error.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#postgresql-log').text(result.data);
|
||||
code({
|
||||
elem: '#postgresql-log'
|
||||
, title: 'postgresql.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#postgresql-config-editor').text(result.data);
|
||||
postgresql_config_editor = ace.edit("postgresql-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql用户配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/userConfig"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#postgresql-user-config-editor').text(result.data);
|
||||
postgresql_user_config_editor = ace.edit("postgresql-user-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql负载状态并渲染
|
||||
table.render({
|
||||
elem: '#postgresql-load-status'
|
||||
, url: '/api/plugins/postgresql16/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '80%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 事件监听
|
||||
$('#postgresql-start').click(function () {
|
||||
layer.confirm('确定要启动PostgreSQL吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在启动PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#postgresql-stop').click(function () {
|
||||
layer.confirm('停止PostgreSQL将导致使用PostgreSQL的网站无法访问,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#postgresql-restart').click(function () {
|
||||
layer.confirm('重启PostgreSQL将导致使用PostgreSQL的网站短时间无法访问,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#postgresql-reload').click(function () {
|
||||
index = layer.msg('正在重载PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#postgresql-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: postgresql_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PostgreSQL配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#postgresql-user-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/userConfig"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: postgresql_user_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PostgreSQL用户配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,77 +0,0 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器 - 添加数据库
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-postgresql-database-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数据库名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="database" lay-verify="required" placeholder="请输入数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" lay-verify="required" placeholder="请输入密码(8位以上大小写数字特殊符号混合)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-postgresql-database-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'table'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-postgresql-database-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/addDatabase"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
table.reload('postgresql-database-list');
|
||||
table.reload('postgresql-user-list');
|
||||
layer.alert('数据库添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,79 +0,0 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器 - 添加用户
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-postgresql-user-form">
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" lay-verify="required"
|
||||
placeholder="请输入密码(8位以上大小写数字特殊符号混合)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数据库</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="database" lay-verify="required" placeholder="输入授权给该用户的数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-postgresql-user-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'table'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-postgresql-user-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/addUser"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
table.reload('postgresql-database-list');
|
||||
table.reload('postgresql-user-list');
|
||||
layer.alert('用户添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,141 +0,0 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器 - 数据库备份
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs12 layui-col-sm12 layui-col-md12">
|
||||
<table class="layui-hide" id="postgresql-backup-list" lay-filter="postgresql-backup-list"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份顶部工具栏 -->
|
||||
<script type="text/html" id="postgresql-database-backup-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="backup_database">备份数据库</button>
|
||||
<button class="layui-btn layui-btn-sm" id="upload_postgresql_backup">上传备份</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份右侧管理 -->
|
||||
<script type="text/html" id="postgresql-database-backup-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'laydate', 'code'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, table = layui.table
|
||||
, upload = layui.upload;
|
||||
|
||||
// 渲染表格
|
||||
table.render({
|
||||
elem: '#postgresql-backup-list'
|
||||
, url: '/api/plugins/postgresql16/backup'
|
||||
, toolbar: '#postgresql-database-backup-bar'
|
||||
, title: '备份列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '备份名称', width: 500}
|
||||
, {field: 'size', title: '文件大小'}
|
||||
, {field: 'right', title: '操作', width: 150, toolbar: '#postgresql-database-backup-control'}
|
||||
]]
|
||||
, text: {
|
||||
none: '无备份数据'
|
||||
}
|
||||
, done: function (res, curr, count) {
|
||||
upload.render({
|
||||
elem: '#upload_postgresql_backup'
|
||||
, url: '/api/plugins/postgresql16/uploadBackup'
|
||||
, accept: 'file'
|
||||
, ext: 'sql|zip|rar|tar|gz|bz2'
|
||||
, before: function (obj) {
|
||||
index = layer.msg('正在上传备份文件,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
}
|
||||
, done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg('上传成功!', {icon: 1});
|
||||
table.reload('postgresql-backup-list');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(postgresql-backup-list)', function (obj) {
|
||||
if (obj.event === 'backup_database') {
|
||||
index = layer.msg('正在备份数据库,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: '/api/plugins/postgresql16/createBackup'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
database: params.data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.alert('备份失败!');
|
||||
return false;
|
||||
}
|
||||
table.reload('postgresql-backup-list');
|
||||
layer.msg('备份成功!', {icon: 1});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(postgresql-backup-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除数据库备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除数据库备份,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/deleteBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('数据库备份删除失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('数据库备份' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'restore') {
|
||||
layer.confirm('高风险操作,确定要恢复数据库备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在恢复数据库备份,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
data.database = params.data.name;
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql16/restoreBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('数据库备份恢复失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.alert('数据库备份' + data.name + '恢复成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,305 +0,0 @@
|
||||
<!--
|
||||
Name: Pure-Ftpd管理器
|
||||
Author: 耗子
|
||||
Date: 2023-08-03
|
||||
-->
|
||||
<title>Pure-Ftpd</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">Pure-Ftpd 运行状态</div>
|
||||
<div class="layui-card-body">
|
||||
<blockquote id="pureftpd-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="pureftpd-start" class="layui-btn">启动</button>
|
||||
<button id="pureftpd-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="pureftpd-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="pureftpd-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>基本设置</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form" lay-filter="pureftpd_setting">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">端口</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="pureftpd_port" value="获取中ing..." class="layui-input"
|
||||
disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">设置Pure-Ftpd的访问端口</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit lay-filter="pureftpd_setting_submit">
|
||||
确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">Pure-Ftpd 用户列表</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="pureftpd-user-list" lay-filter="pureftpd-user-list"></table>
|
||||
<!-- 顶部工具栏 -->
|
||||
<script type="text/html" id="pureftpd-user-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_user">新建用户</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 右侧管理 -->
|
||||
<script type="text/html" id="pureftpd-user-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="change_password">改密</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['index', 'form', 'table', 'view'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view;
|
||||
|
||||
// 获取运行状态并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/pureftpd/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#pureftpd-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#pureftpd-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 获取端口并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/pureftpd/port"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('input[name=pureftpd_port]').val(result.data);
|
||||
$('input').attr('disabled', false);
|
||||
form.render();
|
||||
}
|
||||
});
|
||||
|
||||
// 监听提交
|
||||
form.on('submit(pureftpd_setting_submit)', function (data) {
|
||||
data.field.port = $('input[name=pureftpd_port]').val();
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/pureftpd/port"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.msg('设置成功', {icon: 1});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 获取用户列表
|
||||
table.render({
|
||||
elem: '#pureftpd-user-list'
|
||||
, url: '/api/plugins/pureftpd/list'
|
||||
, toolbar: '#pureftpd-user-list-bar'
|
||||
, title: 'Pure-Ftpd 用户列表'
|
||||
, cols: [[
|
||||
{field: 'username', title: '用户名', fixed: 'left', unresize: true, sort: true}
|
||||
, {field: 'path', title: '目录', unresize: true, sort: true}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#pureftpd-user-list-control', width: 150}
|
||||
]]
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
, page: true
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(pureftpd-user-list)', function (obj) {
|
||||
if (obj.event === 'add_user') {
|
||||
admin.popup({
|
||||
title: '新建Pure-Ftpd用户'
|
||||
, area: ['600px', '400px']
|
||||
, id: 'LAY-popup-pureftpd-user-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/pureftpd/add_user', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-pureftpd-user-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(pureftpd-user-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除用户 <b style="color: red;">' + data.username + '</b> 吗?', function (index) {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/pureftpd/delete"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('Pure-Ftpd用户删除失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert(data.username + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'change_password') {
|
||||
// 弹出输入密码框
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '请输入新密码(6位以上)'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
// 发送请求
|
||||
admin.req({
|
||||
url: "/api/plugins/pureftpd/changePassword"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
username: data.username,
|
||||
password: value
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('密码修改失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.alert('用户' + data.username + '密码修改成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 事件监听
|
||||
$('#pureftpd-start').click(function () {
|
||||
layer.confirm('确定要启动Pure-Ftpd吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/pureftpd/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Pure-Ftpd启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#pureftpd-stop').click(function () {
|
||||
layer.confirm('停止Pure-Ftpd将导致FTP无法连接,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/pureftpd/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Pure-Ftpd停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#pureftpd-restart').click(function () {
|
||||
layer.confirm('确定要重启Pure-Ftpd吗?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/pureftpd/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Pure-Ftpd重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#pureftpd-reload').click(function () {
|
||||
index = layer.msg('请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/pureftpd/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('Pure-Ftpd重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,80 +0,0 @@
|
||||
<!--
|
||||
Name: Pure-Ftpd管理器 - 新建用户
|
||||
Author: 耗子
|
||||
Date: 2023-08-03
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-pureftpd-user-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="username" id="add-pureftpd-user-username"
|
||||
lay-verify="required" placeholder="请输入用户名" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="password" id="add-pureftpd-user-password"
|
||||
lay-verify="required" placeholder="请输入密码" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">目录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="path" id="add-pureftpd-user-path"
|
||||
lay-verify="required" placeholder="请输入目录" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-pureftpd-user-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'form', 'table'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table;
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-pureftpd-user-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/pureftpd/add"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('Pure-Ftpd用户添加失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
table.reload('pureftpd-user-list');
|
||||
layer.alert('Pure-Ftpd用户添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,190 +0,0 @@
|
||||
<!--
|
||||
Name: Redis管理器
|
||||
Author: 耗子
|
||||
Date: 2023-08-09
|
||||
-->
|
||||
<title>Redis</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">Redis 管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">运行状态</li>
|
||||
<li>配置修改</li>
|
||||
<li>负载状态</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<blockquote id="redis-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="redis-start" class="layui-btn">启动</button>
|
||||
<button id="redis-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="redis-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="redis-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是Redis主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="redis-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="redis-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="redis-load-status"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let redis_config_editor;
|
||||
layui.use(['admin', 'jquery', 'element', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, table = layui.table;
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#redis-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#redis-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#redis-config-editor').text(result.data);
|
||||
redis_config_editor = ace.edit("redis-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: '#redis-load-status'
|
||||
, url: '/api/plugins/redis/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '80%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 事件监听
|
||||
$('#redis-start').click(function () {
|
||||
layer.confirm('确定要启动Redis吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在启动Redis,请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Redis启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#redis-stop').click(function () {
|
||||
layer.confirm('停止Redis可能导致使用Redis的网站出现异常,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止Redis,请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Redis停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#redis-restart').click(function () {
|
||||
layer.confirm('重启Redis将导致使用Redis的网站短时间出现异常,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启Redis,请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Redis重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#redis-reload').click(function () {
|
||||
index = layer.msg('正在重载Redis,请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('Redis重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#redis-config-save').click(function () {
|
||||
index = layer.msg('正在保存Redis配置,请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: redis_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('Redis配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,102 +0,0 @@
|
||||
<!--
|
||||
Name: S3fs
|
||||
Author: 耗子
|
||||
Date: 2023-07-25
|
||||
-->
|
||||
<title>S3fs</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">S3fs 挂载列表</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="s3fs-list" lay-filter="s3fs-list"></table>
|
||||
<!-- 顶部工具栏 -->
|
||||
<script type="text/html" id="s3fs-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_mount">新建挂载</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 右侧管理 -->
|
||||
<script type="text/html" id="s3fs-list-control">
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="umount">卸载</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['index', 'code', 'table'], function () {
|
||||
let admin = layui.admin
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view;
|
||||
|
||||
// 获取备份任务列表
|
||||
table.render({
|
||||
elem: '#s3fs-list'
|
||||
, url: '/api/plugins/s3fs/list'
|
||||
, toolbar: '#s3fs-list-bar'
|
||||
, title: 'S3fs挂载列表'
|
||||
, cols: [[
|
||||
{field: 'id', hide: true, title: 'ID', sort: true}
|
||||
, {field: 'bucket', title: 'Bucket', fixed: 'left', unresize: true, sort: true}
|
||||
, {field: 'url', title: 'URL', sort: true}
|
||||
, {field: 'path', title: '挂载目录', sort: true}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#s3fs-list-control', width: 150}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '无挂载'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(s3fs-list)', function (obj) {
|
||||
if (obj.event === 'add_mount') {
|
||||
admin.popup({
|
||||
title: '新建挂载'
|
||||
, area: ['600px', '600px']
|
||||
, id: 'LAY-popup-s3fs-mount-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/s3fs/add_mount', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-s3fs-mount-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(s3fs-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'umount') {
|
||||
layer.confirm('确定要卸载 <b style="color: red;">' + data.path + '</b> 吗?', function (index) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/s3fs/delete"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert(data.path + ' 卸载成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,104 +0,0 @@
|
||||
<!--
|
||||
Name: S3fs - 新增挂载
|
||||
Author: 耗子
|
||||
Date: 2023-07-25
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-mount-s3fs-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Bucket</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="bucket" id="add-mount-s3fs-bucket"
|
||||
lay-verify="required" placeholder="请输入Bucket名" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">输入Bucket名字,腾讯云COS为(xxxx-用户ID)</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">AK</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="ak" id="add-mount-s3fs-ak"
|
||||
lay-verify="required" placeholder="请输入AK密钥" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">访问密钥中的Access Key,需具备Bucket操作权限,腾讯云为SecretId
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">SK</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sk" id="add-mount-s3fs-sk"
|
||||
lay-verify="required" placeholder="请输入SK密钥" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">访问密钥中的Access Key
|
||||
Secret,需具备Bucket操作权限,腾讯云为SecretKey
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">地域节点</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="url" id="add-mount-s3fs-url"
|
||||
lay-verify="required" placeholder="请输入Bucket地域节点" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
地域节点可在<a target="_blank" href="https://github.com/s3fs-fuse/s3fs-fuse/wiki/Non-Amazon-S3">https://github.com/s3fs-fuse/s3fs-fuse/wiki/Non-Amazon-S3</a>查找
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">挂载目录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="path" id="add-mount-s3fs-path"
|
||||
lay-verify="required" placeholder="请输入挂载目录" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">挂载目录,如/data,不存在将会自动创建</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-mount-s3fs-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'jquery', 'cron'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table;
|
||||
|
||||
form.render();
|
||||
|
||||
form.on('submit(add-mount-s3fs-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/s3fs/add"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
table.reload('s3fs-list');
|
||||
layer.alert('S3fs挂载已提交,请自行检查是否挂载成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,451 +0,0 @@
|
||||
<!--
|
||||
Name: Supervisor
|
||||
Author: 耗子
|
||||
Date: 2023-07-26
|
||||
-->
|
||||
<title>Supervisor</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">Supervisor 管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">运行状态</li>
|
||||
<li>进程列表</li>
|
||||
<li>配置修改</li>
|
||||
<li>运行日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<blockquote id="supervisor-status" class="layui-elem-quote layui-quote-nm">
|
||||
当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="supervisor-start" class="layui-btn">启动</button>
|
||||
<button id="supervisor-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="supervisor-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="supervisor-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="supervisor-list" lay-filter="supervisor-list"></table>
|
||||
<!-- 顶部工具栏 -->
|
||||
<script type="text/html" id="supervisor-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_process">添加进程</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 右侧管理 -->
|
||||
<script type="text/html" id="supervisor-list-control">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="log">日志</a>
|
||||
<a class="layui-btn layui-bg-blue layui-btn-xs" lay-event="config">配置</a>
|
||||
<a class="layui-btn layui-border layui-btn-xs" lay-event="start">启动</a>
|
||||
<a class="layui-btn layui-bg-purple layui-btn-xs" lay-event="restart">重启</a>
|
||||
<a class="layui-btn layui-bg-orange layui-btn-xs" lay-event="stop">停止</a>
|
||||
<a class="layui-btn layui-bg-red layui-btn-xs" lay-event="delete">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是Supervisor主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="supervisor-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="supervisor-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="supervisor-clear-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="supervisor-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let supervisor_config_editor;
|
||||
let supervisor_process_config_editor;
|
||||
layui.use(['jquery', 'admin', 'view', 'form', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view
|
||||
, code = layui.code;
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#supervisor-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#supervisor-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: '#supervisor-list'
|
||||
, url: '/api/plugins/supervisor/processes'
|
||||
, toolbar: '#supervisor-list-bar'
|
||||
, title: 'Supervisor进程列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '名称', fixed: 'left', unresize: true, sort: true}
|
||||
, {field: 'status', title: '状态', sort: true}
|
||||
, {field: 'pid', title: 'PID', sort: true}
|
||||
, {field: 'uptime', title: '运行时间(天)', sort: true}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#supervisor-list-control', width: 350}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '无进程'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(supervisor-list)', function (obj) {
|
||||
if (obj.event === 'add_process') {
|
||||
admin.popup({
|
||||
title: '添加进程'
|
||||
, area: ['600px', '600px']
|
||||
, id: 'LAY-popup-supervisor-process-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/supervisor/add_process', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-supervisor-process-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(supervisor-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'log') {
|
||||
admin.popup({
|
||||
title: '日志 - ' + data.name
|
||||
,
|
||||
area: ['80%', '80%']
|
||||
,
|
||||
id: 'process-log'
|
||||
,
|
||||
content: '<pre id="process-log-view" style="overflow: auto; height: 95%;border: 0 none; line-height:23px; padding: 15px; margin: 0; white-space: pre-wrap; background-color: rgb(51,51,51); color:#f1f1f1; border-radius:0;"></pre>'
|
||||
,
|
||||
success: function (layero, index) {
|
||||
index2 = layer.msg('正在获取日志...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: '/api/plugins/supervisor/processLog?process=' + data.name
|
||||
, type: 'GET'
|
||||
, success: function (res) {
|
||||
layer.close(index2);
|
||||
if (res.code === 0) {
|
||||
$('#process-log-view').html(res.data);
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (obj.event === 'config') {
|
||||
admin.req({
|
||||
url: '/api/plugins/supervisor/processConfig?process=' + data.name
|
||||
, type: 'GET'
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
admin.popup({
|
||||
title: '编辑 - ' + data.name
|
||||
,
|
||||
area: ['80%', '80%']
|
||||
,
|
||||
id: 'process-config'
|
||||
,
|
||||
content: '<div id="process-config-editor" style="height: 80%;">' + res.data + '</div><br><button id="process-config-' + data.name + '" class="layui-btn">保存</button>'
|
||||
,
|
||||
success: function (layero, index) {
|
||||
supervisor_process_config_editor = ace.edit("process-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
$('#process-config-' + data.name).click(function () {
|
||||
index2 = layer.msg('正在保存配置...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: '/api/plugins/supervisor/processConfig'
|
||||
, type: 'POST'
|
||||
, data: {
|
||||
process: data.name,
|
||||
config: supervisor_process_config_editor.getValue()
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('保存成功', {icon: 1, time: 1000});
|
||||
table.reload('supervisor-list');
|
||||
layer.close(index2);
|
||||
layer.close(index);
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (obj.event === 'start') {
|
||||
index = layer.msg('正在启动进程...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/startProcess"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
process: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('进程启动成功!');
|
||||
}
|
||||
});
|
||||
}
|
||||
if (obj.event === 'restart') {
|
||||
layer.confirm('确定要重启进程吗?', function (index) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/restartProcess"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
process: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('进程重启成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
if (obj.event === 'stop') {
|
||||
layer.confirm('确定要停止进程吗?', function (index) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/stopProcess"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
process: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('进程停止成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除进程吗?', function (index) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/deleteProcess"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
process: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('进程删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/log"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#supervisor-log').text('Supervisor日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#supervisor-log'
|
||||
, title: 'supervisor.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#supervisor-log').text(result.data);
|
||||
code({
|
||||
elem: '#supervisor-log'
|
||||
, title: 'supervisor.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#supervisor-config-editor').text(result.data);
|
||||
supervisor_config_editor = ace.edit("supervisor-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#supervisor-start').click(function () {
|
||||
layer.confirm('确定要启动Supervisor吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在启动Supervisor...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Supervisor启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#supervisor-stop').click(function () {
|
||||
layer.confirm('确定要停止Supervisor吗?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止Supervisor...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Supervisor停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#supervisor-restart').click(function () {
|
||||
layer.confirm('确定要重启Supervisor吗?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启Supervisor...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Supervisor重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#supervisor-reload').click(function () {
|
||||
index = layer.msg('正在重载Supervisor...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Supervisor重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#supervisor-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: supervisor_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('Supervisor配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#supervisor-clear-log').click(function () {
|
||||
index = layer.msg('正在清空Supervisor日志...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/clearLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.msg('Supervisor日志已清空!');
|
||||
setTimeout(function () {
|
||||
admin.events.refresh();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,94 +0,0 @@
|
||||
<!--
|
||||
Name: Supervisor - 添加进程
|
||||
Author: 耗子
|
||||
Date: 2023-07-26
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-mount-s3fs-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" lay-verify="required" placeholder="请输入名称" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">名称禁止使用中文</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">启动命令</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="command" lay-verify="required" placeholder="请输入启动命令" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">启动命令中的文件请填写绝对路径</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">运行目录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="path" lay-verify="required" placeholder="请输入运行目录" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">运行目录请填写绝对路径</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">启动用户</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入启动用户" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">一般情况下填写www即可</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">进程数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="num" lay-verify="required" placeholder="请输入进程数量" class="layui-input"
|
||||
value="1" min="1" step="1" lay-affix="number">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">一般情况下填写1即可</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="supervisor-add-process-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'jquery', 'table'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table;
|
||||
|
||||
form.render();
|
||||
|
||||
form.on('submit(supervisor-add-process-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/addProcess"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
table.reload('supervisor-list');
|
||||
layer.alert('Supervisor进程添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,302 +0,0 @@
|
||||
<!--
|
||||
Name: 系统工具箱
|
||||
-->
|
||||
<title>系统工具箱</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">系统工具箱</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">DNS</li>
|
||||
<li>SWAP</li>
|
||||
<li>Hosts</li>
|
||||
<li>时区</li>
|
||||
<li>Root密码</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<div class="layui-form" lay-filter="toolbox-dns">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">DNS 1</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="dns1" value="获取中ing..."
|
||||
class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改 DNS 1</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">DNS 2</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="dns2" value="获取中ing..."
|
||||
class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改 DNS 2</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="toolbox-dns-submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
总共:
|
||||
<span class="layui-badge layui-bg-blue"
|
||||
id="toolbox-swap-total">获取中...</span>
|
||||
</blockquote>
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
已用:
|
||||
<span class="layui-badge" id="toolbox-swap-used">获取中...</span>
|
||||
</blockquote>
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
可用:
|
||||
<span class="layui-badge layui-bg-green"
|
||||
id="toolbox-swap-free">获取中...</span>
|
||||
</blockquote>
|
||||
<div class="layui-form" lay-filter="toolbox-swap">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">SWAP 大小</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="swap" value="获取中ing..."
|
||||
class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">MB</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="toolbox-swap-submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是 /etc/hosts 文件。<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="toolbox-hosts-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="toolbox-hosts-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-form" lay-filter="toolbox-timezone">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">时区</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template lay-url="/api/plugins/toolbox/timezone"
|
||||
lay-done="layui.data.done(d);">
|
||||
<select name="timezone">
|
||||
{{# layui.each(d.data.zones, function(index, item){ }}
|
||||
{{# if(item == d.data.zone){ }}
|
||||
<option value="{{ item }}" selected="">{{ item }}</option>
|
||||
{{# }else{ }}
|
||||
<option value="{{ item }}">{{ item }}</option>
|
||||
{{# } }}
|
||||
{{# }); }}
|
||||
</select>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">选择一个时区</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="toolbox-timezone-submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-form" lay-filter="toolbox-root-password">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">root 密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="password" value=""
|
||||
class="layui-input" lay-verify="required">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改 root 密码</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="toolbox-root-password-submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let toolbox_hosts_editor;
|
||||
layui.use(['jquery', 'admin', 'view', 'form'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, form = layui.form;
|
||||
|
||||
form.render();
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/dns"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
form.val('toolbox-dns', {
|
||||
"dns1": result.data[0]
|
||||
, "dns2": result.data[1]
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
form.on('submit(toolbox-dns-submit)', function (data) {
|
||||
index = layer.msg('正在修改DNS...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/dns"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('DNS修改成功!');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/swap"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#toolbox-swap-total').html(result.data.total);
|
||||
$('#toolbox-swap-used').html(result.data.used);
|
||||
$('#toolbox-swap-free').html(result.data.free);
|
||||
form.val('toolbox-swap', {
|
||||
"swap": result.data.size
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
form.on('submit(toolbox-swap-submit)', function (data) {
|
||||
index = layer.msg('正在修改SWAP...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/swap"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
size: data.field.swap
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('SWAP修改成功!');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/hosts"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#toolbox-hosts-editor').text(result.data);
|
||||
toolbox_hosts_editor = ace.edit("toolbox-hosts-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
$('#toolbox-hosts-save').click(function () {
|
||||
index = layer.msg('正在保存Hosts...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/hosts"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
hosts: toolbox_hosts_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('Hosts保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
form.on('submit(toolbox-root-password-submit)', function (data) {
|
||||
index = layer.msg('正在修改root密码...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/rootPassword"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('root密码修改成功!');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
layui.data.done = function (d) {
|
||||
layui.use(['form', 'admin'], function () {
|
||||
let form = layui.form,
|
||||
admin = layui.admin;
|
||||
form.render(null, 'toolbox-timezone');
|
||||
form.on('submit(toolbox-timezone-submit)', function (data) {
|
||||
index = layer.msg('正在修改时区...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/timezone"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('时区修改成功!');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,309 +0,0 @@
|
||||
<!--
|
||||
Name: 系统安全
|
||||
Author: 耗子
|
||||
Date: 2023-08-03
|
||||
-->
|
||||
<title>系统安全</title>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto">
|
||||
<div class="layui-inline">
|
||||
<span style="margin-right: 10px;">防火墙</span>
|
||||
<input type="checkbox" id="safe_firewall" lay-filter="safe_firewall" lay-skin="switch"
|
||||
lay-text="ON|OFF">
|
||||
<span style="margin: 0px 10px;">启用SSH</span>
|
||||
<input type="checkbox" id="safe_ssh" lay-filter="safe_ssh" lay-skin="switch" lay-text="ON|OFF">
|
||||
<span style="margin: 0px 10px 0px 20px;">SSH端口</span>
|
||||
<div class="layui-input-inline" style="width: 80px;">
|
||||
<input type="number" id="safe_ssh_port" class="layui-input" style="height: 30px; margin-top: 5px;"
|
||||
min=1
|
||||
max=65535 disabled>
|
||||
</div>
|
||||
<div class="layui-input-inline">
|
||||
<button id="safe_ssh_port_save" class="layui-btn layui-btn-sm layui-btn-primary">确定
|
||||
</button>
|
||||
</div>
|
||||
<span style="margin: 0px 10px 0px 20px;">允许Ping</span>
|
||||
<input type="checkbox" id="switch_ping" lay-filter="safe_ping" lay-skin="switch" lay-text="ON|OFF">
|
||||
</div>
|
||||
<div class="layui-inline" style="float: right;">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger">清空 OpenResty 日志
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="vm_security">
|
||||
<div class="layui-card">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto">
|
||||
<div class="layui-inline">
|
||||
<span style="margin-right: 10px;">端口控制</span>
|
||||
<div class="layui-input-inline">
|
||||
<input id="safe_add_firewall_rule_port" type="text" name="safe_add_firewall_rule_port"
|
||||
class="layui-input"
|
||||
placeholder="例如:3306、1000-2000">
|
||||
</div>
|
||||
<div class="layui-input-inline">
|
||||
<select id="safe_add_firewall_rule_protocol" lay-filter="safe_add_firewall_rule_protocol"
|
||||
style="height: 30px; margin-top: 5px;">
|
||||
<option value="tcp">TCP</option>
|
||||
<option value="udp">UDP</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="layui-input-inline">
|
||||
<button id="safe_add_firewall_rule" class="layui-btn layui-btn-sm" style="margin-top: -4px;">放行
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="safe-port" lay-filter="safe-port"></table>
|
||||
<!-- 右侧删除端口 -->
|
||||
<script type="text/html" id="safe-port-setting">
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['layer', 'admin', 'form', 'laypage', 'table'], function () {
|
||||
var $ = layui.$;
|
||||
var admin = layui.admin;
|
||||
var table = layui.table;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
|
||||
// 获取防火墙状态
|
||||
admin.req({
|
||||
url: '/api/panel/safe/firewallStatus'
|
||||
, type: 'get'
|
||||
, dataType: 'json'
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// 防火墙
|
||||
if (res.data) {
|
||||
$('#safe_firewall').attr('checked', true);
|
||||
} else {
|
||||
$('#safe_firewall').attr('checked', false);
|
||||
}
|
||||
form.render();
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.1});
|
||||
}
|
||||
}
|
||||
});
|
||||
// 获取SSH状态
|
||||
admin.req({
|
||||
url: '/api/panel/safe/sshStatus'
|
||||
, type: 'get'
|
||||
, dataType: 'json'
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// SSH
|
||||
if (res.data) {
|
||||
$('#safe_ssh').attr('checked', true);
|
||||
} else {
|
||||
$('#safe_ssh').attr('checked', false);
|
||||
}
|
||||
form.render();
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.1});
|
||||
}
|
||||
}
|
||||
});
|
||||
// 获取SSH端口
|
||||
admin.req({
|
||||
url: '/api/panel/safe/sshPort'
|
||||
, type: 'get'
|
||||
, dataType: 'json'
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// SSH端口
|
||||
$('#safe_ssh_port').val(res.data);
|
||||
$('#safe_ssh_port').attr('disabled', false);
|
||||
form.render();
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.1});
|
||||
}
|
||||
}
|
||||
});
|
||||
// 获取ping状态
|
||||
admin.req({
|
||||
url: '/api/panel/safe/pingStatus'
|
||||
, type: 'get'
|
||||
, dataType: 'json'
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// ping
|
||||
if (res.data) {
|
||||
$('#switch_ping').attr('checked', true);
|
||||
} else {
|
||||
$('#switch_ping').attr('checked', false);
|
||||
}
|
||||
form.render();
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.1});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 设置防火墙开关
|
||||
form.on('switch(safe_firewall)', function (data) {
|
||||
admin.req({
|
||||
url: '/api/panel/safe/firewallStatus'
|
||||
, type: 'post'
|
||||
, dataType: 'json'
|
||||
, data: {
|
||||
status: data.elem.checked
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('设置成功', {icon: 1, shade: 0.1});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.1});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 设置SSH开关
|
||||
form.on('switch(safe_ssh)', function (data) {
|
||||
admin.req({
|
||||
url: '/api/panel/safe/sshStatus'
|
||||
, type: 'post'
|
||||
, dataType: 'json'
|
||||
, data: {
|
||||
status: data.elem.checked
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('设置成功', {icon: 1, shade: 0.1});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.1});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 设置ping开关
|
||||
form.on('switch(safe_ping)', function (data) {
|
||||
admin.req({
|
||||
url: '/api/panel/safe/pingStatus'
|
||||
, type: 'post'
|
||||
, dataType: 'json'
|
||||
, data: {
|
||||
status: data.elem.checked
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('设置成功', {icon: 1, shade: 0.1});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.1});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: '#safe-port'
|
||||
, url: '/api/panel/safe/firewallRules'
|
||||
, title: '防火墙'
|
||||
, cols: [[
|
||||
{field: 'port', title: '端口', width: 100, sort: true}
|
||||
, {field: 'protocol', title: '协议', sort: true}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#safe-port-setting', width: 150}
|
||||
]]
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
, page: true
|
||||
});
|
||||
table.on('tool(safe-port)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除 <b style="color: red;">' + data.protocol + '</b> 端口 <b style="color: red;">' + data.port + '</b> 吗?', function (index) {
|
||||
admin.req({
|
||||
url: "/api/panel/safe/deleteFirewallRule"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:端口删除失败,接口返回' + result);
|
||||
layer.msg('网站删除失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('<b style="color: red;">' + data.protocol + '</b> 端口 <b style="color: red;">' + data.port + '</b> 删除成功!');
|
||||
}
|
||||
, error: function (xhr, status, error) {
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error);
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 监听ssh端口保存
|
||||
$('#safe_ssh_port_save').click(function () {
|
||||
var port = Number($('#safe_ssh_port').val());
|
||||
// 判断端口是否合法
|
||||
if (isNaN(port) || port < 1 || port > 65535) {
|
||||
layer.msg('端口号不合法', {icon: 2, shade: 0.1});
|
||||
return false;
|
||||
}
|
||||
var index = layer.load();
|
||||
admin.req({
|
||||
url: '/api/panel/safe/sshPort'
|
||||
, type: 'post'
|
||||
, dataType: 'json'
|
||||
, data: {
|
||||
port: port
|
||||
}
|
||||
, success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
layer.msg('设置成功', {icon: 1, shade: 0.1});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.1});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 监听添加端口保存
|
||||
$('#safe_add_firewall_rule').click(function () {
|
||||
var port = $('#safe_add_firewall_rule_port').val();
|
||||
var protocol = $('#safe_add_firewall_rule_protocol').val();
|
||||
var index = layer.load();
|
||||
admin.req({
|
||||
url: '/api/panel/safe/addFirewallRule'
|
||||
, type: 'post'
|
||||
, dataType: 'json'
|
||||
, data: {
|
||||
port: port,
|
||||
protocol: protocol
|
||||
}
|
||||
, success: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
layer.msg('设置成功', {icon: 1, shade: 0.1});
|
||||
table.reload('safe-port');
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.1});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,175 +0,0 @@
|
||||
<!--
|
||||
Name: 面板设置
|
||||
Author: 耗子
|
||||
Date: 2023-07-21
|
||||
-->
|
||||
<title>面板设置</title>
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">设置</div>
|
||||
<div class="layui-card-body">
|
||||
|
||||
<div class="layui-form" lay-filter="panel_setting">
|
||||
<!--<div class="layui-form-item">
|
||||
<label class="layui-form-label">API 开关</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="api" lay-skin="switch" lay-text="ON|OFF">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">开启后将提供面板API接口的访问支持</div>
|
||||
</div>
|
||||
<div id="setting-api-token" class="layui-form-item">
|
||||
<label class="layui-form-label">API Token</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="api_token" value="获取中ing..." class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">API Token,用于携带访问面板接口</div>
|
||||
</div>-->
|
||||
<!--<div class="layui-form-item">
|
||||
<label class="layui-form-label">多设备登录</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="multi_login" lay-skin="switch" lay-text="ON|OFF">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
开启后将允许多设备同时登录面板,可能具有一定安全隐患
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">面板名称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="name" value="获取中ing..." class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改面板的显示名称</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">面板用户名</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="username" value="获取中ing..." class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改面板的登录用户名</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">面板密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="password" name="password" value="" class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改面板的登录密码(留空不修改)</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">面板邮箱</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="email" value="获取中ing..." class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改面板账号的邮箱,目前用于签发免费SSL证书</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">面板端口</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="port" value="" class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改面板的访问端口(<b style="color: red;">保存后需要重启面板并修改浏览器地址栏的端口为新端口以访问面板</b>)
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">面板入口</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="entrance" value="" class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改面板的访问入口(<b style="color: red;">保存后需要重启面板并修改浏览器地址栏的入口为新入口以访问面板</b>)
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">建站目录</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="website_path" value="获取中ing..." class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改面板的默认建站目录</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备份目录</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="backup_path" value="获取中ing..." class="layui-input" disabled>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改面板的默认备份目录</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="panel_setting_submit">确认修改</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.define(['form', 'upload'], function () {
|
||||
var $ = layui.$
|
||||
, layer = layui.layer
|
||||
, admin = layui.admin
|
||||
, form = layui.form;
|
||||
|
||||
// 渲染表单
|
||||
form.render();
|
||||
$('#setting-api-token').hide();
|
||||
|
||||
admin.req({
|
||||
url: "/api/panel/setting/list"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:系统信息获取失败,接口返回' + result);
|
||||
layer.msg('系统信息获取失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
form.val("panel_setting",
|
||||
result.data
|
||||
);
|
||||
$('input').attr('disabled', false);
|
||||
if (result.data.api === 1) {
|
||||
$('#setting-api-token').show();
|
||||
$('#setting-api-token input').attr('readonly', true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 面板设置
|
||||
form.on('submit(panel_setting_submit)', function (obj) {
|
||||
// 面板API
|
||||
if (obj.field.api === "on") {
|
||||
obj.field.api = 1;
|
||||
} else {
|
||||
obj.field.api = 0;
|
||||
}
|
||||
// 多设备登录
|
||||
if (obj.field.multi_login === "on") {
|
||||
obj.field.multi_login = 1;
|
||||
} else {
|
||||
obj.field.multi_login = 0;
|
||||
}
|
||||
// 提交修改
|
||||
admin.req({
|
||||
url: "/api/panel/setting/save"
|
||||
, type: 'post'
|
||||
, data: obj.field
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:设置保存失败,接口返回' + result);
|
||||
layer.msg('面板设置保存失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
admin.render();
|
||||
layer.msg('面板设置保存成功!');
|
||||
}
|
||||
, error: function (xhr, status, error) {
|
||||
console.log('耗子Linux面板:ajax请求出错,错误' + error);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,159 +0,0 @@
|
||||
<!--
|
||||
Name: SSH
|
||||
Author: 耗子
|
||||
Date: 2023-07-25
|
||||
-->
|
||||
<title>SSH</title>
|
||||
<link href="https://registry.npmmirror.com/xterm/5.2.1/files/css/xterm.css" rel="stylesheet">
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
SSH
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form" style="overflow: hidden;" lay-filter="ssh_setting">
|
||||
<div class="layui-inline">
|
||||
<span style="margin-right: 10px;">地址</span>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="host" class="layui-input"
|
||||
style="height: 30px; margin-top: 5px;">
|
||||
</div>
|
||||
<span style="margin-left: 40px; margin-right: 10px;">端口</span>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="port" class="layui-input"
|
||||
style="height: 30px; margin-top: 5px;">
|
||||
</div>
|
||||
<span style="margin-left: 40px; margin-right: 10px;">账号</span>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="user" class="layui-input"
|
||||
style="height: 30px; margin-top: 5px;">
|
||||
</div>
|
||||
<span style="margin-left: 40px; margin-right: 10px;">密码</span>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="password" class="layui-input"
|
||||
style="height: 30px; margin-top: 5px;">
|
||||
</div>
|
||||
<div class="layui-input-inline">
|
||||
<button lay-filter="save_ssh_setting" lay-submit class="layui-btn layui-btn-sm"
|
||||
style="margin-left: 10px;">
|
||||
保存
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="terminal" style="width: 100%; height: 70vh; background-color: #000000; margin-top: 20px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'jquery', 'form'], function () {
|
||||
var admin = layui.admin;
|
||||
var $ = layui.jquery;
|
||||
var form = layui.form;
|
||||
|
||||
form.render();
|
||||
|
||||
admin.req({
|
||||
url: "/api/panel/ssh/info"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
layer.msg('SSH信息获取失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
form.val("ssh_setting",
|
||||
result.data
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(save_ssh_setting)', function (data) {
|
||||
admin.req({
|
||||
url: "/api/panel/ssh/info"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
layer.alert('SSH信息保存失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.alert('SSH信息保存成功!')
|
||||
admin.events.refresh()
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<script>
|
||||
const msgData = '1'
|
||||
const msgResize = '2'
|
||||
|
||||
var terminal = new Terminal({
|
||||
rendererType: "canvas",
|
||||
fontSize: 15,
|
||||
screenKeys: true,
|
||||
useStyle: true,
|
||||
cursorBlink: true, // 光标闪烁
|
||||
theme: {
|
||||
foreground: "#ECECEC", // 字体
|
||||
background: "#000000", //背景色
|
||||
cursor: "help", // 设置光标
|
||||
lineHeight: 20
|
||||
}
|
||||
});
|
||||
let fitAddon = new FitAddon.FitAddon();
|
||||
terminal.loadAddon(fitAddon);
|
||||
fitAddon.fit()
|
||||
|
||||
let terminalContainer = document.getElementById("terminal")
|
||||
let token = layui.data('HaoZiPanel')['access_token']
|
||||
const webSocket = new WebSocket(`ws://${window.location.host}/api/panel/ssh/session`, [token]);
|
||||
webSocket.binaryType = 'arraybuffer';
|
||||
const enc = new TextDecoder("utf-8");
|
||||
webSocket.onmessage = (event) => {
|
||||
terminal.write(enc.decode(event.data));
|
||||
}
|
||||
|
||||
webSocket.onopen = () => {
|
||||
terminal.open(terminalContainer)
|
||||
fitAddon.fit()
|
||||
terminal.write("\r\nWelcome to HaoZiPanel SSH. Connection success.\r\n")
|
||||
terminal.focus()
|
||||
}
|
||||
|
||||
webSocket.onclose = () => {
|
||||
terminal.write("\r\nSSH connection closed. Please refresh the page.\r\n")
|
||||
}
|
||||
|
||||
webSocket.onerror = (event) => {
|
||||
console.error(event)
|
||||
webSocket.close()
|
||||
}
|
||||
|
||||
terminal.onData((data) => {
|
||||
webSocket.send(msgData + CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data)), ArrayBuffer)
|
||||
})
|
||||
|
||||
terminal.onResize(({cols, rows}) => {
|
||||
if (webSocket.readyState === 1) {
|
||||
webSocket.send(msgResize +
|
||||
CryptoJS.enc.Base64.stringify(
|
||||
CryptoJS.enc.Utf8.parse(
|
||||
JSON.stringify({
|
||||
columns: cols,
|
||||
rows: rows
|
||||
})
|
||||
)
|
||||
), ArrayBuffer
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
fitAddon.fit()
|
||||
}, false)
|
||||
</script>
|
||||
@@ -1,230 +0,0 @@
|
||||
<!--
|
||||
Name: 任务中心
|
||||
Author: 耗子
|
||||
Date: 2023-07-22
|
||||
-->
|
||||
|
||||
<title>任务中心</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">任务列表</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">进行中</li>
|
||||
<li>等待中</li>
|
||||
<li>已完成</li>
|
||||
<li>已失败</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<script type="text/html" template
|
||||
lay-url="/api/panel/task/list?status=running&page=1&limit=10"
|
||||
lay-done="layui.data.done(d);">
|
||||
{{# if(d.data.total != 0){ }}
|
||||
<blockquote class="layui-elem-quote">{{ d.data.items[0].name }}</blockquote>
|
||||
<pre id="plugin-install-log" class="layui-code">
|
||||
日志获取中...
|
||||
</pre>
|
||||
{{# } else { }}
|
||||
<blockquote class="layui-elem-quote">暂无任务</blockquote>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table id="panel-task-waiting" lay-filter="panel-task-waiting"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table id="panel-task-finished" lay-filter="panel-task-finished"></table>
|
||||
<script type="text/html" id="panel-task-finished-control-tpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="remove">移除</a>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table id="panel-task-failed" lay-filter="panel-task-failed"></table>
|
||||
<script type="text/html" id="panel-task-failed-control-tpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="remove">移除</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function render_plugin_install_log(d) {
|
||||
layui.use(['admin', 'jquery'], function () {
|
||||
let admin = layui.admin
|
||||
, $ = layui.jquery;
|
||||
admin.req({
|
||||
url: "/api/panel/task/log?id=" + d.data.items[0].id
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#plugin-install-log').html('实时安装日志获取失败,请刷新重试!');
|
||||
return false;
|
||||
}
|
||||
if (result.data.includes('完成') || result.data.includes('错误')) {
|
||||
setTimeout(function () {
|
||||
location.reload();
|
||||
}, 2000);
|
||||
}
|
||||
$('#plugin-install-log').html(result.data);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
layui.data.done = function (d) {
|
||||
if (d.data.items[0] !== undefined) {
|
||||
render_plugin_install_log(d);
|
||||
setInterval(function () {
|
||||
render_plugin_install_log(d);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
layui.use(['admin', 'table', 'jquery'], function () {
|
||||
var table = layui.table
|
||||
, admin = layui.admin;
|
||||
|
||||
table.render({
|
||||
elem: '#panel-task-waiting'
|
||||
, url: '/api/panel/task/list?status=waiting'
|
||||
, cols: [[
|
||||
{field: 'id', hide: true, title: 'ID', sort: true}
|
||||
, {field: 'name', fixed: 'left', title: '任务名'}
|
||||
, {field: 'created_at', title: '创建时间', width: 200}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: '#panel-task-finished'
|
||||
, id: 'panel-task-finished-table'
|
||||
, url: '/api/panel/task/list?status=finished'
|
||||
, cols: [[
|
||||
{field: 'id', hide: true, title: 'ID', sort: true}
|
||||
, {field: 'name', fixed: 'left', title: '任务名'}
|
||||
, {field: 'created_at', title: '创建时间', width: 200}
|
||||
, {field: 'updated_at', title: '完成时间', width: 200}
|
||||
, {
|
||||
field: 'control'
|
||||
, title: '操作'
|
||||
, width: 100
|
||||
, templet: '#panel-task-finished-control-tpl'
|
||||
, align: 'center'
|
||||
}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
table.on('tool(panel-task-finished)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'remove') {
|
||||
layer.confirm('确定移除该记录吗?', function (index) {
|
||||
layer.close(index);
|
||||
admin.req({
|
||||
url: '/api/panel/task/delete',
|
||||
type: 'post',
|
||||
data: {
|
||||
id: data.id
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code == 0) {
|
||||
layer.msg('移除任务:' + data.name + ' 成功!', {icon: 1, time: 1000}, function () {
|
||||
table.reload('panel-task-finished-table');
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: '#panel-task-failed'
|
||||
, id: 'panel-task-failed-table'
|
||||
, url: '/api/panel/task/list?status=failed'
|
||||
, cols: [[
|
||||
{field: 'id', hide: true, title: 'ID', sort: true}
|
||||
, {field: 'name', fixed: 'left', title: '任务名'}
|
||||
, {field: 'created_at', title: '创建时间', width: 200}
|
||||
, {field: 'updated_at', title: '完成时间', width: 200}
|
||||
, {
|
||||
field: 'control'
|
||||
, title: '操作'
|
||||
, width: 100
|
||||
, templet: '#panel-task-failed-control-tpl'
|
||||
, fixed: 'right'
|
||||
, align: 'center'
|
||||
}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
table.on('tool(panel-task-failed)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'remove') {
|
||||
layer.confirm('确定移除该记录吗?', function (index) {
|
||||
layer.close(index);
|
||||
admin.req({
|
||||
url: '/api/panel/task/delete',
|
||||
type: 'post',
|
||||
data: {
|
||||
id: data.id
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code == 0) {
|
||||
layer.msg('移除任务:' + data.name + ' 成功!', {icon: 1, time: 1000}, function () {
|
||||
table.reload('panel-task-failed-table');
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,14 +0,0 @@
|
||||
<title>404 页面不存在</title>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layadmin-tips">
|
||||
<i class="layui-icon" face></i>
|
||||
<div class="layui-text">
|
||||
<h1>
|
||||
<span class="layui-anim layui-anim-loop layui-anim-">4</span>
|
||||
<span class="layui-anim layui-anim-loop layui-anim-rotate">0</span>
|
||||
<span class="layui-anim layui-anim-loop layui-anim-">4</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
<title>出错了</title>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layadmin-tips">
|
||||
<i class="layui-icon" face></i>
|
||||
|
||||
<div class="layui-text" style="font-size: 20px;">
|
||||
好像出错了呢
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,177 +0,0 @@
|
||||
<div class="layui-layout layui-layout-admin">
|
||||
<div class="layui-header">
|
||||
<!-- 头部区域 -->
|
||||
<ul class="layui-nav layui-layout-left">
|
||||
<li class="layui-nav-item layadmin-flexible" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="flexible" title="侧边伸缩">
|
||||
<i class="layui-icon layui-icon-shrink-right" id="Panel_app_flexible"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="refresh" title="刷新">
|
||||
<i class="layui-icon layui-icon-refresh-3"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="layui-nav layui-layout-right" lay-filter="layadmin-layout-right">
|
||||
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a lay-href="task" layadmin-event="message">
|
||||
<script type="text/html" template lay-url="/api/panel/task/status">
|
||||
{{# if(d.data.task){ }}
|
||||
<i class="layui-icon layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop"></i>
|
||||
{{# } else { }}
|
||||
<i class="layui-icon layui-icon-component"></i>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="theme">
|
||||
<i class="layui-icon layui-icon-theme"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="note">
|
||||
<i class="layui-icon layui-icon-note"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="fullscreen">
|
||||
<i class="layui-icon layui-icon-screen-full"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li style="margin-right: 15px;" class="layui-nav-item" lay-unselect>
|
||||
<script type="text/html" template lay-url="/api/panel/user/info"
|
||||
lay-done="layui.element.render('nav', 'layadmin-layout-right');">
|
||||
<a href="javascript:;">
|
||||
<cite>{{= d.data.username }}</cite>
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a lay-href="setting">修改密码</a></dd>
|
||||
<hr>
|
||||
<dd lay-href="logout" style="text-align: center;"><a>退出</a></dd>
|
||||
</dl>
|
||||
</script>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 侧边菜单 -->
|
||||
<div class="layui-side layui-side-menu">
|
||||
<div class="layui-side-scroll">
|
||||
<script type="text/html" template lay-url="/api/panel/info/menu?v={{ layui.cache.version }}"
|
||||
lay-done="layui.element.render('nav', 'layadmin-system-side-menu');" id="TPL_layout">
|
||||
|
||||
<div class="layui-logo" lay-href="">
|
||||
<span>{{ layui.setter.name }}</span>
|
||||
</div>
|
||||
|
||||
<ul class="layui-nav layui-nav-tree" lay-shrink="all" id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu">
|
||||
{{#
|
||||
var path = layui.router().path
|
||||
,pathURL = layui.admin.correctRouter(path.join('/'))
|
||||
,dataName = layui.setter.response.dataName;
|
||||
|
||||
layui.each(d[dataName], function(index, item){
|
||||
var hasChildren = typeof item.list === 'object' && item.list.length > 0
|
||||
,classSelected = function(){
|
||||
var match = path[0] == item.name || (index == 0 && !path[0])
|
||||
|| (item.jump && pathURL == layui.admin.correctRouter(item.jump)) || item.spread;
|
||||
if(match){
|
||||
return hasChildren ? 'layui-nav-itemed' : 'layui-this';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
,url = (item.jump && typeof item.jump === 'string') ? item.jump : item.name;
|
||||
}}
|
||||
<li data-name="{{= item.name || '' }}" data-jump="{{= item.jump || '' }}" class="layui-nav-item {{= classSelected() }}">
|
||||
<a href="javascript:;" {{- hasChildren ? '' : 'lay-href="'+ url +'"' }} lay-tips="{{= item.title }}" lay-direction="2">
|
||||
<i class="layui-icon {{= item.icon }}"></i>
|
||||
<cite>{{= item.title }}</cite>
|
||||
</a>
|
||||
{{# if(hasChildren){ }}
|
||||
<dl class="layui-nav-child">
|
||||
{{# layui.each(item.list, function(index2, item2){
|
||||
var hasChildren2 = typeof item2.list == 'object' && item2.list.length > 0
|
||||
,classSelected2 = function(){
|
||||
var match = (path[0] == item.name && path[1] == item2.name)
|
||||
|| (item2.jump && pathURL == layui.admin.correctRouter(item2.jump)) || item2.spread;
|
||||
if(match){
|
||||
return hasChildren2 ? 'layui-nav-itemed' : 'layui-this';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
,url2 = (item2.jump && typeof item2.jump === 'string')
|
||||
? item2.jump
|
||||
: [item.name, item2.name, ''].join('/');
|
||||
}}
|
||||
<dd data-name="{{= item2.name || '' }}" data-jump="{{= item2.jump || '' }}"
|
||||
{{- classSelected2() ? ('class="'+ classSelected2() +'"') : '' }}>
|
||||
<a href="javascript:;" {{- hasChildren2 ? '' : 'lay-href="'+ url2 +'"' }}>{{= item2.title }}</a>
|
||||
{{# if(hasChildren2){ }}
|
||||
<dl class="layui-nav-child">
|
||||
{{# layui.each(item2.list, function(index3, item3){
|
||||
var match = (path[0] == item.name && path[1] == item2.name && path[2] == item3.name)
|
||||
|| (item3.jump && pathURL == layui.admin.correctRouter(item3.jump))
|
||||
,url3 = (item3.jump && typeof item3.jump === 'string')
|
||||
? item3.jump
|
||||
: [item.name, item2.name, item3.name].join('/')
|
||||
}}
|
||||
<dd data-name="{{= item3.name || '' }}" data-jump="{{= item3.jump || '' }}"
|
||||
{{- match ? 'class="layui-this"' : '' }}>
|
||||
<a href="javascript:;" lay-href="{{= url3 }}" {{- item3.iframe ? 'lay-iframe="true"' : '' }}>{{= item3.title }}</a>
|
||||
</dd>
|
||||
{{# }); }}
|
||||
</dl>
|
||||
{{# } }}
|
||||
</dd>
|
||||
{{# }); }}
|
||||
</dl>
|
||||
{{# } }}
|
||||
</li>
|
||||
{{# }); }}
|
||||
</ul>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 页面标签 -->
|
||||
<script type="text/html" template lay-done="layui.element.render('nav', 'layadmin-pagetabs-nav')">
|
||||
{{# if(layui.setter.pageTabs){ }}
|
||||
<div class="layadmin-pagetabs" id="Panel_app_tabs">
|
||||
<div class="layui-icon layadmin-tabs-control layui-icon-prev" layadmin-event="leftPage"></div>
|
||||
<div class="layui-icon layadmin-tabs-control layui-icon-next" layadmin-event="rightPage"></div>
|
||||
<div class="layui-icon layadmin-tabs-control layui-icon-down">
|
||||
<ul class="layui-nav layadmin-tabs-select" lay-filter="layadmin-pagetabs-nav">
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a href="javascript:;"></a>
|
||||
<dl class="layui-nav-child layui-anim-fadein">
|
||||
<dd layadmin-event="closeThisTabs"><a href="javascript:;">关闭当前标签页</a></dd>
|
||||
<dd layadmin-event="closeOtherTabs"><a href="javascript:;">关闭其它标签页</a></dd>
|
||||
<dd layadmin-event="closeAllTabs"><a href="javascript:;">关闭全部标签页</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="layui-tab" lay-unauto lay-allowClose="true" lay-filter="layadmin-layout-tabs">
|
||||
<ul class="layui-tab-title" id="Panel_app_tabsheader">
|
||||
<li lay-id="/"><i class="layui-icon layui-icon-home"></i></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="layui-body" id="Panel_app_body">
|
||||
<div class="layadmin-tabsbody-item layui-show"></div>
|
||||
</div>
|
||||
|
||||
<!-- 辅助元素,一般用于移动设备下遮罩 -->
|
||||
<div class="layadmin-body-shade" layadmin-event="shade"></div>
|
||||
|
||||
</div>
|
||||
@@ -1,43 +0,0 @@
|
||||
<!-- 主题设置模板 -->
|
||||
|
||||
<script type="text/html" template lay-done="layui.data.theme();">
|
||||
{{#
|
||||
var local = layui.data(layui.setter.tableName)
|
||||
,theme = local.theme || {}
|
||||
,themeColorIndex = parseInt((theme && theme.color) ? theme.color.index : 0) || 0;
|
||||
}}
|
||||
|
||||
<div class="layui-card-header">
|
||||
配色方案
|
||||
</div>
|
||||
<div class="layui-card-body layadmin-setTheme">
|
||||
<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>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.data.theme = function () {
|
||||
layui.use('form', function () {
|
||||
var form = layui.form
|
||||
, admin = layui.admin
|
||||
|
||||
//隐藏开关
|
||||
form.on('switch(system-theme-sideicon)', function () {
|
||||
admin.theme({
|
||||
hideSideIcon: this.checked
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,160 +0,0 @@
|
||||
<!--
|
||||
Name: 网站 - 添加
|
||||
Author: 耗子
|
||||
Date: 2023-069-29
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-website-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" lay-verify="required" placeholder="请输入网站名(英文,设置后不可修改)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">域名</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="domain" lay-verify="required"
|
||||
placeholder="请输入域名,一行一个支持泛域名(格式:yourdomain.com:88 ,端口不填则默认80端口)"
|
||||
class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">PHP版本</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="php" lay-filter="add-website-php">
|
||||
{{# layui.each(d.params.php, function(index, item){ }}
|
||||
<option value="{{ item.slug }}">{{ item.name }}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">数据库</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="db_type" lay-filter="add-website-db">
|
||||
<option value="false" selected="">不使用</option>
|
||||
{{# if(d.params.mysql){ }}
|
||||
<option value="mysql">MySQL</option>
|
||||
{{# } }}
|
||||
{{# if(d.params.postgresql){ }}
|
||||
<option value="postgresql">PostgreSQL</option>
|
||||
{{# } }}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="add-website-db-info" class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">数据库名</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="db_name" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">数据库用户</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="db_user" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">数据库密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input id="add-website-db-password" type="text" name="db_password" autocomplete="off"
|
||||
class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">目录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="path"
|
||||
placeholder="请输入网站根目录(不填默认为建站目录/网站名)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="note" placeholder="请输入备注内容,可以为空。" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-website-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['jquery', 'admin', 'layer', 'table', 'form'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
|
||||
$('#add-website-db-info').hide()
|
||||
form.render()
|
||||
|
||||
$('#add-website-db-password').hover(function () {
|
||||
layer.tips('必须8位以上大小写数字特殊符号混合', '#add-website-db-password', {
|
||||
tips: 1,
|
||||
time: 0
|
||||
})
|
||||
}, function () {
|
||||
layer.closeAll('tips')
|
||||
})
|
||||
|
||||
form.on('select(add-website-db)', function (data) {
|
||||
if (data.value === "false") {
|
||||
$('#add-website-db-info').hide()
|
||||
return false
|
||||
}
|
||||
if (data.value === 'mysql') {
|
||||
$('#add-website-db-info').show()
|
||||
$('input[name="db_name"]').val($('input[name="name"]').val() + '_mysql')
|
||||
$('input[name="db_user"]').val($('input[name="name"]').val() + '_mysql')
|
||||
} else if (data.value === 'postgresql') {
|
||||
$('#add-website-db-info').show()
|
||||
$('input[name="db_name"]').val($('input[name="name"]').val() + '_postgresql')
|
||||
$('input[name="db_user"]').val($('input[name="name"]').val() + '_postgresql')
|
||||
}
|
||||
})
|
||||
// 提交
|
||||
form.on('submit(add-website-submit)', function (data) {
|
||||
data.field.db = data.field.db_type !== "false";
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: '/api/panel/website/add'
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
layer.msg('新网站添加失败!')
|
||||
return false
|
||||
}
|
||||
table.reload('website-list')
|
||||
layer.alert('新网站添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return false
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,145 +0,0 @@
|
||||
<!--
|
||||
Name: 网站 - 备份
|
||||
Author: 耗子
|
||||
Date: 2023-07-24
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs12 layui-col-sm12 layui-col-md12">
|
||||
<table class="layui-hide" id="website-backup-list" lay-filter="website-backup-list"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份顶部工具栏 -->
|
||||
<script type="text/html" id="website-backup-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="backup_website">备份网站</button>
|
||||
<button class="layui-btn layui-btn-sm" id="upload_website_backup">上传备份</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份右侧管理 -->
|
||||
<script type="text/html" id="website-backup-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'laydate', 'code'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, table = layui.table
|
||||
, upload = layui.upload;
|
||||
|
||||
// 渲染表格
|
||||
table.render({
|
||||
elem: '#website-backup-list'
|
||||
, url: '/api/panel/website/backupList'
|
||||
, toolbar: '#website-backup-bar'
|
||||
, title: '备份列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '备份名称', width: 500}
|
||||
, {field: 'size', title: '文件大小'}
|
||||
, {field: 'right', title: '操作', width: 150, toolbar: '#website-backup-control'}
|
||||
]]
|
||||
, text: {
|
||||
none: '无备份数据'
|
||||
}
|
||||
, done: function (res, curr, count) {
|
||||
upload.render({
|
||||
elem: '#upload_website_backup'
|
||||
, url: '/api/panel/website/uploadBackup'
|
||||
, accept: 'file'
|
||||
, exts: 'zip'
|
||||
, before: function (obj) {
|
||||
index = layer.msg('正在上传备份文件,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
}
|
||||
, done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg('上传成功!', {icon: 1});
|
||||
table.reload('website-backup-list');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(website-backup-list)', function (obj) {
|
||||
if (obj.event === 'backup_website') {
|
||||
index = layer.msg('正在备份网站,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: '/api/panel/website/createBackup'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
id: params.data.id
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.alert('备份失败!');
|
||||
return false;
|
||||
}
|
||||
table.reload('website-backup-list');
|
||||
layer.msg('备份成功!', {icon: 1});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(website-backup-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除网站备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除网站备份,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/panel/website/deleteBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('网站备份删除失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('网站备份' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'restore') {
|
||||
layer.confirm('高风险操作,确定要恢复网站备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在恢复网站备份,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
data.id = params.data.id;
|
||||
admin.req({
|
||||
url: "/api/panel/website/restoreBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('网站备份恢复失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.alert('网站备份' + data.name + '恢复成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,76 +0,0 @@
|
||||
<!--
|
||||
Name: 网站 - 全局设置
|
||||
Author: 耗子
|
||||
Date: 2023-07-21
|
||||
-->
|
||||
<script type="text/html" template lay-url="/api/panel/website/defaultConfig"
|
||||
lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">默认页</li>
|
||||
<li>停止页</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<!-- 默认页 -->
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
设置站点未找到时的提示页面。
|
||||
</blockquote>
|
||||
<div id="index-editor" style="height: 400px;">{{ d.data.index }}</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<!-- 停止页 -->
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
设置站点停止时的提示页面,设置后需重新开关网站方可生效。
|
||||
</blockquote>
|
||||
<div id="stop-editor" style="height: 400px;">{{ d.data.stop }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-footer">
|
||||
<button id="save-website-default-settings" class="layui-btn">保存设置</button>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
let indexEditor = '';
|
||||
let stopEditor = '';
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'laydate', 'code'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer;
|
||||
indexEditor = ace.edit("index-editor", {
|
||||
mode: "ace/mode/html",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
stopEditor = ace.edit("stop-editor", {
|
||||
mode: "ace/mode/html",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
|
||||
$('#save-website-default-settings').click(function () {
|
||||
layer.load();
|
||||
admin.req({
|
||||
url: '/api/panel/website/defaultConfig'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
index: indexEditor.getValue(),
|
||||
stop: stopEditor.getValue()
|
||||
}
|
||||
, success: function (res) {
|
||||
layer.closeAll('loading');
|
||||
if (res.code === 0) {
|
||||
layer.msg('保存成功', {icon: 1, shade: 0.3});
|
||||
setTimeout(function () {
|
||||
admin.render();
|
||||
}, 1000);
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, shade: 0.3});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,482 +0,0 @@
|
||||
<!--
|
||||
Name: 网站 - 编辑
|
||||
Author: 耗子
|
||||
Date: 2023-07-24
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-tab" lay-filter="website-edit-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">域名端口</li>
|
||||
<li>基本设置</li>
|
||||
<li>防火墙</li>
|
||||
<li>SSL</li>
|
||||
<li>伪静态</li>
|
||||
<li>配置原文</li>
|
||||
<li>访问日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<!-- 域名绑定 -->
|
||||
<div class="layui-form">
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">域名</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-input-inline" id="domains">
|
||||
{{# layui.each(d.params.config.domains, function(index, item){ }}
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="domains[]" lay-verify="required" value="{{ item }}"
|
||||
class="layui-input" style="width: 200%;">
|
||||
</div>
|
||||
<div class="layui-input-block" style="margin-left: 480px">
|
||||
<button type="button"
|
||||
class="layui-btn layui-btn-danger layui-btn-sm removeclass"><i
|
||||
class="layui-icon"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{{# }); }}
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 480px">
|
||||
<button id="add-domain" type="button"
|
||||
class="layui-btn layui-btn-warm layui-btn-sm">
|
||||
<i class="layui-icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">端口</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-input-inline" id="ports">
|
||||
{{# layui.each(d.params.config.ports, function(index, item){ }}
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="ports[]" lay-verify="required" value="{{ item }}"
|
||||
class="layui-input" style="width: 200%;">
|
||||
</div>
|
||||
<div class="layui-input-block" style="margin-left: 480px">
|
||||
<button type="button"
|
||||
class="layui-btn layui-btn-danger layui-btn-sm removeclass"><i
|
||||
class="layui-icon"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{{# }); }}
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 480px">
|
||||
<button id="add-port" type="button"
|
||||
class="layui-btn layui-btn-warm layui-btn-sm">
|
||||
<i class="layui-icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<!-- 基本设置 -->
|
||||
<div class="layui-form layui-form-pane">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站目录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="path" autocomplete="off" placeholder="请输入网站目录"
|
||||
class="layui-input" value="{{ d.params.config.path }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">运行目录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="root" autocomplete="off"
|
||||
placeholder="请输入网站运行目录(Laravel等程序需要)"
|
||||
class="layui-input" value="{{ d.params.config.root }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">默认文档</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="index" autocomplete="off" placeholder="请输入默认文档,以空格隔开"
|
||||
class="layui-input" value="{{ d.params.config.index }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">PHP版本</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="php" lay-filter="website-php">
|
||||
{{# layui.each(d.params.php, function(index, item){ }}
|
||||
{{# if(item.slug == d.params.config.php){ }}
|
||||
<option value="{{ item.slug }}" selected="">{{ item.name }}</option>
|
||||
{{# }else{ }}
|
||||
<option value="{{ item.slug }}">{{ item.name }}</option>
|
||||
{{# } }}
|
||||
{{# }); }}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" pane="">
|
||||
<label class="layui-form-label">防跨站攻击</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="open_basedir" lay-skin="switch" lay-text="ON|OFF"
|
||||
{{ d.params.config.open_basedir ? 'checked' : '' }}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<!-- 防火墙 -->
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
面板自带开源的 ngx_waf 防火墙<br>文档参考:<a
|
||||
href="https://docs.addesp.com/ngx_waf/zh-cn/advance/directive.html"
|
||||
target="_blank">https://docs.addesp.com/ngx_waf/zh-cn/advance/directive.html</a>
|
||||
</blockquote>
|
||||
<div class="layui-form layui-form-pane">
|
||||
<div class="layui-form-item" pane="">
|
||||
<label class="layui-form-label">总开关</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="waf" lay-skin="switch" lay-text="ON|OFF"
|
||||
{{ d.params.config.waf ? 'checked' : '' }}>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">只有打开了总开关,下面的设置才会生效!</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">模式</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="waf_mode" autocomplete="off" placeholder="DYNAMIC"
|
||||
class="layui-input" value="{{ d.params.config.waf_mode }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">CC</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="waf_cc_deny" autocomplete="off"
|
||||
placeholder="rate=1000r/m duration=60m"
|
||||
class="layui-input" value="{{ d.params.config.waf_cc_deny }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">缓存</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="waf_cache" autocomplete="off" placeholder="capacity=50"
|
||||
class="layui-input" value="{{ d.params.config.waf_cache }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<!-- SSL -->
|
||||
<div class="layui-form layui-form-pane">
|
||||
<div class="layui-form-item" pane="">
|
||||
<label class="layui-form-label">总开关</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="ssl" lay-skin="switch" lay-text="ON|OFF"
|
||||
{{ d.params.config.ssl ? 'checked' : '' }}>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">只有打开了总开关,下面的设置才会生效!</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">HTTP跳转</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="http_redirect" lay-skin="switch" lay-text="ON|OFF"
|
||||
{{ d.params.config.http_redirect ? 'checked' : '' }}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">HSTS</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="hsts" lay-skin="switch" lay-text="ON|OFF"
|
||||
{{ d.params.config.hsts ? 'checked' : '' }}>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div class="layui-inline">
|
||||
<div class="layui-input-inline">
|
||||
<button id="issue-ssl" class="layui-btn layui-btn-sm">签发免费SSL证书</button>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-form-text">
|
||||
{{# if(d.params.config.ssl){ }}
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
有效期:
|
||||
<span class="layui-badge">{{ d.params.config.ssl_not_before }} ~ {{ d.params.config.ssl_not_after }}</span>
|
||||
</blockquote>
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
域名:
|
||||
{{# layui.each(d.params.config.ssl_dns_names, function(index, item){ }}
|
||||
<span class="layui-badge layui-bg-blue">{{ item }}</span>
|
||||
{{# }); }}
|
||||
</blockquote>
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
签发者:
|
||||
<span class="layui-badge layui-bg-orange">{{ d.params.config.ssl_issuer }}</span>
|
||||
</blockquote>
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
OCSP:
|
||||
{{# layui.each(d.params.config.ssl_ocsp_server, function(index, item){ }}
|
||||
<span class="layui-badge layui-bg-blue">{{ item }}</span>
|
||||
{{# }); }}
|
||||
</blockquote>
|
||||
<label class="layui-form-label">证书</label>
|
||||
{{# }else{ }}
|
||||
<label class="layui-form-label">证书</label>
|
||||
{{# } }}
|
||||
<div class="layui-input-block">
|
||||
<textarea name="ssl_certificate" placeholder="请输入pem证书文件的内容"
|
||||
class="layui-textarea">{{ d.params.config.ssl_certificate }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">私钥</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="ssl_certificate_key" placeholder="请输入key私钥文件的内容"
|
||||
class="layui-textarea">{{ d.params.config.ssl_certificate_key }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<!-- 伪静态 -->
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
设置伪静态规则,填入 <code>location</code> 部分即可
|
||||
</blockquote>
|
||||
<div id="rewrite-editor" style="height: 400px;">{{ d.params.config.rewrite }}</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<!-- 配置原文 -->
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
如果您不了解配置规则,请勿随意修改,否则可能会导致网站无法访问或面板功能异常!如果已经遇到问题,可尝试:
|
||||
<button id="site-config-restore" class="layui-btn layui-btn-xs">重置配置</button>
|
||||
<br>
|
||||
如果你修改了原文,那么点击保存后,其余的修改将不会生效!
|
||||
</blockquote>
|
||||
<div id="config-editor" style="height: 400px;">{{ d.params.config.raw }}</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<!-- 访问日志 -->
|
||||
<button id="clean-site-log" class="layui-btn">清空日志</button>
|
||||
<pre id="website-log" class="layui-code" lay-options="{about: '{{ d.params.config.name }}.log'}">{{ d.params.config.log }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-footer">
|
||||
<button id="save-site-config" class="layui-btn">保存设置</button>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
let rewriteEditor = ''
|
||||
let configEditor = ''
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'laydate', 'code'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, code = layui.code
|
||||
, form = layui.form
|
||||
, element = layui.element
|
||||
form.render()
|
||||
element.render()
|
||||
element.on('tab(website-edit-tab)', function (data) {
|
||||
if (data.index === 6) {
|
||||
// 隐藏保存按钮
|
||||
$('.layui-footer').hide()
|
||||
} else {
|
||||
$('.layui-footer').show()
|
||||
}
|
||||
})
|
||||
rewriteEditor = ace.edit('rewrite-editor', {
|
||||
mode: 'ace/mode/nginx',
|
||||
selectionStyle: 'text'
|
||||
})
|
||||
configEditor = ace.edit('config-editor', {
|
||||
mode: 'ace/mode/nginx',
|
||||
selectionStyle: 'text'
|
||||
})
|
||||
code({
|
||||
elem: '#website-log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
})
|
||||
|
||||
$('#clean-site-log').click(function () {
|
||||
layer.confirm('确定要清空日志吗?', function (index) {
|
||||
layer.close(index)
|
||||
layer.load()
|
||||
admin.req({
|
||||
url: '/api/panel/website/clearLog'
|
||||
, type: 'post'
|
||||
, data: {name: params.config.name}
|
||||
, success: function (res) {
|
||||
layer.closeAll('loading')
|
||||
if (res.code === 0) {
|
||||
layer.msg('已清空', {icon: 1})
|
||||
setTimeout(function () {
|
||||
admin.render()
|
||||
}, 1000)
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
$('#save-site-config').click(function () {
|
||||
layer.load()
|
||||
let ports = $("input[name='ports[]']").map(function () {
|
||||
return $(this).val();
|
||||
}).get().join('\n')
|
||||
|
||||
let domains = $("input[name='domains[]']").map(function () {
|
||||
return $(this).val();
|
||||
}).get().join('\n')
|
||||
var reg = new RegExp(/\n443.*\n?/);
|
||||
// 如果开启了https,就自动添加443端口
|
||||
if ($('input[name="ssl"]').prop('checked') && !reg.test(ports)) {
|
||||
ports = ports + '\n443 ssl http2';
|
||||
}
|
||||
// 如果关闭了https,就自动删除443端口
|
||||
if (!$('input[name="ssl"]').prop('checked') && reg.test(ports)) {
|
||||
ports = ports.replace(/\n443.*\n?/, '');
|
||||
}
|
||||
|
||||
admin.req({
|
||||
url: '/api/panel/website/config'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
id: params.data.id,
|
||||
domains: domains,
|
||||
ports: ports,
|
||||
ssl: $('input[name="ssl"]').prop('checked'),
|
||||
http_redirect: $('input[name="http_redirect"]').prop('checked'),
|
||||
hsts: $('input[name="hsts"]').prop('checked'),
|
||||
ssl_certificate: $('textarea[name="ssl_certificate"]').val(),
|
||||
ssl_certificate_key: $('textarea[name="ssl_certificate_key"]').val(),
|
||||
path: $('input[name="path"]').val(),
|
||||
root: $('input[name="root"]').val(),
|
||||
index: $('input[name="index"]').val(),
|
||||
php: $('select[name="php"]').val(),
|
||||
open_basedir: $('input[name="open_basedir"]').prop('checked'),
|
||||
waf: $('input[name="waf"]').prop('checked') ? 'on' : 'off',
|
||||
waf_mode: $('input[name="waf_mode"]').val(),
|
||||
waf_cc_deny: $('input[name="waf_cc_deny"]').val(),
|
||||
waf_cache: $('input[name="waf_cache"]').val(),
|
||||
rewrite: rewriteEditor.getValue(),
|
||||
raw: configEditor.getValue()
|
||||
}
|
||||
, success: function (res) {
|
||||
layer.closeAll('loading')
|
||||
if (res.code === 0) {
|
||||
layer.msg('保存成功', {icon: 1})
|
||||
setTimeout(function () {
|
||||
admin.render()
|
||||
}, 1000)
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 重置配置
|
||||
$('#site-config-restore').click(function () {
|
||||
layer.confirm('高风险操作,网站配置重置后所有配置均需重新设置,确定要重置配置吗?', function (index) {
|
||||
index = layer.msg('重置网站配置', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
})
|
||||
admin.req({
|
||||
url: '/api/panel/website/resetConfig'
|
||||
, type: 'post'
|
||||
, data: {id: params.data.id}
|
||||
, success: function (res) {
|
||||
layer.close(index)
|
||||
if (res.code === 0) {
|
||||
layer.alert('重置成功,你需要重新添加域名/端口绑定,设置各配置参数!', function (index) {
|
||||
admin.render()
|
||||
layer.close(index)
|
||||
})
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// 监听签发证书按钮
|
||||
$('#issue-ssl').click(function () {
|
||||
layer.confirm('确定要申请签发免费SSL证书吗?', function (index) {
|
||||
index = layer.msg('正在签发证书,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
})
|
||||
admin.req({
|
||||
url: '/api/panel/website/issueSsl'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
name: params.config.name
|
||||
, type: 'lets'
|
||||
}
|
||||
, success: function (res) {
|
||||
layer.close(index)
|
||||
if (res.code === 0) {
|
||||
layer.msg('签发成功', {icon: 1})
|
||||
setTimeout(function () {
|
||||
admin.render()
|
||||
}, 1000)
|
||||
} else {
|
||||
layer.alert(res.message, {icon: 2})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// 动态添加input输入框
|
||||
$("#add-domain").click(function () {
|
||||
var str = '<div class="layui-form-item">' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="text" name="domains[]" placeholder="example.com" lay-verify="required"' +
|
||||
'class="layui-input" style="width: 200%;">' +
|
||||
'</div>' +
|
||||
'<div class="layui-input-block" style="margin-left: 480px">' +
|
||||
'<button type="button" class="layui-btn layui-btn-danger layui-btn-sm removeclass"><i class="layui-icon"></i></button>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
$("#domains").append(str);
|
||||
|
||||
form.render();
|
||||
});
|
||||
$("#add-port").click(function () {
|
||||
var str = '<div class="layui-form-item">' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="text" name="ports[]" placeholder="443 ssl" lay-verify="required"' +
|
||||
'class="layui-input" style="width: 200%;">' +
|
||||
'</div>' +
|
||||
'<div class="layui-input-block" style="margin-left: 480px">' +
|
||||
'<button type="button" class="layui-btn layui-btn-danger layui-btn-sm removeclass"><i class="layui-icon"></i></button>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
$("#ports").append(str);
|
||||
|
||||
form.render();
|
||||
});
|
||||
|
||||
//删除动态添加的input输入框
|
||||
$("body").on('click', ".removeclass", function () {
|
||||
let parentEle = $(this).parent().parent();
|
||||
parentEle.remove();
|
||||
form.render();
|
||||
});
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,246 +0,0 @@
|
||||
<!--
|
||||
Name: 网站 - 列表
|
||||
Author: 耗子
|
||||
Date: 2023-07-74
|
||||
-->
|
||||
<title>网站</title>
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">网站列表</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="website-list" lay-filter="website-list"></table>
|
||||
|
||||
<!-- 顶部工具栏 -->
|
||||
<script type="text/html" id="website-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="website_add">添加网站</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="website_default_config">全局设置
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 右侧网站设置和删除网站 -->
|
||||
<script type="text/html" id="website-control">
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="backup">备份</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">设置</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<!-- 网站运行状态开关 -->
|
||||
<script type="text/html" id="website-run">
|
||||
<input type="checkbox" name="run" lay-skin="switch" lay-text="ON|OFF"
|
||||
lay-filter="website-run-checkbox"
|
||||
value="{{ d.status }}" data-website-id="{{ d.id }}"
|
||||
{{ d.status ? 'checked' : '' }}>
|
||||
</script>
|
||||
<!-- 网站SSL状态 -->
|
||||
<script type="text/html" id="website-ssl">
|
||||
{{ d.ssl ? '已开启' : '未开启' }}
|
||||
</script>
|
||||
<!-- 网站PHP版本 -->
|
||||
<script type="text/html" id="website-php">
|
||||
{{ d.php == '0' ? '不使用' : d.php }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let php, mysql, postgresql
|
||||
layui.use(['admin', 'table', 'form', 'view'], function () {
|
||||
var admin = layui.admin
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view
|
||||
|
||||
// 获取已安装的PHP和DB版本
|
||||
admin.req({
|
||||
url: '/api/panel/info/installedDbAndPhp'
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
php = result.data.php
|
||||
mysql = result.data.mysql
|
||||
postgresql = result.data.postgresql
|
||||
}
|
||||
})
|
||||
table.render({
|
||||
elem: '#website-list'
|
||||
, url: '/api/panel/website/list'
|
||||
, toolbar: '#website-list-bar'
|
||||
, title: '网站列表'
|
||||
, cols: [[
|
||||
{field: 'id', hide: true, title: 'ID', sort: true}
|
||||
, {field: 'name', title: '网站名', width: 150, unresize: true, sort: true}
|
||||
, {field: 'run', title: '运行', width: 100, templet: '#website-run', unresize: true}
|
||||
, {field: 'path', title: '目录', width: 250}
|
||||
, {field: 'php', title: 'PHP', width: 100, templet: '#website-php'}
|
||||
, {field: 'ssl', title: 'SSL', width: 100, templet: '#website-ssl'}
|
||||
, {field: 'remark', title: '备注', edit: 'textarea'}
|
||||
, {fixed: 'right', title: '操作', unresize: true, toolbar: '#website-control', width: 180}
|
||||
]]
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
'code': res.code,
|
||||
'msg': res.message,
|
||||
'count': res.data.total,
|
||||
'data': res.data.items
|
||||
}
|
||||
}
|
||||
, page: true
|
||||
})
|
||||
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(website-list)', function (obj) {
|
||||
if (obj.event === 'website_add') {
|
||||
admin.popup({
|
||||
title: '添加网站'
|
||||
, area: ['80%', '60%']
|
||||
, id: 'LAY-popup-website-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('website/add', {
|
||||
php: php,
|
||||
mysql: mysql,
|
||||
postgresql: postgresql
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-website-add')
|
||||
})
|
||||
}
|
||||
})
|
||||
} else if (obj.event === 'website_default_config') {
|
||||
admin.popup({
|
||||
title: '全局设置'
|
||||
, area: ['80%', '80%']
|
||||
, id: 'LAY-popup-website-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('website/default_config', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-website-default-config')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 行工具事件
|
||||
table.on('tool(website-list)', function (obj) {
|
||||
let data = obj.data
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('删除网站将一并删除站点目录(不包括数据库),是否继续?', function (index) {
|
||||
admin.req({
|
||||
url: '/api/panel/website/delete'
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:网站删除失败,接口返回' + result)
|
||||
layer.msg('网站删除失败,请刷新重试!')
|
||||
return false
|
||||
}
|
||||
obj.del()
|
||||
layer.alert('网站' + data.name + '删除成功!')
|
||||
}
|
||||
})
|
||||
layer.close(index)
|
||||
})
|
||||
} else if (obj.event === 'edit') {
|
||||
let config
|
||||
|
||||
admin.req({
|
||||
url: '/api/panel/website/config?id=' + data.id
|
||||
, type: 'get'
|
||||
, beforeSend: function (request) {
|
||||
layer.load()
|
||||
}
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:网站设置获取失败,接口返回' + result)
|
||||
layer.alert('网站设置获取失败!')
|
||||
return false
|
||||
}
|
||||
config = result.data
|
||||
layer.closeAll('loading')
|
||||
// 打开编辑网站页面
|
||||
admin.popup({
|
||||
title: '编辑网站 - ' + data.name
|
||||
, area: ['80%', '80%']
|
||||
, id: 'LAY-popup-website-edit'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('website/edit', {
|
||||
php: php,
|
||||
mysql: mysql,
|
||||
postgresql: postgresql,
|
||||
data: data,
|
||||
config: config
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-website-edit')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} else if (obj.event === 'backup') {
|
||||
// 打开备份页面
|
||||
admin.popup({
|
||||
title: '备份管理 - ' + data.name
|
||||
, area: ['70%', '80%']
|
||||
, id: 'LAY-popup-website-backup'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('website/backup', {
|
||||
data: data
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-website-backup')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 网站备注编辑
|
||||
table.on('edit(website-list)', function (obj) {
|
||||
let value = obj.value // 得到修改后的值
|
||||
, data = obj.data // 得到行数据
|
||||
admin.req({
|
||||
url: '/api/panel/website/updateRemark'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
id: data.id,
|
||||
remark: value
|
||||
}
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:网站备注更新失败,接口返回' + result)
|
||||
layer.msg('网站备注更新失败,请刷新重试!')
|
||||
return false
|
||||
}
|
||||
layer.alert('网站 ' + data.name + ' 备注更新成功!')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 网站运行状态操作
|
||||
form.on('switch(website-run-checkbox)', function (obj) {
|
||||
let $ = layui.$
|
||||
let website_id = $(this).data('website-id')
|
||||
let status = obj.elem.checked
|
||||
|
||||
admin.req({
|
||||
url: '/api/panel/website/status'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
id: website_id,
|
||||
status: status
|
||||
}
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
console.log('耗子Linux面板:网站运行状态设置失败,接口返回' + result)
|
||||
layer.msg('网站运行状态设置失败,请刷新重试!')
|
||||
return false
|
||||
}
|
||||
layer.alert('运行状态修改成功')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
@@ -1,2 +0,0 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
||||