فهرست منبع

feat: 权限点新增

wanggaokun 3 هفته پیش
والد
کامیت
ea7fb6908d

+ 8 - 7
src/api/interface/system/menu.ts

@@ -59,16 +59,17 @@ export interface MenuBO {
  * 接收后端返回树信息
  */
 export type MenuTreeVO = {
-  id: string
-  menuId: string
+  id?: string
+  menuId?: string
   parentId: string
-  path: string
-  name: string
-  orderNum: number
-  menuType: string
+  path?: string
+  name?: string
+  title?: string
+  orderNum?: number
+  menuType?: string
   component?: string | (() => Promise<unknown>)
   redirect?: string
-  meta: MetaProps
+  meta?: MetaProps
   children?: MenuTreeVO[]
 }
 

+ 9 - 0
src/api/interface/system/permissions.ts

@@ -0,0 +1,9 @@
+/**
+ * 接收后端返回信息
+ */
+export interface PermissionsVO {
+  id: string
+  moduleName: string
+  name: string
+  code: string
+}

+ 19 - 3
src/api/interface/system/role.ts

@@ -1,4 +1,5 @@
 import { MenuVO } from '@/api/interface/system/menu'
+import { PermissionsVO } from './permissions'
 /**
  * 查询参数
  */
@@ -37,7 +38,7 @@ export interface RoleBO {
 }
 
 /**
- * 传入已有角色
+ * 传入已选菜单
  */
 export interface RoleMenuBO {
   roleId: string
@@ -45,10 +46,25 @@ export interface RoleMenuBO {
 }
 
 /**
- * 接收已有角色
+ * 接收已有菜单
  */
 export interface RoleMenuVO {
-  allMenus: MenuVO[]
   treeMenus: Menu.MenuOptions[]
   hasMenus: string[]
 }
+
+/**
+ * 传入已选权限
+ */
+export interface RolePermBO {
+  roleId: string
+  permIds: string[]
+}
+
+/**
+ * 接收已有权限
+ */
+export interface RolePermVO {
+  allPermissions: PermissionsVO[]
+  hasPermissions: string[]
+}

+ 17 - 1
src/api/module/system/role.ts

@@ -1,4 +1,4 @@
-import { RoleVO, RoleQuery, RoleBO, RoleMenuVO, RoleMenuBO } from '@/api/interface/system/role'
+import { RoleVO, RoleQuery, RoleBO, RoleMenuVO, RoleMenuBO, RolePermBO, RolePermVO } from '@/api/interface/system/role'
 import http from '@/axios'
 
 class RoleApi {
@@ -57,5 +57,21 @@ class RoleApi {
   static addMenu = (data: RoleMenuBO): Promise<ResultData<any>> => {
     return http.put({ url: `/system/role/menu/add`, data })
   }
+
+  /**
+   * @name 查询已有权限点
+   * @returns returns
+   */
+  static getPermissions = (permId: string): Promise<ResultData<any>> => {
+    return http.get<RolePermVO>({ url: `/system/role/permission/${permId}` })
+  }
+
+  /**
+   * @name 角色添加权限点
+   * @returns returns
+   */
+  static addPermission = (data: RolePermBO): Promise<ResultData<any>> => {
+    return http.put({ url: `/system/role/permission/add`, data })
+  }
 }
 export default RoleApi

+ 1 - 0
src/types/global.d.ts

@@ -82,6 +82,7 @@ declare namespace Menu {
     parentId: string
     path: string
     name: string
+    title: string
     orderNum: number
     menuType: string
     component?: string | (() => Promise<unknown>)

+ 2 - 2
src/views/demo/tree.vue

@@ -20,7 +20,7 @@
   </div>
 </template>
 <script lang="tsx" setup name="Home">
-import { RoleInfo, RoleQuery } from '@/api/interface/system/role'
+import { RoleVO, RoleQuery } from '@/api/interface/system/role'
 import OrgApi from '@/api/module/system/org'
 import RoleApi from '@/api/module/system/role'
 import { ColumnProps, SearchProps } from '@/components/ProTable/interface'
@@ -29,7 +29,7 @@ const changeTreeFilter = (val: string) => {
   ElMessage.success(`请注意查看请求参数变化 🤔${val}`)
 }
 // 表格配置项
-const columns: ColumnProps<RoleInfo>[] = [
+const columns: ColumnProps<RoleVO>[] = [
   { type: 'selection', width: 60, selectable: row => row.isLock == '1' },
   { prop: 'roleId', label: '编号', width: 80 },
   { prop: 'name', label: '角色名称' },

+ 146 - 50
src/views/system/role/components/PermissionsDrawer.vue

@@ -10,26 +10,30 @@
       </slot>
     </template>
 
-    <el-form ref="ruleFormRef" label-width="100px" label-suffix=" :" :rules="rules" :model="drawerProps.row" @submit.enter.prevent="handleConfirm">
-      <el-form-item label="参数名称" prop="name">
-        <el-input v-model="drawerProps.row.name" placeholder="填写参数名称" clearable />
-      </el-form-item>
-      <el-form-item label="权限标识" prop="code">
-        <el-input v-model="drawerProps.row.code" :disabled="drawerProps.row.roleId === '1'" placeholder="填写权限标识" clearable />
-      </el-form-item>
-      <el-form-item label="排序" prop="orderNum">
-        <el-input-number v-model="drawerProps.row.orderNum" :precision="0" :min="1" :max="999999" />
-      </el-form-item>
-      <el-form-item label="状态" prop="status">
-        <el-radio-group v-model="drawerProps.row.status">
-          <el-radio-button :value="item.dictValue" v-for="(item, index) in commonStatus" :key="index" :label="item.dictLabel" />
-        </el-radio-group>
-      </el-form-item>
-      <el-form-item label="备注" prop="remark">
-        <el-input v-model="drawerProps.row.remark" placeholder="请填写备注" clearable />
-      </el-form-item>
-    </el-form>
+    <el-table :data="mergeData" :span-method="objectSpanMethod" border style="width: 100%; margin-top: 20px">
+      <el-table-column prop="moduleName" width="180">
+        <template #header>
+          <el-checkbox label="权限模块" @change="handleChange"></el-checkbox>
+        </template>
+        <template #default="{ row }">
+          <div>
+            <el-checkbox v-model="row.parentCheck" :label="row.moduleName" @change="handleParentCheck(row)"></el-checkbox>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column prop="code">
+        <template #header>
+          <el-checkbox label="权限点" @change="handleChange"></el-checkbox>
+        </template>
+        <template #default="{ row }">
+          <div>
+            <el-checkbox v-model="row.itemCheck" :label="row.code" @change="handleItemCheck(row)"></el-checkbox>
+          </div>
+        </template>
+      </el-table-column>
 
+      <el-table-column prop="name" label="名称" />
+    </el-table>
     <template #footer>
       <slot name="footer">
         <ElButton @click="drawerVisible = false">取 消</ElButton>
@@ -40,31 +44,99 @@
 </template>
 
 <script setup lang="ts" name="PermissionsDrawer">
-import { RoleBO } from '@/api/interface/system/role'
+import { PermissionsVO } from '@/api/interface/system/permissions'
+import { RoleVO } from '@/api/interface/system/role'
+import RoleApi from '@/api/module/system/role'
 import { ResultEnum } from '@/enums/HttpEnum'
-import { useDictOptions } from '@/hooks'
-
-const commonStatus = useDictOptions('COMMON_STATUS')
-
-import { FormInstance } from 'element-plus'
-const rules = reactive({
-  name: [{ required: true, message: '请填写角色名称' }],
-  code: [{ required: true, message: '请填权限标识' }],
-  orderNum: [{ required: true, message: '排序不能为空' }],
-  status: [{ required: true, message: '状态不能为空' }]
-})
 
 interface EcoDrawerProps {
   api?: (params: any) => Promise<any> // 调用接口
   title: string // 顶部标题
-  isView: boolean
-  row: Partial<RoleBO>
+  row: Partial<RoleVO>
   getTableList?: () => void
 }
 
+interface MergeDataProps extends PermissionsVO {
+  parentCheck: boolean
+  itemCheck: boolean
+}
+const getSpanArr = (data: MergeDataProps[], prop: keyof MergeDataProps) => {
+  const spanArr: { first: number; count: number }[] = []
+  let pos = 0
+
+  for (let i = 0; i < data.length; i++) {
+    if (i === 0) {
+      spanArr.push({ first: 0, count: 1 })
+      pos = 0
+    } else {
+      if (data[i][prop] === data[i - 1][prop]) {
+        spanArr[pos].count++
+        spanArr.push({ first: -1, count: 0 })
+      } else {
+        spanArr.push({ first: i, count: 1 })
+        pos = i
+      }
+    }
+  }
+
+  return spanArr
+}
+const nameSpanArr = computed(() => getSpanArr(mergeData.value, 'moduleName'))
+
+const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: { row: MergeDataProps; column: any; rowIndex: number; columnIndex: number }) => {
+  if (column.property === 'moduleName') {
+    const span = nameSpanArr.value[rowIndex]
+    if (span.first === rowIndex) {
+      return {
+        rowspan: span.count,
+        colspan: 1
+      }
+    } else {
+      return {
+        rowspan: 0,
+        colspan: 0
+      }
+    }
+  }
+}
+
+// 获取选中的 address IDs
+const selectedPermIds = computed(() => {
+  return mergeData.value.filter(item => item.itemCheck).map(item => item.id)
+})
+
+// 处理 moduleName 复选框变化
+const handleParentCheck = (row: MergeDataProps) => {
+  const itemRows = mergeData.value.filter(item => item.moduleName === row.moduleName)
+  itemRows.forEach(item => {
+    item.itemCheck = row.parentCheck
+  })
+}
+
+const handleChange = (val: boolean) => {
+  mergeData.value.forEach(item => {
+    item.parentCheck = val
+    item.itemCheck = val
+  })
+}
+
+// 处理 code 复选框变化
+const handleItemCheck = (row: MergeDataProps) => {
+  const sameItemRows = mergeData.value.filter(item => item.moduleName === row.moduleName)
+  const parentSelected = sameItemRows.every(item => item.itemCheck)
+
+  // 更新对应 moduleName 的选中状态
+  sameItemRows.forEach(item => {
+    item.parentCheck = parentSelected
+  })
+}
+
+const allPermissions = ref<PermissionsVO[]>([])
+const hasPermissions = ref<string[]>([])
+const mergeData = ref<MergeDataProps[]>([])
+
 const drawerVisible = ref(false)
 const drawerProps = ref<EcoDrawerProps>({
-  isView: false,
   title: '',
   row: {}
 })
@@ -76,28 +148,52 @@ const emit = defineEmits(['submit'])
 const acceptParams = (params: EcoDrawerProps) => {
   drawerProps.value = params
   drawerVisible.value = true
-  drawerProps.value.row.status = drawerProps.value.row.status || '1'
+  getPermissions(params.row.roleId || '')
 }
 
-// 提交数据(新增/编辑)
-const ruleFormRef = ref<FormInstance>()
-const handleConfirm = () => {
-  ruleFormRef.value!.validate(async valid => {
-    if (!valid) return
-    try {
-      const { code } = await drawerProps.value.api!(drawerProps.value.row)
-      if (code == ResultEnum.SUCCESS) {
-        ElMessage.success({ message: `${drawerProps.value.title}成功!` })
-        drawerProps.value.getTableList!()
-        emit('submit')
-        drawerVisible.value = false
-      }
-    } catch (error) {
-      console.log(error)
+/**
+ * 获取权限信息
+ * @param roleId
+ */
+const getPermissions = (roleId: string) => {
+  if (!roleId) return
+  RoleApi.getPermissions(roleId).then(res => {
+    allPermissions.value = res.data.allPermissions
+    hasPermissions.value = res.data.hasPermissions
+    handelAllPermissions(allPermissions.value, hasPermissions.value)
+  })
+}
+
+const handelAllPermissions = (allPerms: PermissionsVO[], hasPerms: string[]) => {
+  mergeData.value = allPerms.map(item => {
+    return { ...item, parentCheck: false, itemCheck: false }
+  })
+
+  mergeData.value.forEach(perm => {
+    if (hasPerms.length > 0) {
+      hasPerms.forEach(permId => {
+        if (perm.id === permId) {
+          perm.itemCheck = true
+        }
+      })
     }
   })
 }
 
+const handleConfirm = async () => {
+  try {
+    const { code } = await drawerProps.value.api!({ roleId: drawerProps.value.row.roleId, permIds: selectedPermIds.value })
+    if (code == ResultEnum.SUCCESS) {
+      ElMessage.success({ message: `${drawerProps.value.title}成功!` })
+      drawerProps.value.getTableList!()
+      emit('submit')
+      drawerVisible.value = false
+    }
+  } catch (error) {
+    console.log(error)
+  }
+}
+
 defineExpose({
   acceptParams
 })

+ 9 - 1
src/views/system/role/index.vue

@@ -105,7 +105,15 @@ const openAuthMenuDrawer = (title: string, row: Partial<RoleVO> = {}) => {
 }
 
 const drawerPermissionsRef = ref<InstanceType<typeof PermissionsDrawer> | null>(null)
-const openAuthPermissionsDrawer = (title: string, row: Partial<RoleBO> = {}) => {}
+const openAuthPermissionsDrawer = (title: string, row: Partial<RoleVO> = {}) => {
+  const params = {
+    title,
+    row: { ...row },
+    api: RoleApi.addPermission,
+    getTableList: proTableRef.value?.getTableList
+  }
+  drawerPermissionsRef.value?.acceptParams(params)
+}
 </script>
 <style lang="scss" scoped>
 .operation-group {