8 Commits

Author SHA1 Message Date
wolfcode
3e329a4ea3 fix(install): update ea_system_admin insert statement
- Add missing column for 'status' in ea_system_admin insert statement
- Set 'status' column to 1 for the admin user
2024-11-13 16:30:15 +08:00
wolfcode
f015a90b89 style(layuimini): remove redundant CSS rules for nav more icons- Removed specific margin-top rules for .layuimini-menu-left and .layuimini-menu-left-zoom classes
- Kept the general rule for .layuimini-menu-left .layui-nav .layui-nav-mored and .layuimini-menu-left .layui-nav-itemed > a .layui-nav-more
2024-11-12 17:21:04 +08:00
wolfcode
75c668b966 feat(auth): 新增谷歌验证码登录 implement Google Authenticator support for two-factor authentication
- Add Google Authenticator integration for enhanced login security-Update admin edit page to include login type selection
- Modify login process to support two-factor authentication
- Add new database fields for login type and GA secret
- Update client-side JavaScript to handle GA code input and validation
2024-11-12 10:51:48 +08:00
wolfcode
f3e5a041d1 feat(ueditor): add custom upload service and other enhancements
- Add custom upload service support
- Implement server response preparation function
- Enable loading config from server
- Add content import button to toolbar
- Update image alignment buttons order
- Add tip error function for better error handling
- Remove unused comments and simplify configuration options
2024-11-11 11:22:47 +08:00
wolfcode
3b219cfe7f feat(install): add official website tutorial and common questions links
- Add links to the official website tutorial and common questions in the installation page
- Update the logo image style for better visual presentation
2024-11-04 11:53:39 +08:00
wolfcode
ed99fe79fd feat(admin): 快捷操作支持翻页滚动显示 and optimize UI for better user experience
- Add swiper plugin support for carousel functionality
- Optimize UI for better user experience by using swiper
- Update index.js to support swiper initialization
- Modify welcome.html to include swiper HTML structure
- Adjust welcome.css for better styling of swiper elements
2024-10-29 17:24:54 +08:00
wolfcode
846b8ffafc feat(easy-admin): update window open URL for new tab button
- Change the URL for the "New tab open" button to use the iframe's content URL
- Add fallback to current window URL if iframe content URL cannot be accessed
- Improve user experience by opening the correct URL in a new tab

Signed-off-by: wolfcode <37436228+wolf-leo@users.noreply.github.com>
2024-10-28 18:26:26 +08:00
wolfcode
47ef5d9f10 feat(auth): 改用 zTree 替换 layui 的 tree 组件 use zTree for node authorization
- Replace layui tree with zTree for better performance and flexibility
- Update auth.js to use zTree for node rendering and checking
- Add zTree CSS and JS files to project

Signed-off-by: wolfcode <37436228+wolf-leo@users.noreply.github.com>
2024-10-28 16:35:06 +08:00
44 changed files with 54907 additions and 31922 deletions

View File

@@ -36,11 +36,9 @@ class Index extends AdminController
$mysqlVersion = Db::query("select version() as version")[0]['version'] ?? '未知';
$phpVersion = phpversion();
$versions = compact('tpVersion', 'mysqlVersion', 'phpVersion');
$quicks = SystemQuick::field('id,title,icon,href')
->where(['status' => 1])
->order('sort', 'desc')
->limit(8)
->select();
$quick_list = SystemQuick::field('id,title,icon,href')
->where(['status' => 1])->order('sort', 'desc')->limit(50)->select()->toArray();
$quicks = array_chunk($quick_list, 8);
$this->assign(compact('quicks', 'versions'));
return $this->fetch();
}
@@ -55,7 +53,7 @@ class Index extends AdminController
*/
public function editAdmin(Request $request): string
{
$id = $this->adminUid;
$id = $this->adminUid;
$row = (new SystemAdmin())
->withoutField('password')
->find($id);
@@ -66,15 +64,20 @@ class Index extends AdminController
$rule = [];
$this->validate($post, $rule);
try {
$save = $row
->allowField(['head_img', 'phone', 'remark', 'update_time'])
->save($post);
}catch (Exception $e) {
$login_type = $post['login_type'] ?? 1;
if ($login_type == 2) {
$ga_secret = (new SystemAdmin())->where('id', $id)->value('ga_secret');
if (empty($ga_secret)) $this->error('请先绑定谷歌验证器');
}
$save = $row->allowField(['head_img', 'phone', 'remark', 'update_time', 'login_type'])->save($post);
}catch (\PDOException $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$this->assign('row', $row);
$notes = (new SystemAdmin())->notes;
$this->assign('notes', $notes);
return $this->fetch();
}
@@ -82,13 +85,10 @@ class Index extends AdminController
* 修改密码
* @param Request $request
* @return string
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function editPassword(Request $request): string
{
$id = $this->adminUid;
$id = $this->adminUid;
$row = (new SystemAdmin())
->withoutField('password')
->find($id);
@@ -124,4 +124,37 @@ class Index extends AdminController
return $this->fetch();
}
/**
* 设置谷歌验证码
* @param Request $request
* @return string
* @throws Exception
*/
public function set2fa(Request $request): string
{
$id = $this->adminUid;
$row = (new SystemAdmin())->withoutField('password')->find($id);
if (!$row) $this->error('用户信息不存在');
// You can see: https://gitee.com/wolf-code/authenticator
$ga = new \Wolfcode\Authenticator\google\PHPGangstaGoogleAuthenticator();
if (!$request->isAjax()) {
$old_secret = $row->ga_secret;
$secret = $ga->createSecret(32);
$ga_title = $this->isDemo ? 'EasyAdmin8演示环境' : '可自定义修改显示标题';
$dataUri = $ga->getQRCode($ga_title, $secret)->getDataUri();
$this->assign(compact('row', 'dataUri', 'old_secret', 'secret'));
return $this->fetch();
}
$this->isDemo && $this->error('演示环境下不允许修改');
$post = $request->post();
$ga_secret = $post['ga_secret'] ?? '';
$ga_code = $post['ga_code'] ?? '';
if (empty($ga_code)) $this->error('请输入验证码');
if (!$ga->verifyCode($ga_secret, $ga_code)) $this->error('验证码错误');
$row->ga_secret = $ga_secret;
$row->login_type = 2;
$row->save();
$this->success('操作成功');
}
}

View File

@@ -56,6 +56,11 @@ class Login extends AdminController
if ($admin->status == 0) {
$this->error('账号已被禁用');
}
if ($admin->login_type == 2) {
if (empty($post['ga_code'])) $this->error('请输入谷歌验证码', ['is_ga_code' => true]);
$ga = new \Wolfcode\Authenticator\google\PHPGangstaGoogleAuthenticator();
if (!$ga->verifyCode($admin->ga_secret, $post['ga_code'])) $this->error('谷歌验证码错误');;
}
$admin->login_num += 1;
$admin->save();
$admin = $admin->toArray();

View File

@@ -10,6 +10,13 @@ class SystemAdmin extends TimeModel
protected $deleteTime = 'delete_time';
public array $notes = [
'login_type' => [
1 => '密码登录',
2 => '密码 + 谷歌验证码登录'
],
];
public function getAuthList()
{
$list = (new SystemAuth())

View File

@@ -30,6 +30,15 @@
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">登录方式</label>
<div class="layui-input-block">
{foreach notes.login_type as $key=>$val}
<input type="radio" name="login_type" lay-skin="primary" title="{$val}" value="{$key}" lay-filter="loginType-filter" {if $key==$row.login_type}checked=""{/if}>
{/foreach}
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">备注信息</label>
<div class="layui-input-block">

View File

@@ -0,0 +1,45 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form" autocomplete="off">
{if $old_secret}
<div class="layui-card">
<div class="layui-card-header">提示</div>
<div class="layui-card-body">
当前账号已经绑定过了 谷歌验证码 ,如果重新保存将替换
</div>
</div>
{/if}
<div class="layui-form-item">
<label class="layui-form-label required">验证秘钥</label>
<div class="layui-input-block">
<input type="text" name="ga_secret" class="layui-input" value="{$secret}" readonly disabled>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">二维码</label>
<div class="layui-input-block">
<img src="{$dataUri}" alt="二维码" style="width: 200px;height: 200px">
<div class="layui-text layui-font-cyan layui-font-12">
使用&nbsp;
<a href="https://2fas.com" target="_blank"><span class="layui-text layui-font-blue">2FAS</span></a>
&nbsp;或者&nbsp;
<a href="https://cn.bing.com/search?q=Google+Authenticator" target="_blank"><span class="layui-text layui-font-blue">Google Authenticator</span></a>
&nbsp;APP 扫描二维码 输入验证码 进行绑定
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">谷歌验证码</label>
<div class="layui-input-block">
<input type="text" name="ga_code" class="layui-input" maxlength="6" lay-verify="required" placeholder="扫描二维码,输入验证码" value="">
</div>
</div>
<div class=" hr-line">
</div>
<div class="layui-form-item text-center">
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

View File

@@ -69,16 +69,27 @@
<div class="layui-card-body">
<div class="welcome-module">
<div class="layui-row layui-col-space10">
<div class="swiper mySwiper">
<div class="swiper-wrapper">
{foreach $quicks as $value}
{foreach $quicks as $vo}
<div class="layui-col-xs3 layuimini-qiuck-module">
<a layuimini-content-href="{:url($vo['href'])}" data-title="{$vo['title']}">
<i class="{$vo['icon']|raw}"></i>
<cite>{$vo['title']}</cite>
</a>
<div class="swiper-slide">
{foreach $value as $vo}
<div class="layui-col-xs3 layuimini-qiuck-module">
<a layuimini-content-href="{:url($vo['href'])}" data-title="{$vo['title']}">
<i class="{$vo['icon']|raw}"></i>
<cite>{$vo['title']}</cite>
</a>
</div>
{/foreach}
</div>
{/foreach}
</div>
</div>
{/foreach}
<div class="swiper-pagination"></div>
</div>
</div>
</div>

View File

@@ -22,6 +22,11 @@
<span class="bind-password icon icon-4"></span>
</div>
<div class="item layui-hide" id="gaCode">
<span class="icon icon-3"></span>
<input type="text" name="ga_code" placeholder="谷歌验证码" maxlength="6">
</div>
{if $captcha == 1}
<div id="validatePanel" class="item" style="width: 137px;">
<input type="text" name="captcha" placeholder="请输入验证码" maxlength="4">

View File

@@ -1,4 +1,11 @@
<link rel="stylesheet" href="/static/plugs/zTree/fontawesome.css">
<link rel="stylesheet" href="/static/plugs/zTree/zTreeStyle.css?v={$version}">
<script src='/static/plugs/jquery-3.4.1/jquery-3.4.1.min.js'></script>
<script src='/static/plugs/zTree/jquery.ztree.core.js'></script>
<script src='/static/plugs/zTree/jquery.ztree.excheck.js'></script>
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
@@ -10,8 +17,8 @@
<div class="layui-form-item">
<label class="layui-form-label required">分配节点</label>
<div class="layui-input-block">
<div id="node_ids" class="demo-tree-more"></div>
<div class="layui-input-block" id="zTree">
<ul id="tree" class="ztree"></ul>
</div>
</div>
@@ -24,4 +31,4 @@
</div>
</form>
</div>
</div>

View File

@@ -37,7 +37,8 @@
"qiniu/php-sdk": "v7.11.0",
"ext-mysqli": "*",
"ext-pdo": "*",
"wolf-leo/phplogviewer": "^0.11.1"
"wolf-leo/phplogviewer": "^0.11.3",
"wolfcode/authenticator": "^0.0.3"
},
"require-dev": {
"symfony/var-dumper": ">=4.2",

View File

@@ -97,6 +97,8 @@ CREATE TABLE `ea_system_admin`
`create_time` int(11) DEFAULT NULL COMMENT '创建时间',
`update_time` int(11) DEFAULT NULL COMMENT '更新时间',
`delete_time` int(11) DEFAULT NULL COMMENT '删除时间',
`login_type` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '登录方式',
`ga_secret` varchar(32) NOT NULL DEFAULT '' COMMENT '谷歌验证码秘钥',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`) USING BTREE,
KEY `phone` (`phone`)
@@ -106,7 +108,7 @@ CREATE TABLE `ea_system_admin`
-- Records of ea_system_admin
-- ----------------------------
INSERT INTO `ea_system_admin`
VALUES ('1', null, '/static/admin/images/head.jpg', 'admin', 'a33b679d5581a8692988ec9f92ad2d6a2259eaa7', 'admin', 'admin', '0', '0', '1', '1589454169', '1589476815', null);
VALUES ('1', null, '/static/admin/images/head.jpg', 'admin', 'a33b679d5581a8692988ec9f92ad2d6a2259eaa7', 'admin', 'admin', '0', '0', '1', '1589454169', '1589476815', null,1,'');
-- ----------------------------
-- Table structure for ea_system_auth

View File

@@ -32,7 +32,7 @@
.layuimini-qiuck-module a i {
display: inline-block;
width: 100%;
width: 80%;
height: 60px;
line-height: 60px;
text-align: center;

View File

@@ -1,4 +1,4 @@
define(["jquery", "easy-admin", "echarts", "echarts-theme", "miniAdmin", "miniTab"], function ($, ea, echarts, undefined, miniAdmin, miniTab) {
define(["jquery", "easy-admin", "echarts", "echarts-theme", "miniAdmin", "miniTab", "swiper"], function ($, ea, echarts, undefined, miniAdmin, miniTab) {
return {
index: function () {
@@ -50,6 +50,14 @@ define(["jquery", "easy-admin", "echarts", "echarts-theme", "miniAdmin", "miniTa
},
welcome: function () {
miniTab.listen();
new Swiper('.mySwiper', {
pagination: {
el: '.swiper-pagination',
clickable: true,
},
})
/**
* 查看公告信息
**/
@@ -156,10 +164,22 @@ define(["jquery", "easy-admin", "echarts", "echarts-theme", "miniAdmin", "miniTa
})
},
editAdmin: function () {
let form = layui.form
form.on('radio(loginType-filter)', function (data) {
let elem = data.elem
let value = elem.value
if (value === '2') {
let width = screen.width < 768 ? '85%' : '60%'
ea.open('绑定谷歌验证码', ea.url('index/set2fa'), width, '75%')
}
});
ea.listen();
},
editPassword: function () {
ea.listen();
}
},
set2fa: function () {
ea.listen();
},
};
});

View File

@@ -39,6 +39,12 @@ define(["jquery", "easy-admin"], function ($, ea) {
window.location = ea.url('index');
})
}, function (res) {
let data = res.data
if (data.is_ga_code) {
let elem = $('#gaCode')
elem.removeClass('layui-hide');
elem.find('input').focus()
}
ea.msg.error(res.msg, function () {
$('#refreshCaptcha').trigger("click");
});

View File

@@ -1,89 +1,107 @@
define(["jquery", "easy-admin"], function ($, ea) {
var init = {
table_elem: '#currentTable',
table_render_id: 'currentTableRenderId',
index_url: 'system.auth/index',
add_url: 'system.auth/add',
edit_url: 'system.auth/edit',
delete_url: 'system.auth/delete',
export_url: 'system.auth/export',
modify_url: 'system.auth/modify',
authorize_url: 'system.auth/authorize',
};
var init = {
table_elem: '#currentTable',
table_render_id: 'currentTableRenderId',
index_url: 'system.auth/index',
add_url: 'system.auth/add',
edit_url: 'system.auth/edit',
delete_url: 'system.auth/delete',
export_url: 'system.auth/export',
modify_url: 'system.auth/modify',
authorize_url: 'system.auth/authorize',
};
return {
return {
index: function () {
ea.table.render({
init: init,
cols: [[
{type: "checkbox"},
{field: 'id', width: 80, title: 'ID', searchOp: '='},
{field: 'sort', width: 80, title: '排序', edit: 'text'},
{field: 'title', minWidth: 80, title: '权限名称'},
{field: 'remark', minWidth: 80, title: '备注信息'},
{field: 'status', title: '状态', width: 85, search: 'select', selectList: {0: '禁用', 1: '启用'}, templet: ea.table.switch},
{field: 'create_time', minWidth: 80, title: '创建时间', search: 'range'},
{
width: 250,
title: '操作',
templet: ea.table.tool,
operat: [
'edit',
[{
text: '授权',
url: init.authorize_url,
method: 'open',
auth: 'authorize',
class: 'layui-btn layui-btn-normal layui-btn-xs',
}],
'delete'
]
}
]],
});
ea.listen();
},
add: function () {
ea.listen();
},
edit: function () {
ea.listen();
},
authorize: function () {
var tree = layui.tree;
ea.request.get(
{
url: window.location.href,
}, function (res) {
res.data = res.data || [];
tree.render({
elem: '#node_ids',
data: res.data,
showCheckbox: true,
id: 'nodeDataId',
});
}
);
ea.listen(function (data) {
var checkedData = tree.getChecked('nodeDataId');
var ids = [];
$.each(checkedData, function (i, v) {
ids.push(v.id);
if (v.children !== undefined && v.children.length > 0) {
$.each(v.children, function (ii, vv) {
ids.push(vv.id);
});
}
index: function () {
ea.table.render({
init: init,
cols: [[
{type: "checkbox"},
{field: 'id', width: 80, title: 'ID', searchOp: '='},
{field: 'sort', width: 80, title: '排序', edit: 'text'},
{field: 'title', minWidth: 80, title: '权限名称'},
{field: 'remark', minWidth: 80, title: '备注信息'},
{field: 'status', title: '状态', width: 85, search: 'select', selectList: {0: '禁用', 1: '启用'}, templet: ea.table.switch},
{field: 'create_time', minWidth: 80, title: '创建时间', search: 'range'},
{
width: 250,
title: '操作',
templet: ea.table.tool,
operat: [
'edit',
[{
text: '授权',
url: init.authorize_url,
method: 'open',
auth: 'authorize',
class: 'layui-btn layui-btn-normal layui-btn-xs',
}],
'delete'
]
}
]],
});
data.node = JSON.stringify(ids);
return data;
});
ea.listen();
},
add: function () {
ea.listen();
},
edit: function () {
ea.listen();
},
authorize: function () {
let setting = {
check: {
enable: true,
chkStyle: "checkbox",
},
view: {
showIcon: true,
showLine: true,
selectedMulti: false,
dblClickExpand: false
}, callback: {
onClick: function (e, treeId, treeNode, clickFlag) {
treeObj.checkNode(treeNode, !treeNode.checked, true);
}
}
};
let treeObj
let treeData = []
ea.request.get({url: window.location.href}, function (res) {
res.data = res.data || [];
$.each(res.data, function (index, value) {
treeData[index] = []
treeData[index].id = value.id
treeData[index].name = value.title
treeData[index].pId = 0
treeData[index].open = true
let children = value.children
treeData[index]['children'] = []
$.each(children, function (idx, val) {
treeData[index]['children'].push({id: val.id, name: val.title, checked: val.checked, pId: value.id})
})
})
$.fn.zTree.init($("#tree"), setting, treeData);
treeObj = $.fn.zTree.getZTreeObj("tree");
}
);
ea.listen(function (data) {
let checkedData = treeObj.getCheckedNodes();
let ids = []
for (var i = 0; i < checkedData.length; i++) {
ids.push(checkedData[i].id)
}
data.node = JSON.stringify(ids);
return data;
});
}
}
};
});
}
)

View File

@@ -21,6 +21,7 @@ require.config({
"iconPickerFa": ["plugs/lay-module/iconPicker/iconPickerFa"],
"autocomplete": ["plugs/lay-module/autocomplete/autocomplete"],
"vue": ["plugs/vue-2.6.10/vue.min"],
"swiper": ["plugs/swiper/swiper-bundle.min"],
}
});

View File

@@ -1000,9 +1000,17 @@ define(["jquery", "tableSelect"], function ($, tableSelect) {
},
success: function (layero, index) {
if (window.CONFIG.IFRAME_OPEN_TOP == '1') {
let iframeUrl = ``
try {
let iframeId = $('iframe:eq(0)').attr('id')
let iframe = document.getElementById(iframeId)
iframeUrl = iframe.contentWindow.location.href
} catch (e) {
iframeUrl = location.href
}
let _winTopBtn = `
<span class="_winTopBtn layui-btn layui-btn-primary layui-btn-xs"
style="position: absolute;top: 14px;right: 120px;color: #fff;border-color: #fff;" onclick="window.open(location.href)">
style="position: absolute;top: 14px;right: 120px;color: #fff;border-color: #fff;" onclick="window.open('${iframeUrl}')">
新标签页打开
</span>`
$('.layui-layer-iframe').append(_winTopBtn)

View File

@@ -700,14 +700,6 @@
margin-top: -6px !important;
}
.layuimini-menu-left .layui-nav .layui-nav-mored,.layuimini-menu-left .layui-nav-itemed>a .layui-nav-more{
margin-top: -9px!important;
}
.layuimini-menu-left-zoom.layui-nav .layui-nav-mored,.layuimini-menu-left-zoom.layui-nav-itemed>a .layui-nav-more{
margin-top: -9px!important;
}
.layuimini-menu-left .layui-nav-more:before,.layuimini-menu-left-zoom .layui-nav-more:before {
content: "\e61a";
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -10,14 +10,8 @@
**************************提示********************************/
(function () {
/**
* 编辑器资源文件根路径。它所表示的含义是以编辑器实例化页面为当前路径指向编辑器资源文件即dialog等文件夹的路径。
* 鉴于很多同学在使用编辑器的时候出现的种种路径问题,此处强烈建议大家使用"相对于网站根目录的相对路径"进行配置。
* "相对于网站根目录的相对路径"也就是以斜杠开头的形如"/myProject/ueditor/"这样的路径。
* 如果站点中有多个不在同一层级的页面需要实例化编辑器且引用了同一UEditor的时候此处的URL可能不适用于每个页面的编辑器。
* 因此UEditor提供了针对不同页面的编辑器可单独配置的根路径具体来说在需要实例化编辑器的页面最顶部写上如下代码即可。当然需要令此处的URL等于对应的配置。
* window.UEDITOR_HOME_URL = "/xxxx/xxxx/";
*/
// 资源文件根路径,如果你的页面不是放在根目录下,请注意修改这个路径
// 通常情况下这个可以配置成静态资源CDN的地址
window.UEDITOR_HOME_URL = "/static/plugs/ueditor/";
var URL, CORS_URL;
if (window.UEDITOR_HOME_URL) {
@@ -29,6 +23,8 @@
} else {
URL = getUEBasePath();
}
// 需要能跨域的静态资源请求,主要用户弹窗页面等静态资源
// 通常情况下这个可以配置成静态资源CDN的地址
if (window.UEDITOR_CORS_URL) {
CORS_URL = window.UEDITOR_CORS_URL;
} else if (window.__msRoot) {
@@ -38,6 +34,7 @@
} else {
CORS_URL = getUEBasePath();
}
/**
* 配置项主体。注意此处所有涉及到路径的配置别遗漏URL变量。
*/
@@ -53,10 +50,19 @@
// 服务器统一请求接口路径
serverUrl: "/" + (window.CONFIG.ADMIN || 'admin') + "/ajax/uploadUEditor",
// 从服务器获取配置
loadConfigFromServer: true,
// 服务器统一请求头信息,会在所有请求中带上该信息
serverHeaders: {
// 'Authorization': 'Bearer xxx'
},
// 服务器返回参数统一转换方法,可以在这里统一处理返回参数
serverResponsePrepare: function (res) {
// console.log('serverResponsePrepare', res);
return res;
},
//工具栏上的所有的功能按钮和下拉框可以在new编辑器的实例时选择自己需要的重新定义
toolbars: [
@@ -114,8 +120,8 @@
"|",
"imagenone", // 图片默认
"imageleft", // 图片左浮动
"imageright", // 图片右浮动
"imagecenter", // 图片居中
"imageright", // 图片右浮动
"|",
"simpleupload", // 单图上传
"insertimage", // 多图上传
@@ -154,12 +160,15 @@
"print", // 打印
"preview", // 预览
"searchreplace", // 查询替换
"|",
"contentimport",
"help", // 帮助
]
]
// 自定义工具栏按钮点击,返回 true 表示已经处理点击,会阻止默认事件
, toolbarCallback: function (cmd, editor) {
// console.log('toolbarCallback',cmd, editor);
// switch(cmd){
// case 'insertimage':
// editor.execCommand('insertHtml', '<p><img src="xxxxx" /></p>');
@@ -176,6 +185,33 @@
// }
}
// 自定义上传功能
, uploadServiceEnable: false
// 自定义上传函数,需要在这个函数中实现自定义上传逻辑
// type 上传类型image 图片video 视频audio 音频attachment 附件
// file 文件对象
// callback 回调函数,需要在上传完成后调用 callback.success、callback.error、callback.progress
// option 上传配置,其他一些未来扩展配置
, uploadServiceUpload: function(type, file, callback, option ) {
console.log('uploadServiceUpload', type, file, callback, option);
// var i = 0;
// var call = function(){
// i++;
// if(i > 3){
// callback.success({
// "state": "SUCCESS",
// "url": "https://ms-assets.modstart.com/demo/modstart.jpg",
// })
// return;
// }
// setTimeout(function(){
// callback.progress(0.3 * i);
// call();
// },500);
// }
// call();
}
// 插入图片自定义配置
, imageConfig: {
// 禁止本地上传
@@ -316,7 +352,8 @@
// 是否开启初始化时即全屏,默认关闭
, fullscreen: false
//,imagePopup:true //图片操作的浮层开关,默认打开
// 图片操作的浮层开关,默认打开
//,imagePopup:true
// 自动同步编辑器要提交的数据
//,autoSyncData:true
@@ -359,17 +396,8 @@
// 提交到后台的数据是否包含整个html字符串
, allHtmlEnabled: false
//insertorderedlist
//有序列表的下拉配置,值留空时支持多语言自动识别,若配置值,则以此值为准
//,'insertorderedlist':{
// //自定的样式
// 'num':'1,2,3...',
// 'num1':'1),2),3)...',
// 'num2':'(1),(2),(3)...',
// 'cn':'一,二,三....',
// 'cn1':'一),二),三)....',
// 'cn2':'(一),(二),(三)....',
// //系统自带
// 'decimal' : '' , //'1,2,3...'
// 'lower-alpha' : '' , // 'a,b,c...'
// 'lower-roman' : '' , //'i,ii,iii...'
@@ -380,8 +408,6 @@
//insertunorderedlist
//无序列表的下拉配置,值留空时支持多语言自动识别,若配置值,则以此值为准
//,insertunorderedlist : { //自定的样式
// 'dash' :'— 破折号', //-破折号
// 'dot':' 。 小圆圈', //系统自带
// 'circle' : '', // '○ 小圆圈'
// 'disc' : '', // '● 小圆点'
// 'square' : '' //'■ 小方块'
@@ -465,6 +491,12 @@
"forecolor", // 字体颜色
// "shadowcolor", // 字体阴影
"backcolor", // 背景色
"imagenone",
"imageleft",
"imagecenter",
"imageright",
"insertimage",
"formula",
// "justifyleft", // 居左对齐
// "justifycenter", // 居中对齐
// "justifyright", // 居右对齐
@@ -513,19 +545,19 @@
// 是否自动长高,默认true
, autoHeightEnabled: true
//scaleEnabled
//是否可以拉伸长高,默认true(当开启时,自动长高失效)
// 是否可以拉伸长高默认true(当开启时,自动长高失效)
//,scaleEnabled:false
//,minFrameWidth:800 //编辑器拖动时最小宽度,默认800
//,minFrameHeight:220 //编辑器拖动时最小高度,默认220
//autoFloatEnabled
//是否保持toolbar的位置不动,默认true
//,autoFloatEnabled:true
//浮动时工具栏距离浏览器顶部的高度,用于某些具有固定头部的页面
//,topOffset:30
//编辑器底部距离工具栏高度(如果参数大于等于编辑器高度,则设置无效)
//,toolbarTopOffset:400
// 编辑器最小高度,默认220
, minFrameHeight: 220
// 是否保持toolbar的位置不动,默认true
, autoFloatEnabled: true
// 浮动时工具栏距离浏览器顶部的高度,用于某些具有固定头部的页面
, topOffset: 0
// 编辑器底部距离工具栏高度(如果参数大于等于编辑器高度,则设置无效)
, toolbarTopOffset: 0
//设置远程图片是否抓取到本地保存
, catchRemoteImageEnable: true //设置是否抓取远程图片
@@ -595,7 +627,15 @@
// 允许进入编辑器的 div 标签自动变成 p 标签
, allowDivTransToP: true
// 默认产出的数据中的color自动从rgb格式变成16进制格式
, rgb2Hex: true
, rgb2Hex: true,
tipError: function (msg, param) {
if (window && window.MS && window.MS.dialog) {
window.MS.dialog.tipError(msg);
} else {
alert(msg);
}
}
};
function getUEBasePath(docUrl, confUrl) {
@@ -651,4 +691,4 @@
window.UE = {
getUEBasePath: getUEBasePath
};
})();
})();

6110
public/static/plugs/zTree/fontawesome.css vendored Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,652 @@
/*
* JQuery zTree excheck
* v3.5.48
* http://treejs.cn/
*
* Copyright (c) 2010 Hunter.z
*
* Licensed same as jquery - MIT License
* http://www.opensource.org/licenses/mit-license.php
*
* Date: 2020-11-21
*/
(function ($) {
//default consts of excheck
var _consts = {
event: {
CHECK: "ztree_check"
},
id: {
CHECK: "_check"
},
checkbox: {
STYLE: "checkbox",
DEFAULT: "chk",
DISABLED: "disable",
FALSE: "false",
TRUE: "true",
FULL: "full",
PART: "part",
FOCUS: "focus"
},
radio: {
STYLE: "radio",
TYPE_ALL: "all",
TYPE_LEVEL: "level"
}
},
//default setting of excheck
_setting = {
check: {
enable: false,
autoCheckTrigger: false,
chkStyle: _consts.checkbox.STYLE,
nocheckInherit: false,
chkDisabledInherit: false,
radioType: _consts.radio.TYPE_LEVEL,
chkboxType: {
"Y": "ps",
"N": "ps"
}
},
data: {
key: {
checked: "checked"
}
},
callback: {
beforeCheck: null,
onCheck: null
}
},
//default root of excheck
_initRoot = function (setting) {
var r = data.getRoot(setting);
r.radioCheckedList = [];
},
//default cache of excheck
_initCache = function (treeId) {
},
//default bind event of excheck
_bindEvent = function (setting) {
var o = setting.treeObj,
c = consts.event;
o.bind(c.CHECK, function (event, srcEvent, treeId, node) {
event.srcEvent = srcEvent;
tools.apply(setting.callback.onCheck, [event, treeId, node]);
});
},
_unbindEvent = function (setting) {
var o = setting.treeObj,
c = consts.event;
o.unbind(c.CHECK);
},
//default event proxy of excheck
_eventProxy = function (e) {
var target = e.target,
setting = data.getSetting(e.data.treeId),
tId = "", node = null,
nodeEventType = "", treeEventType = "",
nodeEventCallback = null, treeEventCallback = null;
if (tools.eqs(e.type, "mouseover")) {
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) {
tId = tools.getNodeMainDom(target).id;
nodeEventType = "mouseoverCheck";
}
} else if (tools.eqs(e.type, "mouseout")) {
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) {
tId = tools.getNodeMainDom(target).id;
nodeEventType = "mouseoutCheck";
}
} else if (tools.eqs(e.type, "click")) {
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) {
tId = tools.getNodeMainDom(target).id;
nodeEventType = "checkNode";
}
}
if (tId.length > 0) {
node = data.getNodeCache(setting, tId);
switch (nodeEventType) {
case "checkNode" :
nodeEventCallback = _handler.onCheckNode;
break;
case "mouseoverCheck" :
nodeEventCallback = _handler.onMouseoverCheck;
break;
case "mouseoutCheck" :
nodeEventCallback = _handler.onMouseoutCheck;
break;
}
}
var proxyResult = {
stop: nodeEventType === "checkNode",
node: node,
nodeEventType: nodeEventType,
nodeEventCallback: nodeEventCallback,
treeEventType: treeEventType,
treeEventCallback: treeEventCallback
};
return proxyResult
},
//default init node of excheck
_initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {
if (!n) return;
var checked = data.nodeChecked(setting, n);
n.checkedOld = checked;
if (typeof n.nocheck == "string") n.nocheck = tools.eqs(n.nocheck, "true");
n.nocheck = !!n.nocheck || (setting.check.nocheckInherit && parentNode && !!parentNode.nocheck);
if (typeof n.chkDisabled == "string") n.chkDisabled = tools.eqs(n.chkDisabled, "true");
n.chkDisabled = !!n.chkDisabled || (setting.check.chkDisabledInherit && parentNode && !!parentNode.chkDisabled);
if (typeof n.halfCheck == "string") n.halfCheck = tools.eqs(n.halfCheck, "true");
n.halfCheck = !!n.halfCheck;
n.check_Child_State = -1;
n.check_Focus = false;
n.getCheckStatus = function () {
return data.getCheckStatus(setting, n);
};
if (setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL && checked) {
var r = data.getRoot(setting);
r.radioCheckedList.push(n);
}
},
//add dom for check
_beforeA = function (setting, node, html) {
if (setting.check.enable) {
data.makeChkFlag(setting, node);
html.push("<span ID='", node.tId, consts.id.CHECK, "' class='", view.makeChkClass(setting, node), "' treeNode", consts.id.CHECK, (node.nocheck === true ? " style='display:none;'" : ""), "></span>");
}
},
//update zTreeObj, add method of check
_zTreeTools = function (setting, zTreeTools) {
zTreeTools.checkNode = function (node, checked, checkTypeFlag, callbackFlag) {
var nodeChecked = data.nodeChecked(setting, node);
if (node.chkDisabled === true) return;
if (checked !== true && checked !== false) {
checked = !nodeChecked;
}
callbackFlag = !!callbackFlag;
if (nodeChecked === checked && !checkTypeFlag) {
return;
} else if (callbackFlag && tools.apply(this.setting.callback.beforeCheck, [this.setting.treeId, node], true) == false) {
return;
}
if (tools.uCanDo(this.setting) && this.setting.check.enable && node.nocheck !== true) {
data.nodeChecked(setting, node, checked);
var checkObj = $$(node, consts.id.CHECK, this.setting);
if (checkTypeFlag || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);
view.setChkClass(this.setting, checkObj, node);
view.repairParentChkClassWithSelf(this.setting, node);
if (callbackFlag) {
this.setting.treeObj.trigger(consts.event.CHECK, [null, this.setting.treeId, node]);
}
}
}
zTreeTools.checkAllNodes = function (checked) {
view.repairAllChk(this.setting, !!checked);
}
zTreeTools.getCheckedNodes = function (checked) {
checked = (checked !== false);
var children = data.nodeChildren(setting, data.getRoot(this.setting));
return data.getTreeCheckedNodes(this.setting, children, checked);
}
zTreeTools.getChangeCheckedNodes = function () {
var children = data.nodeChildren(setting, data.getRoot(this.setting));
return data.getTreeChangeCheckedNodes(this.setting, children);
}
zTreeTools.setChkDisabled = function (node, disabled, inheritParent, inheritChildren) {
disabled = !!disabled;
inheritParent = !!inheritParent;
inheritChildren = !!inheritChildren;
view.repairSonChkDisabled(this.setting, node, disabled, inheritChildren);
view.repairParentChkDisabled(this.setting, node.getParentNode(), disabled, inheritParent);
}
var _updateNode = zTreeTools.updateNode;
zTreeTools.updateNode = function (node, checkTypeFlag) {
if (_updateNode) _updateNode.apply(zTreeTools, arguments);
if (!node || !this.setting.check.enable) return;
var nObj = $$(node, this.setting);
if (nObj.get(0) && tools.uCanDo(this.setting)) {
var checkObj = $$(node, consts.id.CHECK, this.setting);
if (checkTypeFlag == true || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);
view.setChkClass(this.setting, checkObj, node);
view.repairParentChkClassWithSelf(this.setting, node);
}
}
},
//method of operate data
_data = {
getRadioCheckedList: function (setting) {
var checkedList = data.getRoot(setting).radioCheckedList;
for (var i = 0, j = checkedList.length; i < j; i++) {
if (!data.getNodeCache(setting, checkedList[i].tId)) {
checkedList.splice(i, 1);
i--;
j--;
}
}
return checkedList;
},
getCheckStatus: function (setting, node) {
if (!setting.check.enable || node.nocheck || node.chkDisabled) return null;
var checked = data.nodeChecked(setting, node),
r = {
checked: checked,
half: node.halfCheck ? node.halfCheck : (setting.check.chkStyle == consts.radio.STYLE ? (node.check_Child_State === 2) : (checked ? (node.check_Child_State > -1 && node.check_Child_State < 2) : (node.check_Child_State > 0)))
};
return r;
},
getTreeCheckedNodes: function (setting, nodes, checked, results) {
if (!nodes) return [];
var onlyOne = (checked && setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL);
results = !results ? [] : results;
for (var i = 0, l = nodes.length; i < l; i++) {
var node = nodes[i];
var children = data.nodeChildren(setting, node);
var nodeChecked = data.nodeChecked(setting, node);
if (node.nocheck !== true && node.chkDisabled !== true && nodeChecked == checked) {
results.push(node);
if (onlyOne) {
break;
}
}
data.getTreeCheckedNodes(setting, children, checked, results);
if (onlyOne && results.length > 0) {
break;
}
}
return results;
},
getTreeChangeCheckedNodes: function (setting, nodes, results) {
if (!nodes) return [];
results = !results ? [] : results;
for (var i = 0, l = nodes.length; i < l; i++) {
var node = nodes[i];
var children = data.nodeChildren(setting, node);
var nodeChecked = data.nodeChecked(setting, node);
if (node.nocheck !== true && node.chkDisabled !== true && nodeChecked != node.checkedOld) {
results.push(node);
}
data.getTreeChangeCheckedNodes(setting, children, results);
}
return results;
},
makeChkFlag: function (setting, node) {
if (!node) return;
var chkFlag = -1;
var children = data.nodeChildren(setting, node);
if (children) {
for (var i = 0, l = children.length; i < l; i++) {
var cNode = children[i];
var nodeChecked = data.nodeChecked(setting, cNode);
var tmp = -1;
if (setting.check.chkStyle == consts.radio.STYLE) {
if (cNode.nocheck === true || cNode.chkDisabled === true) {
tmp = cNode.check_Child_State;
} else if (cNode.halfCheck === true) {
tmp = 2;
} else if (nodeChecked) {
tmp = 2;
} else {
tmp = cNode.check_Child_State > 0 ? 2 : 0;
}
if (tmp == 2) {
chkFlag = 2;
break;
} else if (tmp == 0) {
chkFlag = 0;
}
} else if (setting.check.chkStyle == consts.checkbox.STYLE) {
if (cNode.nocheck === true || cNode.chkDisabled === true) {
tmp = cNode.check_Child_State;
} else if (cNode.halfCheck === true) {
tmp = 1;
} else if (nodeChecked) {
tmp = (cNode.check_Child_State === -1 || cNode.check_Child_State === 2) ? 2 : 1;
} else {
tmp = (cNode.check_Child_State > 0) ? 1 : 0;
}
if (tmp === 1) {
chkFlag = 1;
break;
} else if (tmp === 2 && chkFlag > -1 && i > 0 && tmp !== chkFlag) {
chkFlag = 1;
break;
} else if (chkFlag === 2 && tmp > -1 && tmp < 2) {
chkFlag = 1;
break;
} else if (tmp > -1) {
chkFlag = tmp;
}
}
}
}
node.check_Child_State = chkFlag;
}
},
//method of event proxy
_event = {},
//method of event handler
_handler = {
onCheckNode: function (event, node) {
if (node.chkDisabled === true) return false;
var setting = data.getSetting(event.data.treeId);
if (tools.apply(setting.callback.beforeCheck, [setting.treeId, node], true) == false) return true;
var nodeChecked = data.nodeChecked(setting, node);
data.nodeChecked(setting, node, !nodeChecked);
view.checkNodeRelation(setting, node);
var checkObj = $$(node, consts.id.CHECK, setting);
view.setChkClass(setting, checkObj, node);
view.repairParentChkClassWithSelf(setting, node);
setting.treeObj.trigger(consts.event.CHECK, [event, setting.treeId, node]);
return true;
},
onMouseoverCheck: function (event, node) {
if (node.chkDisabled === true) return false;
var setting = data.getSetting(event.data.treeId),
checkObj = $$(node, consts.id.CHECK, setting);
node.check_Focus = true;
view.setChkClass(setting, checkObj, node);
return true;
},
onMouseoutCheck: function (event, node) {
if (node.chkDisabled === true) return false;
var setting = data.getSetting(event.data.treeId),
checkObj = $$(node, consts.id.CHECK, setting);
node.check_Focus = false;
view.setChkClass(setting, checkObj, node);
return true;
}
},
//method of tools for zTree
_tools = {},
//method of operate ztree dom
_view = {
checkNodeRelation: function (setting, node) {
var pNode, i, l,
r = consts.radio;
var nodeChecked = data.nodeChecked(setting, node);
if (setting.check.chkStyle == r.STYLE) {
var checkedList = data.getRadioCheckedList(setting);
if (nodeChecked) {
if (setting.check.radioType == r.TYPE_ALL) {
for (i = checkedList.length - 1; i >= 0; i--) {
pNode = checkedList[i];
var pNodeChecked = data.nodeChecked(setting, pNode);
if (pNodeChecked && pNode != node) {
data.nodeChecked(setting, pNode, false);
checkedList.splice(i, 1);
view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode);
if (pNode.parentTId != node.parentTId) {
view.repairParentChkClassWithSelf(setting, pNode);
}
}
}
checkedList.push(node);
} else {
var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting);
var children = data.nodeChildren(setting, parentNode);
for (i = 0, l = children.length; i < l; i++) {
pNode = children[i];
var pNodeChecked = data.nodeChecked(setting, pNode);
if (pNodeChecked && pNode != node) {
data.nodeChecked(setting, pNode, false);
view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode);
}
}
}
} else if (setting.check.radioType == r.TYPE_ALL) {
for (i = 0, l = checkedList.length; i < l; i++) {
if (node == checkedList[i]) {
checkedList.splice(i, 1);
break;
}
}
}
} else {
var children = data.nodeChildren(setting, node);
if (nodeChecked && (!children || children.length == 0 || setting.check.chkboxType.Y.indexOf("s") > -1)) {
view.setSonNodeCheckBox(setting, node, true);
}
if (!nodeChecked && (!children || children.length == 0 || setting.check.chkboxType.N.indexOf("s") > -1)) {
view.setSonNodeCheckBox(setting, node, false);
}
if (nodeChecked && setting.check.chkboxType.Y.indexOf("p") > -1) {
view.setParentNodeCheckBox(setting, node, true);
}
if (!nodeChecked && setting.check.chkboxType.N.indexOf("p") > -1) {
view.setParentNodeCheckBox(setting, node, false);
}
}
},
makeChkClass: function (setting, node) {
var c = consts.checkbox, r = consts.radio,
fullStyle = "";
var nodeChecked = data.nodeChecked(setting, node);
if (node.chkDisabled === true) {
fullStyle = c.DISABLED;
} else if (node.halfCheck) {
fullStyle = c.PART;
} else if (setting.check.chkStyle == r.STYLE) {
fullStyle = (node.check_Child_State < 1) ? c.FULL : c.PART;
} else {
fullStyle = nodeChecked ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL : c.PART) : ((node.check_Child_State < 1) ? c.FULL : c.PART);
}
var chkName = setting.check.chkStyle + "_" + (nodeChecked ? c.TRUE : c.FALSE) + "_" + fullStyle;
chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName;
return consts.className.BUTTON + " " + c.DEFAULT + " " + chkName;
},
repairAllChk: function (setting, checked) {
if (setting.check.enable && setting.check.chkStyle === consts.checkbox.STYLE) {
var root = data.getRoot(setting);
var children = data.nodeChildren(setting, root);
for (var i = 0, l = children.length; i < l; i++) {
var node = children[i];
if (node.nocheck !== true && node.chkDisabled !== true) {
data.nodeChecked(setting, node, checked);
}
view.setSonNodeCheckBox(setting, node, checked);
}
}
},
repairChkClass: function (setting, node) {
if (!node) return;
data.makeChkFlag(setting, node);
if (node.nocheck !== true) {
var checkObj = $$(node, consts.id.CHECK, setting);
view.setChkClass(setting, checkObj, node);
}
},
repairParentChkClass: function (setting, node) {
if (!node || !node.parentTId) return;
var pNode = node.getParentNode();
view.repairChkClass(setting, pNode);
view.repairParentChkClass(setting, pNode);
},
repairParentChkClassWithSelf: function (setting, node) {
if (!node) return;
var children = data.nodeChildren(setting, node);
if (children && children.length > 0) {
view.repairParentChkClass(setting, children[0]);
} else {
view.repairParentChkClass(setting, node);
}
},
repairSonChkDisabled: function (setting, node, chkDisabled, inherit) {
if (!node) return;
if (node.chkDisabled != chkDisabled) {
node.chkDisabled = chkDisabled;
}
view.repairChkClass(setting, node);
var children = data.nodeChildren(setting, node);
if (children && inherit) {
for (var i = 0, l = children.length; i < l; i++) {
var sNode = children[i];
view.repairSonChkDisabled(setting, sNode, chkDisabled, inherit);
}
}
},
repairParentChkDisabled: function (setting, node, chkDisabled, inherit) {
if (!node) return;
if (node.chkDisabled != chkDisabled && inherit) {
node.chkDisabled = chkDisabled;
}
view.repairChkClass(setting, node);
view.repairParentChkDisabled(setting, node.getParentNode(), chkDisabled, inherit);
},
setChkClass: function (setting, obj, node) {
if (!obj) return;
if (node.nocheck === true) {
obj.hide();
} else {
obj.show();
}
obj.attr('class', view.makeChkClass(setting, node));
},
setParentNodeCheckBox: function (setting, node, value, srcNode) {
var checkObj = $$(node, consts.id.CHECK, setting);
if (!srcNode) srcNode = node;
data.makeChkFlag(setting, node);
if (node.nocheck !== true && node.chkDisabled !== true) {
data.nodeChecked(setting, node, value);
view.setChkClass(setting, checkObj, node);
if (setting.check.autoCheckTrigger && node != srcNode) {
setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);
}
}
if (node.parentTId) {
var pSign = true;
if (!value) {
var pNodes = data.nodeChildren(setting, node.getParentNode());
for (var i = 0, l = pNodes.length; i < l; i++) {
var pNode = pNodes[i];
var nodeChecked = data.nodeChecked(setting, pNode);
if ((pNode.nocheck !== true && pNode.chkDisabled !== true && nodeChecked)
|| ((pNode.nocheck === true || pNode.chkDisabled === true) && pNode.check_Child_State > 0)) {
pSign = false;
break;
}
}
}
if (pSign) {
view.setParentNodeCheckBox(setting, node.getParentNode(), value, srcNode);
}
}
},
setSonNodeCheckBox: function (setting, node, value, srcNode) {
if (!node) return;
var checkObj = $$(node, consts.id.CHECK, setting);
if (!srcNode) srcNode = node;
var hasDisable = false;
var children = data.nodeChildren(setting, node);
if (children) {
for (var i = 0, l = children.length; i < l; i++) {
var sNode = children[i];
view.setSonNodeCheckBox(setting, sNode, value, srcNode);
if (sNode.chkDisabled === true) hasDisable = true;
}
}
if (node != data.getRoot(setting) && node.chkDisabled !== true) {
if (hasDisable && node.nocheck !== true) {
data.makeChkFlag(setting, node);
}
if (node.nocheck !== true && node.chkDisabled !== true) {
data.nodeChecked(setting, node, value);
if (!hasDisable) node.check_Child_State = (children && children.length > 0) ? (value ? 2 : 0) : -1;
} else {
node.check_Child_State = -1;
}
view.setChkClass(setting, checkObj, node);
if (setting.check.autoCheckTrigger && node != srcNode && node.nocheck !== true && node.chkDisabled !== true) {
setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);
}
}
}
},
_z = {
tools: _tools,
view: _view,
event: _event,
data: _data
};
$.extend(true, $.fn.zTree.consts, _consts);
$.extend(true, $.fn.zTree._z, _z);
var zt = $.fn.zTree,
tools = zt._z.tools,
consts = zt.consts,
view = zt._z.view,
data = zt._z.data,
event = zt._z.event,
$$ = tools.$;
data.nodeChecked = function (setting, node, newChecked) {
if (!node) {
return false;
}
var key = setting.data.key.checked;
if (typeof newChecked !== 'undefined') {
if (typeof newChecked === "string") {
newChecked = tools.eqs(newChecked, "true");
}
newChecked = !!newChecked;
node[key] = newChecked;
} else if (typeof node[key] == "string"){
node[key] = tools.eqs(node[key], "true");
} else {
node[key] = !!node[key];
}
return node[key];
};
data.exSetting(_setting);
data.addInitBind(_bindEvent);
data.addInitUnBind(_unbindEvent);
data.addInitCache(_initCache);
data.addInitNode(_initNode);
data.addInitProxy(_eventProxy, true);
data.addInitRoot(_initRoot);
data.addBeforeA(_beforeA);
data.addZTreeTools(_zTreeTools);
var _createNodes = view.createNodes;
view.createNodes = function (setting, level, nodes, parentNode, index) {
if (_createNodes) _createNodes.apply(view, arguments);
if (!nodes) return;
view.repairParentChkClassWithSelf(setting, parentNode);
}
var _removeNode = view.removeNode;
view.removeNode = function (setting, node) {
var parentNode = node.getParentNode();
if (_removeNode) _removeNode.apply(view, arguments);
if (!node || !parentNode) return;
view.repairChkClass(setting, parentNode);
view.repairParentChkClass(setting, parentNode);
}
var _appendNodes = view.appendNodes;
view.appendNodes = function (setting, level, nodes, parentNode, index, initFlag, openFlag) {
var html = "";
if (_appendNodes) {
html = _appendNodes.apply(view, arguments);
}
if (parentNode) {
data.makeChkFlag(setting, parentNode);
}
return html;
}
})(jQuery);

Binary file not shown.

View File

@@ -0,0 +1,250 @@
/**
* @author zhixin wen <wenzhixin2010@gmail.com>
* version: 1.2.0
* https://github.com/wenzhixin/font-awesome-zTree
*/
.ztree * {
font-size: 14px;
font-family: inherit;
}
.ztree .fa, .ztree .fab, .ztree .fad, .ztree .fal, .ztree .far, .ztree .fas {
font-family: "Font Awesome 5 Free";
}
.ztree .ztree-search {
margin: 5px;
}
.ztree .ztree-search input {
padding: 5px 10px;
}
.ztree .ztree-search .search-clear {
padding: 5px 10px;
font-size: 12px;
line-height: 1;
}
.ztree li ul {
position: relative;
background: none;
margin-left: 12px;
padding-left: 0;
}
.ztree li ul.line {
background: none;
}
.ztree li ul::before {
content: "";
display: block;
width: 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
border-left: 1px dotted #ccc;
}
.ztree li li {
position: relative;
padding-left: 9px;
line-height: inherit;
}
.ztree li li::before {
content: "";
display: block;
width: 10px;
height: 0;
border-top: 1px dotted #ccc;
position: absolute;
top: 13px;
left: 0;
}
.ztree li .noline_open + a + ul li::before {
border-top: none;
}
.ztree li .noline_open + a + ul::before {
border-left: none;
}
.ztree li span.node_name {
margin-right: 6px;
}
.ztree li span.button[class$=Page] {
width: 15px;
}
.ztree li span.button::before {
display: block;
line-height: 26px;
text-align: center;
}
.ztree li span.button.roots_docu, .ztree li span.button.center_docu, .ztree li span.button.bottom_docu {
position: relative;
height: 26px;
padding: 0;
}
.ztree li span.button.roots_docu::before, .ztree li span.button.center_docu::before, .ztree li span.button.bottom_docu::before {
content: "";
display: block;
width: 18px;
height: 0;
border-top: 1px dotted #ccc;
position: absolute;
top: 13px;
left: 0;
}
.ztree li span.button.root_open::before, .ztree li span.button.roots_open::before, .ztree li span.button.center_open::before, .ztree li span.button.bottom_open::before, .ztree li span.button.noline_open::before {
content: "\f146";
color: #3c8dbc;
}
.ztree li span.button.root_close::before, .ztree li span.button.roots_close::before, .ztree li span.button.center_close::before, .ztree li span.button.bottom_close::before, .ztree li span.button.noline_close::before {
content: "\f0fe";
color: #3c8dbc;
}
.ztree li span.button.chk {
color: #6b6b6b;
}
.ztree li span.button.chk[class$=focus]::before {
font-weight: bold;
}
.ztree li span.button.chk[class$=disable] {
color: #ccc;
}
.ztree li span.button.chk.checkbox_true_full::before, .ztree li span.button.chk.checkbox_true_disable::before, .ztree li span.button.chk.checkbox_true_full_focus::before {
content: "\f14a";
font-weight: normal !important;
color: #16b777;
}
.ztree li span.button.chk.checkbox_false_full::before, .ztree li span.button.chk.checkbox_false_disable::before, .ztree li span.button.chk.checkbox_false_full_focus::before {
content: "\f0c8";
font-weight: normal !important;
}
.ztree li span.button.chk.checkbox_true_part::before, .ztree li span.button.chk.checkbox_true_part_focus::before, .ztree li span.button.chk.checkbox_false_part::before, .ztree li span.button.chk.checkbox_false_part_focus::before {
content: "\f146";
font-weight: bold !important;
color: #16B777;
}
.ztree li span.button.chk.radio_true_full::before, .ztree li span.button.chk.radio_true_disable::before, .ztree li span.button.chk.radio_true_full_focus::before {
content: "\f058";
font-weight: normal !important;
}
.ztree li span.button.chk.radio_false_full::before, .ztree li span.button.chk.radio_false_disable::before, .ztree li span.button.chk.radio_false_full_focus::before {
content: "\f111";
font-weight: normal !important;
}
.ztree li span.button.chk.radio_true_part::before, .ztree li span.button.chk.radio_true_part_focus::before, .ztree li span.button.chk.radio_false_part::before, .ztree li span.button.chk.radio_false_part_focus::before {
content: "\f192";
font-weight: normal !important;
}
.ztree li span.button.ico_open::before {
content: "\f07c";
}
.ztree li span.button.ico_close::before {
content: "\f07b";
}
.ztree li span.button.ico_docu::before {
content: "\f15b";
}
.ztree li span.button.add::before {
content: "\f067";
}
.ztree li span.button.edit::before {
content: "\f044";
}
.ztree li span.button.remove::before {
content: "\f2ed";
}
.ztree li span.button.fa_history_ico_open::before, .ztree li span.button.fa_history_ico_close::before, .ztree li span.button.fa_history_ico_docu::before {
font-weight: bold !important;
content: "\f1da";
}
.ztree li span.button.fa_tasks_ico_open::before {
font-weight: bold !important;
content: "\f233";
}
.ztree li span.button.firstPage::before {
content: "\f100";
}
.ztree li span.button.prevPage::before {
content: "\f053";
}
.ztree li span.button.nextPage::before {
content: "\f054";
}
.ztree li span.button.lastPage::before {
content: "\f101";
}
.ztree li a span.button[style="width:0px;height:0px;"]::before, .ztree li a span.button[style^=background]::before {
content: "";
}
.ztree li a.curSelectedNode, .ztree li a.tmpTargetNode_inner {
height: 26px;
}
.ztree li > a {
height: 26px;
line-height: 26px;
}
.ztree li > span {
height: 26px;
}
.ztree li:last-child::before {
height: auto;
top: 13px;
bottom: 0;
}
.ztree li span.button.switch,
.ztree li span.button.chk,
.ztree li a span.button,
.ztree li span.button[class$=Page] {
position: relative;
width: 21px;
height: 26px;
background: none;
background-position: center center !important;
padding: 2px 0;
vertical-align: middle;
display: inline-block;
font: normal normal normal 15px/1 "Font Awesome 5 Free";
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

View File

@@ -10,10 +10,22 @@
<link rel="stylesheet" href="/static/common/css/insatll.css?v={:time()}" media="all">
</head>
<body>
<h1><img src="/static/common/images/logo-1.png"></h1>
<h1><img src="/static/common/images/logo-1.png" alt="" style="width: 100px;height: 100px;"></h1>
<h2>安装 EasyAdmin8 后台系统</h2>
<div class="content">
<form class="layui-form layui-form-pane" action="">
<div class="layui-card">
<blockquote class="layui-elem-quote layui-font-green" style="text-align: left;padding: 5px 10px;">
<div class="layui-row">
<div class="layui-col-lg6 layui-col-xl6 layui-col-xs6 layui-col-sm6 layui-col-xs6">
官网教程:<a href="https://EasyAdmin8.top?spm=001.3e3c9d.29f459" target="_blank" class="layui-font-blue">EasyAdmin8.top</a>
</div>
<div class="layui-col-lg6 layui-col-xl6 layui-col-xs6 layui-col-sm6 layui-col-xs6">
常见问题:<a href="https://EasyAdmin8.top/guide/question.html?spm=001.3e3c9d.29f460" target="_blank" class="layui-font-blue">Question</a>
</div>
</div>
</blockquote>
</div>
{if $errorInfo}
<div class="error">
{$errorInfo}