diff --git a/api/models/acl.py b/api/models/acl.py
index b6e43e0..ec374b2 100644
--- a/api/models/acl.py
+++ b/api/models/acl.py
@@ -74,7 +74,7 @@ class UserQuery(BaseQuery):
class User(CRUDModel, SoftDeleteMixin):
__tablename__ = 'users'
- __bind_key__ = "user"
+ # __bind_key__ = "user"
query_class = UserQuery
uid = db.Column(db.Integer, primary_key=True, autoincrement=True)
diff --git a/api/views/acl/user.py b/api/views/acl/user.py
index e564535..82b6f17 100644
--- a/api/views/acl/user.py
+++ b/api/views/acl/user.py
@@ -33,7 +33,6 @@ class UserView(APIView):
page_size = get_page_size(request.values.get('page_size'))
q = request.values.get("q")
numfound, users = UserCRUD.search(q, page, page_size)
-
id2parents = RoleRelationCRUD.get_parents(uids=[i.uid for i in users])
users = [i.to_dict() for i in users]
diff --git a/ui/package.json b/ui/package.json
index 43220ed..0f71589 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -13,10 +13,14 @@
},
"dependencies": {
"@antv/data-set": "^0.10.2",
+ "@handsontable-pro/vue": "^3.1.1",
+ "@handsontable/vue": "^4.1.1",
"ant-design-vue": "^1.4.2",
"axios": "^0.19.0",
"core-js": "^3.1.2",
"enquire.js": "^2.1.6",
+ "handsontable": "^7.2.2",
+ "handsontable-pro": "^6.2.3",
"js-cookie": "^2.2.0",
"json2csv": "^4.5.2",
"lodash.get": "^4.4.2",
@@ -37,10 +41,7 @@
"vuex": "^3.1.1",
"wangeditor": "^3.1.1",
"xlsx": "latest",
- "@handsontable-pro/vue": "^3.1.1",
- "@handsontable/vue": "^4.1.1",
- "handsontable": "^7.2.2",
- "handsontable-pro": "^6.2.3"
+ "yarn": "^1.19.1"
},
"devDependencies": {
"@ant-design/colors": "^3.2.1",
diff --git a/ui/src/api/acl/app.js b/ui/src/api/acl/app.js
new file mode 100644
index 0000000..c134f36
--- /dev/null
+++ b/ui/src/api/acl/app.js
@@ -0,0 +1,34 @@
+import { axios } from '@/utils/request'
+
+const urlPrefix = '/v1/acl'
+
+export function searchRole (params) {
+ return axios({
+ url: urlPrefix + `/roles`,
+ method: 'GET',
+ params: params
+ })
+}
+
+export function addRole (params) {
+ return axios({
+ url: urlPrefix + '/roles',
+ method: 'POST',
+ data: params
+ })
+}
+
+export function updateRoleById (id, params) {
+ return axios({
+ url: urlPrefix + `/roles/${id}`,
+ method: 'PUT',
+ data: params
+ })
+}
+
+export function deleteRoleById (id) {
+ return axios({
+ url: urlPrefix + `/roles/${id}`,
+ method: 'DELETE'
+ })
+}
diff --git a/ui/src/api/acl/permission.js b/ui/src/api/acl/permission.js
new file mode 100644
index 0000000..3d78a82
--- /dev/null
+++ b/ui/src/api/acl/permission.js
@@ -0,0 +1,56 @@
+import { axios } from '@/utils/request'
+
+const urlPrefix = '/v1/acl'
+
+export function getResourcePerms (resourceID) {
+ return axios({
+ url: urlPrefix + `/resources/${resourceID}/permissions`,
+ method: 'GET'
+ })
+}
+
+export function getResourceTypePerms (typeID) {
+ return axios({
+ url: urlPrefix + `/resource_types/${typeID}/perms`,
+ method: 'GET'
+ })
+}
+
+export function getResourceGroupPerms (resourceGroupID) {
+ return axios({
+ url: urlPrefix + `/resource_groups/${resourceGroupID}/permissions`,
+ method: 'GET'
+ })
+}
+
+export function setRoleResourcePerm (rid, resourceID, params) {
+ return axios({
+ url: urlPrefix + `/roles/${rid}/resources/${resourceID}/grant`,
+ method: 'POST',
+ data: params
+ })
+}
+
+export function setRoleResourceGroupPerm (rid, resourceGroupID, params) {
+ return axios({
+ url: urlPrefix + `/roles/${rid}/resource_groups/${resourceGroupID}/grant`,
+ method: 'POST',
+ data: params
+ })
+}
+
+export function deleteRoleResourcePerm (rid, resourceID, params) {
+ return axios({
+ url: urlPrefix + `/roles/${rid}/resources/${resourceID}/revoke`,
+ method: 'POST',
+ data: params
+ })
+}
+
+export function deleteRoleResourceGroupPerm (rid, resourceGroupID, params) {
+ return axios({
+ url: urlPrefix + `/roles/${rid}/resource_groups/${resourceGroupID}/revoke`,
+ method: 'POST',
+ data: params
+ })
+}
diff --git a/ui/src/api/acl/resource.js b/ui/src/api/acl/resource.js
new file mode 100644
index 0000000..d96eae8
--- /dev/null
+++ b/ui/src/api/acl/resource.js
@@ -0,0 +1,65 @@
+import { axios } from '@/utils/request'
+
+const urlPrefix = '/v1/acl'
+
+export function searchResource (params) {
+ return axios({
+ url: urlPrefix + `/resources`,
+ method: 'GET',
+ params: params
+ })
+}
+
+export function addResource (params) {
+ return axios({
+ url: urlPrefix + '/resources',
+ method: 'POST',
+ data: params
+ })
+}
+
+export function updateResourceById (id, params) {
+ return axios({
+ url: urlPrefix + `/resources/${id}`,
+ method: 'PUT',
+ data: params
+ })
+}
+
+export function deleteResourceById (id) {
+ return axios({
+ url: urlPrefix + `/resources/${id}`,
+ method: 'DELETE'
+ })
+}
+
+export function searchResourceType (params) {
+ return axios({
+ url: urlPrefix + `/resource_types`,
+ method: 'GET',
+ params: params
+ })
+}
+
+export function addResourceType (params) {
+ return axios({
+ url: urlPrefix + '/resource_types',
+ method: 'POST',
+ data: params
+ })
+}
+
+export function updateResourceTypeById (id, params) {
+ return axios({
+ url: urlPrefix + `/resource_types/${id}`,
+ method: 'PUT',
+ data: params
+ })
+}
+
+export function deleteResourceTypeById (id) {
+ return axios({
+ url: urlPrefix + `/resource_types/${id}`,
+ method: 'DELETE'
+ })
+}
diff --git a/ui/src/api/acl/role.js b/ui/src/api/acl/role.js
new file mode 100644
index 0000000..312527b
--- /dev/null
+++ b/ui/src/api/acl/role.js
@@ -0,0 +1,66 @@
+import { axios } from '@/utils/request'
+
+const urlPrefix = '/v1/acl'
+
+export function searchRole (params) {
+ return axios({
+ url: urlPrefix + `/roles`,
+ method: 'GET',
+ params: params
+ })
+}
+
+export function addRole (params) {
+ return axios({
+ url: urlPrefix + '/roles',
+ method: 'POST',
+ data: params
+ })
+}
+
+export function updateRoleById (id, params) {
+ return axios({
+ url: urlPrefix + `/roles/${id}`,
+ method: 'PUT',
+ data: params
+ })
+}
+
+export function deleteRoleById (id) {
+ return axios({
+ url: urlPrefix + `/roles/${id}`,
+ method: 'DELETE'
+ })
+}
+
+export function addParentRole (id, otherID) {
+ return axios({
+ url: urlPrefix + `/roles/${id}/parents`,
+ method: 'POST',
+ data: { parent_id: otherID }
+ })
+}
+
+export function addChildRole (id, otherID) {
+ return axios({
+ url: urlPrefix + `/roles/${otherID}/parents`,
+ method: 'POST',
+ data: { parent_id: id }
+ })
+}
+
+export function delParentRole (cid, pid) {
+ return axios({
+ url: urlPrefix + `/roles/${cid}/parents`,
+ method: 'DELETE',
+ data: { parent_id: pid }
+ })
+}
+
+export function delChildRole (pid, cid) {
+ return axios({
+ url: urlPrefix + `/roles/${cid}/parents`,
+ method: 'DELETE',
+ data: { parent_id: pid }
+ })
+}
diff --git a/ui/src/api/acl/user.js b/ui/src/api/acl/user.js
new file mode 100644
index 0000000..5de6201
--- /dev/null
+++ b/ui/src/api/acl/user.js
@@ -0,0 +1,41 @@
+import { axios } from '@/utils/request'
+
+const urlPrefix = '/v1/acl'
+
+export function currentUser () {
+ return axios({
+ url: urlPrefix + `/users/info`,
+ method: 'GET'
+ })
+}
+
+export function searchUser (params) {
+ return axios({
+ url: urlPrefix + `/users`,
+ method: 'GET',
+ params: params
+ })
+}
+
+export function addUser (params) {
+ return axios({
+ url: urlPrefix + '/users',
+ method: 'POST',
+ data: params
+ })
+}
+
+export function updateUserById (id, params) {
+ return axios({
+ url: urlPrefix + `/users/${id}`,
+ method: 'PUT',
+ data: params
+ })
+}
+
+export function deleteUserById (id) {
+ return axios({
+ url: urlPrefix + `/users/${id}`,
+ method: 'DELETE'
+ })
+}
diff --git a/ui/src/config/router.config.js b/ui/src/config/router.config.js
index ec48c6f..b41bf9b 100644
--- a/ui/src/config/router.config.js
+++ b/ui/src/config/router.config.js
@@ -78,21 +78,28 @@ const cmdbRouter = [
name: 'acl_users',
hideChildrenInMenu: true,
component: () => import('@/views/cmdb/acl/users'),
- meta: { title: 'Users', keepAlive: true }
+ meta: { title: '用户管理', keepAlive: true }
},
{
path: '/acl/roles',
name: 'acl_roles',
hideChildrenInMenu: true,
component: () => import('@/views/cmdb/acl/roles'),
- meta: { title: 'Roles', keepAlive: true }
+ meta: { title: '角色管理', keepAlive: true }
},
{
path: '/acl/resources',
name: 'acl_resources',
hideChildrenInMenu: true,
component: () => import('@/views/cmdb/acl/resources'),
- meta: { title: 'Resources', keepAlive: true }
+ meta: { title: '资源管理', keepAlive: true }
+ },
+ {
+ path: '/acl/resource_types',
+ name: 'acl_resource_types',
+ hideChildrenInMenu: true,
+ component: () => import('@/views/cmdb/acl/resource_types'),
+ meta: { title: '资源类型', keepAlive: true }
}
]
}
diff --git a/ui/src/store/modules/app.js b/ui/src/store/modules/app.js
index 33e1180..9cc8d4e 100644
--- a/ui/src/store/modules/app.js
+++ b/ui/src/store/modules/app.js
@@ -14,6 +14,7 @@ import {
const app = {
state: {
+ name: 'cmdb',
sidebar: true,
device: 'desktop',
theme: '',
diff --git a/ui/src/views/cmdb/acl/module/addRoleRelationForm.vue b/ui/src/views/cmdb/acl/module/addRoleRelationForm.vue
new file mode 100644
index 0000000..5f92dd0
--- /dev/null
+++ b/ui/src/views/cmdb/acl/module/addRoleRelationForm.vue
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+ {{ role.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/views/cmdb/acl/module/permissionForm.vue b/ui/src/views/cmdb/acl/module/permissionForm.vue
new file mode 100644
index 0000000..c7be895
--- /dev/null
+++ b/ui/src/views/cmdb/acl/module/permissionForm.vue
@@ -0,0 +1,238 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/views/cmdb/acl/module/resourceForm.vue b/ui/src/views/cmdb/acl/module/resourceForm.vue
new file mode 100644
index 0000000..0b33211
--- /dev/null
+++ b/ui/src/views/cmdb/acl/module/resourceForm.vue
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ type.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/views/cmdb/acl/module/resourcePermForm.vue b/ui/src/views/cmdb/acl/module/resourcePermForm.vue
new file mode 100644
index 0000000..b5d7966
--- /dev/null
+++ b/ui/src/views/cmdb/acl/module/resourcePermForm.vue
@@ -0,0 +1,211 @@
+
+
+
+
+
+ 添加权限
+
+ 关闭
+
+
+
+
+
+
+ {{ item[0] }}:
+
+
+
+
+
+
+
+
+
+ {{ role.name }}
+
+
+
+
+
+ {{ perm.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/views/cmdb/acl/module/resourceTypeForm.vue b/ui/src/views/cmdb/acl/module/resourceTypeForm.vue
new file mode 100644
index 0000000..9c325f5
--- /dev/null
+++ b/ui/src/views/cmdb/acl/module/resourceTypeForm.vue
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/views/cmdb/acl/module/roleForm.vue b/ui/src/views/cmdb/acl/module/roleForm.vue
new file mode 100644
index 0000000..d56955b
--- /dev/null
+++ b/ui/src/views/cmdb/acl/module/roleForm.vue
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/views/cmdb/acl/module/userForm.vue b/ui/src/views/cmdb/acl/module/userForm.vue
new file mode 100644
index 0000000..7950169
--- /dev/null
+++ b/ui/src/views/cmdb/acl/module/userForm.vue
@@ -0,0 +1,270 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/views/cmdb/acl/permissions.vue b/ui/src/views/cmdb/acl/permissions.vue
new file mode 100644
index 0000000..592fe2b
--- /dev/null
+++ b/ui/src/views/cmdb/acl/permissions.vue
@@ -0,0 +1,311 @@
+
+
+
+
+
+
+
+
setSelectedKeys(e.target.value ? [e.target.value] : [])"
+ @pressEnter="() => handleSearch(selectedKeys, confirm, column)"
+ style="width: 188px; margin-bottom: 8px; display: block;"
+ />
+ handleSearch(selectedKeys, confirm, column)"
+ icon="search"
+ size="small"
+ style="width: 90px; margin-right: 8px"
+ >搜索
+ handleReset(clearFilters, column)"
+ size="small"
+ style="width: 90px"
+ >重置
+
+
+
+
+
+
+ {{ fragment }}
+ {{ fragment }}
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+ {{ perm.name }}
+
+
+
+
+ 编辑
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/views/cmdb/acl/resource_types.vue b/ui/src/views/cmdb/acl/resource_types.vue
new file mode 100644
index 0000000..26a240a
--- /dev/null
+++ b/ui/src/views/cmdb/acl/resource_types.vue
@@ -0,0 +1,320 @@
+
+
+
+
+
+
+
+
setSelectedKeys(e.target.value ? [e.target.value] : [])"
+ @pressEnter="() => handleSearch(selectedKeys, confirm, column)"
+ style="width: 188px; margin-bottom: 8px; display: block;"
+ />
+ handleSearch(selectedKeys, confirm, column)"
+ icon="search"
+ size="small"
+ style="width: 90px; margin-right: 8px"
+ >搜索
+ handleReset(clearFilters, column)"
+ size="small"
+ style="width: 90px"
+ >重置
+
+
+
+
+
+
+ {{ fragment }}
+ {{ fragment }}
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+ {{ perm.name }}
+
+
+
+
+ 编辑
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/views/cmdb/acl/resources.vue b/ui/src/views/cmdb/acl/resources.vue
index 6d9c248..7e3599d 100644
--- a/ui/src/views/cmdb/acl/resources.vue
+++ b/ui/src/views/cmdb/acl/resources.vue
@@ -1,10 +1,310 @@
-
+
+
+
+
+
+
+
setSelectedKeys(e.target.value ? [e.target.value] : [])"
+ @pressEnter="() => handleSearch(selectedKeys, confirm, column)"
+ style="width: 188px; margin-bottom: 8px; display: block;"
+ />
+ handleSearch(selectedKeys, confirm, column)"
+ icon="search"
+ size="small"
+ style="width: 90px; margin-right: 8px"
+ >搜索
+ handleReset(clearFilters, column)"
+ size="small"
+ style="width: 90px"
+ >重置
+
+
+
+
+
+
+ {{ fragment }}
+ {{ fragment }}
+
+
+ {{ text }}
+
+
+ {{ text }}
+
+
+
+ 编辑
+
+ 权限
+
+
+ 删除
+
+
+
+
+
+
+
+
+
-
diff --git a/ui/src/views/cmdb/acl/roles.vue b/ui/src/views/cmdb/acl/roles.vue
index 6d9c248..d947a75 100644
--- a/ui/src/views/cmdb/acl/roles.vue
+++ b/ui/src/views/cmdb/acl/roles.vue
@@ -1,10 +1,326 @@
-
+
+
+
+
+
+
+
setSelectedKeys(e.target.value ? [e.target.value] : [])"
+ @pressEnter="() => handleSearch(selectedKeys, confirm, column)"
+ style="width: 188px; margin-bottom: 8px; display: block;"
+ />
+ handleSearch(selectedKeys, confirm, column)"
+ icon="search"
+ size="small"
+ style="width: 90px; margin-right: 8px"
+ >搜索
+ handleReset(clearFilters, column)"
+ size="small"
+ style="width: 90px"
+ >重置
+
+
+
+
+
+
+ {{ fragment }}
+ {{ fragment }}
+
+
+ {{ text }}
+
+
+
+
+
+
+
+ {{ role.name }}
+
+
+
+
+ 关联角色
+
+ 编辑
+
+
+ 删除
+
+
+
+
+
+
+
+
+
-
diff --git a/ui/src/views/cmdb/acl/users.vue b/ui/src/views/cmdb/acl/users.vue
index 6d9c248..7099751 100644
--- a/ui/src/views/cmdb/acl/users.vue
+++ b/ui/src/views/cmdb/acl/users.vue
@@ -1,10 +1,374 @@
-
+
+
+
+
+
+
+
setSelectedKeys(e.target.value ? [e.target.value] : [])"
+ @pressEnter="() => handleSearch(selectedKeys, confirm, column)"
+ style="width: 188px; margin-bottom: 8px; display: block;"
+ />
+ handleSearch(selectedKeys, confirm, column)"
+ icon="search"
+ size="small"
+ style="width: 90px; margin-right: 8px"
+ >搜索
+ handleReset(clearFilters, column)"
+ size="small"
+ style="width: 90px"
+ >重置
+
+
+
+
+
+
+ {{ fragment }}
+ {{ fragment }}
+
+
+ {{ text }}
+
+
+
+
+
+ {{ fragment }}
+ {{ fragment }}
+
+
+ {{ text }}
+
+
+
+
+
+
+
+
+ 编辑
+
+
+
+ 删除
+
+
+
+
+
+
+
+
-