2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 11:27:17 +08:00

feat: static use cdn

This commit is contained in:
耗子
2023-06-22 19:53:24 +08:00
parent 16d18d1052
commit c16a30c434
18 changed files with 158 additions and 1134 deletions

View File

@@ -0,0 +1,32 @@
package controllers
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
"panel/app/models"
)
type InfoController struct {
//Dependent services
}
func NewInfoController() *InfoController {
return &InfoController{
//Inject services
}
}
func (r *InfoController) Name(ctx http.Context) {
var setting models.Setting
err := facades.Orm().Query().Where("key", "name").First(&setting)
if err != nil {
facades.Log().Error("[面板][InfoController] 查询面板名称失败 ", err)
Error(ctx, http.StatusInternalServerError, "系统内部错误")
return
}
Success(ctx, http.Json{
"name": setting.Value,
})
}

View File

@@ -19,7 +19,7 @@ func (r *LoginRequest) Authorize(ctx http.Context) error {
func (r *LoginRequest) Rules(ctx http.Context) map[string]string {
return map[string]string{
"login": "required",
"username": "required",
"password": "required|min_len:8",
"captcha": "captcha:true",
}
@@ -27,7 +27,7 @@ func (r *LoginRequest) Rules(ctx http.Context) map[string]string {
func (r *LoginRequest) Messages(ctx http.Context) map[string]string {
return map[string]string{
"login.required": "登录名不能为空",
"username.required": "登录名不能为空",
"password.required": "密码不能为空",
"password.min_len": "密码长度不能小于 8 位",
"captcha.captcha": "验证码错误",

View File

@@ -32,20 +32,30 @@
<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="/res/layui/css/layui.css" rel="stylesheet">
<script src="https://cdnjs.cdn.haozi.net/ace/1.6.1/ace.js"></script>
<link href="https://cdnjs.cdn.haozi.net/layui/2.8.8/css/layui.min.css" rel="stylesheet">
</head>
<body>
<div id="Panel_app"></div>
<script src="/res/layui/layui.js"></script>
<script src="https://cdnjs.cdn.haozi.net/layui/2.8.8/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>
var panel_name = '耗子Linux面板'
layui.config({
base: 'res/', // 静态资源所在路径
version: new Date().getTime()
}).use('index', function () {
var layer = layui.layer
var admin = layui.admin
admin.req({
url: '/api/panel/info/name',
type: 'get',
success: function (res) {
if (res.code === 0) {
panel_name = res.data.name
document.title = panel_name
}
}
})
})
</script>
</body>

View File

@@ -136,7 +136,7 @@ layui.define('admin', function (exports) {
})
//独立页面
if (isIndPage || pathURL === '/user/login') { //此处单独判断登入页,是为了兼容旧版(即未在 config.js 配置 indPage 的情况)
if (isIndPage) {
container.render(router.path.join('/')).done(function () {
admin.pageType = 'alone'
})
@@ -146,7 +146,7 @@ layui.define('admin', function (exports) {
if (setter.interceptor) {
var local = layui.data(setter.tableName)
if (!local[setter.request.tokenName]) {
return location.hash = '/user/login/redirect=' + encodeURIComponent(pathURL) //跳转到登入页
return location.hash = '/login/redirect=' + encodeURIComponent(pathURL) //跳转到登入页
}
}

View File

@@ -3,31 +3,25 @@
*/
layui.define(['laytpl', 'layer'], function (exports) {
var $ = layui.jquery
, laytpl = layui.laytpl
, layer = layui.layer
, setter = layui.setter
, device = layui.device()
, hint = layui.hint()
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)
}
//对外接口
, view = function (id) {
return new Class(id)
}
, SHOW = 'layui-show', LAY_BODY = 'Panel_app_body'
, SHOW = 'layui-show', LAY_BODY = 'Panel_app_body'
//构造器
, Class = function (id) {
this.id = id
this.container = $('#' + (id || LAY_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>')
)
elem.append(this.elemLoad = $('<i class="layui-anim layui-anim-rotate layui-anim-loop layui-icon layui-icon-loading layadmin-loading"></i>'))
}
//移除加载
@@ -39,8 +33,7 @@ layui.define(['laytpl', 'layer'], function (exports) {
view.exit = function () {
//清空本地记录的 token
layui.data(setter.tableName, {
key: setter.request.tokenName
, remove: true
key: setter.request.tokenName, remove: true
})
//跳转到登入页
@@ -49,43 +42,29 @@ layui.define(['laytpl', 'layer'], function (exports) {
//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
: ''
}
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
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] || '')
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] || '')
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
return $.ajax($.extend({
type: 'get'
, dataType: 'json'
, success: function (res) {
type: 'get', dataType: 'json', success: function (res) {
var statusCode = response.statusCode
//只有 response 的 code 一切正常才执行 done
@@ -100,21 +79,40 @@ layui.define(['laytpl', 'layer'], function (exports) {
//其它异常
else {
var errorText = [
'<cite>Error</cite> ' + (res[response.msgName] || '返回状态码异常')
, debug()
].join('')
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) {
var errorText = [
'请求异常,请重试<br><cite>错误信息:</cite>' + code
, debug()
].join('')
}, 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)
@@ -124,21 +122,20 @@ layui.define(['laytpl', 'layer'], function (exports) {
//弹窗
view.popup = function (options) {
var success = options.success
, skin = options.skin
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) {
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>&#x1006;</i>')
layero.append(elemClose)
elemClose.on('click', function () {
@@ -152,44 +149,32 @@ layui.define(['laytpl', 'layer'], function (exports) {
//异常提示
view.error = function (content, options) {
return view.popup($.extend({
content: content
, maxWidth: 300
content: content, maxWidth: 300
//,shade: 0.01
, offset: 't'
, anim: 6
, id: 'LAY_adminError'
, 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
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: {
url: views, type: 'get', dataType: 'html', data: {
v: layui.cache.version
}
, success: function (html) {
}, success: function (html) {
html = '<div>' + html + '</div>'
var elemTitle = $(html).find('title')
, title = elemTitle.text() || (html.match(/\<title\>([\s\S]*)\<\/title>/) || [])[1]
var elemTitle = $(html).find('title'),
title = elemTitle.text() || (html.match(/\<title\>([\s\S]*)\<\/title>/) || [])[1]
var res = {
title: title
, body: html
title: title, body: html
}
elemTitle.remove()
@@ -208,8 +193,7 @@ layui.define(['laytpl', 'layer'], function (exports) {
delete that.done
}
}
, error: function (e) {
}, error: function (e) {
view.removeLoad()
if (that.render.isError) {
@@ -230,26 +214,22 @@ layui.define(['laytpl', 'layer'], function (exports) {
//解析模板
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)
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()
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()
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())
@@ -259,11 +239,10 @@ layui.define(['laytpl', 'layer'], function (exports) {
//遍历模板区块
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) //接口请求的头信息
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 + ';')()
@@ -281,23 +260,20 @@ layui.define(['laytpl', 'layer'], function (exports) {
if (url) {
view.req({
type: dataElem.attr('lay-type') || 'get'
, url: url
, data: data
, dataType: 'json'
, headers: headers
, success: function (res) {
type: dataElem.attr('lay-type') || 'get',
url: url,
data: data,
dataType: 'json',
headers: headers,
success: function (res) {
fn({
dataElem: dataElem
, res: res
, done: layDone
dataElem: dataElem, res: res, done: layDone
})
}
})
} else {
fn({
dataElem: dataElem
, done: layDone
dataElem: dataElem, done: layDone
})
}
}())
@@ -315,9 +291,7 @@ layui.define(['laytpl', 'layer'], function (exports) {
//局部刷新模板
Class.prototype.refresh = function (callback) {
var that = this
, next = that.container.next()
, templateid = next.attr('lay-templateid')
var that = this, next = that.container.next(), templateid = next.attr('lay-templateid')
if (that.id != templateid) return that

View File

@@ -34,13 +34,13 @@ layui.define(['all'], function (exports) {
statusName: 'code', // 数据状态的字段名称
statusCode: {
ok: 0, // 数据状态一切正常的状态码
logout: 1001 // 登录状态失效的状态码
logout: 401 // 登录状态失效的状态码
}, msgName: 'message', // 状态信息的字段名称
dataName: 'data' // 数据详情的字段名称
},
// 独立页面路由,可随意添加(无需写参数)
indPage: ['/user/login', // 登入页
indPage: ['/login', // 登入页
],
// 配置业务模块目录中的特殊模块

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -1,160 +0,0 @@
/**
* 内容系统 demo
*/
layui.define(['table', 'form'], function (exports) {
var $ = layui.$
, admin = layui.admin
, view = layui.view
, table = layui.table
, form = layui.form
//文章管理
table.render({
elem: '#LAY-app-content-list'
, url: './res/json/content/list.js' //模拟接口
, cols: [[
{ type: 'checkbox', fixed: 'left' }
, { field: 'id', width: 100, title: '文章ID', sort: true }
, { field: 'label', title: '文章标签', minWidth: 100 }
, { field: 'title', title: '文章标题' }
, { field: 'author', title: '作者' }
, { field: 'uploadtime', title: '上传时间', sort: true }
, { field: 'status', title: '发布状态', templet: '#buttonTpl', minWidth: 80, align: 'center' }
, { title: '操作', minWidth: 150, align: 'center', fixed: 'right', toolbar: '#table-content-list' }
]]
, page: true
, limit: 10
, limits: [10, 15, 20, 25, 30]
, text: '对不起,加载出现异常!'
})
//工具条
table.on('tool(LAY-app-content-list)', function (obj) {
var data = obj.data
if (obj.event === 'del') {
layer.confirm('确定删除此文章?', function (index) {
obj.del()
layer.close(index)
})
} else if (obj.event === 'edit') {
admin.popup({
title: '编辑文章'
, area: ['550px', '550px']
, id: 'LAY-popup-content-edit'
, success: function (layero, index) {
view(this.id).render('app/content/listform', data).done(function () {
form.render(null, 'layuiadmin-app-form-list')
//提交
form.on('submit(layuiadmin-app-form-submit)', function (data) {
var field = data.field //获取提交的字段
//提交 Ajax 成功后,关闭当前弹层并重载表格
//$.ajax({});
layui.table.reload('LAY-app-content-list') //重载表格
layer.close(index) //执行关闭
})
})
}
})
}
})
//分类管理
table.render({
elem: '#LAY-app-content-tags'
, url: './res/json/content/tags.js' //模拟接口
, cols: [[
{ type: 'numbers', fixed: 'left' }
, { field: 'id', width: 100, title: 'ID', sort: true }
, { field: 'tags', title: '分类名', minWidth: 100 }
, { title: '操作', width: 150, align: 'center', fixed: 'right', toolbar: '#layuiadmin-app-cont-tagsbar' }
]]
, text: '对不起,加载出现异常!'
})
//工具条
table.on('tool(LAY-app-content-tags)', function (obj) {
var data = obj.data
if (obj.event === 'del') {
layer.confirm('确定删除此分类?', function (index) {
obj.del()
layer.close(index)
})
} else if (obj.event === 'edit') {
admin.popup({
title: '编辑分类'
, area: ['450px', '200px']
, id: 'LAY-popup-content-tags'
, success: function (layero, index) {
view(this.id).render('app/content/tagsform', data).done(function () {
form.render(null, 'layuiadmin-form-tags')
//提交
form.on('submit(layuiadmin-app-tags-submit)', function (data) {
var field = data.field //获取提交的字段
//提交 Ajax 成功后,关闭当前弹层并重载表格
//$.ajax({});
layui.table.reload('LAY-app-content-tags') //重载表格
layer.close(index) //执行关闭
})
})
}
})
}
})
//评论管理
table.render({
elem: '#LAY-app-content-comm'
, url: './res/json/content/comment.js' //模拟接口
, cols: [[
{ type: 'checkbox', fixed: 'left' }
, { field: 'id', width: 100, title: 'ID', sort: true }
, { field: 'reviewers', title: '评论者', minWidth: 100 }
, { field: 'content', title: '评论内容', minWidth: 100 }
, { field: 'commtime', title: '评论时间', minWidth: 100, sort: true }
, { title: '操作', width: 150, align: 'center', fixed: 'right', toolbar: '#table-content-com' }
]]
, page: true
, limit: 10
, limits: [10, 15, 20, 25, 30]
, text: '对不起,加载出现异常!'
})
//工具条
table.on('tool(LAY-app-content-comm)', function (obj) {
var data = obj.data
if (obj.event === 'del') {
layer.confirm('确定删除此条评论?', function (index) {
obj.del()
layer.close(index)
})
} else if (obj.event === 'edit') {
admin.popup({
title: '编辑评论'
, area: ['450px', '300px']
, id: 'LAY-popup-content-comm'
, success: function (layero, index) {
view(this.id).render('app/content/contform', data).done(function () {
form.render(null, 'layuiadmin-form-comment')
//提交
form.on('submit(layuiadmin-app-com-submit)', function (data) {
var field = data.field //获取提交的字段
//提交 Ajax 成功后,关闭当前弹层并重载表格
//$.ajax({});
layui.table.reload('LAY-app-content-comm') //重载表格
layer.close(index) //执行关闭
})
})
}
})
}
})
exports('contlist', {})
})

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@
<div class="layadmin-user-login-main">
<div class="layadmin-user-login-box layadmin-user-login-header">
<h2 id="login-panel-name">{{ config('panel.name') }}</h2>
<h2 id="panel-login-name">加载中...</h2>
<p></p>
</div>
<div class="layadmin-user-login-box layadmin-user-login-body layui-form">
@@ -24,7 +24,6 @@
placeholder="密码" class="layui-input">
</div>
<div class="layui-form-item" style="margin-bottom: 20px;">
{{--<input type="checkbox" name="remember" id="remember" lay-skin="primary" title="记住我">--}}
<a target="_blank" href="https://jq.qq.com/?_wv=1027&amp;k=I1oJKSTH" class="layadmin-user-jump-change layadmin-link"
style="margin-top: 7px;">忘记密码?</a>
</div>
@@ -42,7 +41,7 @@
</div>
<script>
layui.use(['admin', 'form', 'user'], function () {
layui.use(['admin', 'form'], function () {
let $ = layui.$
, setter = layui.setter
, admin = layui.admin
@@ -50,6 +49,9 @@
, router = layui.router()
, search = router.search;
// 设置面板名称
$('#panel-login-name').text(panel_name);
// 判断并清除定时器
if (typeof home_timer !== 'undefined') {
clearInterval(home_timer);

View File

@@ -11,6 +11,10 @@ import (
func Web() {
facades.Route().Prefix("api/panel").Group(func(r route.Route) {
r.Prefix("info").Group(func(r route.Route) {
infoController := controllers.NewInfoController()
r.Get("name", infoController.Name)
})
r.Prefix("user").Group(func(r route.Route) {
userController := controllers.NewUserController()
r.Post("login", userController.Login)