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

This commit is contained in:
ywxapp
2026-08-16 16:54:14 +08:00
commit 6c1a106bc1
1808 changed files with 238144 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

@@ -0,0 +1,45 @@
/*
* @Author: YwxApp <ywx@ywxapp.cn>
* @Date: 2026-08-06 23:41:01
* @LastEditors: YwxApp <ywx@ywxapp.cn>
* @LastEditTime: 2026-08-06 23:43:05
* @Description:
* @FilePath: \ywxapp_dev\public\static\backend\json\console\prograss.js
* @CustomString: Copyright (c) 2026 YwxApp
*/
{
"code": 0
,"msg": ""
,"count": "100"
,"data": [{
"prograss": "开会"
,"time": "一小时"
,"complete": "已完成"
,"LAY_CHECKED": true
},{
"prograss": "项目开发"
,"time": "两小时"
,"complete": "进行中"
,"LAY_CHECKED": true
},{
"prograss": "陪吃饭"
,"time": "一小时"
,"complete": "未完成"
},{
"prograss": "修改小bug"
,"time": "半小时"
,"complete": "未完成"
},{
"prograss": "修改大bug"
,"time": "两小时"
,"complete": "未完成"
},{
"prograss": "修改小bug"
,"time": "半小时"
,"complete": "未完成"
},{
"prograss": "修改大bug"
,"time": "两小时"
,"complete": "未完成"
}]
}
+196
View File
@@ -0,0 +1,196 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('ad');
var positionMap = {
'home_top': '首页顶部横幅',
'home_side': '首页侧边',
'popup': '全站弹窗',
'list_bottom': '列表底部',
'home_bottom': '首页底部',
'content_top': '内容页顶部',
'content_bottom': '内容页底部',
'sidebar': '通用侧边栏',
'float': '全站悬浮角标'
};
var typeMap = { 1: '图片', 2: '文字', 3: '代码' };
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'title', minWidth: 160, title: '标题' },
{ field: 'position', width: 120, title: '广告位', templet: function (d) { return positionMap[d.position] || d.position || '-'; } },
{ field: 'type', width: 100, title: '类型', templet: function (d) { return typeMap[d.type] || d.type; } },
{ field: 'sort', width: 100, title: '排序', sort: true },
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
{ field: 'create_time', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title, position: data.field.position } });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name=\"title\"]').val('');
$('select[name=\"position\"]').val('');
form.render('select');
table.reload('dataTable', { page: { curr: 1 }, where: { title: '', position: '' } });
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate': active.dataCreate({}); break;
case 'dataDelete':
var check = table.checkStatus('dataTable').data;
active.dataDelete(check.map(function (i) { return i.id; }));
break;
case 'dataRecybin': active.dataRecybin(); break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update': active.dataEdit(data); break;
case 'delete': active.dataDelete([data.id]); break;
}
});
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
http.put('update', { id: this.value, status: status })
.then(function (res) {
if (res.code === 0) { layer.msg('操作成功'); }
else { layer.msg(res.msg || '操作失败'); }
table.reload('dataTable', {}, true);
})
.catch(function () { table.reload('dataTable', {}, true); });
});
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑站点广告' : '添加站点广告';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
id: 'adFormLayer', title: title, content: formHtml, anim: "slideLeft", offset: "r",
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
success: function (layero, index) { callback(layero, index); form.render(); },
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
var active = {
dataDelete: function (ids, force) {
if (ids.length === 0) { return layer.msg('请选择数据'); }
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
});
},
dataCreate: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
if (field.status === undefined) field.status = 0;
field.status = field.status ? 1 : 0;
http.post('save', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataEdit: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
http.put('update', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataRecybin: function () {
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
layer.open({
id: 'adRecybinLayer', title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
success: function () {
table.render({
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '标题', minWidth: 160, fixed: 'left' },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data) {
http.put("restore", { ids: data.id }).then(function (res) {
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '恢复失败'); }
});
},
dataForceDelete: function (data) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
};
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore': active.dataRestore(data); break;
case 'forcedelete': active.dataForceDelete(data); break;
}
});
exports('ad', {});
});
+259
View File
@@ -0,0 +1,259 @@
layui.define(['http', 'setter', 'auth', 'upload', 'form', 'layer', 'table'], function (exports) {
var table = layui.table, form = layui.form, layer = layui.layer, $ = layui.$, upload = layui.upload, http = layui.http
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('addon');
var ADDON_DEV = window.ADDON_DEV || 0;
// 清空后台侧栏菜单的本地缓存(Layui data 存储于 setter.appName 下,键为 'menus')。
// 插件卸载/安装/启停会改变 admin_power 菜单,必须清掉缓存让侧栏重新向后端拉取,
// 否则侧栏会一直显示(或一直缺)已变更插件的菜单。
function clearMenuCache() {
var appName = (layui.setter && layui.setter.appName) || 'backend';
layui.data(appName, { key: 'menus', remove: true });
// 兼容旧键名(历史版本曾写入 'menu'
layui.data(appName, { key: 'menu', remove: true });
}
// ===== 渲染核心表格 =====
var { access_token, refresh_token } = layui.setter.getTokens();
table.render({
elem: '#dataTable'
, url: "index" // 此处应填写你真实的后端接口地址
, cols: [[
{ field: 'title', title: '插件名称', minWidth: 180 },
{ field: 'name', title: '标识', width: 120 },
{ field: 'author', title: '开发者', width: 120 }
, { field: 'version', title: '版本号', width: 100, align: 'center' }
, { field: 'description', title: '功能描述', minWidth: 250 }
, { field: 'status', title: '运行状态', width: 110, align: 'center', templet: '#switchTpl' } // 绑定开关模板
, { fixed: 'right', title: '操作', toolbar: '#operateTpl', width: 300, align: 'right' } // 绑定操作栏模板
]]
, page: true // 开启分页
, limit: 10
, limits: [10, 20, 50]
, skin: 'line' // 设定表格风格为行边框风格
, response: {
statusName: 'code' // 状态码字段
, statusCode: 0 // 成功状态码
, msgName: 'message' // 提示信息字段(后端返回 message)
, countName: 'count' // 数据总数字段
, dataName: 'data' // 数据列表字段
}
, done: function (res, curr, count) {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
// 开发模式关闭时隐藏操作列的「设计」按钮
// if (!ADDON_DEV) { $('.dev-design').remove(); }
}
});
// ===== 事件绑定(提前到这里:即便下方 upload/form 初始化出错,行内按钮依然可用) =====
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate':
active.dataCreate({ pid: 0, type: 1 });
break;
case 'dataRecybin':
active.dataRecybin();
break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
// 插件标识:优先用 name,缺失时回退到 id(后端 index 两种都返回)
var addonName = data.name || data.id || '';
switch (elem.event) {
case 'update':
active.dataEdit(data);
break;
case 'config':
if (!addonName) { layer.msg('缺少插件标识', { icon: 2 }); break; }
location.href = 'setting?addon=' + encodeURIComponent(addonName);
break;
case 'uninstall':
if (!addonName) { layer.msg('缺少插件标识', { icon: 2 }); break; }
active.uninstall(addonName);
break;
case 'more':
var that = this;
var dropdown = layui.dropdown;
// 水平对齐方式
dropdown.render({
elem: that,
align: 'center', // align 已配置在元素 `lay-options` 属性上
show: true,accordion : true,
data: [{
title: '设计',
id: 'design'
}, {
title: '打包',
id: 'pack'
}, {
title: '发布',
id: 'submitOfficial'
}],
click: function (data, othis) {
switch (data.id) {
case 'pack':
// 触发后端 addon::pack 下载该插件的 zip 包(addon/temp/<name>-<version>.zip
if (!addonName) { layer.msg('缺少插件标识', { icon: 2 }); break; }
window.location.href = 'pack?name=' + encodeURIComponent(addonName);
break;
case 'design':
if (!addonName) { layer.msg('缺少插件标识', { icon: 2 }); break; }
location.href = 'design?addon=' + encodeURIComponent(addonName);
break;
case 'submitOfficial':
// 发布到官方市场:打包本机已装插件并 POST 到官方提交接口,进入待审核
if (!addonName) { layer.msg('缺少插件标识', { icon: 2 }); break; }
layer.confirm('确定将「' + (data.title || addonName) + '」发布到官方市场吗?\n提交后需官方审核通过才公开上架。', function (index) {
layer.close(index);
var loadIdx = layer.load(1, { shade: [0.3, '#fff'] });
http.post('submitOfficial', { name: addonName })
.then(function (res) {
layer.close(loadIdx);
if (res.code === 0) {
layer.msg(res.message || '已提交,等待官方审核', { icon: 1 });
} else {
layer.msg(res.message || res.msg || '提交失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loadIdx);
layer.msg('请求失败', { icon: 2 });
});
});
break;
default:
break;
}
},
});
break;
case 'default':
console.warn('未处理的操作事件:', elem.event, data);
}
});
// 顶部功能按钮 + 行内操作共用
var active = {
uninstall: function (name) {
layer.prompt({
formType: 1
, title: '敏感操作,请验证口令'
}, function (value, index) {
layer.close(index);
http.delete('uninstall', { name: name })
.then((res) => {
if (res.code === 0) {
layer.close(index);
clearMenuCache(); // 插件菜单已删除,清掉侧栏菜单缓存
location.reload(); // 重新加载整页,侧栏立即刷新
} else {
layer.msg(res.msg || '操作失败');
}
});
});
},
batchDel: function () { // 批量卸载
var checkStatus = table.checkStatus('dataTable');
var data = checkStatus.data;
if (data.length === 0) {
layer.msg('请至少选中一项进行卸载', { icon: 0 });
return;
}
layer.confirm('确定要批量卸载选中的 ' + data.length + ' 个插件吗?', function (index) {
layer.msg('正在批量卸载...', { icon: 1 });
table.reload('dataTable');
layer.close(index);
});
},
refresh: function () { // 刷新表格
table.reload('dataTable');
layer.msg('已刷新列表', { icon: 1 });
}
};
$('.layui-btn').on('click', function () {
var type = $(this).data('type');
active[type] && active[type].call(this);
});
console.log(layui.setter.getTokens());
var inst = upload.render({
elem: '#buttonInstall',
field: 'file',
url: "upload", // 上传接口地址
accept: 'file', // 只允许上传文件
// 注意:不要设置 acceptMime。该属性会让浏览器文件选择框按 MIME 过滤,
// 而 zip 在本机常被识别为 application/x-zip-compressed / application/octet-stream
// 导致选择框中插件包被置灰、无法选中。仅用 exts 在选完后校验后缀即可。
exts: 'zip', // 仅允许 zip 插件包(后端 AddonService 只支持 zip
headers: { 'Authorization': `Bearer ${access_token}` }, // 鉴权
done: function (res) {
// 上传成功的回调
if (res.code == 0) {
layer.msg('插件安装成功!', { icon: 1 });
clearMenuCache(); // 插件菜单已变化,清掉侧栏菜单缓存
location.reload(); // 重新加载整页,侧栏立即刷新
} else {
layer.msg('安装失败: ' + res.message, { icon: 2 });
}
},
error: function () {
// 上传失败的回调
// 当上传失败时,可在此处生成「重新上传」按钮,并执行该方法重新触发上传提交
/*
$('#btn').on('click', function(){
inst.upload();
})
*/
}
});
// ===== 监听顶部搜索表单提交 =====
form.on('submit(searchBtn)', function (data) {
var field = data.field; // 获取搜索表单的值
// 重载表格,将搜索条件传给后端
table.reload('dataTable', {
where: field,
page: { curr: 1 } // 搜索后回到第一页
});
return false; // 阻止表单默认跳转
});
// ===== 监听状态开关(启用/停用)的切换 =====
form.on('switch(statusSwitch)', function (obj) {
var name = this.value; // value 绑定的是插件名 d.id
var status = obj.elem.checked ? 1 : 0; // 根据开关状态赋值
var action = status ? 'enable' : 'disable';
var that = obj.othis;
http.post('toggle', { name: name, action: action })
.then(function (res) {
if (res.code === 0) {
layer.msg(status ? '已启用' : '已停用', { icon: 1 });
clearMenuCache(); // 菜单可见性已变化,清掉侧栏菜单缓存(下次导航即刷新)
} else {
layer.msg(res.message || '操作失败', { icon: 2 });
that.find('input').prop('checked', !status);
form.render();
}
})
.catch(function () {
layer.msg('请求失败', { icon: 2 });
that.find('input').prop('checked', !status);
form.render();
});
});
exports('addon', {}); // 输出模块接口
});
+410
View File
@@ -0,0 +1,410 @@
layui.define(['http', 'layer', 'laydate', 'util', 'auth'], function (exports) {
var $ = layui.$
, table = layui.table
, form = layui.form
, layer = layui.layer
, laydate = layui.laydate
, util = layui.util
, http = layui.http
, laytpl = layui.laytpl; var auth = layui.auth;
// 使用登录时后端返回的真实权限(已存入 layui.data),并以当前控制器解析裸动作 token
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('admin');
var dataTable = table.render({
elem: '#dataTable'
, url: "index" // 后端数据接口
, page: true
, limit: 15
//, toolbar: '#tableBar'
// , defaultToolbar: auth.renderToolbar(tableActions)
, cols: [[
{ type: 'checkbox', fixed: 'left' }
, { field: 'id', title: 'ID', width: 72, align: 'center', sort: true, fixed: 'left' }
, { field: 'account', title: '账户', width: 120, align: 'center', fixed: 'left' }
, { field: 'nickname', title: '昵称', width: 100, align: 'center' }
// , { field: 'role_id', title: '角色', width: 100, align: 'center', templet: '#roleTpl' }
, { field: 'email', title: '邮箱', minWidth: 180, align: 'center' }
, { field: 'mobile', title: '手机', width: 120, align: 'center' }
, { field: 'login_info', title: '登录信息', width: 160, align: 'center', templet: '#loginInfoTpl' }
, { field: 'status', title: '状态', width: 90, align: 'center', templet: '#statusTpl', unresize: true }
, { field: 'create_at', title: '创建时间', width: 160, align: 'center', sort: true }
, { title: '操作', width: 120, align: 'left', toolbar: '#dataBar', fixed: 'right', unresize: true }
]],
done: function (res, curr, count) {
// 行内按钮按真实权限显隐(data-perm 为完整权限 key,如 admin:edit
$('#dataTable').next('.layui-table-view').find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) {
$(this).remove();
}
});
}
});
// 搜索
form.on('submit(searchBtn)', function (data) {
adminTable.reload({
where: data.field,
page: { curr: 1 }
});
return false;
});
// 状态开关
form.on('switch(statusSwitch)', function (obj) {
var id = this.value;
var status = obj.elem.checked ? 1 : 0;
layer.confirm('确定要' + (status ? '启用' : '禁用') + '该管理员账号吗?', function (index) {
layui.request.post('update', { id: id, status: status }
).then(function (res) {
if (res.code === 0) {
layer.msg(res.msg, { icon: 1 });
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg, { icon: 2 });
obj.elem.checked = !obj.elem.checked;
form.render('checkbox');
}
});
layer.close(index);
}, function () {
obj.elem.checked = !obj.elem.checked;
form.render('checkbox');
});
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate':
active.dataCreate({ pid: 0, type: 1 });
break;
case 'dataDelete':
var checkStatus = table.checkStatus('dataTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
active.dataDelete(ids);
break;
case 'dataRecybin':
active.dataRecybin();
break;
};
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update':
active.dataEdit(data);
break;
case 'delete':
active.dataDelete([data.id]);
break;
}
});
var dataFromFun = function (data, callback, done) {
var title = data ? '编辑数据[' + data.account + ']' : '添加数据';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: data.id ? '编辑菜单' : (data.pid ? '添加子菜单' : '添加根菜单'),
content: formHtml,
anim: "slideLeft",
offset: "r",
btnAlign: "l",
area: ['50% ', '99%'],
shade: 0.1,
shadeClose: true,
btn: ['确定', '取消'],
success: function (layero, index) {
callback(layero, index);
form.render();
},
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem);
layui.off('submit(wxapp-form)', 'from');
return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
//事件
var active = {
dataDelete: function (ids, force = 0) {
if (ids.length === 0) {
return layer.msg('请选择数据');
}
layer.prompt({
formType: 1
, title: '敏感操作,请验证口令'
}, function (value, index) {
layer.close(index);
layer.confirm('确定删除吗?', function (index) {
http.delete('delete', { ids: ids.join(','), force: force })
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
});
});
},
dataCreate: function (data = {}) {
dataFromFun(data,
function (layero, index) { },
function (layero, index, elem) {
var field = elem.field;
field.icon = 'layui-icon ' + field.icon;
field.status = field.status ? 1 : 0;
http.post('create', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataEdit: function (data = {}) {
dataFromFun(data,
function (layero, index) { },
function (layero, index, elem) {
var field = elem.field;
field.icon = 'layui-icon ' + field.icon;
field.status = field.status ? 1 : 0;
http.put('update', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataRecybin: function (data = {}) {
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
layer.open({
title: '资源回收站',
content: formHtml,
anim: "slideLeft",
offset: "r",
area: ['50%', '99%'],
shade: 0.1,
shadeClose: true,
success: function (layero, index) {
layui.table.render({
elem: '#dataRecybinTable',
url: "recyclebin",
height: 'full-100',
defaultToolbar: [{
title: '批量删除数据',
layEvent: 'dataDelete',
icon: 'layui-icon-delete',
onClick: function (obj) {
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
console.log(ids);
}
}, 'filter', 'exports', 'print'],
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '名称', width: 180, fixed: 'left' },
{ field: 'code', title: '代码', width: 180, fixed: 'left' },
{ field: 'description', title: '描述', minWidth: 200, sort: true },
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true,
done: function (res, curr, count, origin) {
console.log('表格渲染完成');
}
});
}
});
},
dataRestore: function (data = {}) {
http.put("restore", { id: data.id })
.then((res) => {
if (res.code === 0) {
layer.msg('恢复成功');
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '恢复失败');
}
});
}
};
// 打开管理员表单
function opendataForm(data) {
var title = data ? '编辑管理员 [' + data.account + ']' : '添加管理员';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
type: 1,
title: title,
area: ['500px', '520px'],
shadeClose: true,
content: formHtml,
success: function (layero, index) {
// 显示/隐藏密码字段
if (data) {
$('#passwordGroup').hide();
} else {
$('#passwordGroup').show();
}
// 表单验证规则
layui.form.verify({
username: function (value) {
if (!/^[\w\u4e00-\u9fa5]{2,20}$/.test(value)) {
return '用户名必须2-20位字符,支持中文、字母、数字和下划线';
}
},
pass: [
/^[\S]{6,20}$/
, '密码必须6到20位,且不能出现空格'
]
});
// 提交表单
form.on('submit(adminFormSubmit)', function (formData) {
var url = data ? "update" : "create";
$.ajax({
url: url,
type: 'POST',
data: formData.field,
success: function (res) {
if (res.code === 1) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
layer.close(index);
adminTable.reload();
});
} else {
layer.msg(res.msg, { icon: 2 });
}
},
error: function () {
layer.msg('操作失败', { icon: 2 });
}
});
return false;
});
form.render();
},
btn: ['保存', '取消'],
yes: function (index, layero) {
// 触发表单提交
layero.find('form').find('button[lay-filter=adminFormSubmit]').click();
}
});
}
// 重置密码
function resetPassword(data) {
layer.confirm('确定要重置管理员 [' + data.username + '] 的密码吗?重置后密码将变为123456', {
btn: ['确定', '取消'],
title: '重置密码'
}, function (index) {
$.ajax({
url: "resetPassword",
type: 'POST',
data: { id: data.id },
success: function (res) {
layer.close(index);
if (res.code === 1) {
layer.msg(res.msg, { icon: 1 });
} else {
layer.msg(res.msg, { icon: 2 });
}
},
error: function () {
layer.msg('操作失败', { icon: 2 });
}
});
});
}
// 删除管理员
function deleteAdmin(data) {
layer.confirm('确定要删除管理员 [' + data.username + '] 吗?此操作不可恢复!', {
btn: ['确定', '取消'],
title: '删除管理员',
icon: 3
}, function (index) {
$.ajax({
url: "delete",
type: 'POST',
data: { id: data.id },
success: function (res) {
layer.close(index);
if (res.code === 1) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
adminTable.reload();
});
} else {
layer.msg(res.msg, { icon: 2 });
}
},
error: function () {
layer.msg('操作失败', { icon: 2 });
}
});
});
}
// 批量删除
function batchDelete(data) {
if (data.length === 0) {
layer.msg('请先选择要删除的管理员', { icon: 3 });
return;
}
var superAdmins = data.filter(function (item) {
return item.is_super == 1;
});
if (superAdmins.length > 0) {
layer.msg('不能删除超级管理员账号', { icon: 2 });
return;
}
var ids = data.map(function (item) {
return item.id;
});
layer.confirm('确定要删除选中的 ' + data.length + ' 个管理员吗?此操作不可恢复!', {
btn: ['确定', '取消'],
title: '批量删除',
icon: 3
}, function (index) {
$.ajax({
url: "batchDelete",
type: 'POST',
data: { ids: ids },
success: function (res) {
layer.close(index);
if (res.code === 1) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
adminTable.reload();
});
} else {
layer.msg(res.msg, { icon: 2 });
}
},
error: function () {
layer.msg('操作失败', { icon: 2 });
}
});
});
}
exports('admin', {});
});
+281
View File
@@ -0,0 +1,281 @@
layui.define(['http', 'setter', 'auth', 'form'], function (exports) {
var $ = layui.$, layer = layui.layer, http = layui.http, auth = layui.auth, form = layui.form;
var _perms = (layui.data('backend').permission) || [];
auth.init(_perms);
auth.setController('addon');
var isDemo = false;
function escapeHtml(s) {
return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
});
}
function priceText(p) {
p = Number(p) || 0;
return p > 0 ? '¥' + p : '免费';
}
function cardHtml(item) {
var logo = item.logo
? '<img src="' + escapeHtml(item.logo) + '" class="m-logo">'
: '<div class="m-logo m-logo-default">' + escapeHtml((item.title || '?').charAt(0)) + '</div>';
var action;
if (item.installed) {
var btns = '<button class="layui-btn layui-btn-xs layui-btn-normal" data-act="manage" data-name="' + escapeHtml(item.name) + '">管理</button>';
if (item.upgradable) {
btns = '<button class="layui-btn layui-btn-xs layui-btn-warm" data-act="upgrade" data-name="' + escapeHtml(item.name) + '" data-version="' + escapeHtml(item.version) + '">升级 v' + escapeHtml(item.version) + '</button>' + btns;
}
if (Number(item.price) > 0) {
btns += '<button class="layui-btn layui-btn-xs layui-btn-danger" data-act="refund" data-name="' + escapeHtml(item.name) + '">退款</button>';
}
action = '<button class="layui-btn layui-btn-xs layui-btn-disabled" disabled>已安装</button>' + btns;
} else {
var label = (Number(item.price) > 0 ? '¥' + item.price + ' 购买安装' : '安装');
action = '<button class="layui-btn layui-btn-xs layui-btn-warm" data-act="install" data-name="' + escapeHtml(item.name) + '" data-version="' + escapeHtml(item.version) + '" data-price="' + Number(item.price || 0) + '">' + label + '</button>';
}
return '<div class="market-card">'
+ '<div class="m-head">' + logo + '<div class="m-meta"><div class="m-title">' + escapeHtml(item.title) + '</div><div class="m-author">' + escapeHtml(item.author || '') + ' · v' + escapeHtml(item.version || '') + '</div></div></div>'
+ '<div class="m-intro">' + escapeHtml(item.intro || '') + '</div>'
+ '<div class="m-foot"><span class="m-price ' + (Number(item.price) > 0 ? 'paid' : 'free') + '">' + priceText(item.price) + '</span>' + action + '</div>'
+ '</div>';
}
function render(list) {
var html = (list || []).map(cardHtml).join('');
$('#marketList').html(html || '<div class="empty">暂无可安装的插件</div>');
// 权限控制:无安装权限则隐藏安装按钮
if (!auth.has('addon:install') && !auth.has('addon:*')) {
$('[data-act="install"]').remove();
}
}
function load() {
http.get('market', {})
.then(function (res) {
if (res.code !== 0) {
layer.msg(res.message || '获取失败', { icon: 2 });
return;
}
isDemo = !!res.data.demo;
render(res.data.list || []);
})
.catch(function () {
layer.msg('请求失败', { icon: 2 });
});
}
$('#marketList').on('click', '[data-act="install"]', function () {
var $btn = $(this);
var name = $btn.data('name');
var version = $btn.data('version');
var price = Number($btn.data('price')) || 0;
var doInstall = function () {
if (isDemo) {
layer.msg('演示模式:已安装「' + name + '」', { icon: 1 });
$btn.parent().html('<button class="layui-btn layui-btn-xs layui-btn-disabled" disabled>已安装</button><button class="layui-btn layui-btn-xs layui-btn-normal" data-act="manage" data-name="' + name + '">管理</button>');
return;
}
var loading = layer.load();
http.post('downloadInstall', { name: name, version: version })
.then(function (res) {
layer.close(loading);
if (res.code === 0) {
layer.msg('安装成功', { icon: 1 });
load();
} else {
layer.msg(res.message || '安装失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loading);
layer.msg('请求失败', { icon: 2 });
});
};
if (price > 0) {
layer.confirm('该付费插件授权绑定当前站点域名(' + location.host + '),换站点安装将被拒绝。确认在当前站点安装?', { title: '域名授权提示' }, function (idx) {
layer.close(idx);
doInstall();
});
} else {
doInstall();
}
});
$('#marketList').on('click', '[data-act="refund"]', function () {
var $btn = $(this);
var name = $btn.data('name');
layer.confirm('确认对插件「' + name + '」发起退款?退款后授权将被吊销,无法再下载或安装。', function (idx) {
layer.close(idx);
var loading = layer.load();
http.post('refund', { name: name })
.then(function (res) {
layer.close(loading);
if (res.code === 0) {
layer.msg('退款成功,授权已吊销', { icon: 1 });
load();
} else {
layer.msg(res.message || '退款失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loading);
layer.msg('请求失败', { icon: 2 });
});
});
});
$('#marketList').on('click', '[data-act="upgrade"]', function () {
var $btn = $(this);
var name = $btn.data('name');
var version = $btn.data('version');
var loading = layer.load();
http.post('upgrade', { name: name, version: version })
.then(function (res) {
layer.close(loading);
if (res.code === 0) {
layer.msg('升级成功', { icon: 1 });
load();
} else {
layer.msg(res.message || '升级失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loading);
layer.msg('请求失败', { icon: 2 });
});
});
$('#marketList').on('click', '[data-act="manage"]', function () {
var name = $(this).data('name');
if (isDemo) {
layer.msg('演示:进入「' + name + '」后台', { icon: 0 });
return;
}
// 真实模式:跳转到插件自己的后台(约定路径,可按实际调整)
window.open('/' + name);
});
// ===== 发布到本服务器(仅开发模式显示) =====
var isDev = $('#appDebug').val() === '1';
var installedList = [];
if (isDev) {
$('#btnPublish').show();
}
function loadInstalled() {
return http.get('index', { page: 1, limit: 9999 })
.then(function (res) {
if (res.code === 0 && Array.isArray(res.data)) {
installedList = res.data;
}
return installedList;
})
.catch(function () { return []; });
}
$('#btnPublish').on('click', function () {
loadInstalled().then(function (list) {
if (!list.length) {
layer.msg('暂无已安装插件可发布', { icon: 2 });
return;
}
var opts = list.map(function (it) {
return '<option value="' + escapeHtml(it.name) + '">' + escapeHtml(it.title || it.name) + ' v' + escapeHtml(it.version || '') + '</option>';
}).join('');
var html =
'<div style="padding:15px;"><div class="layui-form">'
+ '<div class="layui-form-item"><label class="layui-form-label">选择插件</label><div class="layui-input-block"><select id="pubName" class="layui-input">' + opts + '</select></div></div>'
+ '<div class="layui-form-item"><label class="layui-form-label">标题</label><div class="layui-input-block"><input id="pubTitle" class="layui-input"></div></div>'
+ '<div class="layui-form-item"><label class="layui-form-label">作者</label><div class="layui-input-block"><input id="pubAuthor" class="layui-input"></div></div>'
+ '<div class="layui-form-item"><label class="layui-form-label">简介</label><div class="layui-input-block"><textarea id="pubDesc" class="layui-input" rows="3"></textarea></div></div>'
+ '<div class="layui-form-item"><label class="layui-form-label">价格</label><div class="layui-input-block"><input id="pubPrice" type="number" step="0.01" value="0" class="layui-input"></div></div>'
+ '<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn layui-btn-danger" id="pubSubmit">确认发布到本服务器</button></div></div>'
+ '</div></div>';
layer.open({ type: 1, title: '发布到本服务器市场', area: ['520px', 'auto'], content: html });
// 关键:下拉是动态注入到 .layui-form 内的元素,必须显式 render 才会显示选项,
// 否则 layui 增强后的 select 会显示为空(表现为「选择插件」没有任何内容)。
form.render('select');
function fillMeta() {
var name = $('#pubName').val();
var it = list.filter(function (x) { return x.name === name; })[0] || {};
$('#pubTitle').val(it.title || name);
$('#pubAuthor').val(it.author || '');
$('#pubDesc').val(it.description || it.intro || '');
$('#pubPrice').val(it.price != null ? it.price : 0);
}
fillMeta();
$('#pubName').on('change', fillMeta);
$('#pubSubmit').on('click', function () {
var data = {
name: $('#pubName').val(),
title: $('#pubTitle').val(),
author: $('#pubAuthor').val(),
description: $('#pubDesc').val(),
price: $('#pubPrice').val() || 0
};
var loading = layer.load();
http.post('publish', data)
.then(function (res) {
layer.close(loading);
if (res.code === 0) {
layer.msg('发布成功', { icon: 1 });
layer.closeAll();
load();
} else {
layer.msg(res.message || '发布失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loading);
layer.msg('请求失败', { icon: 2 });
});
});
});
});
// ===== 发布到官方公共市场(需开发者令牌,服务端审核) =====
$('#btnSubmitOfficial').on('click', function () {
loadInstalled().then(function (list) {
if (!list.length) {
layer.msg('暂无已安装插件可发布', { icon: 2 });
return;
}
var opts = list.map(function (it) {
return '<option value="' + escapeHtml(it.name) + '">' + escapeHtml(it.title || it.name) + ' v' + escapeHtml(it.version || '') + '</option>';
}).join('');
var html =
'<div style="padding:15px;"><div class="layui-form">'
+ '<div class="layui-form-item"><label class="layui-form-label">选择插件</label><div class="layui-input-block"><select id="offName" class="layui-input">' + opts + '</select></div></div>'
+ '<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn layui-btn-normal" id="offSubmit">提交审核</button></div></div>'
+ '</div></div>';
layer.open({ type: 1, title: '发布到官方市场(需审核)', area: ['520px', 'auto'], content: html });
form.render('select');
$('#offSubmit').on('click', function () {
var loading = layer.load();
http.post('submitOfficial', { name: $('#offName').val() })
.then(function (res) {
layer.close(loading);
if (res.code === 0) {
layer.msg(res.message || '提交成功,等待审核', { icon: 1 });
layer.closeAll();
} else {
layer.msg(res.message || '提交失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loading);
layer.msg('请求失败', { icon: 2 });
});
});
});
});
load();
exports('market', {});
});
+209
View File
@@ -0,0 +1,209 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('card');
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'cardno', minWidth: 160, title: '卡号' },
{ field: 'amount', width: 100, title: '面值', sort: true },
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
{ field: 'user_name', width: 120, title: '兑换会员' },
{ field: 'use_time_text', width: 180, title: '兑换时间' },
{ field: 'sort', width: 100, title: '排序', sort: true },
{ field: 'create_time', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: { cardno: data.field.cardno, status: data.field.status } });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name=\"cardno\"]').val('');
$('select[name=\"status\"]').val('');
form.render('select');
table.reload('dataTable', { page: { curr: 1 }, where: { cardno: '', status: '' } });
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate': active.dataCreate({}); break;
case 'dataBatch': active.dataBatch(); break;
case 'dataDelete':
var check = table.checkStatus('dataTable').data;
active.dataDelete(check.map(function (i) { return i.id; }));
break;
case 'dataRecybin': active.dataRecybin(); break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update': active.dataEdit(data); break;
case 'delete': active.dataDelete([data.id]); break;
}
});
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
http.put('update', { id: this.value, status: status })
.then(function (res) {
if (res.code === 0) { layer.msg('操作成功'); }
else { layer.msg(res.msg || '操作失败'); }
table.reload('dataTable', {}, true);
})
.catch(function () { table.reload('dataTable', {}, true); });
});
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑充值卡密' : '添加充值卡密';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title, content: formHtml, anim: "slideLeft", offset: "r",
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
success: function (layero, index) { callback(layero, index); form.render(); },
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
var active = {
dataDelete: function (ids, force) {
if (ids.length === 0) { return layer.msg('请选择数据'); }
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
});
},
dataCreate: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
if (field.status === undefined) field.status = 0;
field.status = field.status ? 1 : 0;
http.post('save', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataEdit: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
http.put('update', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataBatch: function () {
var formHtml = laytpl($('#batchFormTpl').html()).render({});
layer.open({
title: '批量生成卡密', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
btn: ['生成', '取消'],
success: function () { form.render(); },
yes: function (index, layero) {
var field = layui.form.val('wxapp-batch-form');
http.post('generate', field).then(function (res) {
if (res.code === 0) {
var resultHtml = laytpl($('#batchResultTpl').html()).render({ list: res.data.list, amount: field.amount });
layer.open({
title: '生成结果', content: resultHtml, area: ['600px', '70%'],
shadeClose: true, btn: ['知道了'],
yes: function (i2) { layer.close(i2); layer.close(index); table.reload('dataTable', {}, true); }
});
} else {
layer.msg(res.msg || '生成失败');
}
}).catch(function (e) { layer.msg('请求失败:' + e); });
}
});
},
dataRecybin: function () {
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
layer.open({
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
success: function () {
table.render({
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'cardno', title: '卡号', minWidth: 160, fixed: 'left' },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data) {
http.put("restore", { ids: data.id }).then(function (res) {
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '恢复失败'); }
});
},
dataForceDelete: function (data) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
};
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore': active.dataRestore(data); break;
case 'forcedelete': active.dataForceDelete(data); break;
}
});
exports('card', {});
});
+94
View File
@@ -0,0 +1,94 @@
layui.define(['http', 'auth', 'table', 'layer'], function (exports) {
var table = layui.table,
layer = layui.layer,
auth = layui.auth,
http = layui.http;
// 权限控制器前缀:与后端 BackendPower.namearticles:backend:category:add 等)对齐
auth.setController('articles:backend:category');
auth.render();
var MODULE = 'articles/backend.category',
FUNC = {
index: MODULE + '/index',
delete: MODULE + '/delete'
};
var obj = {
init: function () {
this.render();
this.events();
},
render: function () {
table.render({
elem: '#table',
url: FUNC.index,
toolbar: '#toolbar',
defaultToolbar: ['filter', 'print', 'exports'],
method: 'get',
cols: [[
{field: 'id', title: 'ID', width: 70, sort: true},
{field: 'name', title: '名称', width: 150},
{field: 'alias', title: '别名', width: 150},
{field: 'description', title: '描述'},
{field: 'sort', title: '排序', width: 80, sort: true},
{field: 'status', title: '状态', width: 90, templet: '#statusTpl'},
{field: 'create_at', title: '创建时间', width: 170, templet: function (d) {
return d.create_at ? layui.util.toDateString(d.create_at * 1000, 'yyyy-MM-dd HH:mm:ss') : '';
}},
{title: '操作', width: 130, templet: '#action', fixed: 'right'}
]],
page: true,
limit: 10,
limits: [10, 20, 50, 100],
response: {statusCode: 0},
parseData: function (res) {
return {
code: res.code,
msg: res.msg,
count: res.count,
data: res.data
};
}
});
},
events: function () {
// 顶部工具条
table.on('toolbar(table)', function (obj) {
var event = obj.event;
if (event === 'add') {
if (!auth.has('add')) return layer.msg('无权限', {icon: 2});
window.location.href = '/articles/backend.category/edit';
}
});
// 行内操作
table.on('tool(table)', function (obj) {
var data = obj.data,
event = obj.event;
if (event === 'edit') {
if (!auth.has('edit')) return layer.msg('无权限', {icon: 2});
window.location.href = '/articles/backend.category/edit/id/' + data.id;
} else if (event === 'del') {
if (!auth.has('delete')) return layer.msg('无权限', {icon: 2});
layer.confirm('确定删除该分类吗?', {title: '提示'}, function (index) {
http.delete(FUNC.delete, {id: data.id}, function (res) {
if (res.code === 0) {
layer.msg(res.msg || '删除成功', {icon: 1});
table.reload('table');
} else {
layer.msg(res.msg || '删除失败', {icon: 2});
}
});
layer.close(index);
});
}
});
}
};
obj.init();
exports('category', obj);
});
+170
View File
@@ -0,0 +1,170 @@
// 原始数据
var formData = [
{
"id": 1,
"name": "site_name",
"group": "basic",
"title": "站点名称",
"tip": "请填写站点名称",
"type": "string",
"value": "YFCMF-TP6",
"content": "",
"rule": "required",
"extend": "",
"setting": ""
},
{
"id": 2,
"name": "beian",
"group": "basic",
"title": "备案号",
"tip": "",
"type": "string",
"value": "",
"content": "",
"rule": "",
"extend": "",
"setting": ""
},
{
"id": 3,
"name": "site_description",
"group": "basic",
"title": "站点描述",
"tip": "请填写站点描述",
"type": "textarea",
"value": "这是一个基于TP6的CMS系统",
"content": "",
"rule": "",
"extend": "",
"setting": ""
},
{
"id": 4,
"name": "site_status",
"group": "advanced",
"title": "站点状态",
"tip": "选择站点是否开启",
"type": "select",
"value": "1",
"content": "开启,关闭,维护中",
"rule": "required",
"extend": "",
"setting": ""
},
{
"id": 5,
"name": "allow_comment",
"group": "advanced",
"title": "允许评论",
"tip": "是否允许访客评论",
"type": "radio",
"value": "1",
"content": "是,否",
"rule": "",
"extend": "",
"setting": ""
},
{
"id": 6,
"name": "features",
"group": "advanced",
"title": "功能模块",
"tip": "选择启用的功能模块",
"type": "checkbox",
"value": "文章,评论",
"content": "文章,评论,用户,统计",
"rule": "",
"extend": "",
"setting": ""
},
{
"id": 7,
"name": "max_upload_size",
"group": "upload",
"title": "最大上传大小",
"tip": "单位:MB",
"type": "number",
"value": "10",
"content": "",
"rule": "required",
"extend": "",
"setting": ""
},
{
"id": 8,
"name": "upload_date",
"group": "upload",
"title": "上传日期限制",
"tip": "选择可上传文件的日期范围",
"type": "date",
"value": "2024-01-01",
"content": "",
"rule": "",
"extend": "",
"setting": ""
}
];
// 处理数据:按group分组
function processData(data) {
var groups = {};
var groupNames = [];
// 收集所有分组
data.forEach(function (item) {
if (!groups[item.group]) {
groups[item.group] = [];
groupNames.push(item.group);
}
groups[item.group].push(item);
});
return {
groups: groupNames,
data: groups
};
}
// 初始化Layui
layui.define(['laytpl', 'form', 'element', 'laydate', 'http'], function (exports) {
var laytpl = layui.laytpl;
var form = layui.form;
var element = layui.element;
var laydate = layui.laydate;
var http = layui.http;
http.get('index').then(respon => {
let respona = processData(respon.data);
var getTpl = document.getElementById('formTpl').innerHTML;
var view = document.getElementById('formView');
laytpl(getTpl).render(respona, function (html) {
view.innerHTML = html;
// 重新渲染表单元素
form.render();
element.render('tab');
// 初始化日期选择器
formData.forEach(function (item) {
if (item.type === 'date') {
laydate.render({
elem: '#date-' + item.id,
format: 'yyyy-MM-dd'
});
}
});
// 监听表单提交
form.on('submit', function (data) {
console.log('表单提交数据:', data.field);
http.post('update', data.field).then(respon => {
console.log(respon)
});
layer.msg('表单提交成功!已输出到控制台');
return false;
});
});
})
// 处理数据
var processedData = processData(formData);
// 渲染模板
exports('configure', {});
});
+295
View File
@@ -0,0 +1,295 @@
/**
* console - homepage demo
*/
layui.define('ywxapp',function (exports) {
var ywxapp = layui.ywxapp;
//区块轮播切换
layui.use(['ywxapp', 'carousel'], function () {
var $ = layui.$
, ywxapp = layui.ywxapp
, carousel = layui.carousel
, element = layui.element
, device = layui.device();
//轮播切换
$('.layadmin-carousel').each(function () {
var othis = $(this);
carousel.render({
elem: this
, width: '100%'
, arrow: 'none'
, interval: othis.data('interval')
, autoplay: othis.data('autoplay') === true
, trigger: (device.ios || device.android) ? 'click' : 'hover'
, anim: othis.data('anim')
});
});
element.render('progress');
});
//八卦新闻
layui.use(['carousel', 'echarts'], function () {
var $ = layui.$
, carousel = layui.carousel
, echarts = layui.echarts;
var echartsApp = [], options = [
{
title: {
subtext: '完全实况球员数据',
textStyle: {
fontSize: 14
}
},
tooltip: {
trigger: 'axis'
},
legend: {
x: 'left',
data: ['罗纳尔多', '舍普琴科']
},
polar: [
{
indicator: [
{ text: '进攻', max: 100 },
{ text: '防守', max: 100 },
{ text: '体能', max: 100 },
{ text: '速度', max: 100 },
{ text: '力量', max: 100 },
{ text: '技巧', max: 100 }
],
radius: 130
}
],
series: [
{
type: 'radar',
center: ['50%', '50%'],
itemStyle: {
normal: {
areaStyle: {
type: 'default'
}
}
},
data: [
{ value: [97, 42, 88, 94, 90, 86], name: '舍普琴科' },
{ value: [97, 32, 74, 95, 88, 92], name: '罗纳尔多' }
]
}
]
}
]
, elemDataView = $('#LAY-index-pageone').children('div')
, renderDataView = function (index) {
echartsApp[index] = echarts.init(elemDataView[index], layui.echartsTheme);
echartsApp[index].setOption(options[index]);
window.onresize = echartsApp[index].resize;
};
//没找到DOM,终止执行
if (!elemDataView[0]) return;
renderDataView(0);
});
//访问量
layui.use(['carousel', 'echarts'], function () {
var $ = layui.$
, carousel = layui.carousel
, echarts = layui.echarts;
var echartsApp = [], options = [
{
tooltip: {
trigger: 'axis'
},
calculable: true,
legend: {
data: ['访问量', '下载量', '平均访问量']
},
xAxis: [
{
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
}
],
yAxis: [
{
type: 'value',
name: '访问量',
axisLabel: {
formatter: '{value} 万'
}
},
{
type: 'value',
name: '下载量',
axisLabel: {
formatter: '{value} 万'
}
}
],
series: [
{
name: '访问量',
type: 'line',
data: [900, 850, 950, 1000, 1100, 1050, 1000, 1150, 1250, 1370, 1250, 1100]
},
{
name: '下载量',
type: 'line',
yAxisIndex: 1,
data: [850, 850, 800, 950, 1000, 950, 950, 1150, 1100, 1240, 1000, 950]
},
{
name: '平均访问量',
type: 'line',
data: [870, 850, 850, 950, 1050, 1000, 980, 1150, 1000, 1300, 1150, 1000]
}
]
}
]
, elemDataView = $('#LAY-index-pagetwo').children('div')
, renderDataView = function (index) {
echartsApp[index] = echarts.init(elemDataView[index], layui.echartsTheme);
echartsApp[index].setOption(options[index]);
window.onresize = echartsApp[index].resize;
};
//没找到DOM,终止执行
if (!elemDataView[0]) return;
renderDataView(0);
});
//地图
layui.use(['carousel', 'echarts'], function () {
var $ = layui.$
, carousel = layui.carousel
, echarts = layui.echarts;
var echartsApp = [], options = [
{
title: {
text: '访客地区分布',
subtext: '不完全统计'
},
tooltip: {
trigger: 'item'
},
dataRange: {
orient: 'horizontal',
min: 0,
max: 60000,
text: ['高', '低'],
splitNumber: 0
},
series: [
{
name: '访客地区分布',
type: 'map',
mapType: 'china',
selectedMode: 'multiple',
itemStyle: {
normal: { label: { show: true } },
emphasis: { label: { show: true } }
},
data: [
{ name: '西藏', value: 60 },
{ name: '青海', value: 167 },
{ name: '宁夏', value: 210 },
{ name: '海南', value: 252 },
{ name: '甘肃', value: 502 },
{ name: '贵州', value: 570 },
{ name: '新疆', value: 661 },
{ name: '云南', value: 8890 },
{ name: '重庆', value: 10010 },
{ name: '吉林', value: 5056 },
{ name: '山西', value: 2123 },
{ name: '天津', value: 9130 },
{ name: '江西', value: 10170 },
{ name: '广西', value: 6172 },
{ name: '陕西', value: 9251 },
{ name: '黑龙江', value: 5125 },
{ name: '内蒙古', value: 1435 },
{ name: '安徽', value: 9530 },
{ name: '北京', value: 51919 },
{ name: '福建', value: 3756 },
{ name: '上海', value: 59190 },
{ name: '湖北', value: 37109 },
{ name: '湖南', value: 8966 },
{ name: '四川', value: 31020 },
{ name: '辽宁', value: 7222 },
{ name: '河北', value: 3451 },
{ name: '河南', value: 9693 },
{ name: '浙江', value: 62310 },
{ name: '山东', value: 39231 },
{ name: '江苏', value: 35911 },
{ name: '广东', value: 55891 }
]
}
]
}
]
, elemDataView = $('#LAY-index-pagethree').children('div')
, renderDataView = function (index) {
echartsApp[index] = echarts.init(elemDataView[index], layui.echartsTheme);
echartsApp[index].setOption(options[index]);
window.onresize = echartsApp[index].resize;
};
//没找到DOM,终止执行
if (!elemDataView[0]) return;
renderDataView(0);
});
//项目进展
layui.use('table', function () {
var $ = layui.$
, table = layui.table;
table.render({
elem: '#LAY-index-prograss'
, url: layui.setter.paths.base + 'json/console/prograss.js' //模拟接口
, cols: [[
{ type: 'checkbox', fixed: 'left' }
, { field: 'prograss', title: '任务' }
, { field: 'time', title: '所需时间' }
, {
field: 'complete', title: '完成情况'
, templet: function (d) {
if (d.complete == '已完成') {
return '<del style="color: #16b777;">' + d.complete + '</del>'
} else if (d.complete == '进行中') {
return '<span style="color: #FFB800;">' + d.complete + '</span>'
} else {
return '<span style="color: #FF5722;">' + d.complete + '</span>'
}
}
}
]]
, skin: 'line'
});
});
console.log('进入控制台',layui.ywxapp);
//回复留言
ywxapp.events.replyNote = function (othis) {
var nid = othis.data('id');
layer.prompt({
title: '回复留言 ID:' + nid
, formType: 2
}, function (value, index) {
//这里可以请求 Ajax
//…
layer.msg('得到:' + value);
layer.close(index);
});
};
exports('console', {})
});
+298
View File
@@ -0,0 +1,298 @@
layui.define(['http', 'auth'], function (exports) {
var $ = layui.$, table = layui.table, form = layui.form, layer = layui.layer
, laydate = layui.laydate, laytpl = layui.laytpl, tree = layui.tree, http = layui.http
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('group');
var dataTable = table.render({
elem: '#dataTable'
, url: 'index' // 后端数据接口
, page: true
, limit: 15
, toolbar: '#tableBarTpl'
, cols: [[
{ type: 'checkbox', fixed: 'left' }
, { field: 'id', title: 'ID', width: 60, align: 'center', sort: true, fixed: 'left' }
, { field: 'title', title: '名称', width: 150, align: 'center', fixed: 'left' }
, { field: 'name', title: '代码', width: 150, align: 'center', fixed: 'left' }
, { field: 'description', title: '描述', minWidth: 200, align: 'left' }
, { field: 'status', title: '状态', width: 120, align: 'center', templet: '#statusTpl' }
, { field: 'create_time', title: '创建时间', width: 160, align: 'center', sort: true }
, { title: '操作', width: 160, align: 'left', toolbar: '#dataBarTpl', fixed: 'right', unresize: true }
]]
, done: function (res, curr, count) {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate':
active.dataCreate({ pid: 0, type: 1 });
break;
case 'dataDelete':
var checkStatus = table.checkStatus('dataTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
active.dataDelete(ids);
break;
case 'dataRecybin':
active.dataRecybin();
break;
};
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update':
active.dataEdit(data);
break;
case 'permission':
openPermissionForm(data);
break;
case 'delete':
active.dataDelete([data.id]);
break;
}
});
var dataFromFun = function (data, callback, done) {
var title = data ? '编辑数据[' + data.account + ']' : '添加数据';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: data.id ? '编辑菜单' : (data.pid ? '添加子菜单' : '添加根菜单'),
content: formHtml,
anim: "slideLeft",
offset: "r",
btnAlign: "l",
area: ['50% ', '99%'],
shade: 0.1,
shadeClose: true,
btn: ['确定', '取消'],
success: function (layero, index) {
callback(layero, index);
form.render();
},
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem);
layui.off('submit(wxapp-form)', 'from');
return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
//事件
var active = {
dataDelete: function (ids, force = 0) {
if (ids.length === 0) {
return layer.msg('请选择数据');
}
layer.prompt({
formType: 1
, title: '敏感操作,请验证口令'
}, function (value, index) {
layer.close(index);
layer.confirm('确定删除吗?', function (index) {
http.delete("delete", { ids: ids.join(','), force: force })
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
});
});
},
dataCreate: function (data = {}) {
dataFromFun(data,
function (layero, index) { },
function (layero, index, elem) {
var field = elem.field;
http.post('save', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataEdit: function (data = {}) {
dataFromFun(data,
function (layero, index) { },
function (layero, index, elem) {
var field = elem.field;
http.put('update', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataRecybin: function (data = {}) {
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
layer.open({
title: '资源回收站',
content: formHtml,
anim: "slideLeft",
offset: "r",
area: ['50%', '99%'],
shade: 0.1,
shadeClose: true,
success: function (layero, index) {
table.render({
elem: '#dataRecybinTable',
url: "recyclebin",
defaultToolbar: [{
title: '批量删除数据',
layEvent: 'dataDelete',
icon: 'layui-icon-delete',
onClick: function (obj) {
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
console.log(ids);
}
}, 'filter', 'exports', 'print'],
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '名称', width: 180, fixed: 'left' },
{ field: 'name', title: '代码', width: 180, fixed: 'left' },
{ field: 'description', title: '描述', minWidth: 200, sort: true },
{
fixed: "right", title: "操作", width: 120, align: "center", templet: function (d) {
return `<div class="layui-btn-group">
<a class="layui-btn layui-btn-sm" title="恢复数据" lay-event="restore" > <i class="layui-icon layui-icon-edit"></i> </a >
<a class="layui-btn layui-btn-sm" title="删除数据" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> </a>
</div >`;
}
}
]],
page: true,
done: function () {
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore':
active.dataRestore([data.id]);
break;
case 'delete':
active.dataDelete([data.id], 1);
break;
}
});
table.on('toolbar(dataRecybinTable)', function (elem) {
switch (elem.event) {
case 'dataDelete':
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let idss = checkData.map((item, index, array) => { return item.id; });
active.dataDelete(idss, 1);
break;
case 'dataRestore':
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
active.dataRestore(ids);
break;
};
});
}
});
}
});
},
dataRestore: function (ids) {
if (ids.length === 0) {
return layer.msg('请选择数据');
}
http.put("restore", { ids: ids.join(',') })
.then((res) => {
if (res.code === 0) {
layer.msg('恢复成功');
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '恢复失败');
}
});
}
};
// 打开权限分配表单
function openPermissionForm(data) {
var title = '分配权限 [' + data.name + ']';
var formHtml = laytpl($('#permissionFormTpl').html()).render(data);
var index = layer.open({
anim: "slideLeft",
offset: "r",
btnAlign: "l",
area: ['50% ', '99%'],
shade: 0.1,
shadeClose: true,
content: formHtml,
success: function (layero, index) {
http.get("permission", { id: data.id })
.then((res) => {
if (res.code === 0) {
tree.render({
elem: '#permissionTree',
data: res.data,
showCheckbox: true,
id: 'permissionTree'
});
} else {
layer.msg(res.msg || '获取权限失败', { icon: 2 });
}
});
},
btn: ['保存', '取消'],
yes: function (index, layero) {
var checkedData = layui.tree.getChecked('permissionTree');
var permissionIds = [];
function getIds(data) {
data.forEach(function (item) {
permissionIds.push(item.id);
if (item.children && item.children.length > 0) {
getIds(item.children);
}
});
}
getIds(checkedData);
http.put("permission", {
id: data.id,
permissions: permissionIds
}).then((res) => {
if (res.code === 0) {
layer.msg(res.msg || '保存成功', { icon: 1, time: 1000 }, function () {
layer.close(index);
});
} else {
layer.msg(res.msg || '保存失败', { icon: 2 });
}
});
}
});
}
exports('group', {});
});
+179
View File
@@ -0,0 +1,179 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('help');
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'title', minWidth: 160, title: '标题' },
{ field: 'sort', width: 100, title: '排序', sort: true },
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
{ field: 'create_time', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name=\"title\"]').val('');
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate': active.dataCreate({}); break;
case 'dataDelete':
var check = table.checkStatus('dataTable').data;
active.dataDelete(check.map(function (i) { return i.id; }));
break;
case 'dataRecybin': active.dataRecybin(); break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update': active.dataEdit(data); break;
case 'delete': active.dataDelete([data.id]); break;
}
});
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
http.put('update', { id: this.value, status: status })
.then(function (res) {
if (res.code === 0) { layer.msg('操作成功'); }
else { layer.msg(res.msg || '操作失败'); }
table.reload('dataTable', {}, true);
})
.catch(function () { table.reload('dataTable', {}, true); });
});
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑站点帮助' : '添加站点帮助';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title, content: formHtml, anim: "slideLeft", offset: "r",
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
success: function (layero, index) { callback(layero, index); form.render(); },
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
var active = {
dataDelete: function (ids, force) {
if (ids.length === 0) { return layer.msg('请选择数据'); }
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
});
},
dataCreate: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
if (field.status === undefined) field.status = 0;
field.status = field.status ? 1 : 0;
http.post('save', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataEdit: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
http.put('update', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataRecybin: function () {
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
layer.open({
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
success: function () {
table.render({
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '标题', minWidth: 160, fixed: 'left' },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data) {
http.put("restore", { ids: data.id }).then(function (res) {
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '恢复失败'); }
});
},
dataForceDelete: function (data) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
};
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore': active.dataRestore(data); break;
case 'forcedelete': active.dataForceDelete(data); break;
}
});
exports('help', {});
});
+230
View File
@@ -0,0 +1,230 @@
/**
* Layui Admin Index Module - Theme v2.7.1
* 功能:处理后台管理系统的标签页(Tabs)逻辑,包括打开新标签、切换标签、URL路由监听等。
*/
layui.define(["ywxapp", "http", "route"], function (exports) {
// 获取 Layui 核心模块引用
var $ = layui.$;
var element = layui.element;
var ywxapp = layui.ywxapp;
var http = layui.http;
var route = layui.route;
var setter = layui.setter;
var view = layui.view;
var util = layui.util;
// 状态与配置常量
var tabsPageState = ywxapp.tabsPage; // 当前标签页状态
var TABS_CONTAINER_ID = "layadmin-layout-tabs"; // 标签容器ID
/**
* 核心函数:打开或切换标签页
* @param {Object} options - 配置对象
* @param {String} options.url - 页面URL
* @param {String} options.title - 页面标题
* @param {Boolean} options.escape - 是否转义标题(默认true)
* @param {String} options.highlight - 标题高亮样式
*/
function openOrSwitchTab(options) {
// 合并默认配置
options = $.extend({
url: "",
escape: true
}, options);
var isTabExists = false;
var tabHeaders = $("#LAY_app_tabsheader > li");
// 提取用于匹配的唯一标识(去除协议头和查询参数)
var matchKey = options.url.replace(/(^http(s*):)|(\?[\s\S]*$)/g, "");
// 1. 检查标签是否已存在
tabHeaders.each(function (index) {
if ($(this).attr("lay-id") === options.url) {
isTabExists = true;
tabsPageState.index = index; // 更新当前激活标签索引
}
});
// 设置默认标题
if (!options.title) {
options.title = (tabsPageState.index === 0) ? "" : "\u65b0\u6807\u7b7e\u9875"; // "新标签页"
}
/**
* 执行标签切换动作
*/
function performTabChange() {
element.tabChange(TABS_CONTAINER_ID, options.url);
ywxapp.tabsBodyChange(tabsPageState.index, {
url: options.url,
title: options.title
});
}
// 2. 根据配置决定是新增标签还是刷新现有iframe
if (setter.pageTabs) {
// 如果开启了多标签模式
if (!isTabExists) {
// 延迟添加DOM,确保渲染顺序
setTimeout(function () {
var iframeHtml = [
'<div class="layadmin-tabsbody-item layui-show">',
'<iframe src="' + options.url + '" frameborder="0" class="layadmin-iframe"></iframe>',
"</div>"
].join("");
$("#LAY_app_body").append(iframeHtml);
performTabChange();
}, 10);
// 添加标签头
var displayTitle = options.title;
if (options.escape) {
displayTitle = util.escape(displayTitle);
}
// 处理标题高亮
var titleHtml = displayTitle;
if (options.highlight) {
titleHtml = '<span style="' + options.highlight + '">' + displayTitle + "</span>";
}
element.tabAdd(TABS_CONTAINER_ID, {
title: "<span>" + titleHtml + "</span>",
id: options.url,
attr: matchKey
});
// 更新索引为新添加的标签
tabsPageState.index = tabHeaders.length;
} else {
// 标签已存在,直接切换
performTabChange();
}
} else {
// 如果未开启多标签模式,直接在当前iframe中跳转
var currentIframe = ywxapp.tabsBody(ywxapp.tabsPage.index).find(".layadmin-iframe")[0];
if (currentIframe && currentIframe.contentWindow) {
currentIframe.contentWindow.location.href = options.url;
}
// 即使不新增标签,也可能需要更新内部状态
performTabChange();
}
}
/**
* 构建侧边菜单的HTML结构
* @param {Array} data
* @returns
*/
/**
* 递归构建侧边菜单 HTML(支持任意层级)
* - 顶层用 <li>,嵌套层用 <dd>;有子项者为可展开目录,否则为可点击菜单。
* @param {Array} data 当前层级菜单数组
* @param {Boolean} isTop 是否为顶层(默认 true
* @returns {String}
*/
function buildSideMenu(data, isTop) {
isTop = isTop !== false;
var html = '';
$.each(data || [], function (i, item) {
var hasChild = item.child && item.child.length > 0;
var tag = isTop ? 'li' : 'dd';
var cls = isTop ? 'layui-nav-item' : '';
if (item.spread) {
cls += (cls ? ' ' : '') + 'layui-nav-itemed';
}
var clsAttr = cls ? ' class="' + cls + '"' : '';
if (hasChild) {
html += '<' + tag + ' data-name="' + item.name + '"' + clsAttr + '>';
if (isTop) {
html += ' <a href="javascript:;" lay-tips="' + item.title + '" lay-direction="2">';
html += ' <i class="layui-icon ' + item.icon + '"></i>';
html += ' <cite>' + item.title + '</cite>';
html += ' </a>';
} else {
html += ' <a href="javascript:;">' + item.title + '</a>';
}
// 递归渲染子级,保证第 4 层及更深的菜单也能显示
html += ' <dl class="layui-nav-child">' + buildSideMenu(item.child, false) + '</dl>';
html += '</' + tag + '>';
} else {
html += '<' + tag + ' data-name="' + item.name + '"' + clsAttr + '>';
if (isTop) {
html += ' <a lay-href="' + item.route + '" lay-tips="' + item.title + '" lay-direction="2">';
html += ' <i class="layui-icon ' + item.icon + '"></i>';
html += ' <cite>' + item.title + '</cite>';
html += ' </a>';
} else {
html += ' <a lay-href="' + item.route + '">' + item.title + '</a>';
}
html += '</' + tag + '>';
}
});
return html;
}
const menuApi = route.route('menu');
http.get(menuApi).then(function (res) {
if (res.code === 0) {
var html = buildSideMenu(res.data);
$('#LAY-system-side-menu').html(html);
} else {
layer.msg('菜单加载失败: ' + res.msg, { icon: 2 });
}
element.init(); // 重新渲染导航
}).catch(function (error) {
layer.msg('菜单加载失败: ' + error, { icon: 2 });
element.init();
});
/**
* 初始化路由监听与自动渲染
*/
(function initRouter() {
// 自动渲染视图
view().autoRender();
// 监听 Hash 变化
var hashObj = layui.url().hash;
var recordConfig = setter.record || {};
var path = hashObj.href.replace(/^\//, ""); // 去除开头的斜杠
// 尝试从本地存储获取标题
var storedData = layui.data(setter.tableName).record || {};
var savedTitle = storedData[path] || "";
// 如果配置了记录功能且路径有效
if (recordConfig.url && path) {
var cleanPath = $.trim(path);
// 安全检查:如果是外部链接且不属于当前域名,则通过 openOrSwitchTab 处理
// 注意:原代码逻辑中,正则测试失败(即不是外部链接)或者属于当前域名时,可能不走这个分支,
// 但原代码结构是:如果满足条件则调用 n (即 openOrSwitchTab)。
// 原逻辑:/^(\w*:)*\/\/.+/.test(i) && -1 === i.indexOf(location.hostname)
// 意思是:如果是绝对路径且域名不同,则作为新标签打开。
if (/^(\w*:)*\/\/.+/.test(cleanPath) && cleanPath.indexOf(location.hostname) === -1) {
openOrSwitchTab({
url: cleanPath,
title: savedTitle
});
}
}
// 延迟显示主体内容,避免闪烁
setTimeout(function () { $("#" + setter.container).css("visibility", "visible"); }, 3000);
})();
// 导出模块接口http://127.0.0.1/%7B__CTRL__%7D/menu”。
var exportsData = {
openTabsPage: openOrSwitchTab
};
// 扩展 ywxapp 模块的功能
$.extend(ywxapp, exportsData);
// 完成模块定义
exports("index",{});
});
+285
View File
@@ -0,0 +1,285 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('links');
// 渲染表格
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return {
code: res.code === 0 ? 0 : 1,
msg: res.message || '',
count: res.count || (res.data ? res.data.length : 0),
data: res.data || []
};
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'title', width: 200, title: '网站标题' },
{
field: 'url', title: '链接地址', minWidth: 200, templet: function (d) {
return '<a href="' + d.url + '" target="_blank" style="color:#1E9FFF;">' + d.url + '</a>';
}
},
{
field: 'logo', width: 100, title: 'Logo', templet: function (d) {
return d.logo ? '<img src="' + d.logo + '" style="width:30px;height:30px;border-radius:50%;">' : '无';
}
},
{ field: 'sort', width: 100, title: '排序', sort: true },
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
{ field: 'create_at', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function (res, curr, count) {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
// 搜索
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', {
page: { curr: 1 },
where: { title: data.field.title }
});
return false;
});
$('#btn-reset').on('click', function () {
$('input[name="title"]').val('');
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
});
// 顶部工具条
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate':
active.dataCreate({});
break;
case 'dataDelete':
var checkStatus = table.checkStatus('dataTable'), checkData = checkStatus.data;
let ids = checkData.map((item) => { return item.id; });
active.dataDelete(ids);
break;
case 'dataRecybin':
active.dataRecybin();
break;
};
});
// 行工具
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update':
active.dataEdit(data);
break;
case 'delete':
active.dataDelete([data.id]);
break;
}
});
// 状态开关
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
var id = this.value;
http.put('update', { id: id, status: status })
.then((res) => {
if (res.code === 0) {
layer.msg('操作成功');
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
table.reload('dataTable', {}, true); // 还原界面状态
}
})
.catch(() => { table.reload('dataTable', {}, true); });
});
// 打开表单抽屉
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑友情链接' : '添加友情链接';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title,
content: formHtml,
anim: "slideLeft",
offset: "r",
btnAlign: "l",
area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1,
shadeClose: true,
btn: ['确定', '取消'],
success: function (layero, index) {
callback(layero, index);
form.render();
},
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem);
layui.off('submit(wxapp-form)', 'from');
return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
// 事件
var active = {
dataDelete: function (ids, force = 0) {
if (ids.length === 0) {
return layer.msg('请选择数据');
}
layer.confirm('确定删除吗?' + (force ? '(将彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force })
.then((res) => {
if (res.code === 0) {
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
});
},
dataCreate: function (data = {}) {
dataFromFun(data,
function (layero, index) { },
function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
http.post('save', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataEdit: function (data = {}) {
dataFromFun(data,
function (layero, index) { },
function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
http.put('update', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataRecybin: function (data = {}) {
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
layer.open({
title: '资源回收站',
content: formHtml,
anim: "slideLeft",
offset: "r",
area: ['50%', '99%'],
shade: 0.1,
shadeClose: true,
success: function (layero, index) {
table.render({
elem: '#dataRecybinTable',
url: "recyclebin",
height: 'full-120',
parseData: function (res) {
return {
code: res.code === 0 ? 0 : 1,
msg: res.message || '',
count: res.count || (res.data ? res.data.length : 0),
data: res.data || []
};
},
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '网站标题', width: 180, fixed: 'left' },
{ field: 'url', title: '链接', minWidth: 200 },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 120, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data = {}) {
http.put("restore", { ids: data.id })
.then((res) => {
if (res.code === 0) {
layer.msg('恢复成功');
table.reload('dataRecybinTable', {}, true);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '恢复失败');
}
});
},
dataForceDelete: function (data = {}) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 })
.then((res) => {
if (res.code === 0) {
layer.msg('已彻底删除');
table.reload('dataRecybinTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
});
}
};
// 回收站行操作
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore':
active.dataRestore(data);
break;
case 'forcedelete':
active.dataForceDelete(data);
break;
}
});
exports('links', {});
});
+47
View File
@@ -0,0 +1,47 @@
layui.define(['form', 'http'], function (exports) {
var form = layui.form;
function refreshVerifyCode() {
const verifyImg = document.querySelector('[lay-filter="verifyCode"]');
if (verifyImg) {
verifyImg.style.opacity = '0.7';
setTimeout(() => {
const baseSrc = verifyImg.src.split('?')[0];
verifyImg.src = baseSrc + '?' + Date.now();
verifyImg.style.opacity = '1';
}, 100);
}
}
const verifyImg = document.querySelector('[lay-filter="verifyCode"]');
if (verifyImg) {
verifyImg.addEventListener('click', refreshVerifyCode);
}
form.on('submit(dataSubmit)', function (obj) {
let data = obj.field;
layui.http.post("save", data)
.then(function (res) {
console.log(res);
if (res.code != 0) {
layer.msg(res.message);
refreshVerifyCode();
} else {
layui.setter.setMenus(res.data.menus);
layui.setter.permissions(res.data.permissions);
layer.alert('请稍后!', {
time: 15000,
end: function () {
if (window.self !== window.top) {
// 在 iframe 中,跳转顶级页面
window.top.location.href = "/admin";
} else {
// 顶级窗口,直接跳转
window.location.href = "/admin";
}
}
})
}
});
return false;
});
exports('login', {});
})
+204
View File
@@ -0,0 +1,204 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('medal');
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'title', minWidth: 160, title: '勋章名称' },
{ field: 'sort', width: 100, title: '排序', sort: true },
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
{ field: 'create_time', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name=\"title\"]').val('');
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate': active.dataCreate({}); break;
case 'dataDelete':
var check = table.checkStatus('dataTable').data;
active.dataDelete(check.map(function (i) { return i.id; }));
break;
case 'dataRecybin': active.dataRecybin(); break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update': active.dataEdit(data); break;
case 'delete': active.dataDelete([data.id]); break;
case 'grant': active.dataGrant(data); break;
}
});
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
http.put('update', { id: this.value, status: status })
.then(function (res) {
if (res.code === 0) { layer.msg('操作成功'); }
else { layer.msg(res.msg || '操作失败'); }
table.reload('dataTable', {}, true);
})
.catch(function () { table.reload('dataTable', {}, true); });
});
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑勋章中心' : '添加勋章中心';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title, content: formHtml, anim: "slideLeft", offset: "r",
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
success: function (layero, index) { callback(layero, index); form.render(); },
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
var active = {
dataDelete: function (ids, force) {
if (ids.length === 0) { return layer.msg('请选择数据'); }
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
});
},
dataCreate: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
if (field.status === undefined) field.status = 0;
field.status = field.status ? 1 : 0;
http.post('save', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataEdit: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
http.put('update', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataGrant: function (data) {
var formHtml = ''
+ '<div class="layui-form" style="padding:20px 30px;">'
+ '<div class="layui-form-item"><label class="layui-form-label">勋章</label>'
+ '<div class="layui-input-block"><input class="layui-input" value="' + (data.title || '') + '" disabled></div></div>'
+ '<div class="layui-form-item"><label class="layui-form-label">用户ID</label>'
+ '<div class="layui-input-block"><input class="layui-input" name="uid" id="grantUid" placeholder="输入要授予的用户UID" lay-verify="required"></div></div>'
+ '<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" id="grantSubmit">确认授予</button></div></div>'
+ '</div>';
layer.open({
title: '授予勋章', content: formHtml, anim: 'slideLeft', offset: 'r',
area: ['420px', '320px'], shade: 0.1, shadeClose: true,
success: function (layero, index) {
$('#grantSubmit').on('click', function () {
var uid = parseInt($('#grantUid').val(), 10);
if (!uid || uid <= 0) { return layer.msg('请输入有效的用户ID'); }
http.post('grant', { uid: uid, medal_id: data.id }).then(function (res) {
if (res.code === 0) { layer.close(index); layer.msg(res.message || '授予成功', { icon: 1 }); }
else { layer.msg(res.message || '授予失败', { icon: 2 }); }
}).catch(function () { layer.msg('请求失败', { icon: 2 }); });
});
}
});
},
dataRecybin: function () {
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
layer.open({
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
success: function () {
table.render({
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '勋章名称', minWidth: 160, fixed: 'left' },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data) {
http.put("restore", { ids: data.id }).then(function (res) {
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '恢复失败'); }
});
},
dataForceDelete: function (data) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
};
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore': active.dataRestore(data); break;
case 'forcedelete': active.dataForceDelete(data); break;
}
});
exports('medal', {});
});
+110
View File
@@ -0,0 +1,110 @@
/*
* @Author: YwxApp <ywx@ywxapp.cn>
* @Description: 前台主导航菜单管理(后台)
*/
layui.define(['http', 'auth', 'table', 'treeTable'], function (exports) {
var $ = layui.$,
table = layui.table,
form = layui.form,
layer = layui.layer,
laytpl = layui.laytpl,
http = layui.http,
auth = layui.auth;
auth.init((layui.data('backend').permission) || []);
// 两级树拍平成单表,子项缩进展示
function flatTree(list, level) {
var rows = [];
layui.each(list || [], function (i, item) {
item._level = level;
item._title = (level > 0 ? ' ├ ' : '') + item.title;
rows.push(item);
if (item.child && item.child.length) {
rows = rows.concat(flatTree(item.child, level + 1));
}
});
return rows;
}
var dataTable = table.render({
elem: '#dataTable',
url: 'index',
page: false,
toolbar: '#tableBar',
cols: [[
{ field: 'id', title: 'ID', width: 70, align: 'center' },
{ field: 'title', title: '菜单名称', minWidth: 180, templet: function (d) { return d._title || d.title; } },
{ field: 'parent_id', title: '层级', width: 90, align: 'center', templet: '#parentTpl' },
{ field: 'url', title: '链接', minWidth: 200 },
{ field: 'sort', title: '排序', width: 80, align: 'center' },
{ field: 'status', title: '状态', width: 110, align: 'center', templet: '#statusTpl' },
{ title: '操作', width: 200, align: 'center', toolbar: '#dataBar', fixed: 'right' }
]],
response: { statusCode: 0 },
parseData: function (res) {
return { code: res.code, msg: res.msg, count: res.count || 0, data: flatTree(res.data, 0) };
},
done: function () {
auth.render();
}
});
// 状态开关
form.on('switch(statusSwitch)', function (obj) {
var id = obj.value;
var status = obj.elem.checked ? 1 : 0;
http.post('status', { id: id, status: status }).then(function (res) {
if (res.code !== 0) { layer.msg(res.msg || '操作失败'); dataTable.reload(); }
});
});
// 工具条(新建)
table.on('toolbar(dataTable)', function (obj) {
if (obj.event === 'dataCreate') { openForm({}); }
});
// 行操作
table.on('tool(dataTable)', function (obj) {
var d = obj.data;
if (obj.event === 'update') { openForm(d); }
else if (obj.event === 'addChild') { openForm({ parent_id: d.id }); }
else if (obj.event === 'delete') {
layer.confirm('确定删除该菜单吗?', function (idx) {
http.delete('delete', { id: d.id }).then(function (res) {
if (res.code === 0) { layer.close(idx); dataTable.reload(); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
});
// 表单弹窗:拉取一级菜单作为父级选项
function openForm(data) {
http.get('index').then(function (res) {
var parents = [];
layui.each((res.data || []), function (i, p) {
if (p.parent_id == 0) parents.push(p);
});
var html = laytpl($('#dataFormTpl').html()).render($.extend({ parents: parents }, data));
layer.open({
type: 1, title: data.id ? '编辑菜单' : '新建菜单',
area: ['480px', 'auto'], content: html,
btn: ['保存', '取消'],
success: function () { form.render(); },
yes: function (idx, layero) {
var field = form.val('wxapp-form-submit') || {};
// 用表单序列化兜底
var fd = {};
$(layero).find('form').serializeArray().map(function (x) { fd[x.name] = x.value; });
http.post(data.id ? 'update' : 'save', fd).then(function (r) {
if (r.code === 0) { layer.close(idx); dataTable.reload(); }
else { layer.msg(r.msg || '操作失败'); }
});
}
});
});
}
exports('navbar', {});
});
+202
View File
@@ -0,0 +1,202 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('notice');
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'title', minWidth: 160, title: '标题' },
{ field: 'type', width: 100, title: '类型', templet: '#typeTpl' },
{ field: 'is_top', width: 80, title: '置顶', templet: '#topTpl' },
{ field: 'sort', width: 90, title: '排序', sort: true },
{ field: 'status', width: 90, title: '状态', templet: '#statusTpl' },
{ field: 'start_time', width: 160, title: '开始时间', templet: '#startTpl' },
{ field: 'end_time', width: 160, title: '结束时间', templet: '#endTpl' },
{ field: 'view_count', width: 90, title: '浏览量' },
{ field: 'create_time', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title, type: data.field.type } });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name=\"title\"]').val('');
$('select[name=\"type\"]').val('');
form.render('select');
table.reload('dataTable', { page: { curr: 1 }, where: { title: '', type: '' } });
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate': active.dataCreate({}); break;
case 'dataDelete':
var check = table.checkStatus('dataTable').data;
active.dataDelete(check.map(function (i) { return i.id; }));
break;
case 'dataRecybin': active.dataRecybin(); break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update': active.dataEdit(data); break;
case 'delete': active.dataDelete([data.id]); break;
}
});
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
http.put('update', { id: this.value, status: status })
.then(function (res) {
if (res.code === 0) { layer.msg('操作成功'); }
else { layer.msg(res.msg || '操作失败'); }
table.reload('dataTable', {}, true);
})
.catch(function () { table.reload('dataTable', {}, true); });
});
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑站点公告' : '添加站点公告';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title, content: formHtml, anim: "slideLeft", offset: "r",
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
success: function (layero, index) {
callback(layero, index);
form.render();
// 回填下拉/开关
if (data.type) { layero.contents().find('select[name="type"]').val(String(data.type)); }
if (data.is_top) { layero.contents().find('input[name="is_top"]').prop('checked', true); form.render('checkbox'); }
// 有效期日期选择器
layui.use(['laydate'], function () {
var laydate = layui.laydate;
laydate.render({ elem: layero.contents().find('#start_time')[0], type: 'datetime' });
laydate.render({ elem: layero.contents().find('#end_time')[0], type: 'datetime' });
});
},
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
var active = {
dataDelete: function (ids, force) {
if (ids.length === 0) { return layer.msg('请选择数据'); }
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
});
},
dataCreate: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
if (field.status === undefined) field.status = 0;
field.status = field.status ? 1 : 0;
field.is_top = field.is_top ? 1 : 0;
field.type = field.type ? parseInt(field.type, 10) : 1;
http.post('save', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataEdit: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
field.is_top = field.is_top ? 1 : 0;
field.type = field.type ? parseInt(field.type, 10) : 1;
http.put('update', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataRecybin: function () {
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
layer.open({
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
success: function () {
table.render({
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '标题', minWidth: 160, fixed: 'left' },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data) {
http.put("restore", { ids: data.id }).then(function (res) {
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '恢复失败'); }
});
},
dataForceDelete: function (data) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
};
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore': active.dataRestore(data); break;
case 'forcedelete': active.dataForceDelete(data); break;
}
});
exports('notice', {});
});
+327
View File
@@ -0,0 +1,327 @@
layui.define(['layer', 'http', 'iconPicker', 'auth'], function (exports) {
var $ = layui.$;
var treeTable = layui.treeTable;
var form = layui.form;
var layer = layui.layer;
var laytpl = layui.laytpl;
var iconPicker = layui.iconPicker;
var http = layui.http;
var auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('power');
treeTable.render({
elem: '#dataTable',
url: 'index',
parseData: function (res) { // 预处理返回数据
console.log('原始数据:', res); // 调试输入
return {
code: res.code === 0 ? 0 : 1, // 0 标识成功
data: res.data || [], // 数据数组
msg: res.message || '' // 错误信息
};
},
tree: {
customName: {
children: "children",
isParent: "is_parent",
name: "title",
id: "id",
pid: "pid",
icon: "icon"
},
data: { isSimpleData: true, rootPid: 0 },
view: {},
async: {},
callback: {}
},
height: 'full-100',
toolbar: '#tableBarTpl',
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: 'title', width: 180, fixed: 'left' },
{ field: 'name', title: 'name', width: 180, fixed: 'left' },
{
field: 'type', title: '类型', width: 80, templet: function (d) {
if (d.type === 1) {
return '<span class="layui-badge layui-bg-gray">目录</span>';
} else if (d.type === 2) {
return '<span class="layui-badge layui-bg-gray">菜单</span>';
} else if (d.type === 3) {
return '<span class="layui-badge layui-bg-gray">按钮</span>';
} else if (d.type === 4) {
return '<span class="layui-badge layui-bg-gray">API</span>';
}
}
}, { field: 'route', title: '路由', minWidth: 200, sort: true },
{
field: 'icon', title: '图标', width: 80, sort: true, templet: function (d) {
return '<i class="layui-icon ' + d.icon + '"></i> ';
}
},
{ field: 'sort', title: '排序', width: 80, sort: true },
{ field: 'status', title: '状态', width: 96, align: 'center', templet: '#statusTpl' },
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#dataBarTpl" }
]],
page: true,
done: function (res, curr, count, origin) {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
treeTable.on('toolbar(dataTable)', function (obj) {
var options = obj.config;
switch (obj.event) {
case 'dataCreate':
active.dataCreate({ pid: 0, type: 1 });
break;
case 'dataDelete':
var checkStatus = treeTable.checkStatus('dataTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
active.dataDelete(ids);
break;
case 'dataRecybin':
active.dataRecybin();
break;
};
});
treeTable.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update':
active.dataEdit(data);
break;
case 'create':
active.dataCreate({ pid: data.id });
break;
case 'delete':
active.dataDelete([data.id]);
break;
default:
break;
}
});
// 状态开关
form.on('switch(statusSwitch)', function (obj) {
var id = this.value;
var status = obj.elem.checked ? 1 : 0;
layer.confirm('确定要' + (status ? '启用' : '禁用') + '该数据吗?', function (index) {
layui.request.post('update', { id: id, status: status }).then(function (res) {
if (res.code === 0) {
layer.msg(res.msg, { icon: 1 });
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg, { icon: 2 });
obj.elem.checked = !obj.elem.checked;
form.render('checkbox');
}
});
layer.close(index);
}, function () {
obj.elem.checked = !obj.elem.checked;
form.render('checkbox');
});
});
var dataFromFun = function (data, callback, done) {
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: data.id ? '编辑数据' : (data.pid ? '添加子数据' : '添加根数据'),
content: formHtml,
anim: "slideLeft",
offset: "r",
btnAlign: "l",
area: ['520px', '98%'],
shade: 0.1,
shadeClose: true,
btn: ['确定', '取消'],
success: function (layero, index) {
callback(layero, index);
form.render();
},
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem);
layui.off('submit(wxapp-form)', 'from');
return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
//事件
var active = {
dataDelete: function (ids, force = 0) {
if (ids.length === 0) {
return layer.msg('请选择数据');
}
layer.prompt({
formType: 1
, title: '敏感操作,请验证口令'
}, function (value, index) {
layer.close(index);
layer.confirm('确定删除吗?', function (index) {
http.delete('delete', { ids: ids.join(','), force: force })
.then((res) => {
if (res.code === 0) {
layer.close(index);
treeTable.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
layer.msg('已删除');
treeTable.reload('dataTable', {}, true);
});
});
},
dataCreate: function (data = {}) {
dataFromFun(data,
function (layero, index) {
iconPicker.render({
elem: '#iconPicker',
type: 'fontClass',
search: true,
page: false,
});
},
function (layero, index, elem) {
var field = elem.field;
field.icon = 'layui-icon ' + field.icon;
field.status = field.status ? 1 : 0;
http.post('save', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
treeTable.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataEdit: function (data = {}) {
dataFromFun(data,
function (layero, index) {
iconPicker.render({
elem: '#iconPicker',
type: 'fontClass',
search: true,
page: false,
});
},
function (layero, index, elem) {
var field = elem.field;
field.icon = 'layui-icon ' + field.icon;
field.status = field.status ? 1 : 0;
http.put('update', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
treeTable.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataRecybin: function (data = {}) {
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
layer.open({
title: '资源回收站',
content: formHtml,
anim: "slideLeft",
offset: "r",
area: ['60%', '99%'],
shade: 0.1,
shadeClose: true,
success: function (layero, index) {
layui.table.render({
elem: '#dataRecybinTable',
url: 'recyclebin',
height: 'full-100',
defaultToolbar: [{
title: '批量删除数据',
layEvent: 'dataDelete',
icon: 'layui-icon-delete',
onClick: function (obj) {
var checkStatus = treeTable.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
console.log(ids);
}
}, 'filter', 'exports', 'print'],
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: 'title', width: 180, fixed: 'left' },
{ field: 'name', title: 'name', width: 180, fixed: 'left' },
{ field: 'route', title: '路由', minWidth: 200, sort: true },
{
fixed: "right", title: "操作", width: 120, align: "center", templet: function (d) {
return `<div class="layui-btn-group">
<a class="layui-btn layui-btn-sm" title="恢复数据" lay-event="restore" > <i class="layui-icon layui-icon-edit"></i> </a >
<a class="layui-btn layui-btn-sm" title="删除数据" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> </a>
</div >`;
}
}
]],
page: true,
done: function (res, curr, count, origin) {
layui.table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore':
active.dataRestore([data.id]);
break;
case 'delete':
active.dataDelete([data.id], 1);
break;
}
});
layui.table.on('toolbar(dataRecybinTable)', function (elem) {
switch (elem.event) {
case 'dataDelete':
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let idss = checkData.map((item, index, array) => { return item.id; });
active.dataDelete(idss, 1);
break;
case 'dataRestore':
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
active.dataRestore(ids);
break;
};
});
}
});
}
});
},
dataRestore: function (ids) {
if (ids.length === 0) {
return layer.msg('请选择数据');
}
http.put('restore', { ids: ids.join(',') })
.then((res) => {
if (res.code === 0) {
layer.msg('恢复成功');
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '恢复失败');
}
});
}
};
exports('power', {});
});
+179
View File
@@ -0,0 +1,179 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('prop');
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'title', minWidth: 160, title: '道具名称' },
{ field: 'sort', width: 100, title: '排序', sort: true },
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
{ field: 'create_time', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name=\"title\"]').val('');
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate': active.dataCreate({}); break;
case 'dataDelete':
var check = table.checkStatus('dataTable').data;
active.dataDelete(check.map(function (i) { return i.id; }));
break;
case 'dataRecybin': active.dataRecybin(); break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update': active.dataEdit(data); break;
case 'delete': active.dataDelete([data.id]); break;
}
});
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
http.put('update', { id: this.value, status: status })
.then(function (res) {
if (res.code === 0) { layer.msg('操作成功'); }
else { layer.msg(res.msg || '操作失败'); }
table.reload('dataTable', {}, true);
})
.catch(function () { table.reload('dataTable', {}, true); });
});
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑道具中心' : '添加道具中心';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title, content: formHtml, anim: "slideLeft", offset: "r",
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
success: function (layero, index) { callback(layero, index); form.render(); },
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
var active = {
dataDelete: function (ids, force) {
if (ids.length === 0) { return layer.msg('请选择数据'); }
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
});
},
dataCreate: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
if (field.status === undefined) field.status = 0;
field.status = field.status ? 1 : 0;
http.post('save', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataEdit: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
http.put('update', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataRecybin: function () {
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
layer.open({
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
success: function () {
table.render({
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '道具名称', minWidth: 160, fixed: 'left' },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data) {
http.put("restore", { ids: data.id }).then(function (res) {
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '恢复失败'); }
});
},
dataForceDelete: function (data) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
};
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore': active.dataRestore(data); break;
case 'forcedelete': active.dataForceDelete(data); break;
}
});
exports('prop', {});
});
+297
View File
@@ -0,0 +1,297 @@
layui.define(['http', 'auth'], function (exports) {
var $ = layui.$, table = layui.table, form = layui.form, layer = layui.layer
, laydate = layui.laydate, laytpl = layui.laytpl, tree = layui.tree, http = layui.http
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('role');
var dataTable = table.render({
elem: '#dataTable'
, url: 'index' // 后端数据接口
, page: true
, limit: 15
, toolbar: '#tableBarTpl'
, cols: [[
{ type: 'checkbox', fixed: 'left' }
, { field: 'id', title: 'ID', width: 60, align: 'center', sort: true, fixed: 'left' }
, { field: 'title', title: '名称', width: 150, align: 'center', fixed: 'left' }
, { field: 'name', title: '代码', width: 150, align: 'center', fixed: 'left' }
, { field: 'description', title: '描述', minWidth: 200, align: 'left' }
, { field: 'status', title: '状态', width: 120, align: 'center', templet: '#statusTpl' }
, { field: 'create_at', title: '创建时间', width: 160, align: 'center', sort: true }
, { title: '操作', width: 160, align: 'left', toolbar: '#dataBarTpl', fixed: 'right', unresize: true }
]]
, done: function (res, curr, count) {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate':
active.dataCreate({ pid: 0, type: 1 });
break;
case 'dataDelete':
var checkStatus = table.checkStatus('dataTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
active.dataDelete(ids);
break;
case 'dataRecybin':
active.dataRecybin();
break;
};
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update':
active.dataEdit(data);
break;
case 'permission':
openPermissionForm(data);
break;
case 'delete':
active.dataDelete([data.id]);
break;
}
});
var dataFromFun = function (data, callback, done) {
var title = data ? '编辑数据[' + data.account + ']' : '添加数据';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: data.id ? '编辑菜单' : (data.pid ? '添加子菜单' : '添加根菜单'),
content: formHtml,
anim: "slideLeft",
offset: "r",
btnAlign: "l",
area: ['50% ', '99%'],
shade: 0.1,
shadeClose: true,
btn: ['确定', '取消'],
success: function (layero, index) {
callback(layero, index);
form.render();
},
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem);
layui.off('submit(wxapp-form)', 'from');
return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
//事件
var active = {
dataDelete: function (ids, force = 0) {
if (ids.length === 0) {
return layer.msg('请选择数据');
}
layer.prompt({
formType: 1
, title: '敏感操作,请验证口令'
}, function (value, index) {
layer.close(index);
layer.confirm('确定删除吗?', function (index) {
http.delete("delete", { ids: ids.join(','), force: force })
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
});
});
},
dataCreate: function (data = {}) {
dataFromFun(data,
function (layero, index) { },
function (layero, index, elem) {
var field = elem.field;
http.post("save", field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataEdit: function (data = {}) {
dataFromFun(data,
function (layero, index) { },
function (layero, index, elem) {
var field = elem.field;
http.put("update", field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataRecybin: function (data = {}) {
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
layer.open({
title: '资源回收站',
content: formHtml,
anim: "slideLeft",
offset: "r",
area: ['50%', '99%'],
shade: 0.1,
shadeClose: true,
success: function (layero, index) {
table.render({
elem: '#dataRecybinTable',
url: 'recyclebin',
defaultToolbar: [{
title: '批量删除数据',
layEvent: 'dataDelete',
icon: 'layui-icon-delete',
onClick: function (obj) {
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
console.log(ids);
}
}, 'filter', 'exports', 'print'],
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '名称', width: 180, fixed: 'left' },
{ field: 'name', title: '代码', width: 180, fixed: 'left' },
{ field: 'description', title: '描述', minWidth: 200, sort: true },
{
fixed: "right", title: "操作", width: 120, align: "center", templet: function (d) {
return `<div class="layui-btn-group">
<a class="layui-btn layui-btn-sm" title="恢复数据" lay-event="restore" > <i class="layui-icon layui-icon-edit"></i> </a >
<a class="layui-btn layui-btn-sm" title="删除数据" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> </a>
</div >`;
}
}
]],
page: true,
done: function () {
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore':
active.dataRestore([data.id]);
break;
case 'delete':
active.dataDelete([data.id], 1);
break;
}
});
table.on('toolbar(dataRecybinTable)', function (elem) {
switch (elem.event) {
case 'dataDelete':
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let idss = checkData.map((item, index, array) => { return item.id; });
active.dataDelete(idss, 1);
break;
case 'dataRestore':
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
active.dataRestore(ids);
break;
};
});
}
});
}
});
},
dataRestore: function (ids) {
if (ids.length === 0) {
return layer.msg('请选择数据');
}
http.put("restore", { ids: ids.join(',') })
.then((res) => {
if (res.code === 0) {
layer.msg('恢复成功');
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '恢复失败');
}
});
}
};
// 打开权限分配表单
function openPermissionForm(data) {
var title = '分配权限 [' + data.name + ']';
var formHtml = laytpl($('#permissionFormTpl').html()).render(data);
var index = layer.open({
anim: "slideLeft",
offset: "r",
btnAlign: "l",
area: ['50% ', '99%'],
shade: 0.1,
shadeClose: true,
content: formHtml,
success: function (layero, index) {
http.get("permission", { id: data.id })
.then((res) => {
if (res.code === 0) {
tree.render({
elem: '#permissionTree',
data: res.data,
showCheckbox: true,
id: 'permissionTree'
});
} else {
layer.msg(res.msg || '获取权限失败', { icon: 2 });
}
});
},
btn: ['保存', '取消'],
yes: function (index, layero) {
var checkedData = layui.tree.getChecked('permissionTree');
var permissionIds = [];
function getIds(data) {
data.forEach(function (item) {
permissionIds.push(item.id);
if (item.children && item.children.length > 0) {
getIds(item.children);
}
});
}
getIds(checkedData);
http.put("permission", {
id: data.id,
permissions: permissionIds
}).then((res) => {
if (res.code === 0) {
layer.msg(res.msg || '保存成功', { icon: 1, time: 1000 }, function () {
layer.close(index);
});
} else {
layer.msg(res.msg || '保存失败', { icon: 2 });
}
});
}
});
}
exports('role', {});
});
+277
View File
@@ -0,0 +1,277 @@
layui.define(['layer', 'http', 'iconPicker', 'auth'], function (exports) {
var $ = layui.$;
var treeTable = layui.treeTable;
var form = layui.form;
var layer = layui.layer;
var laytpl = layui.laytpl;
var iconPicker = layui.iconPicker;
var http = layui.http;
var auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('rule');
treeTable.render({
elem: '#dataTable',
url: 'index',
parseData: function (res) { // 预处理返回数据
console.log('原始数据:', res); // 调试输入
return {
code: res.code === 0 ? 0 : 1, // 0 标识成功
data: res.data || [], // 数据数组
msg: res.message || '' // 错误信息
};
},
tree: {
customName: {
isParent: "is_parent",
name: "title",
id: "id",
pid: "pid",
icon: "icon"
},
data: { isSimpleData: true, rootPid: 0 },
view: { showIcon: true },
},
height: 'full-100',
toolbar: '#tableBarTpl',
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, align: 'left' },
{ field: 'title', title: 'title', width: 180, align: 'left' },
{ field: 'name', title: 'name', width: 180, align: 'center' },
{
field: 'module', title: '模块', width: 100, templet: function (d) {
if (d.module === 'frontend') {
return '<span class="layui-badge layui-bg-gray">Frontend</span>';
} else if (d.module === 'member') {
return '<span class="layui-badge layui-bg-gray">Member</span>';
}
}
},
{
field: 'type', title: '类型', width: 80, templet: function (d) {
if (d.type === '1') {
return '<span class="layui-badge layui-bg-gray">目录</span>';
} else if (d.type === '2') {
return '<span class="layui-badge layui-bg-gray">菜单</span>';
} else {
return '<span class="layui-badge layui-bg-gray">按钮</span>';
}
}
}, { field: 'route', title: '路由', minWidth: 200, sort: true },
{
field: 'icon', title: '图标', width: 80, sort: true, templet: function (d) {
return '<i class="layui-icon ' + d.icon + '"></i> ';
}
},
{ field: 'sort', title: '排序', width: 80, sort: true },
{ field: 'status', title: '状态' },
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#dataBarTpl" }
]],
page: true,
skin: 'line',
done: function (res, curr, count, origin) {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
treeTable.on('toolbar(dataTable)', function (obj) {
var options = obj.config;
switch (obj.event) {
case 'dataCreate':
active.dataCreate({ pid: 0, type: 1 });
break;
case 'dataDelete':
var checkStatus = treeTable.checkStatus('dataTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
active.dataDelete(ids);
break;
case 'dataRecybin':
active.dataRecybin();
break;
};
});
treeTable.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update':
active.dataEdit(data);
break;
case 'create':
active.dataCreate({ pid: data.id });
break;
case 'delete':
active.dataDelete([data.id]);
break;
default:
break;
}
});
var dataFromFun = function (data, callback, done) {
var title = data ? '编辑管理员 [' + data.account + ']' : '添加管理员';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: data.id ? '编辑菜单' : (data.pid ? '添加子菜单' : '添加根菜单'),
content: formHtml,
anim: "slideLeft",
offset: "r",
btnAlign: "l",
area: ['520px', '98%'],
shade: 0.1,
shadeClose: true,
btn: ['确定', '取消'],
success: function (layero, index) {
callback(layero, index);
form.render();
},
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem);
layui.off('submit(wxapp-form)', 'from');
return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
//事件
var active = {
dataDelete: function (ids, force = 0) {
if (ids.length === 0) {
return layer.msg('请选择数据');
}
layer.prompt({
formType: 1
, title: '敏感操作,请验证口令'
}, function (value, index) {
layer.close(index);
layer.confirm('确定删除吗?', function (index) {
http.delete("delete", { ids: ids.join(','), force: force })
.then((res) => {
if (res.code === 0) {
layer.close(index);
treeTable.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
layer.msg('已删除');
treeTable.reload('dataTable', {}, true);
});
});
},
dataCreate: function (data = {}) {
dataFromFun(data,
function (layero, index) {
iconPicker.render({
elem: '#iconPicker',
type: 'fontClass',
search: true,
page: false,
});
},
function (layero, index, elem) {
var field = elem.field;
field.icon = 'layui-icon ' + field.icon.indexOf("layui-icon ") == -1 ? field.icon : field.icon.replace('layui-icon ', '');
field.status = field.status ? 1 : 0;
http.post('save', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
treeTable.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataEdit: function (data = {}) {
dataFromFun(data,
function (layero, index) {
iconPicker.render({
elem: '#iconPicker',
type: 'fontClass',
search: true,
page: false,
});
},
function (layero, index, elem) {
var field = elem.field;
field.icon = 'layui-icon ' + field.icon.indexOf("layui-icon ") == -1 ? field.icon : field.icon.replace('layui-icon ', '');
field.status = field.status ? 1 : 0;
http.put('update', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
treeTable.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataRecybin: function (data = {}) {
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
layer.open({
title: '资源回收站',
content: formHtml,
anim: "slideLeft",
offset: "r",
area: ['60%', '99%'],
shade: 0.1,
shadeClose: true,
success: function (layero, index) {
layui.table.render({
elem: '#dataRecybinTable',
url: 'recyclebin',
height: 'full-100',
defaultToolbar: [{
title: '批量删除数据',
layEvent: 'dataDelete',
icon: 'layui-icon-delete',
onClick: function (obj) {
var checkStatus = treeTable.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.id; });
console.log(ids);
}
}, 'filter', 'exports', 'print'],
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: 'title', width: 180, fixed: 'left' },
{ field: 'name', title: 'name', width: 180, fixed: 'left' },
{ field: 'route', title: '路由', minWidth: 200, sort: true },
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#databar" }
]],
page: true,
done: function (res, curr, count, origin) {
console.log('表格渲染完成');
}
});
}
});
},
dataRestore: function (data = {}) {
http.put('restore', { id: data.id })
.then((res) => {
if (res.code === 0) {
layer.msg('恢复成功');
treeTable.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '恢复失败');
}
});
}
};
exports('rule', {});
});
+184
View File
@@ -0,0 +1,184 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('score');
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'name', minWidth: 160, title: '规则名称' },
{ field: 'action', width: 160, title: '触发动作' },
{ field: 'type_text', width: 90, title: '类型', templet: '#typeTpl' },
{ field: 'value', width: 90, title: '变动值', sort: true },
{ field: 'sort', width: 90, title: '排序', sort: true },
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
{ field: 'create_time', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 120, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: { name: data.field.name } });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name="name"]').val('');
table.reload('dataTable', { page: { curr: 1 }, where: { name: '' } });
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate': active.dataCreate({}); break;
case 'dataDelete':
var check = table.checkStatus('dataTable').data;
active.dataDelete(check.map(function (i) { return i.id; }));
break;
case 'dataRecybin': active.dataRecybin(); break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update': active.dataEdit(data); break;
case 'delete': active.dataDelete([data.id]); break;
}
});
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
http.put('update', { id: this.value, status: status })
.then(function (res) {
if (res.code === 0) { layer.msg('操作成功'); }
else { layer.msg(res.msg || '操作失败'); }
table.reload('dataTable', {}, true);
})
.catch(function () { table.reload('dataTable', {}, true); });
});
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑积分规则' : '添加积分规则';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title, content: formHtml, anim: "slideLeft", offset: "r",
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
success: function (layero, index) { callback(layero, index); form.render(); },
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
var active = {
dataDelete: function (ids, force) {
if (ids.length === 0) { return layer.msg('请选择数据'); }
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
});
},
dataCreate: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
if (field.status === undefined) field.status = 0;
field.status = field.status ? 1 : 0;
field.value = parseInt(field.value, 10) || 0;
http.post('save', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataEdit: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
field.value = parseInt(field.value, 10) || 0;
http.put('update', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataRecybin: function () {
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
layer.open({
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
success: function () {
table.render({
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'name', title: '规则名称', minWidth: 160, fixed: 'left' },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data) {
http.put("restore", { ids: data.id }).then(function (res) {
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '恢复失败'); }
});
},
dataForceDelete: function (data) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
};
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore': active.dataRestore(data); break;
case 'forcedelete': active.dataForceDelete(data); break;
}
});
exports('score', {});
});
+179
View File
@@ -0,0 +1,179 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('shop');
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'title', minWidth: 160, title: '商品名称' },
{ field: 'sort', width: 100, title: '排序', sort: true },
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
{ field: 'create_time', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name=\"title\"]').val('');
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate': active.dataCreate({}); break;
case 'dataDelete':
var check = table.checkStatus('dataTable').data;
active.dataDelete(check.map(function (i) { return i.id; }));
break;
case 'dataRecybin': active.dataRecybin(); break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update': active.dataEdit(data); break;
case 'delete': active.dataDelete([data.id]); break;
}
});
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
http.put('update', { id: this.value, status: status })
.then(function (res) {
if (res.code === 0) { layer.msg('操作成功'); }
else { layer.msg(res.msg || '操作失败'); }
table.reload('dataTable', {}, true);
})
.catch(function () { table.reload('dataTable', {}, true); });
});
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑电子商务' : '添加电子商务';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title, content: formHtml, anim: "slideLeft", offset: "r",
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
success: function (layero, index) { callback(layero, index); form.render(); },
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
var active = {
dataDelete: function (ids, force) {
if (ids.length === 0) { return layer.msg('请选择数据'); }
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
});
},
dataCreate: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
if (field.status === undefined) field.status = 0;
field.status = field.status ? 1 : 0;
http.post('save', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataEdit: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
http.put('update', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataRecybin: function () {
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
layer.open({
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
success: function () {
table.render({
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '商品名称', minWidth: 160, fixed: 'left' },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data) {
http.put("restore", { ids: data.id }).then(function (res) {
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '恢复失败'); }
});
},
dataForceDelete: function (data) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
};
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore': active.dataRestore(data); break;
case 'forcedelete': active.dataForceDelete(data); break;
}
});
exports('shop', {});
});
+179
View File
@@ -0,0 +1,179 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('sms');
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'title', minWidth: 160, title: '模板名称' },
{ field: 'sort', width: 100, title: '排序', sort: true },
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
{ field: 'create_time', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name=\"title\"]').val('');
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate': active.dataCreate({}); break;
case 'dataDelete':
var check = table.checkStatus('dataTable').data;
active.dataDelete(check.map(function (i) { return i.id; }));
break;
case 'dataRecybin': active.dataRecybin(); break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update': active.dataEdit(data); break;
case 'delete': active.dataDelete([data.id]); break;
}
});
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
http.put('update', { id: this.value, status: status })
.then(function (res) {
if (res.code === 0) { layer.msg('操作成功'); }
else { layer.msg(res.msg || '操作失败'); }
table.reload('dataTable', {}, true);
})
.catch(function () { table.reload('dataTable', {}, true); });
});
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑短信服务' : '添加短信服务';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title, content: formHtml, anim: "slideLeft", offset: "r",
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
success: function (layero, index) { callback(layero, index); form.render(); },
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
var active = {
dataDelete: function (ids, force) {
if (ids.length === 0) { return layer.msg('请选择数据'); }
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
});
},
dataCreate: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
if (field.status === undefined) field.status = 0;
field.status = field.status ? 1 : 0;
http.post('save', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataEdit: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
http.put('update', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataRecybin: function () {
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
layer.open({
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
success: function () {
table.render({
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '模板名称', minWidth: 160, fixed: 'left' },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data) {
http.put("restore", { ids: data.id }).then(function (res) {
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '恢复失败'); }
});
},
dataForceDelete: function (data) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
};
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore': active.dataRestore(data); break;
case 'forcedelete': active.dataForceDelete(data); break;
}
});
exports('sms', {});
});
+115
View File
@@ -0,0 +1,115 @@
layui.define(['form', 'table', 'http', 'auth', 'laydate'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http,
laydate = layui.laydate,
auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('spider');
// 日期选择
laydate.render({ elem: '#dateInput' });
// 汇总 + 趋势(纯 CSS 迷你条形图,不依赖 echarts)
http.get('stats').then(function (res) {
if (res.code !== 0) { return; }
var summary = (res.data && res.data.summary) || [];
var trend = (res.data && res.data.trend) || { dates: [], series: [] };
var $body = $('#summaryBody').empty();
if (summary.length === 0) {
$body.append('<tr><td colspan="6" style="text-align:center;color:#999;">暂无蜘蛛来访记录</td></tr>');
}
var seriesMap = {};
(trend.series || []).forEach(function (s) { seriesMap[s.name] = s.data; });
summary.forEach(function (row) {
var line = seriesMap[row.label] || [];
var max = Math.max.apply(null, line.concat([1]));
var bars = line.map(function (v, i) {
var h = v > 0 ? Math.max(2, Math.round(v / max * 28)) : 1;
return '<span title="' + (trend.dates[i] || '') + ': ' + v + '" style="display:inline-block;width:5px;margin-right:1px;height:' + h + 'px;background:' + (v > 0 ? '#1E9FFF' : '#e2e2e2') + ';vertical-align:bottom;"></span>';
}).join('');
$body.append('<tr>'
+ '<td>' + row.label + ' <span style="color:#999;">(' + row.spider + ')</span></td>'
+ '<td>' + row.today + '</td>'
+ '<td>' + row.week + '</td>'
+ '<td>' + row.month + '</td>'
+ '<td>' + row.total + '</td>'
+ '<td><div style="height:30px;line-height:30px;">' + bars + '</div></td>'
+ '</tr>');
$('#spiderSelect').append('<option value="' + row.spider + '">' + row.label + '</option>');
});
form.render('select');
});
// 明细表
table.render({
elem: '#dataTable',
url: 'index',
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return {
code: res.code === 0 ? 0 : 1,
msg: res.message || '',
count: res.count || (res.data ? res.data.length : 0),
data: res.data || []
};
},
cols: [[
{ field: 'id', width: 90, title: 'ID', sort: true },
{ field: 'spider_text', width: 110, title: '蜘蛛' },
{ field: 'url', title: '抓取URL', minWidth: 240 },
{ field: 'ip', width: 140, title: '来源IP' },
{ field: 'app', width: 100, title: '应用' },
{ field: 'http_code', width: 90, title: '状态码' },
{ field: 'time_text', width: 170, title: '抓取时间' }
]],
limits: [15, 30, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
// 搜索
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: data.field });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name="ip"],input[name="url"],input[name="date"]').val('');
$('#spiderSelect').val('');
form.render('select');
table.reload('dataTable', { page: { curr: 1 }, where: { spider: '', ip: '', url: '', date: '' } });
});
// 工具条:清理旧日志
table.on('toolbar(dataTable)', function (elem) {
if (elem.event === 'dataClear') {
layer.prompt({ title: '保留最近多少天的明细?(聚合报表不受影响)', value: '30' }, function (value, index) {
layer.close(index);
var days = parseInt(value, 10) || 30;
http.post('clear', { days: days }).then(function (res) {
if (res.code === 0) {
layer.msg(res.message || '清理完成');
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || res.message || '清理失败');
}
});
});
}
});
exports('spider', {});
});
+211
View File
@@ -0,0 +1,211 @@
layui.define(['form', 'table', 'http', 'auth'], function (exports) {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
layer = layui.layer,
http = layui.http, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('task');
table.render({
elem: '#dataTable',
url: "index",
toolbar: '#tableBar',
defaultToolbar: ['filter', 'exports', 'print'],
parseData: function (res) {
return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] };
},
cols: [[
{ type: "checkbox", width: 50 },
{ field: 'id', width: 80, title: 'ID', sort: true },
{ field: 'title', minWidth: 160, title: '任务标题' },
{ field: 'reward_type', width: 110, title: '奖励类型', templet: '#rewardTypeTpl' },
{ field: 'reward_num', width: 100, title: '奖励数量', sort: true },
{ field: 'sort', width: 100, title: '排序', sort: true },
{ field: 'status', width: 100, title: '状态', templet: '#statusTpl' },
{ field: 'create_time', width: 180, title: '创建时间' },
{ title: '操作', minWidth: 150, toolbar: '#dataBar', align: "center" }
]],
limits: [10, 15, 20, 25, 50, 100],
limit: 15,
page: true,
skin: 'line',
done: function () {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(data-search-btn)', function (data) {
table.reload('dataTable', { page: { curr: 1 }, where: { title: data.field.title } });
return false;
});
$('#btn-reset').on('click', function () {
$('input[name=\"title\"]').val('');
table.reload('dataTable', { page: { curr: 1 }, where: { title: '' } });
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate': active.dataCreate({}); break;
case 'dataDelete':
var check = table.checkStatus('dataTable').data;
active.dataDelete(check.map(function (i) { return i.id; }));
break;
case 'dataRecybin': active.dataRecybin(); break;
}
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update': active.dataEdit(data); break;
case 'delete': active.dataDelete([data.id]); break;
}
});
form.on('switch(statusSwitch)', function (obj) {
var status = obj.elem.checked ? 1 : 0;
http.put('update', { id: this.value, status: status })
.then(function (res) {
if (res.code === 0) { layer.msg('操作成功'); }
else { layer.msg(res.msg || '操作失败'); }
table.reload('dataTable', {}, true);
})
.catch(function () { table.reload('dataTable', {}, true); });
});
var dataFromFun = function (data, callback, done) {
var title = data.id ? '编辑站点任务' : '添加站点任务';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title, content: formHtml, anim: "slideLeft", offset: "r",
btnAlign: "l", area: [window.width > 768 ? '50%' : '99%', '99%'],
shade: 0.1, shadeClose: true, btn: ['确定', '取消'],
success: function (layero, index) {
callback(layero, index);
form.render();
// 道具奖励动态表单切换
var $box = $(layero);
var numItem = $box.find('#rewardNumItem');
var propItem = $box.find('#rewardPropItem');
var propNumItem = $box.find('#propNumItem');
var typeSelect = $box.find('select[name="reward_type"]');
function toggleRewardType() {
var t = parseInt(typeSelect.val(), 10);
if (t === 3) {
numItem.hide();
propItem.show();
propNumItem.show();
} else {
numItem.show();
propItem.hide();
propNumItem.hide();
}
}
toggleRewardType();
typeSelect.on('change', toggleRewardType);
},
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem); layui.off('submit(wxapp-form)', 'from'); return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
var active = {
dataDelete: function (ids, force) {
if (ids.length === 0) { return layer.msg('请选择数据'); }
layer.confirm('确定删除吗?' + (force ? '(彻底删除,不可恢复)' : '(可到回收站恢复)'), function (index) {
layer.close(index);
http.delete('delete', { ids: ids.join(','), force: force ? 1 : 0 })
.then(function (res) { if (res.code === 0) { table.reload('dataTable', {}, true); } else { layer.msg(res.msg || '操作失败'); } });
});
},
dataCreate: function (data) {
dataFromFun(data, function () {}, function (layero, index, elem) {
var field = elem.field;
if (field.status === undefined) field.status = 0;
field.status = field.status ? 1 : 0;
http.post('save', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataEdit: function (data) {
dataFromFun(data, function (layero, index) {
var vals = { reward_type: data.reward_type };
if (data.reward_type == 3) {
vals.reward_num = data.reward_num; // 道具下拉选中
vals.prop_num = data.prop_num || 1;
}
form.val('wxapp-form', vals);
}, function (layero, index, elem) {
var field = elem.field;
field.status = field.status ? 1 : 0;
http.put('update', field).then(function (res) {
if (res.code === 0) { layer.close(index); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
},
dataRecybin: function () {
var formHtml = laytpl($('#dataRecybinTpl').html()).render({});
layer.open({
title: '资源回收站', content: formHtml, anim: "slideLeft", offset: "r",
area: ['50%', '99%'], shade: 0.1, shadeClose: true,
success: function () {
table.render({
elem: '#dataRecybinTable', url: "recyclebin", height: 'full-120',
parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || 0, data: res.data || [] }; },
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '任务标题', minWidth: 160, fixed: 'left' },
{ field: 'sort', title: '排序', width: 80 },
{ field: 'delete_at', title: '删除时间', width: 160 },
{ fixed: "right", title: "操作", width: 140, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true
});
}
});
},
dataRestore: function (data) {
http.put("restore", { ids: data.id }).then(function (res) {
if (res.code === 0) { layer.msg('恢复成功'); table.reload('dataRecybinTable', {}, true); table.reload('dataTable', {}, true); }
else { layer.msg(res.msg || '恢复失败'); }
});
},
dataForceDelete: function (data) {
layer.confirm('彻底删除后不可恢复,确定吗?', function (index) {
layer.close(index);
http.delete('delete', { ids: data.id, force: 1 }).then(function (res) {
if (res.code === 0) { layer.msg('已彻底删除'); table.reload('dataRecybinTable', {}, true); }
else { layer.msg(res.msg || '操作失败'); }
});
});
}
};
table.on('tool(dataRecybinTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'restore': active.dataRestore(data); break;
case 'forcedelete': active.dataForceDelete(data); break;
}
});
exports('task', {});
});
+404
View File
@@ -0,0 +1,404 @@
layui.define(['http', 'layer', 'laydate', 'util', 'auth'], function (exports) {
var $ = layui.$
, table = layui.table
, form = layui.form
, layer = layui.layer
, laydate = layui.laydate
, util = layui.util
, http = layui.http
, laytpl = layui.laytpl
, auth = layui.auth;
var _savedPerms = (layui.data('backend').permission) || [];
auth.init(_savedPerms);
auth.setController('user');
// 渲染表格
var dataTable = table.render({
elem: '#dataTable'
, url: 'index' // 后端数据接口
, page: true
, limit: 15
, toolbar: '#tableBar'
, cols: [[
{ type: 'checkbox', fixed: 'left' }
, { field: 'uid', title: 'UID', width: 99, align: 'center', sort: true, fixed: 'left' }
, { field: 'account', title: '账户', width: 120, align: 'center', fixed: 'left' }
, { field: 'nickname', title: '昵称', width: 100, align: 'center' }
// , { field: 'role_id', title: '角色', width: 100, align: 'center', templet: '#roleTpl' }
, { field: 'email', title: '邮箱', minWidth: 180, align: 'center' }
, { field: 'mobile', title: '手机', width: 120, align: 'center' }
, { field: 'login_info', title: '登录信息', width: 160, align: 'center', templet: '#loginInfoTpl' }
, { field: 'status', title: '状态', width: 90, align: 'center', templet: '#statusTpl', unresize: true }
, { field: 'create_at', title: '创建时间', width: 160, align: 'center', sort: true }
, { title: '操作', width: 120, align: 'right', toolbar: '#dataBar', fixed: 'right', unresize: true }
]],
done: function (res, curr, count) {
var view = $('#dataTable').next('.layui-table-view');
view.find('[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
$('.layui-btn[data-perm]').each(function () {
var perm = $(this).attr('data-perm');
if (perm && !auth.has(perm)) { $(this).remove(); }
});
}
});
form.on('submit(searchBtn)', function (data) {
adminTable.reload({
where: data.field,
page: { curr: 1 }
});
return false;
});
form.on('switch(statusSwitch)', function (obj) {
var uid = this.value;
var status = obj.elem.checked ? 1 : 0;
layer.confirm('确定要' + (status ? '启用' : '禁用') + '该管理员账号吗?', function (index) {
layui.http.post('update', { uid: uid, status: status }).then(function (res) {
if (res.code === 0) {
layer.msg(res.msg, { icon: 1 });
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg, { icon: 2 });
obj.elem.checked = !obj.elem.checked;
form.render('checkbox');
}
});
layer.close(index);
}, function () {
obj.elem.checked = !obj.elem.checked;
form.render('checkbox');
});
});
table.on('toolbar(dataTable)', function (elem) {
switch (elem.event) {
case 'dataCreate':
active.dataCreate({ pid: 0, type: 1 });
break;
case 'dataDelete':
var checkStatus = table.checkStatus('dataTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.uid; });
active.dataDelete(ids);
break;
case 'dataRecybin':
active.dataRecybin();
break;
};
});
table.on('tool(dataTable)', function (elem) {
var data = elem.data;
switch (elem.event) {
case 'update':
active.dataEdit(data);
break;
case 'delete':
active.dataDelete([data.uid]);
break;
}
});
var dataFromFun = function (data, callback, done) {
var title = data ? '编辑数据[' + data.account + ']' : '添加数据';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
title: title,
content: formHtml,
anim: "slideLeft",
offset: "r",
btnAlign: "l",
area: ['50% ', '99%'],
shade: 0.1,
shadeClose: true,
btn: ['确定', '取消'],
success: function (layero, index) {
callback(layero, index);
form.render();
},
yes: function (index, layero) {
window.layui.form.on('submit(wxapp-form-submit)', function (elem) {
done(layero, index, elem);
layui.off('submit(wxapp-form)', 'from');
return false;
});
layero.contents().find("#wxapp-form-submit").trigger('click');
}
});
};
//事件
var active = {
dataDelete: function (ids, force = 0) {
if (ids.length === 0) {
return layer.msg('请选择数据');
}
layer.prompt({
formType: 1
, title: '敏感操作,请验证口令'
}, function (value, index) {
layer.close(index);
layer.confirm('确定删除吗?', function (index) {
http.delete('delete', { ids: ids.join(','), force: force })
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
});
});
},
dataCreate: function (data = {}) {
dataFromFun(data,
function (layero, index) { },
function (layero, index, elem) {
var field = elem.field;
field.icon = 'layui-icon ' + field.icon;
field.status = field.status ? 1 : 0;
http.post('save', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataEdit: function (data = {}) {
dataFromFun(data,
function (layero, index) { },
function (layero, index, elem) {
var field = elem.field;
field.icon = 'layui-icon ' + field.icon;
field.status = field.status ? 1 : 0;
http.put('update', field)
.then((res) => {
if (res.code === 0) {
layer.close(index);
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '操作失败');
}
});
}
);
},
dataRecybin: function (data = {}) {
var formHtml = laytpl($('#dataRecybinTpl').html()).render(data || {});
layer.open({
title: '资源回收站',
content: formHtml,
anim: "slideLeft",
offset: "r",
area: ['50%', '99%'],
shade: 0.1,
shadeClose: true,
success: function (layero, index) {
layui.table.render({
elem: '#dataRecybinTable',
url: 'recyclebin',
height: 'full-100',
defaultToolbar: [{
title: '批量删除数据',
layEvent: 'dataDelete',
icon: 'layui-icon-delete',
onClick: function (obj) {
var checkStatus = table.checkStatus('dataRecybinTable'), checkData = checkStatus.data;
let ids = checkData.map((item, index, array) => { return item.uid; });
console.log(ids);
}
}, 'filter', 'exports', 'print'],
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'uid', title: 'UID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '名称', width: 180, fixed: 'left' },
{ field: 'code', title: '代码', width: 180, fixed: 'left' },
{ field: 'description', title: '描述', minWidth: 200, sort: true },
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#dataRecybinBarTpl" }
]],
page: true,
done: function (res, curr, count, origin) {
console.log('表格渲染完成');
}
});
}
});
},
dataRestore: function (data = {}) {
http.put('restore', { uid: data.uid })
.then((res) => {
if (res.code === 0) {
layer.msg('恢复成功');
table.reload('dataTable', {}, true);
} else {
layer.msg(res.msg || '恢复失败');
}
});
}
};
// 打开管理员表单
function opendataForm(data) {
var title = data ? '编辑管理员 [' + data.account + ']' : '添加管理员';
var formHtml = laytpl($('#dataFormTpl').html()).render(data || {});
layer.open({
type: 1,
title: title,
area: ['500px', '520px'],
shadeClose: true,
content: formHtml,
success: function (layero, index) {
// 显示/隐藏密码字段
if (data) {
$('#passwordGroup').hide();
} else {
$('#passwordGroup').show();
}
// 表单验证规则
layui.form.verify({
username: function (value) {
if (!/^[\w\u4e00-\u9fa5]{2,20}$/.test(value)) {
return '用户名必须2-20位字符,支持中文、字母、数字和下划线';
}
},
pass: [
/^[\S]{6,20}$/
, '密码必须6到20位,且不能出现空格'
]
});
// 提交表单
form.on('submit(adminFormSubmit)', function (formData) {
var url = data ? 'update' : 'create';
$.ajax({
url: url,
type: 'POST',
data: formData.field,
success: function (res) {
if (res.code === 1) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
layer.close(index);
adminTable.reload();
});
} else {
layer.msg(res.msg, { icon: 2 });
}
},
error: function () {
layer.msg('操作失败', { icon: 2 });
}
});
return false;
});
form.render();
},
btn: ['保存', '取消'],
yes: function (index, layero) {
// 触发表单提交
layero.find('form').find('button[lay-filter=adminFormSubmit]').click();
}
});
}
// 重置密码
function resetPassword(data) {
layer.confirm('确定要重置管理员 [' + data.username + '] 的密码吗?重置后密码将变为123456', {
btn: ['确定', '取消'],
title: '重置密码'
}, function (index) {
$.ajax({
url: 'resetPassword',
type: 'POST',
data: { id: data.uid },
success: function (res) {
layer.close(index);
if (res.code === 1) {
layer.msg(res.msg, { icon: 1 });
} else {
layer.msg(res.msg, { icon: 2 });
}
},
error: function () {
layer.msg('操作失败', { icon: 2 });
}
});
});
}
// 删除管理员
function deleteAdmin(data) {
layer.confirm('确定要删除管理员 [' + data.username + '] 吗?此操作不可恢复!', {
btn: ['确定', '取消'],
title: '删除管理员',
icon: 3
}, function (index) {
$.ajax({
url: 'delete',
type: 'POST',
data: { uid: data.uid },
success: function (res) {
layer.close(index);
if (res.code === 1) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
adminTable.reload();
});
} else {
layer.msg(res.msg, { icon: 2 });
}
},
error: function () {
layer.msg('操作失败', { icon: 2 });
}
});
});
}
// 批量删除
function batchDelete(data) {
if (data.length === 0) {
layer.msg('请先选择要删除的管理员', { icon: 3 });
return;
}
var superAdmins = data.filter(function (item) {
return item.is_super == 1;
});
if (superAdmins.length > 0) {
layer.msg('不能删除超级管理员账号', { icon: 2 });
return;
}
var ids = data.map(function (item) {
return item.uid;
});
layer.confirm('确定要删除选中的 ' + data.length + ' 个管理员吗?此操作不可恢复!', {
btn: ['确定', '取消'],
title: '批量删除',
icon: 3
}, function (index) {
$.ajax({
url: 'batchDelete',
type: 'POST',
data: { ids: ids },
success: function (res) {
layer.close(index);
if (res.code === 1) {
layer.msg(res.msg, { icon: 1, time: 1000 }, function () {
adminTable.reload();
});
} else {
layer.msg(res.msg, { icon: 2 });
}
},
error: function () {
layer.msg('操作失败', { icon: 2 });
}
});
});
}
exports('user', {});
});
+17
View File
@@ -0,0 +1,17 @@
<div class="layui-card-header">版本</div>
<div class="layui-card-body layui-text layadmin-about">
<blockquote class="layui-elem-quote" style="border: none;">
<script type="text/html" template>
<p>当前版本v{{ layui.ywxapp.version }}</p>
</script>
</blockquote>
</div>
<div class="layui-card-header">关于</div>
<div class="layui-card-body layui-text layadmin-about">
<blockquote class="layui-elem-quote" style="border: none;">
一套纯静态的 HTML 网页界面模板,以开源免费的 Layui 基础组件和页面模板 Demo 为组成,没有任何后端程序及数据库存储等服务端代码。
<br><br>开发者使用该网页模板,可省去前端的大量工作,从而更高效地开发 Web 应用系统。
</blockquote>
</div>
+84
View File
@@ -0,0 +1,84 @@
<!-- 主题设置模板 -->
<script type="text/html" template lay-done="layui.data.theme();">
{{#
var local = layui.data(layui.setter.tableName);
var theme = local.theme || {};
var color = theme.color || {};
var themeColorIndex = parseInt((theme && theme.color) ? theme.color.index : 0) || 0;
}}
<div class="layui-card-header">
<strong>主题设置</strong>
</div>
<div class="layui-card-body layadmin-setTheme">
<h5><strong>配色方案</strong></h5>
<ul class="layadmin-setTheme-color">
{{# layui.each(layui.setter.theme.color, function(index, item){ }}
<li layadmin-event="setTheme" data-index="{{ index }}" data-alias="{{ item.alias }}"
{{- index === themeColorIndex ? 'class="layui-this"' : '' }} title="{{ item.alias }}">
<div class="layadmin-setTheme-header" style="background-color: {{ item.header }};"></div>
<div class="layadmin-setTheme-side" style="background-color: {{ item.main }};">
<div class="layadmin-setTheme-logo" style="background-color: {{ item.logo }};"></div>
</div>
</li>
{{# }); }}
</ul>
<h5><strong>自定义配色</strong></h5>
<ul class="layadmin-setTheme-custom">
<li>主题色 <div class="set-custom-theme" data-name="main" lay-options="{color: '{{= color.main }}'}"></div></li>
<li>选中色 <div class="set-custom-theme" data-name="selected" lay-options="{color: '{{= color.selected }}'}"></div></li>
<li>LOGO 背景色 <div class="set-custom-theme" data-name="logo" lay-options="{color: '{{= color.logo }}'}"></div></li>
<li>头部拦背景色 <div class="set-custom-theme" data-name="header" lay-options="{color: '{{= color.header }}'}"></div></li>
<li>恢复默认主题 <div class="set-default-theme"><button class="layui-btn layui-btn-primary"><i class="layui-icon layui-icon-refresh-1"></i></button></div></li>
</ul>
</script>
<script>
layui.data.theme = function () {
layui.use(['form', 'colorpicker'], function () {
var $ = layui.$;
var layer = layui.layer;
var form = layui.form
var colorpicker = layui.colorpicker
var ywxapp = layui.ywxapp;
var view = layui.view;
var local = layui.data(layui.setter.tableName);
var theme = local.theme || {};
var color = theme.color || {};
// 自定义配色
colorpicker.render({
elem: '.set-custom-theme',
done: function (value) {
var elem = this.elem;
var NAME = elem.data('name');
color[NAME] = value;
ywxapp.theme({
color: color
});
}
});
// 恢复默认主题
$('.set-default-theme').on('click', function () {
layer.confirm('确认恢复默认主题吗?', function (i) {
layer.close(i);
ywxapp.events.setTheme($('.layadmin-setTheme-color>li:eq(0)'));
ywxapp.initTheme(0);
view('LAY_adminPopupTheme').render('system/theme');
})
});
// 事件-隐藏开关
form.on('switch(system-theme-sideicon)', function () {
ywxapp.theme({
hideSideIcon: this.checked
})
});
});
};
</script>