Kaynağa Gözat

数据权限

ZaiZai 1 yıl önce
ebeveyn
işleme
130c9a23a4

+ 6 - 0
src/styles/app/element.scss

@@ -207,3 +207,9 @@
     color: #a9abb2;
     cursor: not-allowed;
 }
+
+//弹窗卡片
+.el-dialog.hc-new-dialog.hc-modal-no-padding .el-card {
+    --el-card-border-radius: 0;
+    --el-card-padding: 8px;
+}

+ 22 - 7
src/views/authority/data.vue

@@ -15,16 +15,20 @@
                 {{ getSystemNmae(row.sysId) }}
             </template>
             <template #action="{ row }">
-                <el-link type="primary">权限配置</el-link>
+                <el-link type="primary" @click="authRowClick(row)">权限配置</el-link>
             </template>
         </hc-table>
+
+        <!-- 权限配置 -->
+        <HcDataAuth v-model="isDataAuthShow" :mid="rowAuthInfo.id" :title="rowAuthInfo.name" @close="dataAuthClose" />
     </hc-new-card>
 </template>
 
 <script setup>
-import { onActivated, ref } from 'vue'
+import { nextTick, onActivated, ref } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { formValidate, getArrValue, getObjValue } from 'js-fast-way'
+import HcDataAuth from './modules/data/auth.vue'
 import { getClinetAll } from '~api/other'
 import mainApi from '~api/authority/data'
 import menuApi from '~api/system/menu'
@@ -74,9 +78,8 @@ const tableColumn = ref([
     { key: 'sysId', name: '所属系统' },
     { key: 'path', name: '路由地址' },
     { key: 'code', name: '菜单编号' },
-    { key: 'category', name: '菜单类型', width: 90, align: 'center' },
     { key: 'sort', name: '排序', width: 80, align: 'center' },
-    { key: 'action', name: '操作', width: 200, align: 'center' },
+    { key: 'action', name: '操作', width: 90, align: 'center' },
 ])
 const tableData = ref([{}])
 
@@ -110,8 +113,20 @@ const getLazyList = async (id) => {
     }
     return newArr
 }
-</script>
 
-<style scoped lang="scss">
+//数据权限配置
+const isDataAuthShow = ref(false)
+const rowAuthInfo = ref({})
+const authRowClick = (row) => {
+    rowAuthInfo.value = row
+    nextTick(() => {
+        isDataAuthShow.value = true
+    })
+}
 
-</style>
+//关闭权限配置弹窗
+const dataAuthClose = () => {
+    isDataAuthShow.value = false
+    rowAuthInfo.value = {}
+}
+</script>

+ 332 - 0
src/views/authority/modules/data/auth.vue

@@ -0,0 +1,332 @@
+<template>
+    <div>
+        <hc-new-dialog v-model="isShow" widths="90%" :padding="false" :title="`[${menuTitle}] 数据权限配置`" is-table :footer="false" @close="dialogClose">
+            <hc-new-card>
+                <template #header>
+                    <div class="w-60">
+                        <hc-search-input v-model="searchForm.scopeName" placeholder="请输入权限名称" @search="searchClick" />
+                    </div>
+                </template>
+                <template #extra>
+                    <el-button hc-btn type="primary" @click="addClick">新增</el-button>
+                    <el-button hc-btn type="danger" @click="delClick">删除</el-button>
+                </template>
+                <hc-table
+                    :column="tableColumn" :datas="tableData" :loading="tableLoading"
+                    :is-index="false" is-new is-check :check-style="{ width: 29 }"
+                    @selection-change="tableCheckChange"
+                >
+                    <template #scopeType="{ row }">{{ getScopeTypeName(row) }}</template>
+                    <template #action="{ row }">
+                        <el-link type="warning" @click="editRowClick(row)">修改</el-link>
+                        <el-link type="danger" @click="delRowClick(row)">删除</el-link>
+                    </template>
+                </hc-table>
+                <template #action>
+                    <hc-pages :pages="searchForm" @change="pageChange" />
+                </template>
+            </hc-new-card>
+        </hc-new-dialog>
+        <!-- 新增/修改 -->
+        <hc-new-dialog v-model="isDialogShow" widths="50rem" is-footer-center :title="dialogTitle" @close="dialogFormClose">
+            <el-form ref="formRef" :model="formModel" :rules="formRules" label-position="top" label-width="auto">
+                <el-row :gutter="20">
+                    <el-col :span="12">
+                        <el-form-item label="权限名称:" prop="scopeName">
+                            <el-input v-model="formModel.scopeName" clearable />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="权限编号:" prop="resourceCode">
+                            <el-input v-model="formModel.resourceCode" clearable />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="权限字段:" prop="scopeColumn">
+                            <el-input v-model="formModel.scopeColumn" clearable />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="规则类型:" prop="scopeType">
+                            <el-select v-model="searchForm.scopeType" placeholder="选择规则类型" filterable clearable block>
+                                <el-option v-for="item in scopeTypeData" :key="item.value" :label="item.label" :value="item.value" />
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="可见字段:" prop="scopeField">
+                            <el-input v-model="formModel.scopeField" clearable />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="权限类名:" prop="scopeClass">
+                            <el-input v-model="formModel.scopeClass" clearable />
+                        </el-form-item>
+                    </el-col>
+                    <el-col v-if="searchForm.scopeType === 5" :span="24">
+                        <el-form-item label="规则值:">
+                            <el-input v-model="formModel.scopeValue" :autosize="{ minRows: 5, maxRows: 5 }" type="textarea" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="24">
+                        <el-form-item label="备注说明:">
+                            <el-input v-model="formModel.remark" clearable />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+            </el-form>
+            <template #footer>
+                <el-button hc-btn @click="dialogClose">取消</el-button>
+                <el-button hc-btn type="primary" :loading="submitLoading" @click="dialogSubmit">提交</el-button>
+            </template>
+        </hc-new-dialog>
+    </div>
+</template>
+
+<script setup>
+import { nextTick, ref, watch } from 'vue'
+import { arrToId, formValidate, getArrValue, isNullES } from 'js-fast-way'
+import { getDictionaryData } from '~uti/tools'
+import { delMessage } from 'hc-vue3-ui'
+import mainApi from '~api/authority/data'
+
+const props = defineProps({
+    mid: {
+        type: [String, Number],
+        default: '',
+    },
+    title: {
+        type: [String, Number],
+        default: '',
+    },
+})
+
+//事件
+const emit = defineEmits(['close'])
+
+//双向绑定
+const isShow = defineModel('modelValue', {
+    default: false,
+})
+
+//监听内容
+const menuId = ref(props.mid)
+const menuTitle = ref(props.title)
+watch(() =>[props.mid, props.title], ([id, title]) => {
+    menuId.value = id
+    menuTitle.value = title
+}, { immediate: true, deep: true })
+
+//监听显示
+watch(isShow, (val) => {
+    if (val) {
+        getDataApi()
+    }
+})
+
+//获取数据
+const getDataApi = () => {
+    if (isNullES(menuId.value)) return
+    searchForm.value.menuId = menuId.value
+    getScopeTypeData()
+    searchClick()
+}
+
+//获取字典数据
+const scopeTypeData = ref([])
+const getScopeTypeData = async () => {
+    scopeTypeData.value = await getDictionaryData('data_scope_type')
+}
+const getScopeTypeName = ({ scopeType }) => {
+    if (isNullES(scopeType)) return '-'
+    const item = scopeTypeData.value.find((item) => item.value === scopeType)
+    if (isNullES(item)) return scopeType
+    return item.label ?? scopeType
+}
+
+//搜索表单
+const searchForm = ref({
+    scopeName: null, menuId: '',
+    current: 1, size: 30, total: 0,
+})
+
+//搜索
+const searchClick = () => {
+    searchForm.value.current = 1
+    getTableData()
+}
+
+//分页
+const pageChange = ({ current, size }) => {
+    searchForm.value.current = current
+    searchForm.value.size = size
+    getTableData()
+}
+
+//表格数据
+const tableColumn = ref([
+    { key: 'scopeName', name: '权限名称' },
+    { key: 'resourceCode', name: '权限编号' },
+    { key: 'scopeColumn', name: '权限字段' },
+    { key: 'scopeType', name: '规则类型' },
+    { key: 'scopeField', name: '可见字段' },
+    { key: 'scopeClass', name: '权限类名' },
+    { key: 'scopeValue', name: '规则值' },
+    { key: 'remark', name: '备注' },
+    { key: 'action', name: '操作', width: 90, align: 'center' },
+])
+const tableData = ref([{}])
+
+//获取表格数据
+const tableLoading = ref(false)
+const getTableData = async () => {
+    tableData.value = []
+    tableLoading.value = true
+    const { error, code, data } = await mainApi.page({
+        ...searchForm.value,
+        total: null,
+    })
+    tableLoading.value = false
+    if (!error && code === 200) {
+        tableData.value = getArrValue(data['records'])
+        searchForm.value.total = data['total']
+    } else {
+        tableData.value = []
+        searchForm.value.total = 0
+    }
+}
+
+//表格被选择
+const tableCheckKeys = ref([])
+const tableCheckChange = (rows) => {
+    tableCheckKeys.value = rows
+}
+
+
+//新增/修改 弹窗
+const isDialogShow = ref(false)
+const dialogTitle = ref('')
+
+//菜单表单
+const formRef = ref(null)
+const formModel = ref({})
+const formRules = {
+    scopeName: {
+        required: true,
+        trigger: 'blur',
+        message: '请输入权限名称',
+    },
+    resourceCode: {
+        required: true,
+        trigger: 'blur',
+        message: '请输入数据权限编号',
+    },
+    scopeColumn: {
+        required: true,
+        trigger: 'blur',
+        message: '请输入数据权限编号',
+    },
+    scopeType: {
+        required: true,
+        trigger: 'blur',
+        message: '请选择规则类型',
+    },
+    scopeField: {
+        required: true,
+        trigger: 'blur',
+        message: '请输入数据权限可见的字段',
+    },
+    scopeClass: {
+        required: true,
+        trigger: 'blur',
+        message: '请输入MybatisMapper对应方法的完整类名路径',
+    },
+}
+
+
+//新增
+const addClick = () => {
+    dialogTitle.value = '新增对象存储'
+    formModel.value = { category: 1 }
+    //显示表单弹窗
+    nextTick(() => {
+        isDialogShow.value = true
+    })
+}
+
+//修改菜单
+const editRowClick = (row) => {
+    formModel.value = {}
+    dialogTitle.value = '修改对象存储'
+    formModel.value = { ...row }
+    //显示表单弹窗
+    nextTick(() => {
+        isDialogShow.value = true
+    })
+}
+
+
+//提交表单
+const submitLoading = ref(false)
+const dialogSubmit = async () => {
+    const formRes = await formValidate(formRef.value)
+    if (!formRes) return false
+    submitLoading.value = true
+    //发起请求
+    const { error, code, msg } = await mainApi.submit(formModel.value)
+    submitLoading.value = false
+    if (!error && code === 200) {
+        dialogFormClose()
+        window?.$message?.success('操作成功')
+        getTableData().then()
+    } else {
+        window?.$message?.error(msg ?? '操作失败')
+    }
+}
+
+//关闭弹窗
+const dialogFormClose = () => {
+    isDialogShow.value = false
+    submitLoading.value = false
+    formModel.value = {}
+}
+
+//删除
+const delRowClick = (row) => {
+    delMessage(async () => {
+        const { code, msg } = await mainApi.del(row.id)
+        if (code === 200) {
+            window.$message.success('删除成功')
+            getTableData().then()
+        } else {
+            window.$message.error(msg ?? '删除失败')
+        }
+    })
+}
+
+//批量删除
+const delClick = () => {
+    const rows = tableCheckKeys.value
+    if (rows.length <= 0) {
+        window.$message.warning('请选择要删除的数据')
+        return false
+    }
+    //确认删除菜单
+    delMessage(async () => {
+        const ids = arrToId(rows)
+        const { code, msg } = await mainApi.del(ids)
+        if (code === 200) {
+            window.$message.success('删除成功')
+            getTableData().then()
+        } else {
+            window.$message.error(msg ?? '删除失败')
+        }
+    })
+}
+
+//关闭弹窗
+const dialogClose = () => {
+    isShow.value = false
+    emit('close')
+}
+</script>