feat: 升级权限管理模式

This commit is contained in:
augushong
2025-03-20 16:57:05 +08:00
parent 1887733b32
commit d3e85fa552
50 changed files with 330 additions and 1125 deletions

View File

@@ -7,7 +7,7 @@ use base\admin\controller\mall\CateBase;
/**
* Class Admin.
* @ControllerAnnotation(title="商品分类管理")
* @ControllerAnnotation(title="商品分类管理",module="商城")
*/
class Cate extends CateBase
{

View File

@@ -7,7 +7,7 @@ use base\admin\controller\mall\GoodsBase;
/**
* Class Goods.
* @ControllerAnnotation(title="商城商品管理")
* @ControllerAnnotation(title="商城商品管理",module="商城")
*/
class Goods extends GoodsBase
{

View File

@@ -6,7 +6,7 @@ use app\admin\service\annotation\ControllerAnnotation;
use base\admin\controller\mall\TagBase;
/**
* @ControllerAnnotation(title="mall_tag")
* @ControllerAnnotation(title="mall_tag",module="商城")
*/
class Tag extends TagBase
{

View File

@@ -8,7 +8,7 @@ use base\admin\controller\system\AdminBase;
/**
* Class Admin.
* @ControllerAnnotation(title="管理员管理")
* @ControllerAnnotation(title="管理员管理",module="系统")
*
* @NodeAnotation(title="自定义权限标识符",name="customFlag")
*/

View File

@@ -6,7 +6,7 @@ use app\admin\service\annotation\ControllerAnnotation;
use base\admin\controller\system\AuthBase;
/**
* @ControllerAnnotation(title="角色权限管理")
* @ControllerAnnotation(title="角色权限管理",module="系统")
* Class Auth
*/
class Auth extends AuthBase

View File

@@ -7,7 +7,7 @@ use base\admin\controller\system\ConfigBase;
/**
* Class Config.
* @ControllerAnnotation(title="系统配置管理")
* @ControllerAnnotation(title="系统配置管理",module="系统")
*/
class Config extends ConfigBase
{

View File

@@ -7,7 +7,7 @@ use base\admin\controller\system\MenuBase;
/**
* Class Menu.
* @ControllerAnnotation(title="菜单管理",auth=true)
* @ControllerAnnotation(title="菜单管理",module="系统")
*/
class Menu extends MenuBase
{

View File

@@ -6,7 +6,7 @@ use app\admin\service\annotation\ControllerAnnotation;
use base\admin\controller\system\NodeBase;
/**
* @ControllerAnnotation(title="系统节点管理")
* @ControllerAnnotation(title="系统节点管理",module="系统")
* Class Node
*/
class Node extends NodeBase

View File

@@ -6,7 +6,7 @@ use app\admin\service\annotation\ControllerAnnotation;
use base\admin\controller\system\QuickBase;
/**
* @ControllerAnnotation(title="快捷入口管理")
* @ControllerAnnotation(title="快捷入口管理",module="系统")
* Class Quick
*/
class Quick extends QuickBase

View File

@@ -6,7 +6,7 @@ use app\admin\service\annotation\ControllerAnnotation;
use base\admin\controller\system\UploadfileBase;
/**
* @ControllerAnnotation(title="上传文件管理")
* @ControllerAnnotation(title="上传文件管理",module="系统")
* Class Uploadfile
*/
class Uploadfile extends UploadfileBase

View File

@@ -1,9 +0,0 @@
<?php
namespace app\admin\model;
use base\admin\model\SystemNodeBase;
class SystemNode extends SystemNodeBase
{
}

View File

@@ -1,9 +0,0 @@
<?php
namespace app\common\command;
use base\common\command\NodeBase;
class Node extends NodeBase
{
}

View File

@@ -31,9 +31,7 @@ class SystemAuthNode extends Migrator
$table = $this->table('system_auth_node')
->setComment('角色与节点关系表')
->addColumn(Column::bigInteger('auth_id')->setUnsigned()->setComment('角色ID'))
->addColumn(Column::bigInteger('node_id')->setUnsigned()->setComment('节点ID'))
->addIndex('auth_id')
->addIndex('node_id')
->create();
}
}

View File

@@ -1,42 +0,0 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
class SystemNode extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
$table = $this->table('system_node')
->setComment('系统节点表')
->addColumn(Column::char('node', 100)->setDefault('')->setComment('节点代码'))
->addColumn(Column::char('title')->setDefault('')->setComment('节点标题'))
->addColumn(Column::tinyInteger('type')->setUnsigned()->setLimit(1)->setComment('节点类型1控制器2节点'))
->addColumn(Column::tinyInteger('is_auth')->setUnsigned()->setLimit(1)->setDefault(1)->setComment('是否启动RBAC权限控制'))
->addColumn(Column::integer('create_time')->setLimit(11)->setUnsigned()->setDefault(0)->setComment('创建时间'))
->addColumn(Column::integer('update_time')->setLimit(11)->setUnsigned()->setDefault(0))
->addIndex('node')
->create();
}
}

View File

@@ -0,0 +1,35 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
class NewAuthNodeColumn extends Migrator
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
$system_auth_node = $this->table('system_auth_node');
$system_auth_node->addColumn(Column::char('node', 100)->setDefault(''));
$system_auth_node->update();
}
}

View File

@@ -6,6 +6,7 @@ use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnotation;
use app\admin\service\NodeService;
use app\admin\service\TriggerService;
use app\common\controller\AdminController;
use think\App;
@@ -36,11 +37,30 @@ class AuthBase extends AdminController
{
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
if ($this->request->isAjax()) {
$list = $this->model->getAuthorizeNodeListByAdminId($id);
$this->success('获取成功', $list);
$checkNodeList = (new SystemAuthNode())
->where('auth_id', $id)
->column('node');
$module_list = (new NodeService())->getNodeTree();
foreach ($module_list as $module_key => $module) {
foreach ($module['children'] as $controllerKey => $controller) {
foreach ($controller['children'] as $actionKey => $action) {
$checked = in_array($action['node'], $checkNodeList);
$checked_string = $checked? 'checked' : '';
$disabled_string = '';
if(!$action['auth']){
$checked_string = 'checked';
$disabled_string = 'disabled';
}
$module_list[$module_key]['children'][$controllerKey]['children'][$actionKey]['checked'] = $checked_string;
$module_list[$module_key]['children'][$controllerKey]['children'][$actionKey]['disabled'] = $disabled_string;
}
}
}
$this->assign('row', $row);
$this->assign('checked_node_list', $checkNodeList);
$this->assign('module_list', $module_list);
return $this->fetch();
}
@@ -52,8 +72,8 @@ class AuthBase extends AdminController
{
$this->checkPostRequest();
$id = $this->request->post('id');
$node = $this->request->post('node', '[]');
$node = json_decode($node, true);
$node = $this->request->post('node', []);
$row = $this->model->find($id);
empty($row) && $this->error('数据不存在');
try {
@@ -64,7 +84,7 @@ class AuthBase extends AdminController
foreach ($node as $vo) {
$saveAll[] = [
'auth_id' => $id,
'node_id' => $vo,
'node' => $vo,
];
}
$authNode->saveAll($saveAll);

View File

@@ -3,9 +3,9 @@
namespace base\admin\controller\system;
use app\admin\model\SystemMenu;
use app\admin\model\SystemNode;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnotation;
use app\admin\service\NodeService;
use app\admin\service\TriggerService;
use app\common\constants\MenuConstant;
use app\common\controller\AdminController;
@@ -14,7 +14,7 @@ use think\facade\Db;
/**
* Class Menu.
* @ControllerAnnotation(title="菜单管理",auth=true)
* @ControllerAnnotation(title="菜单管理")
*/
class MenuBase extends AdminController
{
@@ -206,10 +206,8 @@ class MenuBase extends AdminController
public function getMenuTips()
{
$node = input('get.keywords');
$list = SystemNode::whereLike('node', "%{$node}%")
->field('node,title')
->limit(10)
->select();
$list = (new NodeService())->getNodeCollection();
$list = $list->whereLike('node', $node);
return json([
'code' => 0,

View File

@@ -2,7 +2,6 @@
namespace base\admin\controller\system;
use app\admin\model\SystemNode;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnotation;
use app\admin\service\NodeService;
@@ -21,7 +20,6 @@ class NodeBase extends AdminController
public function __construct(App $app)
{
parent::__construct($app);
$this->model = new SystemNode();
}
/**
@@ -29,82 +27,8 @@ class NodeBase extends AdminController
*/
public function index()
{
if ($this->request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
$count = $this->model
->count();
$list = $this->model
->getNodeTreeList();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
$module_list = (new NodeService())->getNodeTree();
$this->assign('module_list', $module_list);
return $this->fetch();
}
/**
* @NodeAnotation(title="系统节点更新")
*/
public function refreshNode($force = 0)
{
$this->checkPostRequest();
$nodeList = (new NodeService())->getNodelist();
empty($nodeList) && $this->error('暂无需要更新的系统节点');
$model = new SystemNode();
try {
if ($force == 1) {
$updateNodeList = $model->whereIn('node', array_column($nodeList, 'node'))->select();
$formatNodeList = array_format_key($nodeList, 'node');
foreach ($updateNodeList as $vo) {
isset($formatNodeList[$vo['node']]) && $model->where('id', $vo['id'])->update([
'title' => $formatNodeList[$vo['node']]['title'],
'is_auth' => $formatNodeList[$vo['node']]['is_auth'],
]);
}
}
$existNodeList = $model->field('node,title,type,is_auth')->select();
foreach ($nodeList as $key => $vo) {
foreach ($existNodeList as $v) {
if ($vo['node'] == $v->node) {
unset($nodeList[$key]);
break;
}
}
}
$model->saveAll($nodeList);
TriggerService::updateNode();
} catch (\Exception $e) {
$this->error('节点更新失败');
}
$this->success('节点更新成功');
}
/**
* @NodeAnotation(title="清除失效节点")
*/
public function clearNode()
{
$this->checkPostRequest();
$nodeList = (new NodeService())->getNodelist();
$model = new SystemNode();
try {
$existNodeList = $model->field('id,node,title,type,is_auth')->select()->toArray();
$formatNodeList = array_format_key($nodeList, 'node');
foreach ($existNodeList as $vo) {
!isset($formatNodeList[$vo['node']]) && $model->where('id', $vo['id'])->delete();
}
TriggerService::updateNode();
} catch (\Exception $e) {
$this->error('节点更新失败');
}
$this->success('节点更新成功');
}
}

View File

@@ -3,7 +3,7 @@
namespace base\admin\model;
use app\admin\model\SystemAuthNode;
use app\admin\model\SystemNode;
use app\admin\service\NodeService;
use app\common\model\TimeModel;
class SystemAuthBase extends TimeModel
@@ -22,13 +22,9 @@ class SystemAuthBase extends TimeModel
{
$checkNodeList = (new SystemAuthNode())
->where('auth_id', $authId)
->column('node_id');
$systemNode = new SystemNode();
$nodelList = $systemNode
->where('is_auth', 1)
->field('id,node,title,type,is_auth')
->select()
->toArray();
->column('node');
$nodelList = (new NodeService())->getNodelist();
$newNodeList = [];
foreach ($nodelList as $vo) {
if ($vo['type'] == 1) {
@@ -39,7 +35,7 @@ class SystemAuthBase extends TimeModel
foreach ($nodelList as $v) {
if ($v['type'] == 2 && strpos($v['node'], $vo['node'] . '/') !== false) {
$v = array_merge($v, ['field' => 'node', 'spread' => true]);
$v['checked'] = in_array($v['id'], $checkNodeList) ? true : false;
$v['checked'] = in_array($v['node'], $checkNodeList) ? true : false;
$v['title'] = "{$v['title']}{$v['node']}";
$children[] = $v;
}

View File

@@ -1,37 +0,0 @@
<?php
namespace base\admin\model;
use app\common\model\TimeModel;
class SystemNodeBase extends TimeModel
{
protected $deleteTime = false;
public function getNodeTreeList()
{
$list = $this->select()->toArray();
$list = $this->buildNodeTree($list);
return $list;
}
protected function buildNodeTree($list)
{
$newList = [];
$repeatString = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
foreach ($list as $vo) {
if ($vo['type'] == 1) {
$newList[] = $vo;
foreach ($list as $v) {
if ($v['type'] == 2 && strpos($v['node'], $vo['node'] . '/') !== false) {
$v['node'] = "{$repeatString}{$repeatString}" . $v['node'];
$newList[] = $v;
}
}
}
}
return $newList;
}
}

View File

@@ -10,7 +10,6 @@ use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\admin\model\SystemConfig;
use app\admin\model\SystemMenu;
use app\admin\model\SystemNode;
use app\admin\model\SystemQuick;
use app\common\constants\AdminConstant;
@@ -126,11 +125,6 @@ class AdminInitServiceBase
$list_auth_node = $this->requireData('SystemAuthNode');
$this->installData(SystemAuthNode::class, $list_auth_node);
$output->writeln('开始初始化系统节点');
$list_node = $this->requireData('SystemNode');
$this->installData(SystemNode::class, $list_node);
}
protected function installData($model_name, $list)

View File

@@ -22,4 +22,56 @@ class NodeServiceBase
return $nodeList;
}
public function getNodeParis()
{
$node_list = $this->getNodelist();
return array_column($node_list, null, 'node');
}
public function getNodeCollection()
{
$nodeList = $this->getNodelist();
$nodeCollection = collect($nodeList);
return $nodeCollection;
}
/**
* 获取节点服务
* @return array
* @throws \Doctrine\Common\Annotations\AnnotationException
* @throws \ReflectionException
*/
public function getNodeTree()
{
$nodelList = $this->getNodelist();
$newNodeList = [];
foreach ($nodelList as $vo) {
if ($vo['type'] == 1) {
if (!isset($newNodeList[$vo['module']])) {
$newNodeList[$vo['module']] = [
'title' => $vo['module'],
'children' => [],
];
}
$vo['title'] = "{$vo['title']}";
$children = [];
foreach ($nodelList as $v) {
if ($v['type'] == 2 && strpos($v['node'], $vo['node'] . '/') !== false) {
$v['title'] = "{$v['title']}";
$children[] = $v;
}
}
!empty($children) && $vo['children'] = $children;
$newNodeList[$vo['module']]['children'][] = $vo;
}
}
$newNodeList = array_values($newNodeList);
array_unshift($newNodeList, ['title' => '全部', 'children' => []]);
return $newNodeList;
}
}

View File

@@ -1,726 +0,0 @@
<?php
$ul_system_node = array(
array(
"id" => 1,
"node" => "system.admin",
"title" => "管理员管理",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347263,
"update_time" => 1657347263
),
array(
"id" => 2,
"node" => "system.admin/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347263,
"update_time" => 1657347263
),
array(
"id" => 3,
"node" => "system.admin/add",
"title" => "添加",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347263,
"update_time" => 1657347263
),
array(
"id" => 4,
"node" => "system.admin/edit",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347263,
"update_time" => 1657347263
),
array(
"id" => 5,
"node" => "system.admin/password",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347263,
"update_time" => 1657347263
),
array(
"id" => 6,
"node" => "system.admin/delete",
"title" => "删除",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347263,
"update_time" => 1657347263
),
array(
"id" => 7,
"node" => "system.admin/modify",
"title" => "属性修改",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347263,
"update_time" => 1657347263
),
array(
"id" => 8,
"node" => "system.admin/export",
"title" => "导出",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347264,
"update_time" => 1657347264
),
array(
"id" => 9,
"node" => "system.auth",
"title" => "角色权限管理",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347264,
"update_time" => 1657347264
),
array(
"id" => 10,
"node" => "system.auth/authorize",
"title" => "授权",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347264,
"update_time" => 1657347264
),
array(
"id" => 11,
"node" => "system.auth/saveAuthorize",
"title" => "授权保存",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347264,
"update_time" => 1657347264
),
array(
"id" => 12,
"node" => "system.auth/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347264,
"update_time" => 1657347264
),
array(
"id" => 13,
"node" => "system.auth/add",
"title" => "添加",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347264,
"update_time" => 1657347264
),
array(
"id" => 14,
"node" => "system.auth/edit",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347264,
"update_time" => 1657347264
),
array(
"id" => 15,
"node" => "system.auth/delete",
"title" => "删除",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347265,
"update_time" => 1657347265
),
array(
"id" => 16,
"node" => "system.auth/export",
"title" => "导出",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347265,
"update_time" => 1657347265
),
array(
"id" => 17,
"node" => "system.auth/modify",
"title" => "属性修改",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347265,
"update_time" => 1657347265
),
array(
"id" => 18,
"node" => "system.config",
"title" => "系统配置管理",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347265,
"update_time" => 1657347265
),
array(
"id" => 19,
"node" => "system.config/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347265,
"update_time" => 1657347265
),
array(
"id" => 20,
"node" => "system.config/save",
"title" => "保存",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347265,
"update_time" => 1657347265
),
array(
"id" => 21,
"node" => "system.menu",
"title" => "菜单管理",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347265,
"update_time" => 1657347265
),
array(
"id" => 22,
"node" => "system.menu/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347265,
"update_time" => 1657347265
),
array(
"id" => 23,
"node" => "system.menu/add",
"title" => "添加",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347266,
"update_time" => 1657347266
),
array(
"id" => 24,
"node" => "system.menu/edit",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347266,
"update_time" => 1657347266
),
array(
"id" => 25,
"node" => "system.menu/delete",
"title" => "删除",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347266,
"update_time" => 1657347266
),
array(
"id" => 26,
"node" => "system.menu/modify",
"title" => "属性修改",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347266,
"update_time" => 1657347266
),
array(
"id" => 27,
"node" => "system.menu/getMenuTips",
"title" => "添加菜单提示",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347266,
"update_time" => 1657347266
),
array(
"id" => 28,
"node" => "system.menu/export",
"title" => "导出",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347266,
"update_time" => 1657347266
),
array(
"id" => 29,
"node" => "system.node",
"title" => "系统节点管理",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347266,
"update_time" => 1657347266
),
array(
"id" => 30,
"node" => "system.node/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347266,
"update_time" => 1657347266
),
array(
"id" => 31,
"node" => "system.node/refreshNode",
"title" => "系统节点更新",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347267,
"update_time" => 1657347267
),
array(
"id" => 32,
"node" => "system.node/clearNode",
"title" => "清除失效节点",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347267,
"update_time" => 1657347267
),
array(
"id" => 33,
"node" => "system.node/add",
"title" => "添加",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347267,
"update_time" => 1657347267
),
array(
"id" => 34,
"node" => "system.node/edit",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347267,
"update_time" => 1657347267
),
array(
"id" => 35,
"node" => "system.node/delete",
"title" => "删除",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347267,
"update_time" => 1657347267
),
array(
"id" => 36,
"node" => "system.node/export",
"title" => "导出",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347267,
"update_time" => 1657347267
),
array(
"id" => 37,
"node" => "system.node/modify",
"title" => "属性修改",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347267,
"update_time" => 1657347267
),
array(
"id" => 38,
"node" => "system.uploadfile",
"title" => "上传文件管理",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347268,
"update_time" => 1657347268
),
array(
"id" => 39,
"node" => "system.uploadfile/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347268,
"update_time" => 1657347268
),
array(
"id" => 40,
"node" => "system.uploadfile/add",
"title" => "添加",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347268,
"update_time" => 1657347268
),
array(
"id" => 41,
"node" => "system.uploadfile/edit",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347268,
"update_time" => 1657347268
),
array(
"id" => 42,
"node" => "system.uploadfile/delete",
"title" => "删除",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347268,
"update_time" => 1657347268
),
array(
"id" => 43,
"node" => "system.uploadfile/export",
"title" => "导出",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347268,
"update_time" => 1657347268
),
array(
"id" => 44,
"node" => "system.uploadfile/modify",
"title" => "属性修改",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347268,
"update_time" => 1657347268
),
array(
"id" => 45,
"node" => "mall.cate",
"title" => "商品分类管理",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347268,
"update_time" => 1657347268
),
array(
"id" => 46,
"node" => "mall.cate/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347269,
"update_time" => 1657347269
),
array(
"id" => 47,
"node" => "mall.cate/add",
"title" => "添加",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347269,
"update_time" => 1657347269
),
array(
"id" => 48,
"node" => "mall.cate/edit",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347269,
"update_time" => 1657347269
),
array(
"id" => 49,
"node" => "mall.cate/delete",
"title" => "删除",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347269,
"update_time" => 1657347269
),
array(
"id" => 50,
"node" => "mall.cate/export",
"title" => "导出",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347269,
"update_time" => 1657347269
),
array(
"id" => 51,
"node" => "mall.cate/modify",
"title" => "属性修改",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347269,
"update_time" => 1657347269
),
array(
"id" => 52,
"node" => "mall.goods",
"title" => "商城商品管理",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347269,
"update_time" => 1657347269
),
array(
"id" => 53,
"node" => "mall.goods/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347270,
"update_time" => 1657347270
),
array(
"id" => 54,
"node" => "mall.goods/stock",
"title" => "入库",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347270,
"update_time" => 1657347270
),
array(
"id" => 55,
"node" => "mall.goods/add",
"title" => "添加",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347270,
"update_time" => 1657347270
),
array(
"id" => 56,
"node" => "mall.goods/edit",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347270,
"update_time" => 1657347270
),
array(
"id" => 57,
"node" => "mall.goods/delete",
"title" => "删除",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347270,
"update_time" => 1657347270
),
array(
"id" => 58,
"node" => "mall.goods/export",
"title" => "导出",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347270,
"update_time" => 1657347270
),
array(
"id" => 59,
"node" => "mall.goods/modify",
"title" => "属性修改",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347270,
"update_time" => 1657347270
),
array(
"id" => 60,
"node" => "system.quick",
"title" => "快捷入口管理",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347270,
"update_time" => 1657347270
),
array(
"id" => 61,
"node" => "system.quick/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347271,
"update_time" => 1657347271
),
array(
"id" => 62,
"node" => "system.quick/add",
"title" => "添加",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347271,
"update_time" => 1657347271
),
array(
"id" => 63,
"node" => "system.quick/edit",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347271,
"update_time" => 1657347271
),
array(
"id" => 64,
"node" => "system.quick/delete",
"title" => "删除",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347271,
"update_time" => 1657347271
),
array(
"id" => 65,
"node" => "system.quick/export",
"title" => "导出",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347271,
"update_time" => 1657347271
),
array(
"id" => 66,
"node" => "system.quick/modify",
"title" => "属性修改",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347271,
"update_time" => 1657347271
),
array(
"id" => 69,
"node" => "debug.log",
"title" => "debug_log",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347271,
"update_time" => 1657347271
),
array(
"id" => 70,
"node" => "debug.log/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347272,
"update_time" => 1657347272
),
array(
"id" => 71,
"node" => "debug.log/add",
"title" => "添加",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347272,
"update_time" => 1657347272
),
array(
"id" => 72,
"node" => "debug.log/edit",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347272,
"update_time" => 1657347272
),
array(
"id" => 73,
"node" => "debug.log/delete",
"title" => "删除",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347272,
"update_time" => 1657347272
),
array(
"id" => 74,
"node" => "debug.log/export",
"title" => "导出",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347272,
"update_time" => 1657347272
),
array(
"id" => 75,
"node" => "debug.log/modify",
"title" => "属性修改",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347272,
"update_time" => 1657347272
),
array(
"id" => 76,
"node" => "mall.tag",
"title" => "mall_tag",
"type" => 1,
"is_auth" => 1,
"create_time" => 1657347614,
"update_time" => 1657347614
),
array(
"id" => 77,
"node" => "mall.tag/index",
"title" => "列表",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347614,
"update_time" => 1657347614
),
array(
"id" => 78,
"node" => "mall.tag/add",
"title" => "添加",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347615,
"update_time" => 1657347615
),
array(
"id" => 79,
"node" => "mall.tag/edit",
"title" => "编辑",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347615,
"update_time" => 1657347615
),
array(
"id" => 80,
"node" => "mall.tag/delete",
"title" => "删除",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347615,
"update_time" => 1657347615
),
array(
"id" => 81,
"node" => "mall.tag/export",
"title" => "导出",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347615,
"update_time" => 1657347615
),
array(
"id" => 82,
"node" => "mall.tag/modify",
"title" => "属性修改",
"type" => 2,
"is_auth" => 1,
"create_time" => 1657347615,
"update_time" => 1657347615
)
);
return $ul_system_node;

View File

@@ -44,4 +44,15 @@ return [
'php think migrate:run',
],
],
[
'version' => 'v2.0.116',
'desc' => [
'本次更新使用了新的权限模式,需要运行以下命令更新表结构:',
'php think migrate:run',
'由于使用了新的权限模式,您需要重新设置角色的权限设置,原来的权限已失效,',
'本次更新弃用了system_node表建议手动删除',
'本次更新弃用了system_auth_node表的node_id字段建议手动删除',
'本版本之后,修改了上述表格结构的安装文件,无需手动处理。',
],
],
];

View File

@@ -39,9 +39,9 @@ class ControllerAnnotationBase
public $title = '';
/**
* 是否开启权限控制.
* @Enum({true,false})
* @var bool
* 功能所属模块.
*
* @var string
*/
public $auth = true;
public $module = '通用';
}

View File

@@ -87,7 +87,7 @@ class NodeBase
$actionList[] = [
'node' => $controllerFormat . '/' . $method_name,
'title' => $actionTitle,
'is_auth' => $actionAuth,
'auth' => $actionAuth,
'type' => 2,
];
}
@@ -100,7 +100,7 @@ class NodeBase
$actionList[] = [
'node' => $controllerFormat . '/' . $nodeAnnotation->name,
'title' => $nodeAnnotation->title,
'is_auth' => $nodeAnnotation->auth,
'auth' => $nodeAnnotation->auth,
'type' => 2,
];
}
@@ -110,12 +110,16 @@ class NodeBase
if (!empty($actionList)) {
// 读取Controller的注解
$controllerAnnotation = $reader->getClassAnnotation($reflectionClass, ControllerAnnotation::class);
$controllerTitle = !empty($controllerAnnotation) && !empty($controllerAnnotation->title) ? $controllerAnnotation->title : null;
$controllerAuth = !empty($controllerAnnotation) && !empty($controllerAnnotation->auth) ? $controllerAnnotation->auth : false;
$controllerTitle = null;
$controllerModule = '通用';
if(!empty($controllerAnnotation)){
$controllerTitle = $controllerAnnotation->title;
$controllerModule = $controllerAnnotation->module;
}
$nodeList[] = [
'node' => $controllerFormat,
'title' => $controllerTitle,
'is_auth' => $controllerAuth,
'module' => $controllerModule,
'type' => 1,
];
$nodeList = array_merge($nodeList, $actionList);

View File

@@ -13,7 +13,7 @@
<!-- 基础js -->
<script src="__STATIC__/plugs/jquery-3.4.1/jquery-3.4.1.min.js?t={:get_site_version_key()}"></script>
<script src="__STATIC__/common/js/app.js?t={:get_site_version_key()}"></script>
<script src="__STATIC__/plugs/layui-v2.9.18/layui.js?t={:get_site_version_key()}" charset="utf-8"></script>
<script src="__STATIC__/plugs/layui-v2.10.1/layui.js?t={:get_site_version_key()}" charset="utf-8"></script>
<script src="__STATIC__/plugs/vue-2.6.10/vue.min.js?t={:get_site_version_key()}"></script>
<script src="__STATIC__/plugs/Sortable.min.js?t={:get_site_version_key()}"></script>

View File

@@ -11,7 +11,39 @@
<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>
<table class="layui-table" lay-size="sm">
<colgroup>
<col>
<col>
<col>
</colgroup>
<thead>
<tr>
<th>模块</th>
<th>功能</th>
<th>权限</th>
</tr>
</thead>
<tbody>
{volist name='$module_list' id='module'}
{volist name='$module.children' id='controller_item'}
<tr class="auth-node-tr">
<td style="white-space: nowrap;">{$controller_item.module}</td>
<td title="{$controller_item.node}">
<input lay-filter="controller-checkbox" type="checkbox" title="{$controller_item.title}">
</td>
<td>
{volist name='controller_item.children' id='action'}
<div title="{$action.node}" style="display: inline-block;">
<input type="checkbox" lay-filter="action-checkbox" name="node[]" title="{$action.title}" {$action.checked} {$action.disabled} value="{$action.node}">
</div>
{/volist}
</td>
</tr>
{/volist}
{/volist}
</tbody>
</table>
</div>
</div>

View File

@@ -1,32 +1,50 @@
$(function () {
var tree = layui.tree;
ua.request.get(
{
url: window.location.href,
}, function (res) {
res.data = res.data || [];
tree.render({
elem: '#node_ids',
data: res.data,
showCheckbox: true,
id: 'nodeDataId',
});
}
);
ua.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);
});
layui.form.on('checkbox(controller-checkbox)', function (data) {
var elem = data.elem;
var checked = elem.checked;
$(elem).closest('tr').find('input').each(function(i,input){
if(!$(input).prop('disabled')){
$(input).prop('checked', checked);
}
});
data.node = JSON.stringify(ids);
return data;
})
});
layui.form.on('checkbox(action-checkbox)', function (data) {
initCheckedStatus();
});
function initCheckedStatus() {
$('.auth-node-tr').each(function (i, elem) {
var checkedCount = 0;
var totalCount = 0;
$(elem).find('[lay-filter="action-checkbox"]').each(function (j, checkbox) {
totalCount++;
if ($(checkbox).prop('checked')) {
checkedCount++;
}
});
var checkedStatus;
if (checkedCount === totalCount) {
checkedStatus = 1; // 全部选中
} else if (checkedCount === 0) {
checkedStatus = -1; // 全部未选中
} else {
checkedStatus = 0; // 部分选中
}
if (checkedStatus === 0) {
$(elem).find('[lay-filter="controller-checkbox"]').prop('checked', false);
$(elem).find('[lay-filter="controller-checkbox"]').prop('indeterminate', true);
} else if (checkedStatus > 0) {
$(elem).find('[lay-filter="controller-checkbox"]').prop('checked', true);
$(elem).find('[lay-filter="controller-checkbox"]').prop('indeterminate', false);
} else {
$(elem).find('[lay-filter="controller-checkbox"]').prop('checked', false);
$(elem).find('[lay-filter="controller-checkbox"]').prop('indeterminate', false);
}
layui.form.render('checkbox');
});
}
initCheckedStatus();
ua.listen();
});

View File

@@ -22,6 +22,7 @@ $(function () {
method: 'open',
auth: 'authorize',
class: 'layui-btn layui-btn-normal layui-btn-xs',
extend: 'data-full="true"'
}],
'delete'
]

View File

@@ -1,10 +1,61 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-refresh="{:auth('system.node/refreshNode')}"
data-auth-clear="{:auth('system.node/clearNode')}"
data-auth-modify="{:auth('system.node/modify')}"
lay-filter="currentTable">
</table>
<div class="layui-tabs">
<ul class="layui-tabs-header">
{volist name='module_list' id='vo'}
<li>{$vo.title}</li>
{/volist}
</ul>
<div class="layui-tabs-body">
{volist name='module_list' id='module_tab'}
<div class="layui-tabs-item">
<table class="layui-table" lay-size="sm">
<colgroup>
<col>
<col>
<col>
</colgroup>
<thead>
<tr>
<th>模块</th>
<th>功能</th>
<th>权限</th>
</tr>
</thead>
<tbody>
{volist name='$module_list' id='module'}
{volist name='$module.children' id='controller_item'}
{if $module_tab.title == '全部' || $controller_item.module == $module_tab.title }
<tr>
<td style="white-space: nowrap;">{$controller_item.module}</td>
<td title="{$controller_item.node}">{$controller_item.title}</td>
<td>
<div class="layui-btn-container">
{volist name='controller_item.children' id='action'}
<button type="button" class="layui-btn layui-btn-primary layui-btn-xs" title="{$action.node}">
{$action.title}
{if $action.auth}
<span class="layui-badge layui-bg-blue" title="已开启权限控制">
开启
</span>
{else/}
<span class="layui-badge" title="已关闭权限控制">
关闭
</span>
{/if}
</button>
{/volist}
</div>
</td>
</tr>
{/if}
{/volist}
{/volist}
</tbody>
</table>
</div>
{/volist}
</div>
</div>
</div>
</div>

View File

@@ -1,47 +1,3 @@
$(function () {
ua.table.render({
init: init,
search: false,
page: false,
toolbar: ['refresh',
[{
text: '更新节点',
title: '确定更新新节点?',
url: 'system.node/refreshNode?force=0',
method: 'request',
auth: 'refresh',
class: 'layui-btn layui-btn-success layui-btn-sm',
icon: 'fa fa-hourglass',
extend: 'data-table="' + init.tableRenderId + '"',
}, {
text: '强制更新节点',
title: '该操作会覆盖已存在的节点信息。<br>确定强制更新节点?',
url: 'system.node/refreshNode?force=1',
method: 'request',
auth: 'refresh',
class: 'layui-btn layui-btn-sm layui-btn-normal',
icon: 'fa fa-hourglass',
extend: 'data-table="' + init.tableRenderId + '"',
}, {
text: '清除失效节点',
title: '确定清除失效节点?',
url: 'system.node/clearNode',
method: 'request',
auth: 'clear',
class: 'layui-btn layui-btn-sm layui-btn-danger',
icon: 'fa fa-trash-o',
extend: 'data-table="' + init.tableRenderId + '"',
}
]],
cols: [[
{ field: 'node', sort: false, minWidth: 200, align: 'left', title: '系统节点' },
{ field: 'title', sort: false, minWidth: 80, title: '节点名称 <i class="table-edit-tips color-red">*</i>', edit: 'text' },
{ field: 'update_time', sort: false, minWidth: 80, title: '更新时间', search: 'range' },
{ field: 'is_auth', sort: false, title: '节点控制', width: 85, search: 'select', selectList: { 0: '禁用', 1: '启用' }, templet: ua.table.switch },
]],
});
ua.listen();
});

View File

@@ -1,64 +0,0 @@
<?php
namespace base\common\command;
use app\admin\model\SystemNode;
use app\admin\service\NodeService;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class NodeBase extends Command
{
protected function configure()
{
$this->setName('node')
->addOption('force', null, Option::VALUE_REQUIRED, '是否强制刷新', 0)
->setDescription('系统节点刷新服务');
}
protected function execute(Input $input, Output $output)
{
$force = $input->getOption('force');
$output->writeln('========正在刷新节点服务:=====' . date('Y-m-d H:i:s'));
$check = $this->refresh($force);
$check !== true && $output->writeln('节点刷新失败:' . $check);
$output->writeln('刷新完成:' . date('Y-m-d H:i:s'));
}
protected function refresh($force)
{
$nodeList = (new NodeService())->getNodelist();
if (empty($nodeList)) {
return true;
}
$model = new SystemNode();
try {
if ($force == 1) {
$updateNodeList = $model->whereIn('node', array_column($nodeList, 'node'))->select();
$formatNodeList = array_format_key($nodeList, 'node');
foreach ($updateNodeList as $vo) {
isset($formatNodeList[$vo['node']]) && $model->where('id', $vo['id'])->update([
'title' => $formatNodeList[$vo['node']]['title'],
'is_auth' => $formatNodeList[$vo['node']]['is_auth'],
]);
}
}
$existNodeList = $model->field('node,title,type,is_auth')->select();
foreach ($nodeList as $key => $vo) {
foreach ($existNodeList as $v) {
if ($vo['node'] == $v->node) {
unset($nodeList[$key]);
break;
}
}
}
$model->insertAll($nodeList);
} catch (\Exception $e) {
return $e->getMessage();
}
return true;
}
}

View File

@@ -17,7 +17,7 @@ class VersionBase extends Command
public const PRODUCT_VERSION = '';
public const LAYUI_VERSION = '2.9.18';
public const LAYUI_VERSION = 'v2.10.1';
public const COMMENT = [
'版本更新说明:',

View File

@@ -48,7 +48,6 @@ class AdminControllerBase extends BaseController
'sort',
'remark',
'is_delete',
'is_auth',
'title',
];

View File

@@ -2,7 +2,10 @@
namespace base\common\service;
use app\admin\model\SystemAuthNode;
use app\admin\service\NodeService;
use app\common\constants\AdminConstant;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Db;
@@ -26,7 +29,6 @@ class AuthServiceBase
'auth_on' => true, // 权限开关
'system_admin' => 'system_admin', // 用户表
'system_auth' => 'system_auth', // 权限表
'system_node' => 'system_node', // 节点表
'system_auth_node' => 'system_auth_node', // 权限-节点表
];
@@ -48,6 +50,8 @@ class AuthServiceBase
*/
protected $adminNode;
protected $nodeService;
/***
* 构造方法
* AuthService constructor.
@@ -58,6 +62,8 @@ class AuthServiceBase
*/
public function __construct($adminId = null)
{
$this->nodeService = new NodeService();
$this->adminId = $adminId;
$this->adminInfo = $this->getAdminInfo();
$this->nodeList = $this->getNodeList();
@@ -66,7 +72,7 @@ class AuthServiceBase
return $this;
}
public function isSuperAdmin()
public function isSuperAdmin()
{
return $this->adminId == AdminConstant::SUPER_ADMIN_ID;
}
@@ -100,7 +106,7 @@ class AuthServiceBase
return Config::get('admin.default_auth_check');
}
$nodeInfo = $this->nodeList[$node];
if ($nodeInfo['is_auth'] == 0) {
if (!$nodeInfo['auth']) {
return true;
}
// 用户验证,优先获取缓存信息
@@ -143,20 +149,7 @@ class AuthServiceBase
}
if (!empty($adminInfo) && !empty($adminInfo['auth_ids'])) {
$buildAuthSql = Db::name($this->config['system_auth'])
->distinct(true)
->whereIn('id', $adminInfo['auth_ids'])
->field('id')
->buildSql(true);
$buildAuthNodeSql = Db::name($this->config['system_auth_node'])
->distinct(true)
->where("auth_id IN {$buildAuthSql}")
->field('node_id')
->buildSql(true);
$nodeList = Db::name($this->config['system_node'])
->distinct(true)
->where("id IN {$buildAuthNodeSql}")
->column('node');
$nodeList = SystemAuthNode::where('auth_id', 'in', $adminInfo['auth_ids'])->cache(60)->column('node');
}
return $nodeList;
@@ -170,9 +163,15 @@ class AuthServiceBase
*/
public function getNodeList()
{
return Db::name($this->config['system_node'])
->autoCache(null, null, 'table')
->column('id,node,title,type,is_auth', 'node');
$cache_key = 'node_paris';
$node_list = Cache::get($cache_key);
if (!$node_list) {
$node_list = $this->nodeService->getNodeParis();
Cache::set($cache_key, $node_list, 60);
}
return $node_list;
}
/**

View File

@@ -1,5 +1,5 @@
@charset "UTF-8";
@import url("../../plugs/layui-v2.9.18/css/layui.css");
@import url("../../plugs/layui-v2.10.1/css/layui.css");
@import url("../../plugs/font-awesome-4.7.0/css/font-awesome.min.css");
@import url("../css/iconfont.css");
@import url("../../plugs/jq-module/city-picker/css/city-picker.css");

View File

@@ -1,4 +1,4 @@
@import url("../../plugs/layui-v2.9.18/css/layui.css");
@import url("../../plugs/layui-v2.10.1/css/layui.css");
@import url("../../plugs/font-awesome-4.7.0/css/font-awesome.min.css");
@import url("../css/iconfont.css");
@import url('../../plugs/jq-module/city-picker/css/city-picker.css');

File diff suppressed because one or more lines are too long

View File

@@ -14,15 +14,19 @@
/>
<missing-glyph />
<glyph glyph-name="edge" unicode="&#59019;" d="M240.185509 821.062741C322.180562 871.479699 415.37494 897.48813 509.969233 895.934224 845.948962 895.934224 1023.938224 648.353161 1023.938224 456.964708c-0.199988-65.396055-25.998431-127.79229-71.795669-174.389479-45.797237-46.397201-107.993485-72.995596-173.389539-73.995536-150.390927 0-182.98896 46.197213-182.98896 63.996139 0 7.599542 2.399855 12.399252 9.599421 18.798866l1.99988 2.399855 0.799951 3.199807c20.998733 22.998612 31.798082 52.396839 31.798082 83.194981 0 157.390504-164.390082 285.382782-367.977799 285.382782-75.075471 0.599964-149.071006-17.798926-215.027027-53.796754 53.996742 115.03306 165.430019 195.188224 182.628981 207.627473 1.599903 1.099934 0.599964 1.679899 0.599964 1.679899z m31.198118-636.081624c-2.799831-59.99638 9.199445-119.992761 32.798021-174.389479 27.198359-52.796815 65.396055-101.993847 112.993183-138.591638-118.992821 22.998612-222.966548 87.794703-298.781974 178.589225C42.237452 143.383627 0 259.176641 0 380.169341c0 102.393822 124.792471 188.78861 271.983591 188.78861 73.195584 1.199928 144.791264-21.798685 203.587717-65.396054l-7.199566-2.399856c-102.993786-35.197876-196.988115-181.389056-196.988115-316.180924zM939.543315 95.986486l-1.399915-0.199987c-23.598576-37.597732-51.796875-70.195765-84.394908-98.994028-61.596284-55.996622-136.191783-90.99451-217.586873-99.793979-37.197756-0.599964-73.59556 6.399614-107.593509 22.798624-51.196911 20.598757-94.194317 59.99638-123.192567 105.993605-28.798263 47.797116-42.197454 103.393762-37.997708 159.190396-1.199928 40.197575 10.799348 80.595138 29.99819 116.392978 27.798323-66.196006 74.995475-122.592604 135.191844-161.590251 60.196368-38.997647 130.992097-58.996441 202.787766-57.196549 61.99626-0.599964 124.192507 13.399192 180.389116 40.997526l3.799771 1.799892c7.799529 4.599722 15.399071 7.799529 23.1986 0 8.999457-9.799409 3.599783-18.39889-2.399855-27.998311-0.399976-0.399976-0.599964-0.99994-0.799952-1.399916z" horiz-adv-x="1024" />
<glyph glyph-name="sound" unicode="&#59037;" d="M631.4-29.7c-5.1 0-10.1 1.3-14.5 3.7L277.1 162.2H116.8c-16 0-28.9 13-28.9 28.9v384c0 16 13 28.9 28.9 28.9h160.3l339.7 189.9c4.5 2.5 9.5 3.8 14.6 3.8 5.3 0 10.6-1.4 15.1-4.1 9.1-5.3 14.8-15.2 14.8-25.8v-767.6c0-10.5-5.6-20.4-14.7-25.8-4.6-2.7-9.9-4.1-15.2-4.1zM305.8 551.5v-336.7L601.4 51V716.8L305.8 551.5zM145.7 220.1h102.2v326H145.7v-326zM829.4 93c-7.1 0-13.9 2.2-19.8 6.2-7.5 5.3-12.6 13.2-14.2 22.3-1.6 9.1 0.4 18.2 5.7 25.8 48.7 69.5 74.5 151.3 74.5 236.6 0 84.1-25.2 165.1-72.7 234.1-5.2 7.6-7.2 16.7-5.5 25.8 1.7 9.1 6.8 16.9 14.3 22.2 5.8 4 12.5 6.1 19.5 6.1 11.4 0 22-5.6 28.4-14.9 55.6-80.5 84.9-175 84.9-273.2 0-99.5-30.1-195-87-276.2-6.3-9.3-16.8-14.8-28.1-14.8zM755 221.4c-4.8 0-9.5 1-13.9 2.9-8.4 3.7-14.9 10.5-18.2 19.1-3.3 8.6-3.1 18 0.6 26.4 16 36.3 24.1 75 24.1 115 0 38.6-7.5 75.9-22.4 111.1-3.6 8.5-3.7 17.9-0.2 26.4s10 15.2 18.5 18.8c4.3 1.8 8.8 2.7 13.4 2.7 13.9 0 26.4-8.3 31.8-21.1 18.5-43.7 27.9-90.2 27.9-138 0-49.6-10.1-97.7-29.9-142.8-5.6-12.4-18-20.5-31.7-20.5z" horiz-adv-x="1024" />
<glyph glyph-name="leaf" unicode="&#59137;" d="M1017.948269 886.876437c-4.863707 5.785251-12.031275 9.113051-19.557222 9.113051l-26.110427 0c-258.032454 0.102394-461.847374 0.153591-611.905533-35.735447-80.635142-19.301237-142.992985-48.432282-190.606116-89.031436-51.401703-43.82456-86.420393-101.216302-107.155144-175.554223-13.77197-49.353826-20.222782-138.487656 6.96278-227.160714 10.034595-32.766026 25.700852-63.688963 46.589193-92.103251-62.255449-97.530124-116.063407-225.983185-116.063407-378.805977 0-14.130349 11.468109-25.598458 25.598458-25.598458s25.598458 11.468109 25.598458 25.598458c0 235.761795 139.665185 410.650458 222.91137 493.845446 59.7468 59.7468 127.275532 110.175762 195.367429 145.808815 63.381781 33.175601 123.947732 51.4529 170.536925 51.4529 14.130349 0 25.598458 11.468109 25.598458 25.598458s-11.468109 25.598458-25.598458 25.598458c-55.497456 0-122.667809-19.813206-194.241097-57.340545-72.597226-38.039308-144.477695-91.591282-207.80828-154.973063-26.72479-26.72479-58.876453-62.357843-90.823328-105.977615-12.389654 19.506025-22.014674 40.189579-28.619076 61.794677-25.598458 83.553366-16.178225 164.034917-6.604402 198.388047 73.211589 262.384191 351.313233 263.049751 855.858835 262.896161-60.156376-321.926204-172.328817-530.29765-333.599101-619.533873-149.597387-82.785412-297.966048-37.629733-354.845821-14.335136-11.980078 4.914904-24.06255 10.95614-35.786644 17.91892-12.133669 7.218765-27.851122 3.225406-35.069887-8.908263s-3.225406-27.851122 8.908263-35.069887c13.925561-8.2939 28.260697-15.461468 42.595834-21.349114 31.844481-13.004017 83.143791-29.694211 146.679163-35.172281 14.027955-1.228726 27.902319-1.791892 41.674289-1.791892 75.208269 0 145.860012 18.072511 210.675307 53.910352 82.375837 45.565255 153.641943 119.749585 211.904033 220.351524 68.296685 118.00889 119.698388 274.51786 152.720399 465.175173 1.279923 7.423553-0.767954 15.051893-5.631661 20.837145z" horiz-adv-x="1025" />
<glyph glyph-name="bot" unicode="&#59350;" d="M511.453867 861.866667c35.498667 0 63.8976-28.398933 63.8976-63.8976 0-22.9376-12.014933-42.5984-30.037334-54.0672V657.066667h306.926934c18.568533 0 33.860267-15.291733 33.860266-33.860267v-613.853867c0-18.568533-15.291733-33.860267-33.860266-33.860266H170.666667c-18.568533 0-33.860267 15.291733-33.860267 33.860266V623.2064c0 18.568533 15.291733 33.860267 33.860267 33.860267h306.926933V743.901867c-17.476267 10.922667-29.4912 30.583467-30.037333 52.974933v1.092267c0 35.498667 28.398933 63.8976 63.8976 63.8976zM809.642667 580.608H213.265067v-528.657067h596.923733l-0.546133 528.657067z m-170.3936-367.547733c4.9152 0 8.738133-3.822933 8.738133-8.738134v-51.336533c0-4.9152-3.822933-8.738133-8.738133-8.738133H383.658667c-4.9152 0-8.738133 3.822933-8.738134 8.738133v51.336533c0 4.9152 3.822933 8.738133 8.738134 8.738134h255.5904zM93.661867 504.149333c4.9152 0 8.738133-3.822933 8.738133-8.738133v-323.857067c0-4.9152-3.822933-8.738133-8.738133-8.738133H42.325333c-4.9152 0-8.738133 3.822933-8.738133 8.738133V495.4112c0 4.9152 3.822933 8.738133 8.738133 8.738133h51.336534z m886.920533 0c4.9152 0 8.738133-3.822933 8.738133-8.738133v-323.857067c0-4.9152-3.822933-8.738133-8.738133-8.738133h-51.336533c-4.9152 0-8.738133 3.822933-8.738134 8.738133V495.4112c0 4.9152 3.822933 8.738133 8.738134 8.738133h51.336533zM332.322133 435.882667c32.768 0 59.528533-26.760533 59.528534-59.528534s-26.760533-59.528533-59.528534-59.528533-59.528533 26.760533-59.528533 59.528533 26.760533 59.528533 59.528533 59.528534z m358.263467 0c32.768 0 59.528533-26.760533 59.528533-59.528534s-26.760533-59.528533-59.528533-59.528533-59.528533 26.760533-59.528533 59.528533 26.2144 59.528533 59.528533 59.528534z" horiz-adv-x="1024" />
<glyph glyph-name="folder" unicode="&#60094;" d="M970.666667 682.666667H542.173333L429.793333 795.046667A52.986667 52.986667 0 0 1 392.08 810.666667H96a53.393333 53.393333 0 0 1-53.333333-53.333334v-704a53.393333 53.393333 0 0 1 53.333333-53.333333h874.666667a53.393333 53.393333 0 0 1 53.333333 53.333333V629.333333a53.393333 53.393333 0 0 1-53.333333 53.333334zM96 768h296.08a10.573333 10.573333 0 0 0 7.54-3.126667L481.826667 682.666667H96a53.546667 53.546667 0 0 1-10.666667-1.073334V757.333333a10.666667 10.666667 0 0 0 10.666667 10.666667z m885.333333-714.666667a10.666667 10.666667 0 0 0-10.666666-10.666666H96a10.666667 10.666667 0 0 0-10.666667 10.666666V629.333333a10.666667 10.666667 0 0 0 10.666667 10.666667h874.666667a10.666667 10.666667 0 0 0 10.666666-10.666667z" horiz-adv-x="1024" />
<glyph glyph-name="edge" unicode="&#59019;" d="M257.173915 793.74632C334.044277 841.012218 421.414006 865.395122 510.096156 863.938335 825.077152 863.938335 991.942085 631.831088 991.942085 452.404414c-0.187489-61.308802-24.373529-119.805272-67.30844-163.490137-42.93491-43.497376-101.243892-68.433371-162.552692-69.370815-140.991494 0-171.55215 43.309887-171.55215 59.996381 0 7.124571 2.249864 11.624299 8.999457 17.623936l1.874887 2.249864 0.749954 2.99982c19.686312 21.561199 29.810702 49.122037 29.810702 77.995294 0 147.553597-154.115702 267.546358-344.979186 267.546358-70.383254 0.562466-139.754068-16.686493-201.587838-50.434457 50.621946 107.843494 155.090643 182.98896 171.214669 194.650756 1.499909 1.031188 0.562466 1.574905 0.562467 1.574906z m29.248235-596.326523c-2.624842-56.246606 8.62448-112.493213 30.748145-163.490136 25.498462-49.497014 61.308802-95.619232 105.931109-129.929661-111.55577 21.561199-209.031139 82.307534-280.108101 167.427398C71.597611 158.42215 32 266.978101 32 380.408757c0 95.994208 116.992942 176.989322 254.984617 176.989322 68.62086 1.124932 135.74181-20.436267 190.863484-61.308801l-6.749593-2.249865c-96.556674-32.998009-184.676358-170.05224-184.676358-296.419616zM912.821858 113.987331l-1.312421-0.187488c-22.123665-35.247874-48.55957-65.80853-79.120226-92.806901-57.746516-52.496833-127.679797-85.307353-203.987693-93.556856-34.872896-0.562466-68.995837 5.999638-100.868915 21.37371-47.997104 19.311335-88.307172 56.246606-115.493031 99.369005-26.998372 44.809796-39.560113 96.931652-35.622852 149.240996-1.124932 37.685227 10.124389 75.557942 28.123303 109.118417 26.060928-62.058756 70.308258-114.930566 126.742354-151.49086 56.434095-36.560294 122.805091-55.309163 190.113531-53.621765 58.121494-0.562466 116.430475 12.561742 169.114796 38.435181l3.562285 1.687398c7.312058 4.312239 14.436629 7.312058 21.748688 0 8.436991-9.186946 3.374797-17.248959-2.249864-26.248416-0.374978-0.374978-0.562466-0.937444-0.749955-1.312421z" horiz-adv-x="1024" />
<glyph glyph-name="folder-open" unicode="&#60097;" d="M1003.153333 491.04a52.933333 52.933333 0 0 1-42.38 20.96H896V629.333333a53.393333 53.393333 0 0 1-53.333333 53.333334H461.253333a10.573333 10.573333 0 0 0-7.54 3.126666L344.46 795.046667A52.986667 52.986667 0 0 1 306.746667 810.666667H53.333333a53.393333 53.393333 0 0 1-53.333333-53.333334v-704a53.393333 53.393333 0 0 1 53.333333-53.333333h796.893334a53.453333 53.453333 0 0 1 51.453333 39.333333l110.546667 405.333334a52.953333 52.953333 0 0 1-9.073334 46.373333zM53.333333 768h253.413334a10.573333 10.573333 0 0 0 7.54-3.126667l109.253333-109.253333A52.986667 52.986667 0 0 1 461.253333 640H842.666667a10.666667 10.666667 0 0 0 10.666666-10.666667v-117.333333H173.773333a53.453333 53.453333 0 0 1-51.453333-39.333333L42.666667 180.633333V757.333333a10.666667 10.666667 0 0 0 10.666666 10.666667z m917.726667-312.14l-110.546667-405.333333a10.666667 10.666667 0 0 0-10.286666-7.86H63.226667a10.666667 10.666667 0 0 0-10.286667 13.473333l110.546667 405.333333A10.666667 10.666667 0 0 0 173.773333 469.333333h787a10.666667 10.666667 0 0 0 10.286667-13.473333z" horiz-adv-x="1024" />
<glyph glyph-name="leaf" unicode="&#59137;" d="M956.681096 804.64791c-4.274742 5.084693-10.574363 8.009517-17.188965 8.009518l-22.948617 0c-226.786337 0.089995-405.920544 0.134992-537.807598-31.408108-70.87073-16.963978-125.677428-42.567435-167.524906-78.250286-45.177278-38.51768-75.955424-88.95964-94.179326-154.295703-12.104271-43.377386-17.773929-121.717666 6.119631-199.652972 8.819468-28.798265 22.588639-55.976628 40.947533-80.950123-54.716703-85.719836-102.008854-198.618034-102.008854-332.93494 0-12.419252 10.079393-22.498645 22.498645-22.498645s22.498645 10.079393 22.498644 22.498645c0 207.212515 122.752604 360.923254 195.918197 434.043849 52.511836 52.511836 111.863261 96.834166 171.709654 128.152278 55.706643 29.158243 108.938436 45.222275 149.885969 45.222276 12.419252 0 22.498645 10.079393 22.498645 22.498645s-10.079393 22.498645-22.498645 22.498644c-48.777061 0-107.813504-17.413951-170.719714-50.396963-63.806156-33.432986-126.982349-80.50015-182.643996-136.206794-23.488585-23.488585-51.746883-54.806698-79.825191-93.144388-10.889344 17.143967-19.348835 35.322872-25.153484 54.311728-22.498645 73.435576-14.219143 144.171314-5.804651 174.364494 64.346123 230.611105 308.771396 231.19607 752.21968 231.061079-52.871815-282.942953-151.460874-466.081919-293.202335-544.512193-131.482078-72.760616-261.884222-33.073008-311.87621-12.59924-10.529365 4.31974-21.148726 9.62942-31.453105 15.74905-10.664358 6.344618-24.478525 2.83483-30.823143-7.829528s-2.83483-24.478525 7.829528-30.823142c12.239263-7.289561 24.838503-13.589181 37.437745-18.76387 27.988313-11.429312 73.075598-26.098428 128.917233-30.913138 12.329257-1.079935 24.523523-1.574905 36.627793-1.574905 66.101018 0 128.197276 15.884043 185.163844 47.382145 72.400638 40.047587 135.036864 105.248659 186.243779 193.668332 60.026383 103.718751 105.203661 241.275463 134.226913 408.845367 1.124932 6.524607-0.67496 13.229203-4.949702 18.313897z" horiz-adv-x="1025" />
<glyph glyph-name="gitee" unicode="&#59035;" d="M512-128C229.222-128 0 101.222 0 384S229.222 896 512 896s512-229.222 512-512-229.222-512-512-512z m259.149 568.883h-290.74a25.293 25.293 0 0 1-25.292-25.293l-0.026-63.206c0-13.952 11.315-25.293 25.267-25.293h177.024c13.978 0 25.293-11.315 25.293-25.267v-12.646a75.853 75.853 0 0 0-75.853-75.853h-240.23a25.293 25.293 0 0 0-25.267 25.293V478.797a75.853 75.853 0 0 0 75.827 75.853h353.946a25.293 25.293 0 0 1 25.267 25.292l0.077 63.207a25.293 25.293 0 0 1-25.268 25.293H417.152a189.62 189.62 0 0 1-189.62-189.645V124.85c0-13.977 11.316-25.293 25.294-25.293h372.94a170.65 170.65 0 0 1 170.65 170.65V415.616a25.293 25.293 0 0 1-25.293 25.267z" horiz-adv-x="1024" />
<glyph glyph-name="folder" unicode="&#60094;" d="M947.911111 679.727408H519.417777L407.037777 792.107408A52.986667 52.986667 0 0 1 369.324444 807.727408H73.244444a53.393333 53.393333 0 0 1-53.333333-53.333334v-704a53.393333 53.393333 0 0 1 53.333333-53.333333h874.666667a53.393333 53.393333 0 0 1 53.333333 53.333333V626.394074a53.393333 53.393333 0 0 1-53.333333 53.333334zM73.244444 765.060741h296.08a10.573333 10.573333 0 0 0 7.54-3.126667L459.071111 679.727408H73.244444a53.546667 53.546667 0 0 1-10.666667-1.073334V754.394074a10.666667 10.666667 0 0 0 10.666667 10.666667z m885.333333-714.666667a10.666667 10.666667 0 0 0-10.666666-10.666666H73.244444a10.666667 10.666667 0 0 0-10.666667 10.666666V626.394074a10.666667 10.666667 0 0 0 10.666667 10.666667h874.666667a10.666667 10.666667 0 0 0 10.666666-10.666667z" horiz-adv-x="1024" />
<glyph glyph-name="folder-open" unicode="&#60097;" d="M1003.153333 488.100741a52.933333 52.933333 0 0 1-42.38 20.96H896V626.394074a53.393333 53.393333 0 0 1-53.333333 53.333334H461.253333a10.573333 10.573333 0 0 0-7.54 3.126666L344.46 792.107408A52.986667 52.986667 0 0 1 306.746667 807.727408H53.333333a53.393333 53.393333 0 0 1-53.333333-53.333334v-704a53.393333 53.393333 0 0 1 53.333333-53.333333h796.893334a53.453333 53.453333 0 0 1 51.453333 39.333333l110.546667 405.333334a52.953333 52.953333 0 0 1-9.073334 46.373333zM53.333333 765.060741h253.413334a10.573333 10.573333 0 0 0 7.54-3.126667l109.253333-109.253333A52.986667 52.986667 0 0 1 461.253333 637.060741H842.666667a10.666667 10.666667 0 0 0 10.666666-10.666667v-117.333333H173.773333a53.453333 53.453333 0 0 1-51.453333-39.333333L42.666667 177.694074V754.394074a10.666667 10.666667 0 0 0 10.666666 10.666667z m917.726667-312.14l-110.546667-405.333333a10.666667 10.666667 0 0 0-10.286666-7.86H63.226667a10.666667 10.666667 0 0 0-10.286667 13.473333l110.546667 405.333333A10.666667 10.666667 0 0 0 173.773333 466.394074h787a10.666667 10.666667 0 0 0 10.286667-13.473333z" horiz-adv-x="1024" />
<glyph glyph-name="gitee" unicode="&#59035;" d="M512-96C246.895625-96 32 118.895625 32 384S246.895625 864 512 864s480-214.895625 480-480-214.895625-480-480-480z m242.952188 533.327813h-272.568751a23.712187 23.712187 0 0 1-23.71125-23.712188l-0.024375-59.255625c0-13.08 10.607812-23.712187 23.687813-23.712187h165.96c13.104375 0 23.712187-10.607812 23.712187-23.687813v-11.855625a71.112188 71.112188 0 0 0-71.112187-71.112187h-225.215625a23.712187 23.712187 0 0 0-23.687812 23.712187V472.872187a71.112188 71.112188 0 0 0 71.087812 71.112188h331.824375a23.712187 23.712187 0 0 1 23.687812 23.71125l0.072188 59.256563a23.712187 23.712187 0 0 1-23.68875 23.712187H423.08a177.76875 177.76875 0 0 1-177.76875-177.792188V141.046875c0-13.103438 10.60875-23.712187 23.713125-23.712187h349.63125a159.984375 159.984375 0 0 1 159.984375 159.984375V413.64a23.712187 23.712187 0 0 1-23.712187 23.687812z" horiz-adv-x="1024" />
<glyph glyph-name="github" unicode="&#59047;" d="M512 883.32190493c275.66730126 0 499.32190493-223.65460366 499.32190493-499.32190493 0-220.40901063-143.01411555-407.65472541-341.32813256-473.98131826-25.34058667-4.53550763-34.45321159 11.06830222-34.45321159 24.05067207 0 16.26957255 0.6657627 70.19633778 0.66576271 137.18869334 0 46.81142841-15.60380985 76.72913237-33.7874489 92.33294222 111.18234397 12.35821682 228.19011015 54.63413874 228.1901113 246.41536 0 54.63413874-19.51516445 98.82412715-51.34693604 133.9431003 5.20127033 13.02397952 22.09499477 63.70515285-5.20127033 132.61157604-41.61015922 13.02397952-137.18869333-51.34693603-137.18869333-51.34693604a469.36259015 469.36259015 0 0 1-249.6609519 0S291.63259904 689.58500523 250.02244096 676.56102571c-27.29626397-68.90642318-10.40253952-119.62920619-5.20127033-132.61157604-31.87338126-35.11897429-51.34693603-79.3089627-51.34693604-133.9431003 0-191.15706937 116.38361429-234.05714318 227.56595826-246.41536-14.31389411-13.02397952-27.29626397-35.11897429-31.87338126-66.95074588-28.62778937-13.02397952-101.44556715-35.11897429-144.96979285 41.61015921-27.29626397 47.47719111-76.72913237 51.34693603-76.72913351 51.34693604-48.76710571 0.6657627-3.24559189-30.54185699-3.2455919-30.541857 32.49753429-14.93804715 55.25829063-72.81777778 55.25829064-72.81777777 29.25194126-89.08735033 168.39631189-59.16964523 168.39631302-59.16964523 0-41.61015922 0.6657627-80.5988773 0.66576157-92.95709525 0-13.02397952-9.11262493-28.62778937-34.45321045-24.05067094C155.77543111-23.61311459000001 12.76131555 163.63259903999995 12.76131555 384.04160967c0 275.66730126 223.65460366 499.32190493 499.32190493 499.32190492zM201.87948715 166.21242937c1.28991459 2.62144-0.6657627 5.86703189-4.53550763 7.78109952-3.91135459 1.28991459-7.15694763 0.6657627-8.44686222-1.2899146-1.28991459-2.62144 0.6657627-5.86703189 4.53550763-7.78109952 3.24559189-1.9556773 7.15694763-1.28991459 8.44686222 1.2899146z m20.13931634-22.13660444c2.62144 1.9556773 1.9556773 6.49118493-1.2899146 10.40253952-3.24559189 3.24559189-7.78109952 4.53550763-10.40253952 1.95567729-2.62144-1.9556773-1.9556773-6.49118493 1.2899146-10.40253952 3.24559189-3.24559189 7.78109952-4.53550763 10.40253952-1.95567729z m19.51516444-29.25194127c3.24559189 2.62144 3.24559189 7.78109952 0 12.35821682-2.62144 4.53550763-7.78109952 6.49118493-11.06830222 3.91135459-3.24559189-1.9556773-3.24559189-7.15694763 0-11.69245411s8.44686222-6.49118493 11.06830222-4.53550763z m27.29626396-27.2962651c2.62144 2.62144 1.28991459 8.44686222-2.62144 12.35821795-4.53550763 4.53550763-10.40253952 5.20127033-13.02397952 1.9556773-3.24559189-2.62144-1.9556773-8.44686222 2.62144-12.35821682 4.53550763-4.53550763 10.40253952-5.20127033 13.02397952-1.95567843z m37.0746516-16.26957141c1.28991459 3.91135459-2.62144 8.44686222-8.44686223 10.40253952-5.20127033 1.28991459-11.06830222-0.6657627-12.35821681-4.53550763s2.62144-8.44686222 8.44686222-9.73677682c5.20127033-1.9556773 11.06830222 0 12.35821682 3.9113546z m40.94439651-3.24559304c0 4.53550763-5.20127033 7.78109952-11.06830222 7.15694763-5.86703189 0-10.40253952-3.24559189-10.40253952-7.15694763 0-4.53550763 4.53550763-7.78109952 11.06830222-7.15694648 5.86703189 0 10.40253952 3.24559189 10.40253952 7.15694648z m37.69880349 6.49118493c-0.6657627 3.91135459-5.86703189 6.49118493-11.69245412 5.86703303-5.86703189-1.28991459-9.73677682-5.20127033-9.11262492-9.73677796 0.6657627-3.91135459 5.86703189-6.49118493 11.69245411-5.20126918s9.73677682 5.20127033 9.11262493 9.11262492z" horiz-adv-x="1024" />

Before

Width:  |  Height:  |  Size: 322 KiB

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

Binary file not shown.

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,8 +10,8 @@
<title>ulthon_admin | 一款基于ThinkPHP8和Layui的快速开发的后台管理框架系统</title>
<link rel="stylesheet" href="//layui.ulthon.com/cdn/layui-ul.css">
<link rel="stylesheet" href="__STATIC__/common/css/welcome.css?v={$version}">
<link rel="stylesheet" href="/static/plugs/layui-v2.9.18/css/layui.css">
<script src="/static/plugs/layui-v2.9.18/layui.js"></script>
<link rel="stylesheet" href="/static/plugs/layui-v2.10.1/css/layui.css">
<script src="/static/plugs/layui-v2.10.1/layui.js"></script>
</head>