✨ init Project
This commit is contained in:
174
src/view/superAdmin/authority/components/apis.vue
Normal file
174
src/view/superAdmin/authority/components/apis.vue
Normal file
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="sticky top-0.5 z-10 flex space-x-2">
|
||||
<el-input
|
||||
v-model="filterTextName"
|
||||
class="flex-1"
|
||||
placeholder="筛选名字"
|
||||
/>
|
||||
<el-input
|
||||
v-model="filterTextPath"
|
||||
class="flex-1"
|
||||
placeholder="筛选路径"
|
||||
/>
|
||||
<el-button class="float-right" type="primary" @click="authApiEnter"
|
||||
>确 定</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="tree-content">
|
||||
<el-scrollbar>
|
||||
<el-tree
|
||||
ref="apiTree"
|
||||
:data="apiTreeData"
|
||||
:default-checked-keys="apiTreeIds"
|
||||
:props="apiDefaultProps"
|
||||
default-expand-all
|
||||
highlight-current
|
||||
node-key="onlyId"
|
||||
show-checkbox
|
||||
:filter-node-method="filterNode"
|
||||
@check="nodeChange"
|
||||
>
|
||||
<template #default="{ _, data }">
|
||||
<div class="flex items-center justify-between w-full pr-1">
|
||||
<span>{{ data.description }} </span>
|
||||
<el-tooltip :content="data.path">
|
||||
<span
|
||||
class="max-w-[240px] break-all overflow-ellipsis overflow-hidden"
|
||||
>{{ data.path }}</span
|
||||
>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getAllApis } from '@/api/api'
|
||||
import { UpdateCasbin, getPolicyPathByAuthorityId } from '@/api/casbin'
|
||||
import { ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
defineOptions({
|
||||
name: 'Apis'
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
default: function () {
|
||||
return {}
|
||||
},
|
||||
type: Object
|
||||
}
|
||||
})
|
||||
|
||||
const apiDefaultProps = ref({
|
||||
children: 'children',
|
||||
label: 'description'
|
||||
})
|
||||
const filterTextName = ref('')
|
||||
const filterTextPath = ref('')
|
||||
const apiTreeData = ref([])
|
||||
const apiTreeIds = ref([])
|
||||
const activeUserId = ref('')
|
||||
const init = async () => {
|
||||
const res2 = await getAllApis()
|
||||
const apis = res2.data.apis
|
||||
|
||||
apiTreeData.value = buildApiTree(apis)
|
||||
const res = await getPolicyPathByAuthorityId({
|
||||
authorityId: props.row.authorityId
|
||||
})
|
||||
activeUserId.value = props.row.authorityId
|
||||
apiTreeIds.value = []
|
||||
res.data.paths &&
|
||||
res.data.paths.forEach((item) => {
|
||||
apiTreeIds.value.push('p:' + item.path + 'm:' + item.method)
|
||||
})
|
||||
}
|
||||
|
||||
init()
|
||||
|
||||
const needConfirm = ref(false)
|
||||
const nodeChange = () => {
|
||||
needConfirm.value = true
|
||||
}
|
||||
// 暴露给外层使用的切换拦截统一方法
|
||||
const enterAndNext = () => {
|
||||
authApiEnter()
|
||||
}
|
||||
|
||||
// 创建api树方法
|
||||
const buildApiTree = (apis) => {
|
||||
const apiObj = {}
|
||||
apis &&
|
||||
apis.forEach((item) => {
|
||||
item.onlyId = 'p:' + item.path + 'm:' + item.method
|
||||
if (Object.prototype.hasOwnProperty.call(apiObj, item.apiGroup)) {
|
||||
apiObj[item.apiGroup].push(item)
|
||||
} else {
|
||||
Object.assign(apiObj, { [item.apiGroup]: [item] })
|
||||
}
|
||||
})
|
||||
const apiTree = []
|
||||
for (const key in apiObj) {
|
||||
const treeNode = {
|
||||
ID: key,
|
||||
description: key + '组',
|
||||
children: apiObj[key]
|
||||
}
|
||||
apiTree.push(treeNode)
|
||||
}
|
||||
return apiTree
|
||||
}
|
||||
|
||||
// 关联关系确定
|
||||
const apiTree = ref(null)
|
||||
const authApiEnter = async () => {
|
||||
const checkArr = apiTree.value.getCheckedNodes(true)
|
||||
var casbinInfos = []
|
||||
checkArr &&
|
||||
checkArr.forEach((item) => {
|
||||
var casbinInfo = {
|
||||
path: item.path,
|
||||
method: item.method
|
||||
}
|
||||
casbinInfos.push(casbinInfo)
|
||||
})
|
||||
const res = await UpdateCasbin({
|
||||
authorityId: activeUserId.value,
|
||||
casbinInfos
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage({ type: 'success', message: 'api设置成功' })
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
needConfirm,
|
||||
enterAndNext
|
||||
})
|
||||
|
||||
const filterNode = (value, data) => {
|
||||
if (!filterTextName.value && !filterTextPath.value) return true
|
||||
let matchesName, matchesPath
|
||||
if (!filterTextName.value) {
|
||||
matchesName = true
|
||||
} else {
|
||||
matchesName =
|
||||
data.description && data.description.includes(filterTextName.value)
|
||||
}
|
||||
if (!filterTextPath.value) {
|
||||
matchesPath = true
|
||||
} else {
|
||||
matchesPath = data.path && data.path.includes(filterTextPath.value)
|
||||
}
|
||||
return matchesName && matchesPath
|
||||
}
|
||||
watch([filterTextName, filterTextPath], () => {
|
||||
apiTree.value.filter('')
|
||||
})
|
||||
</script>
|
||||
145
src/view/superAdmin/authority/components/datas.vue
Normal file
145
src/view/superAdmin/authority/components/datas.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<div>
|
||||
<warning-bar
|
||||
title="此功能仅用于创建角色和角色的many2many关系表,具体使用还须自己结合表实现业务,详情参考示例代码(客户示例)。此功能不建议使用,建议使用插件市场【组织管理功能(点击前往)】来管理资源权限。"
|
||||
href="https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=36"
|
||||
/>
|
||||
<div class="sticky top-0.5 z-10 my-4">
|
||||
<el-button class="float-left" type="primary" @click="all">全选</el-button>
|
||||
<el-button class="float-left" type="primary" @click="self"
|
||||
>本角色</el-button
|
||||
>
|
||||
<el-button class="float-left" type="primary" @click="selfAndChildren"
|
||||
>本角色及子角色</el-button
|
||||
>
|
||||
<el-button class="float-right" type="primary" @click="authDataEnter"
|
||||
>确 定</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="clear-both pt-4">
|
||||
<el-checkbox-group v-model="dataAuthorityId" @change="selectAuthority">
|
||||
<el-checkbox
|
||||
v-for="(item, key) in authoritys"
|
||||
:key="key"
|
||||
:label="item"
|
||||
>{{ item.authorityName }}</el-checkbox
|
||||
>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { setDataAuthority } from '@/api/authority'
|
||||
import WarningBar from '@/components/warningBar/warningBar.vue'
|
||||
import { ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
defineOptions({
|
||||
name: 'Datas'
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
default: function () {
|
||||
return {}
|
||||
},
|
||||
type: Object
|
||||
},
|
||||
authority: {
|
||||
default: function () {
|
||||
return []
|
||||
},
|
||||
type: Array
|
||||
}
|
||||
})
|
||||
|
||||
const authoritys = ref([])
|
||||
const needConfirm = ref(false)
|
||||
// 平铺角色
|
||||
const roundAuthority = (authoritysData) => {
|
||||
authoritysData &&
|
||||
authoritysData.forEach((item) => {
|
||||
const obj = {}
|
||||
obj.authorityId = item.authorityId
|
||||
obj.authorityName = item.authorityName
|
||||
authoritys.value.push(obj)
|
||||
if (item.children && item.children.length) {
|
||||
roundAuthority(item.children)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const dataAuthorityId = ref([])
|
||||
const init = () => {
|
||||
roundAuthority(props.authority)
|
||||
props.row.dataAuthorityId &&
|
||||
props.row.dataAuthorityId.forEach((item) => {
|
||||
const obj =
|
||||
authoritys.value &&
|
||||
authoritys.value.filter(
|
||||
(au) => au.authorityId === item.authorityId
|
||||
) &&
|
||||
authoritys.value.filter(
|
||||
(au) => au.authorityId === item.authorityId
|
||||
)[0]
|
||||
dataAuthorityId.value.push(obj)
|
||||
})
|
||||
}
|
||||
|
||||
init()
|
||||
|
||||
// 暴露给外层使用的切换拦截统一方法
|
||||
const enterAndNext = () => {
|
||||
authDataEnter()
|
||||
}
|
||||
|
||||
const emit = defineEmits(['changeRow'])
|
||||
const all = () => {
|
||||
dataAuthorityId.value = [...authoritys.value]
|
||||
emit('changeRow', 'dataAuthorityId', dataAuthorityId.value)
|
||||
needConfirm.value = true
|
||||
}
|
||||
const self = () => {
|
||||
dataAuthorityId.value = authoritys.value.filter(
|
||||
(item) => item.authorityId === props.row.authorityId
|
||||
)
|
||||
emit('changeRow', 'dataAuthorityId', dataAuthorityId.value)
|
||||
needConfirm.value = true
|
||||
}
|
||||
const selfAndChildren = () => {
|
||||
const arrBox = []
|
||||
getChildrenId(props.row, arrBox)
|
||||
dataAuthorityId.value = authoritys.value.filter(
|
||||
(item) => arrBox.indexOf(item.authorityId) > -1
|
||||
)
|
||||
emit('changeRow', 'dataAuthorityId', dataAuthorityId.value)
|
||||
needConfirm.value = true
|
||||
}
|
||||
const getChildrenId = (row, arrBox) => {
|
||||
arrBox.push(row.authorityId)
|
||||
row.children &&
|
||||
row.children.forEach((item) => {
|
||||
getChildrenId(item, arrBox)
|
||||
})
|
||||
}
|
||||
// 提交
|
||||
const authDataEnter = async () => {
|
||||
const res = await setDataAuthority(props.row)
|
||||
if (res.code === 0) {
|
||||
ElMessage({ type: 'success', message: '资源设置成功' })
|
||||
}
|
||||
}
|
||||
|
||||
// 选择
|
||||
const selectAuthority = () => {
|
||||
dataAuthorityId.value = dataAuthorityId.value.filter((item) => item)
|
||||
emit('changeRow', 'dataAuthorityId', dataAuthorityId.value)
|
||||
needConfirm.value = true
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
enterAndNext,
|
||||
needConfirm
|
||||
})
|
||||
</script>
|
||||
233
src/view/superAdmin/authority/components/menus.vue
Normal file
233
src/view/superAdmin/authority/components/menus.vue
Normal file
@@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="sticky top-0.5 z-10">
|
||||
<el-input v-model="filterText" class="w-3/5" placeholder="筛选" />
|
||||
<el-button class="float-right" type="primary" @click="relation"
|
||||
>确 定</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="tree-content clear-both">
|
||||
<el-scrollbar>
|
||||
<el-tree
|
||||
ref="menuTree"
|
||||
:data="menuTreeData"
|
||||
:default-checked-keys="menuTreeIds"
|
||||
:props="menuDefaultProps"
|
||||
default-expand-all
|
||||
highlight-current
|
||||
node-key="ID"
|
||||
show-checkbox
|
||||
:filter-node-method="filterNode"
|
||||
@check="nodeChange"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span class="custom-tree-node">
|
||||
<span>{{ node.label }}</span>
|
||||
<span v-if="node.checked">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
:style="{
|
||||
color:
|
||||
row.defaultRouter === data.name ? '#E6A23C' : '#85ce61'
|
||||
}"
|
||||
@click="() => setDefault(data)"
|
||||
>
|
||||
{{ row.defaultRouter === data.name ? '首页' : '设为首页' }}
|
||||
</el-button>
|
||||
</span>
|
||||
<span v-if="data.menuBtn.length">
|
||||
<el-button type="primary" link @click="() => OpenBtn(data)">
|
||||
分配按钮
|
||||
</el-button>
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<el-dialog v-model="btnVisible" title="分配按钮" destroy-on-close>
|
||||
<el-table
|
||||
ref="btnTableRef"
|
||||
:data="btnData"
|
||||
row-key="ID"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="按钮名称" prop="name" />
|
||||
<el-table-column label="按钮备注" prop="desc" />
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="closeDialog">取 消</el-button>
|
||||
<el-button type="primary" @click="enterDialog">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
getBaseMenuTree,
|
||||
getMenuAuthority,
|
||||
addMenuAuthority
|
||||
} from '@/api/menu'
|
||||
import { updateAuthority } from '@/api/authority'
|
||||
import { getAuthorityBtnApi, setAuthorityBtnApi } from '@/api/authorityBtn'
|
||||
import { nextTick, ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
defineOptions({
|
||||
name: 'Menus'
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
default: function () {
|
||||
return {}
|
||||
},
|
||||
type: Object
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['changeRow'])
|
||||
const filterText = ref('')
|
||||
const menuTreeData = ref([])
|
||||
const menuTreeIds = ref([])
|
||||
const needConfirm = ref(false)
|
||||
const menuDefaultProps = ref({
|
||||
children: 'children',
|
||||
label: function (data) {
|
||||
return data.meta.title
|
||||
},
|
||||
disabled: function (data) {
|
||||
return props.row.defaultRouter === data.name
|
||||
}
|
||||
})
|
||||
|
||||
const init = async () => {
|
||||
// 获取所有菜单树
|
||||
const res = await getBaseMenuTree()
|
||||
menuTreeData.value = res.data.menus
|
||||
const res1 = await getMenuAuthority({ authorityId: props.row.authorityId })
|
||||
const menus = res1.data.menus
|
||||
const arr = []
|
||||
menus.forEach((item) => {
|
||||
// 防止直接选中父级造成全选
|
||||
if (!menus.some((same) => same.parentId === item.menuId)) {
|
||||
arr.push(Number(item.menuId))
|
||||
}
|
||||
})
|
||||
menuTreeIds.value = arr
|
||||
}
|
||||
|
||||
init()
|
||||
|
||||
const setDefault = async (data) => {
|
||||
const res = await updateAuthority({
|
||||
authorityId: props.row.authorityId,
|
||||
AuthorityName: props.row.authorityName,
|
||||
parentId: props.row.parentId,
|
||||
defaultRouter: data.name
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage({ type: 'success', message: '设置成功' })
|
||||
emit('changeRow', 'defaultRouter', res.data.authority.defaultRouter)
|
||||
}
|
||||
}
|
||||
const nodeChange = () => {
|
||||
needConfirm.value = true
|
||||
}
|
||||
// 暴露给外层使用的切换拦截统一方法
|
||||
const enterAndNext = () => {
|
||||
relation()
|
||||
}
|
||||
// 关联树 确认方法
|
||||
const menuTree = ref(null)
|
||||
const relation = async () => {
|
||||
const checkArr = menuTree.value.getCheckedNodes(false, true)
|
||||
const res = await addMenuAuthority({
|
||||
menus: checkArr,
|
||||
authorityId: props.row.authorityId
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '菜单设置成功!'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ enterAndNext, needConfirm })
|
||||
|
||||
const btnVisible = ref(false)
|
||||
|
||||
const btnData = ref([])
|
||||
const multipleSelection = ref([])
|
||||
const btnTableRef = ref()
|
||||
let menuID = ''
|
||||
const OpenBtn = async (data) => {
|
||||
menuID = data.ID
|
||||
const res = await getAuthorityBtnApi({
|
||||
menuID: menuID,
|
||||
authorityId: props.row.authorityId
|
||||
})
|
||||
if (res.code === 0) {
|
||||
openDialog(data)
|
||||
await nextTick()
|
||||
if (res.data.selected) {
|
||||
res.data.selected.forEach((id) => {
|
||||
btnData.value.some((item) => {
|
||||
if (item.ID === id) {
|
||||
btnTableRef.value.toggleRowSelection(item, true)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
multipleSelection.value = val
|
||||
}
|
||||
|
||||
const openDialog = (data) => {
|
||||
btnVisible.value = true
|
||||
btnData.value = data.menuBtn
|
||||
}
|
||||
|
||||
const closeDialog = () => {
|
||||
btnVisible.value = false
|
||||
}
|
||||
const enterDialog = async () => {
|
||||
const selected = multipleSelection.value.map((item) => item.ID)
|
||||
const res = await setAuthorityBtnApi({
|
||||
menuID,
|
||||
selected,
|
||||
authorityId: props.row.authorityId
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage({ type: 'success', message: '设置成功' })
|
||||
btnVisible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const filterNode = (value, data) => {
|
||||
if (!value) return true
|
||||
// console.log(data.mate.title)
|
||||
return data.meta.title.indexOf(value) !== -1
|
||||
}
|
||||
|
||||
watch(filterText, (val) => {
|
||||
menuTree.value.filter(val)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom-tree-node {
|
||||
span + span {
|
||||
@apply ml-3;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user