feat: 系统功能开发,菜单、操作、资源相关接口
diff --git a/sql/system.sql b/sql/system.sql
new file mode 100644
index 0000000..0ecf059
--- /dev/null
+++ b/sql/system.sql
@@ -0,0 +1,424 @@
+
+
+CREATE TABLE `TB_U_ACCOUNT` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `USERNAME` VARCHAR(200) NOT NULL COMMENT '账号',
+  `PASSWORD` VARCHAR(200) NOT NULL COMMENT '密码',
+
+  `ENABLED` INT(11) NOT NULL COMMENT '是否可用,1 可用,0 不可用,默认:1',
+  `ACCOUNT_NON_EXPIRED` INT(11) NOT NULL COMMENT '账号未过期,1 未过期,0 过期,默认:1',
+  `ACCOUNT_NON_LOCKED` INT(11) NOT NULL COMMENT '账号未锁定,1 未锁定,0 锁定,默认:1',
+  `CREDENTIALS_NON_EXPIRED` INT(11) NOT NULL COMMENT '密码未过期,1 未过期,0 过期,默认:1',
+
+  `NAME` VARCHAR(200) NOT NULL COMMENT '姓名',
+  `STATUS` VARCHAR(10) NOT NULL COMMENT '状态(1 启用,0 停用)',
+
+  `MOBILE` VARCHAR(100) COMMENT '登录手机',
+  `EMAIL` VARCHAR(100) COMMENT '登录邮箱',
+
+  PRIMARY KEY (`ID`),
+  UNIQUE KEY `UQ_USERNAME` (`USERNAME`)
+)
+COMMENT = '帐号表';
+
+
+CREATE TABLE `TB_U_GROUP` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `CODE` VARCHAR(200) NOT NULL COMMENT '代码',
+  `NAME` VARCHAR(200) NOT NULL COMMENT '名称',
+  `MEMO` VARCHAR(500) COMMENT '备注',
+  `STATUS` VARCHAR(10) NOT NULL COMMENT '状态(1 启用,0 停用)',
+
+  PRIMARY KEY (`ID`),
+  UNIQUE KEY `UQ_CODE` (`COMPANY_ID`,`CODE`)
+)
+COMMENT = '用户组表';
+
+
+CREATE TABLE `TB_U_ROLE` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `CODE` VARCHAR(200) NOT NULL COMMENT '代码',
+  `NAME` VARCHAR(200) NOT NULL COMMENT '名称',
+  `MEMO` VARCHAR(500) COMMENT '备注',
+  `STATUS` VARCHAR(10) NOT NULL COMMENT '状态(1 启用,0 停用)',
+
+  PRIMARY KEY (`ID`),
+  UNIQUE KEY `UQ_CODE` (`COMPANY_ID`,`CODE`)
+)
+COMMENT = '角色表';
+
+
+
+CREATE TABLE `TB_U_ACCOUNT_GROUP` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `ACCOUNT_ID` VARCHAR(200) NOT NULL COMMENT '帐号ID',
+  `GROUP_ID` VARCHAR(200) NOT NULL COMMENT '用户组ID',
+
+  PRIMARY KEY (`ID`)
+)
+COMMENT = '用户组 - 帐号关联表';
+
+
+
+CREATE TABLE `TB_U_ACCOUNT_ROLE` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `ACCOUNT_ID` VARCHAR(200) NOT NULL COMMENT '帐号ID',
+  `ROLE_ID` VARCHAR(200) NOT NULL COMMENT '角色ID',
+
+  PRIMARY KEY (`ID`)
+)
+COMMENT = '帐号 - 角色关联表';
+
+
+
+CREATE TABLE `TB_U_GROUP_ROLE` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `GROUP_ID` VARCHAR(200) NOT NULL COMMENT '用户组ID',
+  `ROLE_ID` VARCHAR(200) NOT NULL COMMENT '角色ID',
+
+  PRIMARY KEY (`ID`)
+)
+COMMENT = '用户组 - 角色关联表';
+
+
+
+CREATE TABLE `TB_U_PERMISSION` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `CODE` VARCHAR(200) NOT NULL COMMENT '代码',
+  `NAME` VARCHAR(200) NOT NULL COMMENT '名称',
+  `MEMO` VARCHAR(500) COMMENT '备注',
+  `STATUS` VARCHAR(10) NOT NULL COMMENT '状态(1 启用,0 停用)',
+
+  `TYPE_` VARCHAR(10) NOT NULL COMMENT '类型(1 应用,2 菜单,3 操作)',
+  `URL` VARCHAR(500) COMMENT 'URL地址',
+
+  `PARENT_ID` VARCHAR(100) NOT NULL COMMENT '父级ID', 
+  `ORDER_` INT(11) NOT NULL COMMENT '排序',
+  `LEVEL_` INT(11) NOT NULL COMMENT '层次',
+  `LFT` INT(11) NOT NULL COMMENT '左索引',
+  `RGT` INT(11) NOT NULL COMMENT '右索引',
+
+  PRIMARY KEY (`ID`),
+  UNIQUE KEY `UQ_CODE` (`COMPANY_ID`,`CODE`)
+)
+COMMENT = '权限表';
+
+
+
+CREATE TABLE `TB_U_ROLE_PERMISSION` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `ROLE_ID` VARCHAR(200) NOT NULL COMMENT '角色ID',
+  `PERMISSION_ID` VARCHAR(200) NOT NULL COMMENT '权限ID',
+
+  PRIMARY KEY (`ID`)
+)
+COMMENT = '角色 - 权限关联表';
+
+
+
+CREATE TABLE `TB_U_RESOURCE` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `CODE` VARCHAR(200) NOT NULL COMMENT '代码',
+  `NAME` VARCHAR(200) NOT NULL COMMENT '名称',
+  `MEMO` VARCHAR(500) COMMENT '备注',
+  `STATUS` VARCHAR(10) NOT NULL COMMENT '状态(1 启用,0 停用)',
+
+  `METHOD` VARCHAR(100) COMMENT '请求方式(GET、POST、PUT、DELETE 等)',
+  `PATH` VARCHAR(500) COMMENT '请求地址',
+
+  PRIMARY KEY (`ID`),
+  UNIQUE KEY `UQ_CODE` (`COMPANY_ID`,`CODE`)
+)
+COMMENT = '资源(API)表';
+
+
+CREATE TABLE `TB_U_PERMISSION_RESOURCE` (
+  `ID` VARCHAR(100) NOT NULL COMMENT '',
+  `COMPANY_ID` VARCHAR(100) COMMENT 'CompanyID',
+  `DELETED` INT(1) COMMENT '是否删除',
+  `ADD_ACCOUNT` VARCHAR(100) COMMENT '创建人',
+  `ADD_TIME` DATETIME COMMENT '创建时间',
+  `EDIT_ACCOUNT` VARCHAR(100) COMMENT '修改人',
+  `EDIT_TIME` DATETIME COMMENT '修改时间',
+  `DELETE_ACCOUNT` VARCHAR(100) COMMENT '删除人',
+  `DELETE_TIME` DATETIME COMMENT '删除时间',
+
+  `PERMISSION_ID` VARCHAR(200) NOT NULL COMMENT '权限ID',
+  `RESOURCE_ID` VARCHAR(200) NOT NULL COMMENT '资源ID',
+
+  PRIMARY KEY (`ID`)
+)
+COMMENT = '角色 - 权限关联表';
+
+
+
+insert into TB_U_ACCOUNT (ID, DELETED, USERNAME, PASSWORD, ENABLED, ACCOUNT_NON_EXPIRED, ACCOUNT_NON_LOCKED, CREDENTIALS_NON_EXPIRED, NAME, STATUS) 
+values ('1', 0, 'admin', 'admin', 1, 1, 1, 1, 'Admin', '1');
+
+commit;
+
+
+insert into TB_U_GROUP (ID, DELETED, CODE, NAME, STATUS) 
+values ('1', 0, 'users', '所有用户', '1');
+
+commit;
+
+
+insert into TB_U_ROLE (ID, DELETED, CODE, NAME, STATUS) 
+values ('1', 0, 'administrator', '超级管理员', '1');
+insert into TB_U_ROLE (ID, DELETED, CODE, NAME, STATUS) 
+values ('2', 0, 'user', '普通用户', '1');
+
+commit;
+
+
+insert into TB_U_ACCOUNT_GROUP (ID, DELETED, ACCOUNT_ID, GROUP_ID) 
+values ('1_1', 0, '1', '1');
+
+commit;
+
+
+insert into TB_U_ACCOUNT_ROLE (ID, DELETED, ACCOUNT_ID, ROLE_ID) 
+values ('1_1', 0, '1', '1');
+
+insert into TB_U_ACCOUNT_ROLE (ID, DELETED, ACCOUNT_ID, ROLE_ID) 
+values ('1_2', 0, '1', '2');
+
+commit;
+
+
+insert into TB_U_GROUP_ROLE (ID, DELETED, GROUP_ID, ROLE_ID) 
+values ('1', 0, '1', '2');
+
+commit;
+
+/*
+insert into TB_U_PERMISSION (ID, DELETED, CODE, NAME, STATUS, TYPE_, URL, PARENT_ID, ORDER_, LEVEL_, LFT, RGT) 
+values ('1', 0, 'client', 'Client', '1', '1', '', '0', 1, 1, 1, 10);
+*/
+
+insert into TB_U_PERMISSION (ID, DELETED, CODE, NAME, STATUS, TYPE_, URL, PARENT_ID, ORDER_, LEVEL_, LFT, RGT) 
+values ('10000', 0, 'admin.system', '系统管理', '1', '2', '', '0', 1000, 1, 1, 14);
+
+insert into TB_U_PERMISSION (ID, DELETED, CODE, NAME, STATUS, TYPE_, URL, PARENT_ID, ORDER_, LEVEL_, LFT, RGT) 
+values ('10100', 0, 'admin.system.account', '帐号管理', '1', '2', '', '10000', 10100, 2, 2, 3);
+insert into TB_U_PERMISSION (ID, DELETED, CODE, NAME, STATUS, TYPE_, URL, PARENT_ID, ORDER_, LEVEL_, LFT, RGT) 
+values ('10200', 0, 'admin.system.group', '用户组管理', '1', '2', '', '10000', 10200, 2, 4, 5);
+insert into TB_U_PERMISSION (ID, DELETED, CODE, NAME, STATUS, TYPE_, URL, PARENT_ID, ORDER_, LEVEL_, LFT, RGT) 
+values ('10300', 0, 'admin.system.role', '角色管理', '1', '2', '', '10000', 10300, 2, 6, 7);
+insert into TB_U_PERMISSION (ID, DELETED, CODE, NAME, STATUS, TYPE_, URL, PARENT_ID, ORDER_, LEVEL_, LFT, RGT) 
+values ('10400', 0, 'admin.system.menu', '菜单管理', '1', '2', '', '10000', 10400, 2, 8, 9);
+insert into TB_U_PERMISSION (ID, DELETED, CODE, NAME, STATUS, TYPE_, URL, PARENT_ID, ORDER_, LEVEL_, LFT, RGT) 
+values ('10500', 0, 'admin.system.operation', '操作管理', '1', '2', '', '10000', 10500, 2, 10, 11);
+insert into TB_U_PERMISSION (ID, DELETED, CODE, NAME, STATUS, TYPE_, URL, PARENT_ID, ORDER_, LEVEL_, LFT, RGT) 
+values ('10600', 0, 'admin.system.resource', '资源管理', '1', '2', '', '10000', 10600, 2, 12, 13);
+
+commit;
+
+
+insert into TB_U_ROLE_PERMISSION (ID, DELETED, ROLE_ID, PERMISSION_ID) 
+values ('2_1', 0, '2', '1');
+
+insert into TB_U_ROLE_PERMISSION (ID, DELETED, ROLE_ID, PERMISSION_ID) 
+select CONCAT('1_', ID), 0, '1', ID from TB_U_PERMISSION;
+
+commit;
+
+
+
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10101', 0, 'SystemAdminAccount.query', '查询帐号', '1', 'GET', '/api/system/v1/admin/accounts');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10102', 0, 'SystemAdminAccount.load', '获取帐号', '1', 'GET', '/api/system/v1/admin/accounts/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10103', 0, 'SystemAdminAccount.create', '创建帐号', '1', 'POST', '/api/system/v1/admin/accounts');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10104', 0, 'SystemAdminAccount.update', '修改帐号', '1', 'PUT', '/api/system/v1/admin/accounts/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10105', 0, 'SystemAdminAccount.delete', '删除帐号', '1', 'DELETE', '/api/system/v1/admin/accounts/{id}');
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10106', 0, 'SystemAdminAccount.accountGroups', '获取帐号的用户组', '1', 'GET', '/api/system/v1/admin/accounts/{id}/groups');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10107', 0, 'SystemAdminAccount.relateGroups', '关联帐号的用户组', '1', 'POST', '/api/system/v1/admin/accounts/{id}/groups');
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10108', 0, 'SystemAdminAccount.accountRoles', '获取帐号的角色', '1', 'GET', '/api/system/v1/admin/accounts/{id}/roles');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10109', 0, 'SystemAdminAccount.relateRoles', '关联帐号的角色', '1', 'POST', '/api/system/v1/admin/accounts/{id}/roles');
+
+
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10201', 0, 'SystemAdminGroup.query', '查询用户组', '1', 'GET', '/api/system/v1/admin/groups');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10202', 0, 'SystemAdminGroup.load', '获取用户组', '1', 'GET', '/api/system/v1/admin/groups/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10203', 0, 'SystemAdminGroup.create', '创建用户组', '1', 'POST', '/api/system/v1/admin/groups');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10204', 0, 'SystemAdminGroup.update', '修改用户组', '1', 'PUT', '/api/system/v1/admin/groups/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10205', 0, 'SystemAdminGroup.delete', '删除用户组', '1', 'DELETE', '/api/system/v1/admin/groups/{id}');
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10206', 0, 'SystemAdminGroup.groupAccounts', '获取用户组的帐号', '1', 'GET', '/api/system/v1/admin/groups/{id}/accounts');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10207', 0, 'SystemAdminGroup.relateAccounts', '关联用户组的帐号', '1', 'POST', '/api/system/v1/admin/groups/{id}/accounts');
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10208', 0, 'SystemAdminGroup.groupRoles', '获取用户组的角色', '1', 'GET', '/api/system/v1/admin/groups/{id}/roles');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10209', 0, 'SystemAdminGroup.relateRoles', '关联用户组的角色', '1', 'POST', '/api/system/v1/admin/groups/{id}/roles');
+
+
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10301', 0, 'SystemAdminRole.query', '查询角色', '1', 'GET', '/api/system/v1/admin/roles');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10302', 0, 'SystemAdminRole.load', '获取角色', '1', 'GET', '/api/system/v1/admin/roles/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10303', 0, 'SystemAdminRole.create', '创建角色', '1', 'POST', '/api/system/v1/admin/roles');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10304', 0, 'SystemAdminRole.update', '修改角色', '1', 'PUT', '/api/system/v1/admin/roles/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10305', 0, 'SystemAdminRole.delete', '删除角色', '1', 'DELETE', '/api/system/v1/admin/roles/{id}');
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10306', 0, 'SystemAdminRole.roleAccounts', '获取角色的帐号', '1', 'GET', '/api/system/v1/admin/roles/{id}/accounts');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10307', 0, 'SystemAdminRole.relateAccounts', '关联角色的帐号', '1', 'POST', '/api/system/v1/admin/roles/{id}/accounts');
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10308', 0, 'SystemAdminRole.roleGroups', '获取角色的用户组', '1', 'GET', '/api/system/v1/admin/roles/{id}/groups');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10309', 0, 'SystemAdminRole.relateGroups', '关联角色的用户组', '1', 'POST', '/api/system/v1/admin/roles/{id}/groups');
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10310', 0, 'SystemAdminRole.rolePermissions', '获取角色的权限', '1', 'GET', '/api/system/v1/admin/roles/{id}/permissions');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10311', 0, 'SystemAdminRole.relatePermissions', '关联角色的权限', '1', 'POST', '/api/system/v1/admin/roles/{id}/permissions');
+
+
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10401', 0, 'SystemAdminMenu.query', '查询菜单', '1', 'GET', '/api/system/v1/admin/menus');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10402', 0, 'SystemAdminMenu.load', '获取菜单', '1', 'GET', '/api/system/v1/admin/menus/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10403', 0, 'SystemAdminMenu.create', '创建菜单', '1', 'POST', '/api/system/v1/admin/menus');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10404', 0, 'SystemAdminMenu.update', '修改菜单', '1', 'PUT', '/api/system/v1/admin/menus/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10405', 0, 'SystemAdminMenu.delete', '删除菜单', '1', 'DELETE', '/api/system/v1/admin/menus/{id}');
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10406', 0, 'SystemAdminMenu.tree', '树形菜单', '1', 'GET', '/api/system/v1/admin/menus/tree');
+
+
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10501', 0, 'SystemAdminOperation.query', '查询操作', '1', 'GET', '/api/system/v1/admin/operations');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10502', 0, 'SystemAdminOperation.load', '获取操作', '1', 'GET', '/api/system/v1/admin/operations/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10503', 0, 'SystemAdminOperation.create', '创建操作', '1', 'POST', '/api/system/v1/admin/operations');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10504', 0, 'SystemAdminOperation.update', '修改操作', '1', 'PUT', '/api/system/v1/admin/operations/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10505', 0, 'SystemAdminOperation.delete', '删除操作', '1', 'DELETE', '/api/system/v1/admin/operations/{id}');
+
+
+
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10601', 0, 'SystemAdminResource.query', '查询资源', '1', 'GET', '/api/system/v1/admin/resources');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10602', 0, 'SystemAdminResource.load', '获取资源', '1', 'GET', '/api/system/v1/admin/resources/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10603', 0, 'SystemAdminResource.create', '创建资源', '1', 'POST', '/api/system/v1/admin/resources');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10604', 0, 'SystemAdminResource.update', '修改资源', '1', 'PUT', '/api/system/v1/admin/resources/{id}');
+insert into TB_U_RESOURCE (ID, DELETED, CODE, NAME, STATUS, METHOD, PATH)
+values ('10605', 0, 'SystemAdminResource.delete', '删除资源', '1', 'DELETE', '/api/system/v1/admin/resources/{id}');
+
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminGroupController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminGroupController.java
new file mode 100644
index 0000000..9de8744
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminGroupController.java
@@ -0,0 +1,270 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+import java.util.HashMap;
+
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.DefaultApiResponse;
+import com.supwisdom.institute.backend.system.api.vo.request.GroupCreateRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.GroupQueryRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.GroupRelateAccountsRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.GroupRelateRolesRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.GroupRelatedAccountsRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.GroupRelatedRolesRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.GroupUpdateRequest;
+import com.supwisdom.institute.backend.system.api.vo.response.GroupCreateResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.GroupLoadResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.GroupQueryResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.GroupRelateAccountsResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.GroupRelateRolesResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.GroupRelatedAccountsResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.GroupRelatedRolesResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.GroupRemoveResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.GroupUpdateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.AccountGroup;
+import com.supwisdom.institute.backend.system.domain.entity.Group;
+import com.supwisdom.institute.backend.system.domain.entity.GroupRole;
+import com.supwisdom.institute.backend.system.domain.service.GroupService;
+
+@Api(value = "SystemAdminGroup", tags = { "SystemAdminGroup" }, description = "用户组的操作接口")
+@Slf4j
+@RestController
+@RequestMapping("/v1/admin/groups")
+public class AdminGroupController {
+
+  @Autowired
+  private GroupService groupService;
+
+  @GetMapping(produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<GroupQueryResponseData> query(GroupQueryRequest queryRequest) {
+
+    Page<Group> page = groupService.selectPageList(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(),
+        queryRequest.getMapBean(),
+        queryRequest.getOrderBy());
+
+    GroupQueryResponseData data = GroupQueryResponseData.of(queryRequest).build(page);
+
+    return new DefaultApiResponse<GroupQueryResponseData>(data);
+  }
+  
+  @GetMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<GroupLoadResponseData> load(@PathVariable("id") String id) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Group group = groupService.selectById(id);
+
+    if (group == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+    
+    GroupLoadResponseData data = GroupLoadResponseData.of(group);
+
+    return new DefaultApiResponse<GroupLoadResponseData>(data);
+  }
+
+  @PostMapping(consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<GroupCreateResponseData> create(
+      @RequestBody GroupCreateRequest createRequest) {
+    
+    // FIXME: 验证数据有效性
+    
+    Group group = createRequest.getEntity();
+    
+    Group ret = groupService.insert(group);
+    
+    GroupCreateResponseData data = GroupCreateResponseData.build(ret);
+
+    return new DefaultApiResponse<GroupCreateResponseData>(data);
+  }
+  
+  @PutMapping(path = "/{id}", consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<GroupUpdateResponseData> update(
+      @PathVariable("id") String id, 
+      @RequestBody GroupUpdateRequest updateRequest) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.update.id.must.not.empty");
+    }
+
+    Group tmp = groupService.selectById(id);
+    if (tmp == null) {
+      throw new RuntimeException("exception.update.domain.not.exist");
+    }
+
+    Group group = updateRequest.getEntity();
+    group.setId(id);
+
+    group = EntityUtils.merge(tmp, group);
+
+    Group ret = groupService.update(group);
+
+    GroupUpdateResponseData data = GroupUpdateResponseData.build(ret);
+    
+    return new DefaultApiResponse<GroupUpdateResponseData>(data);
+  }
+
+  @DeleteMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<GroupRemoveResponseData> delete(
+      @PathVariable("id") String id) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.delete.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Group tmp = groupService.selectById(id);
+    if (tmp == null) {
+      throw new RuntimeException("exception.delete.domain.not.exist"); // FIXME: RestException
+    }
+
+    groupService.deleteById(id);
+
+    GroupRemoveResponseData data = GroupRemoveResponseData.build(tmp);
+    return new DefaultApiResponse<GroupRemoveResponseData>(data);
+  }
+
+  
+  
+  @RequestMapping(method = RequestMethod.GET, path = "/{id}/accounts", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public DefaultApiResponse<GroupRelatedAccountsResponseData> groupAccounts(
+      @PathVariable("id") String id, 
+      GroupRelatedAccountsRequest request) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Group group = groupService.selectById(id);
+
+    if (group == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    if (request.getMapBean() == null) {
+      request.setMapBean(new HashMap<String, Object>());
+    }
+    request.getMapBean().put("groupId", group.getId());
+
+    Page<AccountGroup> page = groupService.selectGroupAccounts(
+        request.getPageIndex(),
+        request.getPageSize(), 
+        request.getMapBean());
+
+    GroupRelatedAccountsResponseData data = GroupRelatedAccountsResponseData.of(request).build(page);
+
+    return new DefaultApiResponse<GroupRelatedAccountsResponseData>(data);
+  }
+
+  @RequestMapping(method = RequestMethod.POST, path = "/{id}/accounts", consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public DefaultApiResponse<GroupRelateAccountsResponseData> relateAccounts(
+      @PathVariable("id") String id, 
+      @RequestBody GroupRelateAccountsRequest groupAccounts) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Group group = groupService.selectById(id);
+
+    if (group == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    groupService.relateGroupAccounts(group, groupAccounts.getGroupAccounts());
+
+    GroupRelateAccountsResponseData data = GroupRelateAccountsResponseData.of("info.relate.success");
+
+    return new DefaultApiResponse<GroupRelateAccountsResponseData>(data);
+  }
+
+  
+  @RequestMapping(method = RequestMethod.GET, path = "/{id}/roles", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public DefaultApiResponse<GroupRelatedRolesResponseData> groupRoles(
+      @PathVariable("id") String id, 
+      GroupRelatedRolesRequest request) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Group group = groupService.selectById(id);
+
+    if (group == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    if (request.getMapBean() == null) {
+      request.setMapBean(new HashMap<String, Object>());
+    }
+    request.getMapBean().put("groupId", group.getId());
+
+    Page<GroupRole> page = groupService.selectGroupRoles(
+        request.getPageIndex(),
+        request.getPageSize(), 
+        request.getMapBean());
+
+    GroupRelatedRolesResponseData data = GroupRelatedRolesResponseData.of(request).build(page);
+
+    return new DefaultApiResponse<GroupRelatedRolesResponseData>(data);
+  }
+
+  @RequestMapping(method = RequestMethod.POST, path = "/{id}/roles", consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public DefaultApiResponse<GroupRelateRolesResponseData> relateRoles(
+      @PathVariable("id") String id, 
+      @RequestBody GroupRelateRolesRequest groupRoles) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Group group = groupService.selectById(id);
+
+    if (group == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    groupService.relateGroupRoles(group, groupRoles.getGroupRoles());
+
+    GroupRelateRolesResponseData data = GroupRelateRolesResponseData.of("info.relate.success");
+
+    return new DefaultApiResponse<GroupRelateRolesResponseData>(data);
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminMenuController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminMenuController.java
new file mode 100644
index 0000000..4d03563
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminMenuController.java
@@ -0,0 +1,182 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.DefaultApiResponse;
+import com.supwisdom.institute.backend.system.api.vo.request.PermissionCreateRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.PermissionQueryRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.PermissionUpdateRequest;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionCreateResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionLoadResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionQueryResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionRemoveResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionTreeResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionUpdateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+import com.supwisdom.institute.backend.system.domain.service.PermissionService;
+
+@Api(value = "SystemAdminMenu", tags = { "SystemAdminMenu" }, description = "菜单的操作接口")
+@Slf4j
+@RestController
+@RequestMapping("/v1/admin/menus")
+public class AdminMenuController {
+
+  @Autowired
+  private PermissionService permissionService;
+
+  @GetMapping(produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionQueryResponseData> query(PermissionQueryRequest queryRequest) {
+    
+    if (queryRequest.getMapBean() == null) {
+      queryRequest.setMapBean(new HashMap<String, Object>());
+    }
+    queryRequest.getMapBean().put("type", Permission.TYPE_MENU);
+
+    Page<Permission> page = permissionService.selectPageList(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(),
+        queryRequest.getMapBean(),
+        queryRequest.getOrderBy());
+
+    PermissionQueryResponseData data = PermissionQueryResponseData.of(queryRequest).build(page);
+
+    return new DefaultApiResponse<PermissionQueryResponseData>(data);
+  }
+  
+  @GetMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionLoadResponseData> load(@PathVariable("id") String id) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Permission permission = permissionService.selectById(id);
+
+    if (permission == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+    if (!Permission.TYPE_MENU.equals(permission.getType())) {
+      throw new RuntimeException("exception.get.domain.type.error");
+    }
+    
+    PermissionLoadResponseData data = PermissionLoadResponseData.of(permission);
+
+    return new DefaultApiResponse<PermissionLoadResponseData>(data);
+  }
+
+  @PostMapping(consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionCreateResponseData> create(
+      @RequestBody PermissionCreateRequest createRequest) {
+    
+    // FIXME: 验证数据有效性
+    
+    Permission permission = createRequest.getEntity();
+    permission.setType(Permission.TYPE_MENU);
+    
+    Permission ret = permissionService.insert(permission);
+    
+    PermissionCreateResponseData data = PermissionCreateResponseData.build(ret);
+
+    return new DefaultApiResponse<PermissionCreateResponseData>(data);
+  }
+  
+  @PutMapping(path = "/{id}", consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionUpdateResponseData> update(
+      @PathVariable("id") String id, 
+      @RequestBody PermissionUpdateRequest updateRequest) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.update.id.must.not.empty");
+    }
+
+    Permission tmp = permissionService.selectById(id);
+    if (tmp == null) {
+      throw new RuntimeException("exception.update.domain.not.exist");
+    }
+    if (!Permission.TYPE_MENU.equals(tmp.getType())) {
+      throw new RuntimeException("exception.update.domain.type.error");
+    }
+
+    Permission permission = updateRequest.getEntity();
+    permission.setId(id);
+
+    permission = EntityUtils.merge(tmp, permission);
+
+    Permission ret = permissionService.update(permission);
+
+    PermissionUpdateResponseData data = PermissionUpdateResponseData.build(ret);
+    
+    return new DefaultApiResponse<PermissionUpdateResponseData>(data);
+  }
+
+  @DeleteMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionRemoveResponseData> delete(
+      @PathVariable("id") String id) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.delete.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Permission tmp = permissionService.selectById(id);
+    if (tmp == null) {
+      throw new RuntimeException("exception.delete.domain.not.exist"); // FIXME: RestException
+    }
+    if (!Permission.TYPE_MENU.equals(tmp.getType())) {
+      throw new RuntimeException("exception.delete.domain.type.error");
+    }
+
+    permissionService.deleteById(id);
+
+    PermissionRemoveResponseData data = PermissionRemoveResponseData.build(tmp);
+    return new DefaultApiResponse<PermissionRemoveResponseData>(data);
+  }
+
+  
+  @GetMapping(path = "/tree", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionTreeResponseData> tree() {
+    
+    Map<String, Object> mapBean = new HashMap<String, Object>();
+    mapBean.put("type", Permission.TYPE_MENU);
+
+    List<Permission> permissions = permissionService.selectPermissionTree(mapBean);
+
+    PermissionTreeResponseData data = PermissionTreeResponseData.of(permissions);
+
+    return new DefaultApiResponse<PermissionTreeResponseData>(data);
+  }
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminOperationController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminOperationController.java
new file mode 100644
index 0000000..d4e60f5
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminOperationController.java
@@ -0,0 +1,164 @@
+package com.supwisdom.institute.backend.system.api.v1.admin;
+
+import io.swagger.annotations.Api;
+
+import java.util.HashMap;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.DefaultApiResponse;
+import com.supwisdom.institute.backend.system.api.vo.request.PermissionCreateRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.PermissionQueryRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.PermissionUpdateRequest;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionCreateResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionLoadResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionQueryResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionRemoveResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.PermissionUpdateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+import com.supwisdom.institute.backend.system.domain.service.PermissionService;
+
+@Api(value = "SystemAdminOperation", tags = { "SystemAdminOperation" }, description = "操作的操作接口")
+@Slf4j
+@RestController
+@RequestMapping("/v1/admin/operations")
+public class AdminOperationController {
+
+  @Autowired
+  private PermissionService permissionService;
+
+  @GetMapping(produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionQueryResponseData> query(PermissionQueryRequest queryRequest) {
+    
+    if (queryRequest.getMapBean() == null) {
+      queryRequest.setMapBean(new HashMap<String, Object>());
+    }
+    queryRequest.getMapBean().put("type", Permission.TYPE_OPERATION);
+
+    Page<Permission> page = permissionService.selectPageList(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(),
+        queryRequest.getMapBean(),
+        queryRequest.getOrderBy());
+
+    PermissionQueryResponseData data = PermissionQueryResponseData.of(queryRequest).build(page);
+
+    return new DefaultApiResponse<PermissionQueryResponseData>(data);
+  }
+  
+  @GetMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionLoadResponseData> load(@PathVariable("id") String id) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Permission permission = permissionService.selectById(id);
+
+    if (permission == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+    if (!Permission.TYPE_OPERATION.equals(permission.getType())) {
+      throw new RuntimeException("exception.get.domain.type.error");
+    }
+    
+    PermissionLoadResponseData data = PermissionLoadResponseData.of(permission);
+
+    return new DefaultApiResponse<PermissionLoadResponseData>(data);
+  }
+
+  @PostMapping(consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionCreateResponseData> create(
+      @RequestBody PermissionCreateRequest createRequest) {
+    
+    // FIXME: 验证数据有效性
+    
+    Permission permission = createRequest.getEntity();
+    permission.setType(Permission.TYPE_OPERATION);
+    
+    Permission ret = permissionService.insert(permission);
+    
+    PermissionCreateResponseData data = PermissionCreateResponseData.build(ret);
+
+    return new DefaultApiResponse<PermissionCreateResponseData>(data);
+  }
+  
+  @PutMapping(path = "/{id}", consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionUpdateResponseData> update(
+      @PathVariable("id") String id, 
+      @RequestBody PermissionUpdateRequest updateRequest) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.update.id.must.not.empty");
+    }
+
+    Permission tmp = permissionService.selectById(id);
+    if (tmp == null) {
+      throw new RuntimeException("exception.update.domain.not.exist");
+    }
+    if (!Permission.TYPE_OPERATION.equals(tmp.getType())) {
+      throw new RuntimeException("exception.update.domain.type.error");
+    }
+
+    Permission permission = updateRequest.getEntity();
+    permission.setId(id);
+
+    permission = EntityUtils.merge(tmp, permission);
+
+    Permission ret = permissionService.update(permission);
+
+    PermissionUpdateResponseData data = PermissionUpdateResponseData.build(ret);
+    
+    return new DefaultApiResponse<PermissionUpdateResponseData>(data);
+  }
+
+  @DeleteMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<PermissionRemoveResponseData> delete(
+      @PathVariable("id") String id) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.delete.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Permission tmp = permissionService.selectById(id);
+    if (tmp == null) {
+      throw new RuntimeException("exception.delete.domain.not.exist"); // FIXME: RestException
+    }
+    if (!Permission.TYPE_OPERATION.equals(tmp.getType())) {
+      throw new RuntimeException("exception.delete.domain.type.error");
+    }
+
+    permissionService.deleteById(id);
+
+    PermissionRemoveResponseData data = PermissionRemoveResponseData.build(tmp);
+    return new DefaultApiResponse<PermissionRemoveResponseData>(data);
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminFunctionController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminPermissionController.java
similarity index 61%
rename from system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminFunctionController.java
rename to system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminPermissionController.java
index fcb3c6a..d72d034 100644
--- a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminFunctionController.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminPermissionController.java
@@ -1,5 +1,5 @@
 package com.supwisdom.institute.backend.system.api.v1.admin;
 
-public class AdminFunctionController {
+public class AdminPermissionController {
 
 }
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminResourceController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminResourceController.java
index 929d755..a16bd63 100644
--- a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminResourceController.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminResourceController.java
@@ -1,5 +1,146 @@
 package com.supwisdom.institute.backend.system.api.v1.admin;
 
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.DefaultApiResponse;
+import com.supwisdom.institute.backend.system.api.vo.request.ResourceCreateRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.ResourceQueryRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.ResourceUpdateRequest;
+import com.supwisdom.institute.backend.system.api.vo.response.ResourceCreateResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.ResourceLoadResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.ResourceQueryResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.ResourceRemoveResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.ResourceUpdateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Resource;
+import com.supwisdom.institute.backend.system.domain.service.ResourceService;
+
+@Api(value = "SystemAdminResource", tags = { "SystemAdminResource" }, description = "资源(API)的操作接口")
+@Slf4j
+@RestController
+@RequestMapping("/v1/admin/resources")
 public class AdminResourceController {
 
+  @Autowired
+  private ResourceService resourceService;
+
+  @GetMapping(produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ResourceQueryResponseData> query(ResourceQueryRequest queryRequest) {
+
+    Page<Resource> page = resourceService.selectPageList(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(),
+        queryRequest.getMapBean(),
+        queryRequest.getOrderBy());
+
+    ResourceQueryResponseData data = ResourceQueryResponseData.of(queryRequest).build(page);
+
+    return new DefaultApiResponse<ResourceQueryResponseData>(data);
+  }
+  
+  @GetMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ResourceLoadResponseData> load(@PathVariable("id") String id) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Resource resource = resourceService.selectById(id);
+
+    if (resource == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+    
+    ResourceLoadResponseData data = ResourceLoadResponseData.of(resource);
+
+    return new DefaultApiResponse<ResourceLoadResponseData>(data);
+  }
+
+  @PostMapping(consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ResourceCreateResponseData> create(
+      @RequestBody ResourceCreateRequest createRequest) {
+    
+    // FIXME: 验证数据有效性
+    
+    Resource resource = createRequest.getEntity();
+    
+    Resource ret = resourceService.insert(resource);
+    
+    ResourceCreateResponseData data = ResourceCreateResponseData.build(ret);
+
+    return new DefaultApiResponse<ResourceCreateResponseData>(data);
+  }
+  
+  @PutMapping(path = "/{id}", consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ResourceUpdateResponseData> update(
+      @PathVariable("id") String id, 
+      @RequestBody ResourceUpdateRequest updateRequest) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.update.id.must.not.empty");
+    }
+
+    Resource tmp = resourceService.selectById(id);
+    if (tmp == null) {
+      throw new RuntimeException("exception.update.domain.not.exist");
+    }
+
+    Resource resource = updateRequest.getEntity();
+    resource.setId(id);
+
+    resource = EntityUtils.merge(tmp, resource);
+
+    Resource ret = resourceService.update(resource);
+
+    ResourceUpdateResponseData data = ResourceUpdateResponseData.build(ret);
+    
+    return new DefaultApiResponse<ResourceUpdateResponseData>(data);
+  }
+
+  @DeleteMapping(path = "/{id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseStatus(value = HttpStatus.OK)
+  @ResponseBody
+  public DefaultApiResponse<ResourceRemoveResponseData> delete(
+      @PathVariable("id") String id) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.delete.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Resource tmp = resourceService.selectById(id);
+    if (tmp == null) {
+      throw new RuntimeException("exception.delete.domain.not.exist"); // FIXME: RestException
+    }
+
+    resourceService.deleteById(id);
+
+    ResourceRemoveResponseData data = ResourceRemoveResponseData.build(tmp);
+    return new DefaultApiResponse<ResourceRemoveResponseData>(data);
+  }
+
 }
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminRoleController.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminRoleController.java
index 34fb317..b64adda 100644
--- a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminRoleController.java
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/v1/admin/AdminRoleController.java
@@ -26,22 +26,27 @@
 import com.supwisdom.institute.backend.system.api.vo.request.RoleCreateRequest;
 import com.supwisdom.institute.backend.system.api.vo.request.RoleRelateAccountsRequest;
 import com.supwisdom.institute.backend.system.api.vo.request.RoleRelateGroupsRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.RoleRelatePermissionsRequest;
 import com.supwisdom.institute.backend.system.api.vo.request.RoleRelatedAccountsRequest;
 import com.supwisdom.institute.backend.system.api.vo.request.RoleRelatedGroupsRequest;
+import com.supwisdom.institute.backend.system.api.vo.request.RoleRelatedPermissionsRequest;
 import com.supwisdom.institute.backend.system.api.vo.request.RoleUpdateRequest;
 import com.supwisdom.institute.backend.system.api.vo.request.RoleQueryRequest;
 import com.supwisdom.institute.backend.system.api.vo.response.RoleCreateResponseData;
 import com.supwisdom.institute.backend.system.api.vo.response.RoleLoadResponseData;
 import com.supwisdom.institute.backend.system.api.vo.response.RoleRelateAccountsResponseData;
 import com.supwisdom.institute.backend.system.api.vo.response.RoleRelateGroupsResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.RoleRelatePermissionsResponseData;
 import com.supwisdom.institute.backend.system.api.vo.response.RoleRelatedAccountsResponseData;
 import com.supwisdom.institute.backend.system.api.vo.response.RoleRelatedGroupsResponseData;
+import com.supwisdom.institute.backend.system.api.vo.response.RoleRelatedPermissionsResponseData;
 import com.supwisdom.institute.backend.system.api.vo.response.RoleRemoveResponseData;
 import com.supwisdom.institute.backend.system.api.vo.response.RoleUpdateResponseData;
 import com.supwisdom.institute.backend.system.api.vo.response.RoleQueryResponseData;
 import com.supwisdom.institute.backend.system.domain.entity.AccountRole;
 import com.supwisdom.institute.backend.system.domain.entity.GroupRole;
 import com.supwisdom.institute.backend.system.domain.entity.Role;
+import com.supwisdom.institute.backend.system.domain.entity.RolePermission;
 import com.supwisdom.institute.backend.system.domain.service.RoleService;
 
 @Api(value = "SystemAdminRole", tags = { "SystemAdminRole" }, description = "角色的操作接口")
@@ -247,7 +252,7 @@
   @ResponseBody
   public DefaultApiResponse<RoleRelateGroupsResponseData> relateGroups(
       @PathVariable("id") String id, 
-      @RequestBody RoleRelateGroupsRequest accountGroups) {
+      @RequestBody RoleRelateGroupsRequest roleGroups) {
 
     if (id == null || id.length() == 0) {
       throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
@@ -259,12 +264,66 @@
       throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
     }
 
-    roleService.relateRoleGroups(role, accountGroups.getRoleGroups());
+    roleService.relateRoleGroups(role, roleGroups.getRoleGroups());
 
     RoleRelateGroupsResponseData data = RoleRelateGroupsResponseData.of("info.relate.success");
 
     return new DefaultApiResponse<RoleRelateGroupsResponseData>(data);
   }
 
-  
+
+  @RequestMapping(method = RequestMethod.GET, path = "/{id}/permissions", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public DefaultApiResponse<RoleRelatedPermissionsResponseData> rolePermissions(
+      @PathVariable("id") String id, 
+      RoleRelatedPermissionsRequest request) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Role role = roleService.selectById(id);
+
+    if (role == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    if (request.getMapBean() == null) {
+      request.setMapBean(new HashMap<String, Object>());
+    }
+    request.getMapBean().put("roleId", role.getId());
+
+    Page<RolePermission> page = roleService.selectRolePermissions(
+        request.getPageIndex(),
+        request.getPageSize(), 
+        request.getMapBean());
+
+    RoleRelatedPermissionsResponseData data = RoleRelatedPermissionsResponseData.of(request).build(page);
+
+    return new DefaultApiResponse<RoleRelatedPermissionsResponseData>(data);
+  }
+
+  @RequestMapping(method = RequestMethod.POST, path = "/{id}/permissions", consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public DefaultApiResponse<RoleRelatePermissionsResponseData> relatePermissions(
+      @PathVariable("id") String id, 
+      @RequestBody RoleRelatePermissionsRequest rolePermissions) {
+
+    if (id == null || id.length() == 0) {
+      throw new RuntimeException("exception.get.id.must.not.empty"); // FIXME: RestException
+    }
+
+    Role role = roleService.selectById(id);
+
+    if (role == null) {
+      throw new RuntimeException("exception.get.domain.not.exist"); // FIXME: RestException
+    }
+
+    roleService.relateRolePermissions(role, rolePermissions.getRolePermissions());
+
+    RoleRelatePermissionsResponseData data = RoleRelatePermissionsResponseData.of("info.relate.success");
+
+    return new DefaultApiResponse<RoleRelatePermissionsResponseData>(data);
+  }
+
 }
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupCreateRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupCreateRequest.java
new file mode 100644
index 0000000..cc54393
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupCreateRequest.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiCreateRequest;
+import com.supwisdom.institute.backend.system.domain.entity.Group;
+
+/**
+ * @author loie
+ */
+public class GroupCreateRequest extends Group implements IApiCreateRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -5922604207821365121L;
+
+  public Group getEntity() {
+    return EntityUtils.copy(this, new Group());
+  }
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupQueryRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupQueryRequest.java
new file mode 100644
index 0000000..ad06060
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupQueryRequest.java
@@ -0,0 +1,40 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @author loie
+ */
+public class GroupQueryRequest implements IApiQueryRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -4023230222050081483L;
+
+  @Getter
+  @Setter
+  private boolean loadAll = false;
+  @Getter
+  @Setter
+  private int pageIndex = 0;
+  @Getter
+  @Setter
+  private int pageSize = 20;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, Object> mapBean;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, String> orderBy;
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelateAccountsRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelateAccountsRequest.java
new file mode 100644
index 0000000..fd95dd0
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelateAccountsRequest.java
@@ -0,0 +1,22 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiRequest;
+import com.supwisdom.institute.backend.system.domain.entity.AccountGroup;
+
+public class GroupRelateAccountsRequest implements IApiRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 440910731161851824L;
+
+  @Getter
+  @Setter
+  private List<AccountGroup> groupAccounts;
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelateRolesRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelateRolesRequest.java
new file mode 100644
index 0000000..5aa77fe
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelateRolesRequest.java
@@ -0,0 +1,22 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiRequest;
+import com.supwisdom.institute.backend.system.domain.entity.GroupRole;
+
+public class GroupRelateRolesRequest implements IApiRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 795337416058792163L;
+
+  @Getter
+  @Setter
+  private List<GroupRole> groupRoles;
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelatedAccountsRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelatedAccountsRequest.java
new file mode 100644
index 0000000..e2354d2
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelatedAccountsRequest.java
@@ -0,0 +1,40 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @author loie
+ */
+public class GroupRelatedAccountsRequest implements IApiQueryRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -3102006206798574212L;
+
+  @Getter
+  @Setter
+  private boolean loadAll = false;
+  @Getter
+  @Setter
+  private int pageIndex = 0;
+  @Getter
+  @Setter
+  private int pageSize = 20;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, Object> mapBean;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, String> orderBy;
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelatedRolesRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelatedRolesRequest.java
new file mode 100644
index 0000000..64dd04d
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupRelatedRolesRequest.java
@@ -0,0 +1,40 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @author loie
+ */
+public class GroupRelatedRolesRequest implements IApiQueryRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -6642264903131667637L;
+
+  @Getter
+  @Setter
+  private boolean loadAll = false;
+  @Getter
+  @Setter
+  private int pageIndex = 0;
+  @Getter
+  @Setter
+  private int pageSize = 20;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, Object> mapBean;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, String> orderBy;
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupUpdateRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupUpdateRequest.java
new file mode 100644
index 0000000..348658d
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/GroupUpdateRequest.java
@@ -0,0 +1,28 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiUpdateRequest;
+import com.supwisdom.institute.backend.system.domain.entity.Group;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class GroupUpdateRequest extends Group implements IApiUpdateRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -6406242462582902819L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  public Group getEntity() {
+    return EntityUtils.copy(this, new Group());
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/PermissionCreateRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/PermissionCreateRequest.java
new file mode 100644
index 0000000..24a6c19
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/PermissionCreateRequest.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiCreateRequest;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+
+/**
+ * @author loie
+ */
+public class PermissionCreateRequest extends Permission implements IApiCreateRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8247861768124918116L;
+
+  public Permission getEntity() {
+    return EntityUtils.copy(this, new Permission());
+  }
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/PermissionQueryRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/PermissionQueryRequest.java
new file mode 100644
index 0000000..4b26b8c
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/PermissionQueryRequest.java
@@ -0,0 +1,40 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @author loie
+ */
+public class PermissionQueryRequest implements IApiQueryRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -3944162671254599673L;
+
+  @Getter
+  @Setter
+  private boolean loadAll = false;
+  @Getter
+  @Setter
+  private int pageIndex = 0;
+  @Getter
+  @Setter
+  private int pageSize = 20;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, Object> mapBean;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, String> orderBy;
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/PermissionUpdateRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/PermissionUpdateRequest.java
new file mode 100644
index 0000000..f128f35
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/PermissionUpdateRequest.java
@@ -0,0 +1,28 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiUpdateRequest;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class PermissionUpdateRequest extends Permission implements IApiUpdateRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -5923008482749557479L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  public Permission getEntity() {
+    return EntityUtils.copy(this, new Permission());
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ResourceCreateRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ResourceCreateRequest.java
new file mode 100644
index 0000000..edcc582
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ResourceCreateRequest.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiCreateRequest;
+import com.supwisdom.institute.backend.system.domain.entity.Resource;
+
+/**
+ * @author loie
+ */
+public class ResourceCreateRequest extends Resource implements IApiCreateRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -7999657157256566904L;
+
+  public Resource getEntity() {
+    return EntityUtils.copy(this, new Resource());
+  }
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ResourceQueryRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ResourceQueryRequest.java
new file mode 100644
index 0000000..780f827
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ResourceQueryRequest.java
@@ -0,0 +1,40 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @author loie
+ */
+public class ResourceQueryRequest implements IApiQueryRequest {
+  
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -911488989591489730L;
+
+  @Getter
+  @Setter
+  private boolean loadAll = false;
+  @Getter
+  @Setter
+  private int pageIndex = 0;
+  @Getter
+  @Setter
+  private int pageSize = 20;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, Object> mapBean;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, String> orderBy;
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ResourceUpdateRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ResourceUpdateRequest.java
new file mode 100644
index 0000000..7013336
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/ResourceUpdateRequest.java
@@ -0,0 +1,28 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiUpdateRequest;
+import com.supwisdom.institute.backend.system.domain.entity.Resource;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ResourceUpdateRequest extends Resource implements IApiUpdateRequest {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8922380312193462613L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  public Resource getEntity() {
+    return EntityUtils.copy(this, new Resource());
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/RoleRelatePermissionsRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/RoleRelatePermissionsRequest.java
new file mode 100644
index 0000000..e4ed807
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/RoleRelatePermissionsRequest.java
@@ -0,0 +1,22 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiRequest;
+import com.supwisdom.institute.backend.system.domain.entity.RolePermission;
+
+public class RoleRelatePermissionsRequest implements IApiRequest {
+  
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -7524940232102183145L;
+
+  @Getter
+  @Setter
+  private List<RolePermission> rolePermissions;
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/RoleRelatedPermissionsRequest.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/RoleRelatedPermissionsRequest.java
new file mode 100644
index 0000000..b31c761
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/request/RoleRelatedPermissionsRequest.java
@@ -0,0 +1,40 @@
+package com.supwisdom.institute.backend.system.api.vo.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @author loie
+ */
+public class RoleRelatedPermissionsRequest implements IApiQueryRequest {
+  
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5695303573516182415L;
+
+  @Getter
+  @Setter
+  private boolean loadAll = false;
+  @Getter
+  @Setter
+  private int pageIndex = 0;
+  @Getter
+  @Setter
+  private int pageSize = 20;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, Object> mapBean;
+  @Getter
+  @Setter
+  @ApiModelProperty(hidden = true)
+  private Map<String, String> orderBy;
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupCreateResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupCreateResponseData.java
new file mode 100644
index 0000000..b5b64bd
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupCreateResponseData.java
@@ -0,0 +1,33 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiCreateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Group;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class GroupCreateResponseData extends Group implements IApiCreateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 3720317246428656184L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private GroupCreateResponseData() {
+
+  }
+
+  public static GroupCreateResponseData build(Group entity) {
+    GroupCreateResponseData data = new GroupCreateResponseData();
+
+    return EntityUtils.copy(entity, data);
+  }
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupLoadResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupLoadResponseData.java
new file mode 100644
index 0000000..9462642
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupLoadResponseData.java
@@ -0,0 +1,33 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiLoadResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Group;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class GroupLoadResponseData extends Group implements IApiLoadResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 8064680472492241116L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private GroupLoadResponseData() {
+
+  }
+
+  public static GroupLoadResponseData of(Group entity) {
+    GroupLoadResponseData data = new GroupLoadResponseData();
+    return EntityUtils.copy(entity, data);
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupQueryResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupQueryResponseData.java
new file mode 100644
index 0000000..43ee6f8
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupQueryResponseData.java
@@ -0,0 +1,80 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Group;
+
+/**
+ * @author loie
+ */
+public class GroupQueryResponseData implements IApiQueryResponseData<Group> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -1512126460241874099L;
+
+  private GroupQueryResponseData(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    this.loadAll = loadAll;
+    this.pageIndex = pageIndex;
+    this.pageSize = pageSize;
+    this.mapBean = mapBean;
+    this.orderBy = orderBy;
+  }
+
+  public static GroupQueryResponseData of(IApiQueryRequest queryRequest) {
+    GroupQueryResponseData configQueryResponse = new GroupQueryResponseData(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(), 
+        queryRequest.getMapBean(), 
+        queryRequest.getOrderBy()
+    );
+    
+    return configQueryResponse;
+  }
+  
+  public GroupQueryResponseData build(Page<Group> page) {
+    this.currentItemCount = page.getNumberOfElements();
+    this.pageCount = page.getTotalPages();
+    this.recordCount = page.getTotalElements();
+    this.items = page.getContent();
+
+    return this;
+  }
+
+  @Getter
+  private boolean loadAll;
+  @Getter
+  private int pageIndex;
+  @Getter
+  private int pageSize;
+  @Getter
+  private Map<String, Object> mapBean;
+  @Getter
+  private Map<String, String> orderBy;
+  
+  @Getter
+  @Setter
+  private int pageCount;
+  @Getter
+  @Setter
+  private long recordCount;
+  
+  @Getter
+  @Setter
+  private int currentItemCount;
+  
+  @Getter
+  @Setter
+  private List<Group> items;
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelateAccountsResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelateAccountsResponseData.java
new file mode 100644
index 0000000..84794bc
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelateAccountsResponseData.java
@@ -0,0 +1,29 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiResponseData;
+
+public class GroupRelateAccountsResponseData implements IApiResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -6510043291221068404L;
+
+  @Getter
+  @Setter
+  private String message;
+
+  public GroupRelateAccountsResponseData(String message) {
+    this.message = message;
+  }
+
+  public static GroupRelateAccountsResponseData of(String message) {
+    GroupRelateAccountsResponseData data = new GroupRelateAccountsResponseData(message);
+    
+    return data;
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelateRolesResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelateRolesResponseData.java
new file mode 100644
index 0000000..b9ecbd7
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelateRolesResponseData.java
@@ -0,0 +1,29 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiResponseData;
+
+public class GroupRelateRolesResponseData implements IApiResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1758005341902663320L;
+
+  @Getter
+  @Setter
+  private String message;
+
+  public GroupRelateRolesResponseData(String message) {
+    this.message = message;
+  }
+
+  public static GroupRelateRolesResponseData of(String message) {
+    GroupRelateRolesResponseData data = new GroupRelateRolesResponseData(message);
+    
+    return data;
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelatedAccountsResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelatedAccountsResponseData.java
new file mode 100644
index 0000000..efc5a28
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelatedAccountsResponseData.java
@@ -0,0 +1,80 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.AccountGroup;
+
+/**
+ * @author loie
+ */
+public class GroupRelatedAccountsResponseData implements IApiQueryResponseData<AccountGroup> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -6697630069320874813L;
+
+  private GroupRelatedAccountsResponseData(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    this.loadAll = loadAll;
+    this.pageIndex = pageIndex;
+    this.pageSize = pageSize;
+    this.mapBean = mapBean;
+    this.orderBy = orderBy;
+  }
+
+  public static GroupRelatedAccountsResponseData of(IApiQueryRequest queryRequest) {
+    GroupRelatedAccountsResponseData configQueryResponse = new GroupRelatedAccountsResponseData(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(), 
+        queryRequest.getMapBean(), 
+        queryRequest.getOrderBy()
+    );
+    
+    return configQueryResponse;
+  }
+  
+  public GroupRelatedAccountsResponseData build(Page<AccountGroup> page) {
+    this.currentItemCount = page.getNumberOfElements();
+    this.pageCount = page.getTotalPages();
+    this.recordCount = page.getTotalElements();
+    this.items = page.getContent();
+
+    return this;
+  }
+
+  @Getter
+  private boolean loadAll;
+  @Getter
+  private int pageIndex;
+  @Getter
+  private int pageSize;
+  @Getter
+  private Map<String, Object> mapBean;
+  @Getter
+  private Map<String, String> orderBy;
+  
+  @Getter
+  @Setter
+  private int pageCount;
+  @Getter
+  @Setter
+  private long recordCount;
+  
+  @Getter
+  @Setter
+  private int currentItemCount;
+  
+  @Getter
+  @Setter
+  private List<AccountGroup> items;
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelatedRolesResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelatedRolesResponseData.java
new file mode 100644
index 0000000..747ca50
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRelatedRolesResponseData.java
@@ -0,0 +1,80 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.GroupRole;
+
+/**
+ * @author loie
+ */
+public class GroupRelatedRolesResponseData implements IApiQueryResponseData<GroupRole> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1574248919628509262L;
+
+  private GroupRelatedRolesResponseData(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    this.loadAll = loadAll;
+    this.pageIndex = pageIndex;
+    this.pageSize = pageSize;
+    this.mapBean = mapBean;
+    this.orderBy = orderBy;
+  }
+
+  public static GroupRelatedRolesResponseData of(IApiQueryRequest queryRequest) {
+    GroupRelatedRolesResponseData configQueryResponse = new GroupRelatedRolesResponseData(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(), 
+        queryRequest.getMapBean(), 
+        queryRequest.getOrderBy()
+    );
+    
+    return configQueryResponse;
+  }
+  
+  public GroupRelatedRolesResponseData build(Page<GroupRole> page) {
+    this.currentItemCount = page.getNumberOfElements();
+    this.pageCount = page.getTotalPages();
+    this.recordCount = page.getTotalElements();
+    this.items = page.getContent();
+
+    return this;
+  }
+
+  @Getter
+  private boolean loadAll;
+  @Getter
+  private int pageIndex;
+  @Getter
+  private int pageSize;
+  @Getter
+  private Map<String, Object> mapBean;
+  @Getter
+  private Map<String, String> orderBy;
+  
+  @Getter
+  @Setter
+  private int pageCount;
+  @Getter
+  @Setter
+  private long recordCount;
+  
+  @Getter
+  @Setter
+  private int currentItemCount;
+  
+  @Getter
+  @Setter
+  private List<GroupRole> items;
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRemoveResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRemoveResponseData.java
new file mode 100644
index 0000000..4289989
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupRemoveResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiRemoveResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Group;
+
+/**
+ * @author loie
+ */
+public class GroupRemoveResponseData implements IApiRemoveResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -8704397808353314340L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private GroupRemoveResponseData() {
+    
+  }
+  
+  public static GroupRemoveResponseData build(Group entity) {
+    GroupRemoveResponseData data = new GroupRemoveResponseData();
+    
+    return EntityUtils.copy(entity, data);
+  }
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupUpdateResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupUpdateResponseData.java
new file mode 100644
index 0000000..a069602
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/GroupUpdateResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiUpdateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Group;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class GroupUpdateResponseData extends Group implements IApiUpdateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -1248124641996970651L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private GroupUpdateResponseData() {
+
+  }
+
+  public static GroupUpdateResponseData build(Group entity) {
+    GroupUpdateResponseData data = new GroupUpdateResponseData();
+
+    return EntityUtils.copy(entity, data);
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionCreateResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionCreateResponseData.java
new file mode 100644
index 0000000..ac89dd3
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionCreateResponseData.java
@@ -0,0 +1,33 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiCreateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class PermissionCreateResponseData extends Permission implements IApiCreateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 4619013116994825066L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private PermissionCreateResponseData() {
+
+  }
+
+  public static PermissionCreateResponseData build(Permission entity) {
+    PermissionCreateResponseData data = new PermissionCreateResponseData();
+
+    return EntityUtils.copy(entity, data);
+  }
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionLoadResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionLoadResponseData.java
new file mode 100644
index 0000000..6114186
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionLoadResponseData.java
@@ -0,0 +1,33 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiLoadResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class PermissionLoadResponseData extends Permission implements IApiLoadResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -2692036336252091453L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private PermissionLoadResponseData() {
+
+  }
+
+  public static PermissionLoadResponseData of(Permission entity) {
+    PermissionLoadResponseData data = new PermissionLoadResponseData();
+    return EntityUtils.copy(entity, data);
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionQueryResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionQueryResponseData.java
new file mode 100644
index 0000000..28f6bf6
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionQueryResponseData.java
@@ -0,0 +1,80 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+
+/**
+ * @author loie
+ */
+public class PermissionQueryResponseData implements IApiQueryResponseData<Permission> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -8586983968415937644L;
+
+  private PermissionQueryResponseData(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    this.loadAll = loadAll;
+    this.pageIndex = pageIndex;
+    this.pageSize = pageSize;
+    this.mapBean = mapBean;
+    this.orderBy = orderBy;
+  }
+
+  public static PermissionQueryResponseData of(IApiQueryRequest queryRequest) {
+    PermissionQueryResponseData configQueryResponse = new PermissionQueryResponseData(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(), 
+        queryRequest.getMapBean(), 
+        queryRequest.getOrderBy()
+    );
+    
+    return configQueryResponse;
+  }
+  
+  public PermissionQueryResponseData build(Page<Permission> page) {
+    this.currentItemCount = page.getNumberOfElements();
+    this.pageCount = page.getTotalPages();
+    this.recordCount = page.getTotalElements();
+    this.items = page.getContent();
+
+    return this;
+  }
+
+  @Getter
+  private boolean loadAll;
+  @Getter
+  private int pageIndex;
+  @Getter
+  private int pageSize;
+  @Getter
+  private Map<String, Object> mapBean;
+  @Getter
+  private Map<String, String> orderBy;
+  
+  @Getter
+  @Setter
+  private int pageCount;
+  @Getter
+  @Setter
+  private long recordCount;
+  
+  @Getter
+  @Setter
+  private int currentItemCount;
+  
+  @Getter
+  @Setter
+  private List<Permission> items;
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionRemoveResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionRemoveResponseData.java
new file mode 100644
index 0000000..c5fc2bc
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionRemoveResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiRemoveResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+
+/**
+ * @author loie
+ */
+public class PermissionRemoveResponseData implements IApiRemoveResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 216116075050505802L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private PermissionRemoveResponseData() {
+    
+  }
+  
+  public static PermissionRemoveResponseData build(Permission entity) {
+    PermissionRemoveResponseData data = new PermissionRemoveResponseData();
+    
+    return EntityUtils.copy(entity, data);
+  }
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionTreeResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionTreeResponseData.java
new file mode 100644
index 0000000..1f885fc
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionTreeResponseData.java
@@ -0,0 +1,20 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import java.util.List;
+
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+
+public class PermissionTreeResponseData implements IApiResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -6659447453323545811L;
+
+  public static PermissionTreeResponseData of(List<Permission> permissions) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionUpdateResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionUpdateResponseData.java
new file mode 100644
index 0000000..e9aa597
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/PermissionUpdateResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiUpdateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class PermissionUpdateResponseData extends Permission implements IApiUpdateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -7627522286872083527L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private PermissionUpdateResponseData() {
+
+  }
+
+  public static PermissionUpdateResponseData build(Permission entity) {
+    PermissionUpdateResponseData data = new PermissionUpdateResponseData();
+
+    return EntityUtils.copy(entity, data);
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceCreateResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceCreateResponseData.java
new file mode 100644
index 0000000..79cfe20
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceCreateResponseData.java
@@ -0,0 +1,33 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiCreateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Resource;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ResourceCreateResponseData extends Resource implements IApiCreateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -1679712204106541555L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private ResourceCreateResponseData() {
+
+  }
+
+  public static ResourceCreateResponseData build(Resource entity) {
+    ResourceCreateResponseData data = new ResourceCreateResponseData();
+
+    return EntityUtils.copy(entity, data);
+  }
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceLoadResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceLoadResponseData.java
new file mode 100644
index 0000000..7a129e8
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceLoadResponseData.java
@@ -0,0 +1,33 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiLoadResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Resource;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ResourceLoadResponseData extends Resource implements IApiLoadResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -8194462780086471511L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private ResourceLoadResponseData() {
+
+  }
+
+  public static ResourceLoadResponseData of(Resource entity) {
+    ResourceLoadResponseData data = new ResourceLoadResponseData();
+    return EntityUtils.copy(entity, data);
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceQueryResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceQueryResponseData.java
new file mode 100644
index 0000000..fb85017
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceQueryResponseData.java
@@ -0,0 +1,80 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Resource;
+
+/**
+ * @author loie
+ */
+public class ResourceQueryResponseData implements IApiQueryResponseData<Resource> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 241098548786558434L;
+
+  private ResourceQueryResponseData(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    this.loadAll = loadAll;
+    this.pageIndex = pageIndex;
+    this.pageSize = pageSize;
+    this.mapBean = mapBean;
+    this.orderBy = orderBy;
+  }
+
+  public static ResourceQueryResponseData of(IApiQueryRequest queryRequest) {
+    ResourceQueryResponseData configQueryResponse = new ResourceQueryResponseData(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(), 
+        queryRequest.getMapBean(), 
+        queryRequest.getOrderBy()
+    );
+    
+    return configQueryResponse;
+  }
+  
+  public ResourceQueryResponseData build(Page<Resource> page) {
+    this.currentItemCount = page.getNumberOfElements();
+    this.pageCount = page.getTotalPages();
+    this.recordCount = page.getTotalElements();
+    this.items = page.getContent();
+
+    return this;
+  }
+
+  @Getter
+  private boolean loadAll;
+  @Getter
+  private int pageIndex;
+  @Getter
+  private int pageSize;
+  @Getter
+  private Map<String, Object> mapBean;
+  @Getter
+  private Map<String, String> orderBy;
+  
+  @Getter
+  @Setter
+  private int pageCount;
+  @Getter
+  @Setter
+  private long recordCount;
+  
+  @Getter
+  @Setter
+  private int currentItemCount;
+  
+  @Getter
+  @Setter
+  private List<Resource> items;
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceRemoveResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceRemoveResponseData.java
new file mode 100644
index 0000000..b7f8ecb
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceRemoveResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiRemoveResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Resource;
+
+/**
+ * @author loie
+ */
+public class ResourceRemoveResponseData implements IApiRemoveResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 2847742767960670522L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private ResourceRemoveResponseData() {
+    
+  }
+  
+  public static ResourceRemoveResponseData build(Resource entity) {
+    ResourceRemoveResponseData data = new ResourceRemoveResponseData();
+    
+    return EntityUtils.copy(entity, data);
+  }
+  
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceUpdateResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceUpdateResponseData.java
new file mode 100644
index 0000000..c185a0a
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/ResourceUpdateResponseData.java
@@ -0,0 +1,34 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import com.supwisdom.institute.backend.common.framework.entity.EntityUtils;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiUpdateResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.Resource;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author loie
+ */
+public class ResourceUpdateResponseData extends Resource implements IApiUpdateResponseData {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 893314081061207360L;
+
+  @Getter
+  @Setter
+  private String id;
+
+  private ResourceUpdateResponseData() {
+
+  }
+
+  public static ResourceUpdateResponseData build(Resource entity) {
+    ResourceUpdateResponseData data = new ResourceUpdateResponseData();
+
+    return EntityUtils.copy(entity, data);
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/RoleRelatePermissionsResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/RoleRelatePermissionsResponseData.java
new file mode 100644
index 0000000..f5089b0
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/RoleRelatePermissionsResponseData.java
@@ -0,0 +1,29 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiResponseData;
+
+public class RoleRelatePermissionsResponseData implements IApiResponseData {
+  
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5398594379968952750L;
+
+  @Getter
+  @Setter
+  private String message;
+
+  public RoleRelatePermissionsResponseData(String message) {
+    this.message = message;
+  }
+
+  public static RoleRelatePermissionsResponseData of(String message) {
+    RoleRelatePermissionsResponseData data = new RoleRelatePermissionsResponseData(message);
+    
+    return data;
+  }
+
+}
diff --git a/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/RoleRelatedPermissionsResponseData.java b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/RoleRelatedPermissionsResponseData.java
new file mode 100644
index 0000000..31453e4
--- /dev/null
+++ b/system/api/src/main/java/com/supwisdom/institute/backend/system/api/vo/response/RoleRelatedPermissionsResponseData.java
@@ -0,0 +1,80 @@
+package com.supwisdom.institute.backend.system.api.vo.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+
+import com.supwisdom.institute.backend.common.framework.vo.request.IApiQueryRequest;
+import com.supwisdom.institute.backend.common.framework.vo.response.data.IApiQueryResponseData;
+import com.supwisdom.institute.backend.system.domain.entity.RolePermission;
+
+/**
+ * @author loie
+ */
+public class RoleRelatedPermissionsResponseData implements IApiQueryResponseData<RolePermission> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -7556328257191962088L;
+
+  private RoleRelatedPermissionsResponseData(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    this.loadAll = loadAll;
+    this.pageIndex = pageIndex;
+    this.pageSize = pageSize;
+    this.mapBean = mapBean;
+    this.orderBy = orderBy;
+  }
+
+  public static RoleRelatedPermissionsResponseData of(IApiQueryRequest queryRequest) {
+    RoleRelatedPermissionsResponseData configQueryResponse = new RoleRelatedPermissionsResponseData(
+        queryRequest.isLoadAll(), 
+        queryRequest.getPageIndex(), 
+        queryRequest.getPageSize(), 
+        queryRequest.getMapBean(), 
+        queryRequest.getOrderBy()
+    );
+    
+    return configQueryResponse;
+  }
+  
+  public RoleRelatedPermissionsResponseData build(Page<RolePermission> page) {
+    this.currentItemCount = page.getNumberOfElements();
+    this.pageCount = page.getTotalPages();
+    this.recordCount = page.getTotalElements();
+    this.items = page.getContent();
+
+    return this;
+  }
+
+  @Getter
+  private boolean loadAll;
+  @Getter
+  private int pageIndex;
+  @Getter
+  private int pageSize;
+  @Getter
+  private Map<String, Object> mapBean;
+  @Getter
+  private Map<String, String> orderBy;
+  
+  @Getter
+  @Setter
+  private int pageCount;
+  @Getter
+  @Setter
+  private long recordCount;
+  
+  @Getter
+  @Setter
+  private int currentItemCount;
+  
+  @Getter
+  @Setter
+  private List<RolePermission> items;
+  
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Permission.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Permission.java
new file mode 100644
index 0000000..72e2184
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Permission.java
@@ -0,0 +1,175 @@
+package com.supwisdom.institute.backend.system.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity
+@Table(name = "TB_U_PERMISSION")
+public class Permission extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = -8834200833972243635L;
+
+  public static final String TYPE_MENU = "2";
+  public static final String TYPE_OPERATION = "3";
+
+  /**
+   * 代码
+   */
+  @Column(name = "CODE")
+  private String code;
+
+  /**
+   * 名称
+   */
+  @Column(name = "NAME")
+  private String name;
+
+  /**
+   * 备注
+   */
+  @Column(name = "MEMO", nullable = true)
+  private String memo;
+
+  /**
+   * 状态(1 启用,0 停用)
+   */
+  @Column(name = "STATUS")
+  private String status;
+
+  /**
+   * 类型(1 应用,2 菜单,3 操作)
+   */
+  @Column(name = "TYPE_")
+  private String type;
+
+  /**
+   * URL地址
+   */
+  @Column(name = "URL", nullable = true)
+  private String url;
+
+  /**
+   * 父级ID
+   */
+  @Column(name = "PARENT_ID")
+  private String parentId;
+
+  /**
+   * 排序
+   */
+  @Column(name = "ORDER_")
+  private Integer order;
+
+  /**
+   * 层次
+   */
+  @Column(name = "LEVEL_")
+  private Integer level;
+
+  /**
+   * 左序
+   */
+  @Column(name = "LFT")
+  private Integer lft;
+
+  /**
+   * 右序
+   */
+  @Column(name = "RGT")
+  private Integer rgt;
+
+  public String getCode() {
+    return code;
+  }
+
+  public void setCode(String code) {
+    this.code = code;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getMemo() {
+    return memo;
+  }
+
+  public void setMemo(String memo) {
+    this.memo = memo;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public void setType(String type) {
+    this.type = type;
+  }
+
+  public String getUrl() {
+    return url;
+  }
+
+  public void setUrl(String url) {
+    this.url = url;
+  }
+
+  public String getParentId() {
+    return parentId;
+  }
+
+  public void setParentId(String parentId) {
+    this.parentId = parentId;
+  }
+
+  public Integer getOrder() {
+    return order;
+  }
+
+  public void setOrder(Integer order) {
+    this.order = order;
+  }
+
+  public Integer getLevel() {
+    return level;
+  }
+
+  public void setLevel(Integer level) {
+    this.level = level;
+  }
+
+  public int getLft() {
+    return lft;
+  }
+
+  public void setLft(int lft) {
+    this.lft = lft;
+  }
+
+  public int getRgt() {
+    return rgt;
+  }
+
+  public void setRgt(int rgt) {
+    this.rgt = rgt;
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Resource.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Resource.java
new file mode 100644
index 0000000..b34016e
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/Resource.java
@@ -0,0 +1,61 @@
+package com.supwisdom.institute.backend.system.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity
+@Table(name = "TB_U_RESOURCE")
+public class Resource extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 4288268877209267453L;
+
+  /**
+   * 代码
+   */
+  @Getter
+  @Setter
+  @Column(name = "CODE")
+  private String code;
+
+  /**
+   * 名称
+   */
+  @Getter
+  @Setter
+  @Column(name = "NAME")
+  private String name;
+
+  /**
+   * 备注
+   */
+  @Getter
+  @Setter
+  @Column(name = "MEMO", nullable = true)
+  private String memo;
+
+  /**
+   * 状态(1 启用,0 停用)
+   */
+  @Getter
+  @Setter
+  @Column(name = "STATUS")
+  private String status;
+
+  /**
+   * URL地址
+   */
+  @Getter
+  @Setter
+  @Column(name = "URL", nullable = true)
+  private String url;
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/RolePermission.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/RolePermission.java
new file mode 100644
index 0000000..252d32a
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/entity/RolePermission.java
@@ -0,0 +1,46 @@
+package com.supwisdom.institute.backend.system.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import com.supwisdom.institute.backend.common.framework.entity.ABaseEntity;
+
+@Entity
+@Table(name = "TB_U_ROLE_PERMISSION")
+public class RolePermission extends ABaseEntity {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5293251541687343949L;
+
+  /**
+   * 角色ID
+   */
+  @Column(name = "ROLE_ID")
+  private String roleId;
+
+  /**
+   * 权限ID
+   */
+  @Column(name = "PERMISSION_ID")
+  private String permissionId;
+
+  public String getRoleId() {
+    return roleId;
+  }
+
+  public void setRoleId(String roleId) {
+    this.roleId = roleId;
+  }
+
+  public String getPermissionId() {
+    return permissionId;
+  }
+
+  public void setPermissionId(String permissionId) {
+    this.permissionId = permissionId;
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/AccountRepository.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/AccountRepository.java
index 526350f..e23f46e 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/AccountRepository.java
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/AccountRepository.java
@@ -16,30 +16,38 @@
 @Repository
 public interface AccountRepository extends BaseJpaRepository<Account> {
   
-  public default Page<Account> selectPageList(int pageIndex, int pageSize, Account probe) {
-    
-    ExampleMatcher matcher = ExampleMatcher.matching()
-        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.contains())
-        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
-        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
-    
-    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
-    Example<Account> example = Example.of(probe, matcher);
-    
-    Page<Account> page = this.findAll(example, pageRequest);
-    
-    return page;
-  }
+//  public default Page<Account> selectPageList(int pageIndex, int pageSize, Account probe) {
+//    
+//    ExampleMatcher matcher = ExampleMatcher.matching()
+//        .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.contains())
+//        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+//        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
+//    
+//    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+//    Example<Account> example = Example.of(probe, matcher);
+//    
+//    Page<Account> page = this.findAll(example, pageRequest);
+//    
+//    return page;
+//  }
   
-  public default Page<Account> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+  @Override
+  public default Page<Account> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
     Account probe = new Account();
     if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
       probe.setUsername(MapBeanUtils.getString(mapBean, "username"));
       probe.setName(MapBeanUtils.getString(mapBean, "name"));
       probe.setStatus(MapBeanUtils.getString(mapBean, "status"));
     }
     
     ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
         .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.contains())
         .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
         .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/GroupRepository.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/GroupRepository.java
index ba8607a..28a0b66 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/GroupRepository.java
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/GroupRepository.java
@@ -15,9 +15,16 @@
 @Repository
 public interface GroupRepository extends BaseJpaRepository<Group> {
 
-  public default Page<Group> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+  @Override
+  public default Page<Group> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
     Group probe = new Group();
     if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
       probe.setCode(MapBeanUtils.getString(mapBean, "code"));
       probe.setName(MapBeanUtils.getString(mapBean, "name"));
       probe.setMemo(MapBeanUtils.getString(mapBean, "memo"));
@@ -25,6 +32,7 @@
     }
     
     ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
         .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.contains())
         .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
         .withMatcher("memo", ExampleMatcher.GenericPropertyMatchers.contains())
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/PermissionRepository.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/PermissionRepository.java
new file mode 100644
index 0000000..42b70c8
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/PermissionRepository.java
@@ -0,0 +1,300 @@
+package com.supwisdom.institute.backend.system.domain.repo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.transaction.Transactional;
+
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+
+@Repository
+@Transactional
+public interface PermissionRepository extends BaseJpaRepository<Permission> {
+
+  @Override
+  public default Page<Permission> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    Permission probe = new Permission();
+    if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
+      probe.setCode(MapBeanUtils.getString(mapBean, "code"));
+      probe.setName(MapBeanUtils.getString(mapBean, "name"));
+      probe.setMemo(MapBeanUtils.getString(mapBean, "memo"));
+      probe.setStatus(MapBeanUtils.getString(mapBean, "status"));
+      probe.setType(MapBeanUtils.getString(mapBean, "type"));
+    }
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("memo", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("type", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<Permission> example = Example.of(probe, matcher);
+    
+    Page<Permission> page = this.findAll(example, pageRequest);
+    
+    return page;
+  }
+  
+  
+  
+  @Query(value = "select max(p.rgt) from Permission p")
+  public int selectMaxRgt();
+  
+  @Query(value = "select p from Permission p where p.lft>:lft and p.rgt<:rgt order by p.lft")
+  public List<Permission> selectBetweenLftRgt(@Param("lft") int lft, @Param("rgt") int rgt);
+  
+  @Modifying
+  @Query(value = "update TB_U_PERMISSION "
+      + "set "
+      + "  LFT = (case when LFT >= :rgt then LFT + :offset else LFT end), "
+      + "  RGT = RGT + :offset "
+      + "where RGT >= :rgt", nativeQuery = true)
+  public int updateLftRgtWhenInsert(@Param("rgt") int rgt, @Param("offset") int offset);
+
+  @Modifying
+  @Query(value = "update TB_U_PERMISSION "
+      + "set "
+      + "  LFT = (case when LFT >= :rgt then LFT - :offset else LFT end), "
+      + "  RGT = RGT - :offset "
+      + "where RGT >= :rgt", nativeQuery = true)
+  public int updateLftRgtWhenDelete(@Param("rgt") int rgt, @Param("offset") int offset);
+  
+  
+  @Override
+  public default Permission insert(Permission entity) {
+
+    if (entity.getParentId() == null) {
+      entity.setParentId("0");
+    }
+
+    if (entity.getParentId() == null || entity.getParentId().isEmpty() || "0".equals(entity.getParentId())) {
+      int maxRgt = selectMaxRgt();
+      entity.setLft((maxRgt+1));
+      entity.setRgt((maxRgt+1) + 1);
+      
+      entity.setLevel(1);
+    } else {
+      Permission parentEntity = this.selectById(entity.getParentId());
+      if (parentEntity == null) {
+        throw new RuntimeException(String.format("父级对象不存在!"));
+      } else {
+        // 将 lft或rgt 大于等于父级对象 rgt 的记录的 lft、rgt +offset
+        int rgt = parentEntity.getRgt();
+        int offset = 2;
+        updateLftRgtWhenInsert(rgt, offset);
+        
+        entity.setLft(rgt);
+        entity.setRgt(rgt + 1);
+        
+        entity.setLevel(parentEntity.getLevel() + 1);
+      }
+    }
+    
+    return BaseJpaRepository.super.insert(entity);
+  }
+  
+  @Override
+  public default Permission update(Permission entity) {
+
+    Permission originEntity = this.selectById(entity.getId());
+    if (originEntity == null) {
+      return null;
+    }
+    
+    //if (!this.checkFieldExists("code", entity.getCode(), entity.getId())) {
+    //  throw new RuntimeException(String.format("代码重复!"));
+    //}
+    
+    if (originEntity.getParentId() == null) {
+      originEntity.setParentId("0");
+    }
+    
+    if (entity.getParentId() == null) {
+      entity.setParentId("0");
+    }
+    
+    if (!originEntity.getParentId().equals(entity.getParentId()) ) {
+
+      int lft = originEntity.getLft();
+      int rgt = originEntity.getRgt();
+      int level = originEntity.getLevel();
+      int offset = rgt - lft +1;
+      
+      List<Permission> childEntities = this.selectBetweenLftRgt(lft, rgt);
+
+      if (entity.getParentId() == null || entity.getParentId().isEmpty() || "0".equals(entity.getParentId())) {
+        // 将 lft或rgt 大于等于该对象 rgt 的记录的 lft、rgt -offset
+        updateLftRgtWhenDelete(rgt, offset);
+  
+        int maxRgt = selectMaxRgt();
+        entity.setLft((maxRgt+1));
+        entity.setRgt((maxRgt+1) + 1 +offset-2);
+        
+        entity.setLevel(1);
+      } else {
+        // 将 lft或rgt 大于等于该对象 rgt 的记录的 lft、rgt -offset
+        updateLftRgtWhenDelete(rgt, offset);
+
+        Permission parentEntity = this.selectById(entity.getParentId());
+        if (parentEntity == null) {
+          throw new RuntimeException(String.format("父级对象不存在!"));
+        }
+        //System.out.println(String.format("pLft %s, pRgt %s", parentEntity.getLft(), parentEntity.getRgt()));
+        if (parentEntity.getLft() >= originEntity.getLft() && parentEntity.getRgt() <= originEntity.getRgt()) {
+          throw new RuntimeException(String.format("不能设置自身或自身的子节点作为父级!"));
+        }
+        
+        //parentEntity = this.selectById(entity.getParentId()); System.out.println(String.format("pLft %s, pRgt %s", parentEntity.getLft(), parentEntity.getRgt()));
+        // 将 lft或rgt 大于等于父级对象 rgt 的记录的 lft、rgt +offset
+        //int pLft = parentEntity.getLft();
+        int pRgt = parentEntity.getRgt();
+        updateLftRgtWhenInsert(pRgt, offset);
+        
+        entity.setLft(pRgt);
+        entity.setRgt(pRgt + 1 + offset-2);
+        
+        entity.setLevel(parentEntity.getLevel() + 1);
+      }
+      
+      int newLft = entity.getLft();
+      int newRgt = entity.getRgt();
+      int newLevel = entity.getLevel();
+      //System.out.println(String.format("newLft %s, newRgt %s, newLevel %s", newLft, newRgt, newLevel));
+      //System.out.println(String.format("lft %s, rgt %s, level %s", lft, rgt, level));
+      for (Permission childEntity : childEntities) {
+        //Permission pEntity = this.selectById(childEntity.getParentId());
+        
+        int cLft = childEntity.getLft();
+        int cRgt = childEntity.getRgt();
+        int cLevel = childEntity.getLevel();
+        
+        childEntity.setLft(cLft + (newLft - lft));
+        childEntity.setRgt(cRgt + (newRgt - rgt));
+        
+        childEntity.setLevel(cLevel + (newLevel - level));
+        
+        BaseJpaRepository.super.update(childEntity);
+      }
+
+    }
+    
+    return BaseJpaRepository.super.update(entity);
+  }
+
+  @Override
+  public default void delete(String id) {
+    
+    Permission originEntity = this.selectById(id);
+    if (originEntity == null) {
+      return;
+    }
+
+    int lft = originEntity.getLft();
+    int rgt = originEntity.getRgt();
+    int offset = rgt - lft +1;
+
+    // FIXME: 判断是否有子节点
+    //if (lft + 1 != rgt) {
+    //  return;
+    //}
+
+    List<Permission> childEntities = this.selectBetweenLftRgt(lft, rgt);
+    for (Permission childEntity : childEntities) {
+      BaseJpaRepository.super.delete(childEntity.getId());
+    }
+    
+    // 将 lft或rgt 大于等于该对象 rgt 的记录的 lft、rgt -offset
+    updateLftRgtWhenDelete(rgt, offset);
+    
+    BaseJpaRepository.super.delete(id);
+  }
+
+  public default Permission selectApplicationPermissionByCode(String code) {
+    Permission probe = new Permission();
+    probe.setCode(code);
+    probe.setType("1");
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("type", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    Example<Permission> example = Example.of(probe, matcher);
+    
+    Optional<Permission> o = this.findOne(example);
+    
+    if (o.isPresent()) {
+      return o.get();
+    }
+    
+    return null;
+  }
+  
+ 
+
+  @Query(value = "select p from Permission p "
+      + "inner join RolePermission rp on p.id=rp.permissionId "
+      + "inner join Role r on rp.roleId=r.id "
+      + "inner join AccountRole ar on r.id=ar.roleId "
+      + "inner join Account a on ar.accountId=a.id "
+      + "where a.username=:username "
+      + "and p.lft >= :lft and p.rgt <= :rgt "
+      + "and (:type is null or p.type=:type) "
+      + "and p.status='1' and r.status='1' and a.status='1' and a.enabled=1 ")
+  public List<Permission> selectAccountRolePermissionByUsername(@Param("username") String username, @Param("lft") int lft, @Param("rgt") int rgt, @Param("type") String type);
+  
+  @Query(value = "select p from Permission p "
+      + "inner join RolePermission rp on p.id=rp.permissionId "
+      + "inner join Role r on rp.roleId=r.id "
+      + "inner join GroupRole gr on r.id=gr.roleId "
+      + "inner join Group_ g on gr.groupId=g.id "
+      + "inner join AccountGroup ag on g.id=ag.groupId "
+      + "inner join Account a on ag.accountId=a.id "
+      + "where a.username=:username "
+      + "and p.lft >= :lft and p.rgt <= :rgt "
+      + "and (:type is null or p.type=:type) "
+      + "and p.status='1' and r.status='1' and g.status='1' and a.status='1' and a.enabled=1 ")
+  public List<Permission> selectAccountGroupRolePermissionByUsername(@Param("username") String username, @Param("lft") int lft, @Param("rgt") int rgt, @Param("type") String type);
+
+  public default List<Permission> selectByUsername(String username, String applicationCode, String type) {
+    List<Permission> permissions = new ArrayList<Permission>();
+    
+    Permission applicationPermission = selectApplicationPermissionByCode(applicationCode);
+    if (applicationPermission == null) {
+      return permissions;
+    }
+    
+    int lft = applicationPermission.getLft();
+    int rgt = applicationPermission.getRgt();
+    
+    List<Permission> accountRolePermissions = selectAccountRolePermissionByUsername(username, lft, rgt, type);
+    permissions.addAll(accountRolePermissions);
+    
+    List<Permission> accountGroupRolePermissions = selectAccountGroupRolePermissionByUsername(username, lft, rgt, type);
+    permissions.addAll(accountGroupRolePermissions);
+    
+    return permissions;
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/ResourceRepository.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/ResourceRepository.java
new file mode 100644
index 0000000..693c10a
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/ResourceRepository.java
@@ -0,0 +1,68 @@
+package com.supwisdom.institute.backend.system.domain.repo;
+
+import java.util.Map;
+import java.util.Optional;
+
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+import com.supwisdom.institute.backend.system.domain.entity.Resource;
+
+@Repository
+public interface ResourceRepository extends BaseJpaRepository<Resource> {
+
+  @Override
+  public default Page<Resource> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
+    Resource probe = new Resource();
+    if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
+      probe.setCode(MapBeanUtils.getString(mapBean, "code"));
+      probe.setName(MapBeanUtils.getString(mapBean, "name"));
+      probe.setMemo(MapBeanUtils.getString(mapBean, "memo"));
+      probe.setStatus(MapBeanUtils.getString(mapBean, "status"));
+    }
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("memo", ExampleMatcher.GenericPropertyMatchers.contains())
+        .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<Resource> example = Example.of(probe, matcher);
+    
+    Page<Resource> page = this.findAll(example, pageRequest);
+    
+    return page;
+  }
+
+  public default Resource selectByCode(String code) {
+    Resource probe = new Resource();
+    probe.setCode(code);
+    
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.exact());
+    
+    Example<Resource> example = Example.of(probe, matcher);
+    
+    Optional<Resource> o = this.findOne(example);
+    
+    if (o.isPresent()) {
+      return o.get();
+    }
+    
+    return null;
+  }
+  
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/RolePermissionRepository.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/RolePermissionRepository.java
new file mode 100644
index 0000000..97ff9e6
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/RolePermissionRepository.java
@@ -0,0 +1,193 @@
+package com.supwisdom.institute.backend.system.domain.repo;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Repository;
+
+import com.supwisdom.institute.backend.common.framework.repo.BaseJpaRepository;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+import com.supwisdom.institute.backend.system.domain.entity.Role;
+import com.supwisdom.institute.backend.system.domain.entity.RolePermission;
+
+@Repository
+public interface RolePermissionRepository extends BaseJpaRepository<RolePermission> {
+
+  public default Page<RolePermission> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+    RolePermission probe = new RolePermission();
+    if (mapBean != null) {
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+      probe.setPermissionId(MapBeanUtils.getString(mapBean, "permissionId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("permissionId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    Page<RolePermission> page = this.findAll(example, pageRequest);
+
+    return page;
+  }
+
+  public default Page<RolePermission> selectRolePermissions(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    RolePermission probe = new RolePermission();
+    if (mapBean != null) {
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+      probe.setPermissionId(MapBeanUtils.getString(mapBean, "permissionId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("permissionId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<RolePermission> page = this.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public default void relateRolePermissions(Role role, List<RolePermission> rolePermissions) {
+
+    List<RolePermission> existRolePermissions = this.selectListByRoleId(role.getId());
+
+    Map<String, RolePermission> existMapRolePermissions = new LinkedHashMap<String, RolePermission>();
+    for (RolePermission rolePermission : existRolePermissions) {
+      String k = String.format("%s", rolePermission.getPermissionId());
+      existMapRolePermissions.put(k, rolePermission);
+    }
+
+    for (RolePermission rolePermission : rolePermissions) {
+      String k = String.format("%s", rolePermission.getPermissionId());
+
+      if (existMapRolePermissions.containsKey(k)) {
+        existMapRolePermissions.remove(k);
+      } else {
+        rolePermission.setCompanyId(role.getCompanyId());
+        rolePermission.setRoleId(role.getId());
+
+        this.insert(rolePermission);
+      }
+    }
+
+    for (RolePermission rolePermission : existMapRolePermissions.values()) {
+      this.deleteById(rolePermission.getId());
+    }
+  }
+
+  public default List<RolePermission> selectListByRoleId(String roleId) {
+
+    RolePermission probe = new RolePermission();
+    probe.setRoleId(roleId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("roleId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    List<RolePermission> rolePermissions = this.findAll(example);
+
+    return rolePermissions;
+  }
+
+  public default void relatePermissionRoles(Permission permission, List<RolePermission> rolePermissions) {
+
+    // 获取权限已关联的角色
+    List<RolePermission> existPermissionRoles = this.selectListByPermissionId(permission.getId());
+
+    Map<String, RolePermission> existMapPermissionRoles = new LinkedHashMap<String, RolePermission>();
+    for (RolePermission rolePermission : existPermissionRoles) {
+      String k = String.format("%s", rolePermission.getRoleId());
+      existMapPermissionRoles.put(k, rolePermission);
+    }
+
+    // 保存未关联的角色
+    for (RolePermission rolePermission : rolePermissions) {
+      String k = String.format("%s", rolePermission.getRoleId());
+
+      if (existMapPermissionRoles.containsKey(k)) {
+        existMapPermissionRoles.remove(k);
+      } else {
+        rolePermission.setCompanyId(permission.getCompanyId());
+        rolePermission.setPermissionId(permission.getId());
+
+        this.insert(rolePermission);
+      }
+    }
+
+    // 删除移除关联的角色
+    for (RolePermission rolePermission : existMapPermissionRoles.values()) {
+      this.deleteById(rolePermission.getId());
+    }
+  }
+
+  public default List<RolePermission> selectListByPermissionId(String permissionId) {
+
+    RolePermission probe = new RolePermission();
+    probe.setPermissionId(permissionId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("permissionId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    List<RolePermission> rolePermissions = this.findAll(example);
+
+    return rolePermissions;
+  }
+
+  public default RolePermission selectOneByRolePermission(String roleId, String permissionId) {
+
+    RolePermission probe = new RolePermission();
+    probe.setRoleId(roleId);
+    probe.setPermissionId(permissionId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("permissionId", ExampleMatcher.GenericPropertyMatchers.exact())
+        ;
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+    
+    Optional<RolePermission> o = this.findOne(example);
+    
+    return o.isPresent() ? o.get() : null;
+  }
+
+  public default void addRolePermission(String roleId, String permissionId) {
+
+    RolePermission rolePermission = this.selectOneByRolePermission(roleId, permissionId);
+    
+    if (rolePermission == null) {
+      rolePermission = new RolePermission();
+      //rolePermission.setCompanyId(companyId);
+      rolePermission.setRoleId(roleId);
+      rolePermission.setPermissionId(permissionId);
+      
+      this.insert(rolePermission);
+    }
+  }
+
+  public default void removeRolePermission(String roleId, String permissionId) {
+
+    RolePermission rolePermission = this.selectOneByRolePermission(roleId, permissionId);
+    
+    if (rolePermission != null) {
+      this.deleteById(rolePermission.getId());
+    }
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/RoleRepository.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/RoleRepository.java
index 44787bb..9a8763d 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/RoleRepository.java
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/repo/RoleRepository.java
@@ -20,9 +20,16 @@
 @Repository
 public interface RoleRepository extends BaseJpaRepository<Role> {
 
-  public default Page<Role> selectPageList(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+  @Override
+  public default Page<Role> selectPageList(boolean loadAll, int pageIndex, int pageSize, Map<String, Object> mapBean, Map<String, String> orderBy) {
+    if (loadAll) {
+      pageIndex = 0;
+      pageSize = Integer.MAX_VALUE;
+    }
+    
     Role probe = new Role();
     if (mapBean != null) {
+      probe.setDeleted(MapBeanUtils.getBoolean(mapBean, "deleted"));
       probe.setCode(MapBeanUtils.getString(mapBean, "code"));
       probe.setName(MapBeanUtils.getString(mapBean, "name"));
       probe.setMemo(MapBeanUtils.getString(mapBean, "memo"));
@@ -30,6 +37,7 @@
     }
     
     ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("deleted", ExampleMatcher.GenericPropertyMatchers.exact())
         .withMatcher("code", ExampleMatcher.GenericPropertyMatchers.contains())
         .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains())
         .withMatcher("memo", ExampleMatcher.GenericPropertyMatchers.contains())
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/AccountService.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/AccountService.java
index e59b9fd..83405ae 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/AccountService.java
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/AccountService.java
@@ -84,7 +84,7 @@
     }
 
     for (AccountGroup accountGroup : existMapAccountGroups.values()) {
-      this.deleteById(accountGroup.getId());
+      accountGroupRepository.deleteById(accountGroup.getId());
     }
   }
 
@@ -150,7 +150,7 @@
     }
 
     for (AccountRole accountRole : existMapAccountRoles.values()) {
-      this.deleteById(accountRole.getId());
+      accountRoleRepository.deleteById(accountRole.getId());
     }
   }
 
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/GroupService.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/GroupService.java
index 4290954..1e9eb6b 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/GroupService.java
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/GroupService.java
@@ -1,11 +1,26 @@
 package com.supwisdom.institute.backend.system.domain.service;
 
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Service;
 
 import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+import com.supwisdom.institute.backend.common.util.MapBeanUtils;
+import com.supwisdom.institute.backend.system.domain.entity.AccountGroup;
 import com.supwisdom.institute.backend.system.domain.entity.Group;
+import com.supwisdom.institute.backend.system.domain.entity.GroupRole;
+import com.supwisdom.institute.backend.system.domain.repo.AccountGroupRepository;
 import com.supwisdom.institute.backend.system.domain.repo.GroupRepository;
+import com.supwisdom.institute.backend.system.domain.repo.GroupRoleRepository;
 
+@Service
 public class GroupService extends ABaseService<Group, GroupRepository> {
   
   @Override
@@ -16,4 +31,145 @@
   @Autowired
   private GroupRepository groupRepository;
 
+  @Autowired
+  private AccountGroupRepository accountGroupRepository;
+
+  @Autowired
+  private GroupRoleRepository groupRoleRepository;
+
+
+
+  public Page<AccountGroup> selectGroupAccounts(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    AccountGroup probe = new AccountGroup();
+    if (mapBean != null) {
+      probe.setAccountId(MapBeanUtils.getString(mapBean, "accountId"));
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("accountId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+    ;
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<AccountGroup> page = accountGroupRepository.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public void relateGroupAccounts(Group group, List<AccountGroup> accountGroups) {
+
+    List<AccountGroup> existGroupAccounts = this.selectGroupAccountsByGroupId(group.getId());
+
+    Map<String, AccountGroup> existMapGroupAccounts = new LinkedHashMap<String, AccountGroup>();
+    for (AccountGroup accountGroup : existGroupAccounts) {
+      String k = String.format("%s", accountGroup.getAccountId());
+      existMapGroupAccounts.put(k, accountGroup);
+    }
+
+    for (AccountGroup accountGroup : accountGroups) {
+      String k = String.format("%s", accountGroup.getAccountId());
+
+      if (existMapGroupAccounts.containsKey(k)) {
+        existMapGroupAccounts.remove(k);
+      } else {
+        accountGroup.setCompanyId(group.getCompanyId());
+        accountGroup.setGroupId(group.getId());
+
+        accountGroupRepository.insert(accountGroup);
+      }
+    }
+
+    for (AccountGroup accountGroup : existMapGroupAccounts.values()) {
+      accountGroupRepository.deleteById(accountGroup.getId());
+    }
+  }
+
+  public List<AccountGroup> selectGroupAccountsByGroupId(String groupId) {
+
+    AccountGroup probe = new AccountGroup();
+    probe.setGroupId(groupId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<AccountGroup> example = Example.of(probe, matcher);
+
+    List<AccountGroup> accountGroups = accountGroupRepository.findAll(example);
+
+    return accountGroups;
+  }
+  
+  
+  
+
+  public Page<GroupRole> selectGroupRoles(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    GroupRole probe = new GroupRole();
+    if (mapBean != null) {
+      probe.setGroupId(MapBeanUtils.getString(mapBean, "groupId"));
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("groupId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<GroupRole> page = groupRoleRepository.findAll(example, pageRequest);  // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public void relateGroupRoles(Group group, List<GroupRole> groupRoles) {
+
+    List<GroupRole> existGroupRoles = this.selectGroupRolesByGroupId(group.getId());
+
+    Map<String, GroupRole> existMapGroupRoles = new LinkedHashMap<String, GroupRole>();
+    for (GroupRole groupRole : existGroupRoles) {
+      String k = String.format("%s", groupRole.getRoleId());
+      existMapGroupRoles.put(k, groupRole);
+    }
+
+    for (GroupRole groupRole : groupRoles) {
+      String k = String.format("%s", groupRole.getRoleId());
+
+      if (existMapGroupRoles.containsKey(k)) {
+        existMapGroupRoles.remove(k);
+      } else {
+        groupRole.setCompanyId(group.getCompanyId());
+        groupRole.setGroupId(group.getId());
+
+        groupRoleRepository.insert(groupRole);
+      }
+    }
+
+    for (GroupRole groupRole : existMapGroupRoles.values()) {
+      groupRoleRepository.deleteById(groupRole.getId());
+    }
+  }
+
+  public List<GroupRole> selectGroupRolesByGroupId(String groupId) {
+
+    GroupRole probe = new GroupRole();
+    probe.setGroupId(groupId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("groupId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<GroupRole> example = Example.of(probe, matcher);
+
+    List<GroupRole> groupRoles = groupRoleRepository.findAll(example);
+
+    return groupRoles;
+  }
+
+
 }
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/PermissionService.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/PermissionService.java
new file mode 100644
index 0000000..b00011c
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/PermissionService.java
@@ -0,0 +1,30 @@
+package com.supwisdom.institute.backend.system.domain.service;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+import com.supwisdom.institute.backend.system.domain.entity.Permission;
+import com.supwisdom.institute.backend.system.domain.repo.PermissionRepository;
+
+@Service
+public class PermissionService extends ABaseService<Permission, PermissionRepository> {
+  
+  @Override
+  public PermissionRepository getRepo() {
+    return permissionRepository;
+  }
+
+  @Autowired
+  private PermissionRepository permissionRepository;
+
+  public List<Permission> selectPermissionTree(Map<String, Object> mapBean) {
+    
+    
+    return null;
+  }
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/ResourceService.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/ResourceService.java
new file mode 100644
index 0000000..65eab2d
--- /dev/null
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/ResourceService.java
@@ -0,0 +1,21 @@
+package com.supwisdom.institute.backend.system.domain.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.supwisdom.institute.backend.common.framework.service.ABaseService;
+import com.supwisdom.institute.backend.system.domain.entity.Resource;
+import com.supwisdom.institute.backend.system.domain.repo.ResourceRepository;
+
+@Service
+public class ResourceService extends ABaseService<Resource, ResourceRepository> {
+  
+  @Override
+  public ResourceRepository getRepo() {
+    return resourceRepository;
+  }
+
+  @Autowired
+  private ResourceRepository resourceRepository;
+
+}
diff --git a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/RoleService.java b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/RoleService.java
index 41952ed..068eeeb 100644
--- a/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/RoleService.java
+++ b/system/domain/src/main/java/com/supwisdom/institute/backend/system/domain/service/RoleService.java
@@ -9,16 +9,20 @@
 import org.springframework.data.domain.ExampleMatcher;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Service;
 
 import com.supwisdom.institute.backend.common.framework.service.ABaseService;
 import com.supwisdom.institute.backend.common.util.MapBeanUtils;
 import com.supwisdom.institute.backend.system.domain.entity.AccountRole;
 import com.supwisdom.institute.backend.system.domain.entity.GroupRole;
 import com.supwisdom.institute.backend.system.domain.entity.Role;
+import com.supwisdom.institute.backend.system.domain.entity.RolePermission;
 import com.supwisdom.institute.backend.system.domain.repo.AccountRoleRepository;
 import com.supwisdom.institute.backend.system.domain.repo.GroupRoleRepository;
+import com.supwisdom.institute.backend.system.domain.repo.RolePermissionRepository;
 import com.supwisdom.institute.backend.system.domain.repo.RoleRepository;
 
+@Service
 public class RoleService extends ABaseService<Role, RoleRepository> {
   
   @Override
@@ -35,6 +39,9 @@
   @Autowired
   private GroupRoleRepository groupRoleRepository;
 
+  @Autowired
+  private RolePermissionRepository rolePermissionRepository;
+
   
 
   public Page<AccountRole> selectRoleAccounts(int pageIndex, int pageSize, Map<String, Object> mapBean) {
@@ -82,7 +89,7 @@
     }
 
     for (AccountRole accountRole : existMapRoleAccounts.values()) {
-      this.deleteById(accountRole.getId());
+      accountRoleRepository.deleteById(accountRole.getId());
     }
   }
 
@@ -148,7 +155,7 @@
     }
 
     for (GroupRole groupRole : existMapRoleGroups.values()) {
-      this.deleteById(groupRole.getId());
+      groupRoleRepository.deleteById(groupRole.getId());
     }
   }
 
@@ -167,5 +174,69 @@
     return groupRoles;
   }
 
-  
+
+  public Page<RolePermission> selectRolePermissions(int pageIndex, int pageSize, Map<String, Object> mapBean) {
+
+    RolePermission probe = new RolePermission();
+    if (mapBean != null) {
+      probe.setRoleId(MapBeanUtils.getString(mapBean, "roleId"));
+      probe.setPermissionId(MapBeanUtils.getString(mapBean, "permissionId"));
+    }
+
+    ExampleMatcher matcher = ExampleMatcher.matching()
+        .withMatcher("roleId", ExampleMatcher.GenericPropertyMatchers.exact())
+        .withMatcher("permissionId", ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    PageRequest pageRequest = PageRequest.of(pageIndex, pageSize);
+
+    Page<RolePermission> page = rolePermissionRepository.findAll(example, pageRequest); // FIXME: 多表关联查询
+
+    return page;
+  }
+
+  public void relateRolePermissions(Role role, List<RolePermission> rolePermissions) {
+
+    List<RolePermission> existRolePermissions = this.selectRolePermissionsByRoleId(role.getId());
+
+    Map<String, RolePermission> existMapRolePermissions = new LinkedHashMap<String, RolePermission>();
+    for (RolePermission rolePermission : existRolePermissions) {
+      String k = String.format("%s", rolePermission.getPermissionId());
+      existMapRolePermissions.put(k, rolePermission);
+    }
+
+    for (RolePermission rolePermission : rolePermissions) {
+      String k = String.format("%s", rolePermission.getPermissionId());
+
+      if (existMapRolePermissions.containsKey(k)) {
+        existMapRolePermissions.remove(k);
+      } else {
+        rolePermission.setCompanyId(role.getCompanyId());
+        rolePermission.setRoleId(role.getId());
+
+        rolePermissionRepository.insert(rolePermission);
+      }
+    }
+
+    for (RolePermission rolePermission : existMapRolePermissions.values()) {
+      rolePermissionRepository.deleteById(rolePermission.getId());
+    }
+  }
+
+  public List<RolePermission> selectRolePermissionsByRoleId(String roleId) {
+
+    RolePermission probe = new RolePermission();
+    probe.setRoleId(roleId);
+
+    ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("roleId",
+        ExampleMatcher.GenericPropertyMatchers.exact());
+
+    Example<RolePermission> example = Example.of(probe, matcher);
+
+    List<RolePermission> rolePermissions = rolePermissionRepository.findAll(example);
+
+    return rolePermissions;
+  }
+
 }