init Project

This commit is contained in:
2025-04-09 12:10:46 +08:00
parent 505d08443c
commit 75a1447d66
207 changed files with 26387 additions and 13 deletions

View 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>

View 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>

View 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>