| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- <template>
- <xn-form-container
- title="授权权限"
- :width="drawerWidth"
- :visible="visible"
- :destroy-on-close="true"
- :show-pagination="false"
- @close="onClose"
- >
- <a-alert
- message="注:此功能界面需要与代码查询条件配合使用,并非所有接口都需设置数据范围,多用于业务模块!"
- type="warning"
- closable
- />
- <a-spin :spinning="spinningLoading">
- <a-table
- class="mt-4"
- size="middle"
- :columns="columns"
- :data-source="loadDatas"
- bordered
- :row-key="(record) => record.api"
- >
- <template #headerCell="{ column }">
- <template v-if="column.key === 'api'">
- <a-checkbox @update:checked="(val) => onCheckAllChange(val)"> 接口 </a-checkbox>
- </template>
- <template v-if="column.key === 'dataScope'">
- <span>{{ column.title }}</span>
- <a-radio-group v-model:value="scopeRadioValue" @change="radioChange" style="padding: 0 10px">
- <a-radio value="SCOPE_ALL"> 全部 </a-radio>
- <a-radio value="SCOPE_SELF"> 仅自已 </a-radio>
- <a-radio value="SCOPE_ORG"> 所属组织 </a-radio>
- <a-radio value="SCOPE_ORG_CHILD"> 所属组织及以下 </a-radio>
- </a-radio-group>
- </template>
- </template>
- <template #customFilterDropdown="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }">
- <div style="padding: 8px">
- <a-input
- ref="searchInput"
- placeholder="请输入接口或接口名称"
- :value="selectedKeys[0]"
- style="width: 188px; margin-bottom: 8px; display: block"
- @change="(e) => setSelectedKeys(e.target.value ? [e.target.value] : [])"
- @pressEnter="handleSearch(selectedKeys, confirm, column.dataIndex)"
- />
- <a-button
- type="primary"
- size="small"
- style="width: 90px; margin-right: 8px"
- @click="handleSearch(selectedKeys, confirm, column.dataIndex)"
- >
- <template #icon><SearchOutlined /></template>
- 搜索
- </a-button>
- <a-button size="small" style="width: 90px" @click="handleReset(clearFilters)"> 重置 </a-button>
- </div>
- </template>
- <template #customFilterIcon="{ filtered }">
- <search-outlined :style="{ color: filtered ? '#108ee9' : undefined }" />
- </template>
- <template #bodyCell="{ column, record }">
- <template v-if="column.dataIndex === 'api'">
- <a-checkbox :checked="record.check" @update:checked="(val) => changeApi(record, val)">
- {{ record.api }}
- </a-checkbox>
- </template>
- <template v-if="column.dataIndex === 'dataScope'">
- <template v-if="record.dataScope.length > 0">
- <template v-for="item in record.dataScope" :key="item.id + record.api">
- <a-radio
- v-model:checked="item.check"
- :name="item.title"
- @change="(evt) => changeDataScope(record, evt)"
- >
- <a-badge
- v-if="
- (item.value === 'SCOPE_ORG_DEFINE') &
- record.dataScope[4].check &
- (item.scopeDefineOrgIdList !== undefined)
- "
- :count="item.scopeDefineOrgIdList.length"
- :number-style="{ backgroundColor: '#52c41a' }"
- >
- {{ item.title }}</a-badge
- >
- <div v-else>{{ item.title }}</div>
- </a-radio>
- </template>
- <a-button v-if="record.dataScope[4].check" type="link" size="small" @click="handleDefineOrg(record)"
- >选择组织</a-button
- >
- </template>
- </template>
- </template>
- </a-table>
- </a-spin>
- <template #footer>
- <a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
- <a-button type="primary" :loading="submitLoading" @click="onSubmit">保存</a-button>
- </template>
- <ScopeDefineOrg ref="scopeDefineOrgModal" @click="scopeDefineOrgClick" />
- </xn-form-container>
- </template>
- <script setup name="grantResourceForm">
- import { SearchOutlined } from '@ant-design/icons-vue'
- import userApi from '@/api/sys/userApi'
- import roleApi from '@/api/sys/roleApi'
- import ScopeDefineOrg from './scopeDefineOrg.vue'
- const visible = ref(false)
- const spinningLoading = ref(false)
- const scopeDefineOrgModal = ref(null)
- const emit = defineEmits({ successful: null })
- const submitLoading = ref(false)
- const CustomValue = 'SCOPE_ORG_DEFINE'
- // 抽屉的宽度
- const drawerWidth = 1000
- // 自动获取宽度,默认获取浏览器的宽度的90%
- //(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) * 0.9
- const loadDatas = ref([])
- // 标题接口列搜索, 数据范围默认
- const scopeRadioValue = ref()
- const state = reactive({
- searchText: '',
- searchedColumn: ''
- })
- const searchInput = ref()
- const columns = [
- {
- key: 'api',
- title: '接口',
- dataIndex: 'api',
- width: 380,
- customFilterDropdown: true,
- onFilter: (value, record) => record.api.includes(value),
- onFilterDropdownVisibleChange: (visible) => {
- if (visible) {
- setTimeout(() => {
- searchInput.value.focus()
- }, 100)
- }
- }
- },
- {
- key: 'dataScope',
- title: '数据范围',
- dataIndex: 'dataScope'
- }
- ]
- // 获取数据
- const loadData = async () => {
- spinningLoading.value = true
- const res = await roleApi.rolePermissionTreeSelector()
- // 获取他已有的权限
- const param = {
- id: grantPermissionParam.id
- }
- const resOwn = await userApi.userOwnPermission(param)
- // 数据转换
- echoModuleData(res, resOwn)
- spinningLoading.value = false
- }
- // 数据转换
- const echoModuleData = (res, resOwn) => {
- res.forEach((api) => {
- const obj = {
- api: api,
- dataScope: datascope(api),
- check: false
- }
- if (resOwn.grantInfoList.length > 0) {
- resOwn.grantInfoList.forEach((item) => {
- if (item.apiUrl === subStrApi(api)) {
- obj.check = true
- // dataScopeInfo
- obj.dataScope.forEach((o) => {
- if (o.value === item.scopeCategory) {
- o.check = true
- // 如果是自定义
- if (item.scopeCategory === 'SCOPE_ORG_DEFINE') {
- o.scopeDefineOrgIdList = item.scopeDefineOrgIdList
- }
- }
- })
- }
- })
- }
- loadDatas.value.push(obj)
- })
- }
- const datascope = (id) => {
- return [
- {
- id: `SCOPE_ALL_${id}`,
- title: '全部',
- value: 'SCOPE_ALL',
- check: false
- },
- {
- id: `SCOPE_SELF_${id}`,
- title: '仅自己',
- value: 'SCOPE_SELF',
- check: false
- },
- {
- id: `SCOPE_ORG_${id}`,
- title: '所属组织',
- value: 'SCOPE_ORG',
- check: false
- },
- {
- id: `SCOPE_ORG_CHILD_${id}`,
- title: '所属组织及以下',
- value: 'SCOPE_ORG_CHILD',
- check: false
- },
- {
- id: `SCOPE_ORG_DEFINE_${id}`,
- title: '自定义',
- value: 'SCOPE_ORG_DEFINE',
- check: false
- }
- ]
- }
- // 点击数据权限选择
- const changeDataScope = (record, evt) => {
- const name = evt.target.name
- // 这里做互斥,每个
- record.dataScope.forEach((item) => {
- if (item.title !== name) {
- item.check = false
- }
- })
- changeChildCheckBox(record, evt)
- }
- // 处理自定义
- const handleDefineOrg = (recordDataScope) => {
- // 弹框选择子自定义
- const data = recordDataScope.dataScope.find((f) => f.value === CustomValue)
- // 选中了
- if (data.check) {
- // 获取到选中的key数组,传过去,让其那边回显
- const checkKeysStr = recordDataScope.dataScope[4].scopeDefineOrgIdList
- scopeDefineOrgModal.value.onOpen(data.id, checkKeysStr)
- } else {
- // 清理缓存中的结构,去掉就行
- handleDatascope(false, record.id, null)
- }
- }
- // 自定义数据弹窗回调
- const scopeDefineOrgClick = (value) => {
- handleDatascope(true, value.dataScopeId, value.defineOrgIdData.scopeDefineOrgIdList)
- }
- // 处理Datascope数据被选中自定义或取消自定义数据
- const handleDatascope = (check, id, orgData) => {
- loadDatas.value.forEach((item) => {
- if (id === 'SCOPE_ORG_DEFINE_' + item.api) {
- item.dataScope.forEach((items) => {
- if (items.value === 'SCOPE_ORG_DEFINE') {
- if (check) {
- items.scopeDefineOrgIdList = orgData
- } else {
- items.scopeDefineOrgIdList = []
- }
- }
- })
- }
- })
- }
- // 打开抽屉
- const onOpen = (record) => {
- grantPermissionParam.id = record.id
- visible.value = true
- loadData()
- }
- // 关闭抽屉
- const onClose = () => {
- // 将这些缓存的给清空
- loadDatas.value = []
- scopeRadioValue.value = ''
- visible.value = false
- }
- // 全选
- const onCheckAllChange = (value) => {
- spinningLoading.value = true
- loadDatas.value.forEach((data) => {
- changeApi(data, value)
- spinningLoading.value = false
- })
- }
- // 选中接口
- const changeApi = (record, val) => {
- record.check = val
- if (val) {
- let checkStatus = 0
- for (let i = 0; i < record.dataScope.length; i++) {
- if (record.dataScope[i].check) {
- checkStatus++
- }
- }
- if (checkStatus === 0) {
- record.dataScope[0].check = true
- }
- } else {
- // 去掉已选中的
- record.dataScope.forEach((item) => {
- item.check = false
- if (item.value === 'SCOPE_ORG_DEFINE') {
- item.scopeDefineOrgIdList = []
- }
- })
- }
- }
- // 设置选中状态
- const changeChildCheckBox = (record, evt) => {
- let checked = evt.target.checked
- if (!checked) {
- record.check = false
- } else if (checked) {
- record.check = checked
- }
- }
- // 提交数据模型
- let grantPermissionParam = {
- // 角色id
- id: '',
- // 授权权限信息
- grantInfoList: []
- }
- // 提交之前转换数据
- const convertData = () => {
- grantPermissionParam.grantInfoList = []
- loadDatas.value.forEach((table) => {
- if (table.check) {
- table.dataScope.forEach((item) => {
- if (item.check) {
- const dataScopeInfo = {
- apiUrl: subStrApi(table.api),
- scopeCategory: item.value,
- scopeDefineOrgIdList: item.scopeDefineOrgIdList === undefined ? [] : item.scopeDefineOrgIdList
- }
- grantPermissionParam.grantInfoList.push(dataScopeInfo)
- }
- })
- }
- })
- return grantPermissionParam
- }
- // 截取api串中的中文及括号
- const subStrApi = (api) => {
- return api.substring(0, api.indexOf('['))
- }
- // 验证并提交数据
- const onSubmit = () => {
- const param = convertData()
- submitLoading.value = true
- userApi
- .userGrantPermission(param)
- .then(() => {
- onClose()
- emit('successful')
- })
- .finally(() => {
- submitLoading.value = false
- })
- }
- // 标题接口列搜索
- const handleSearch = (selectedKeys, confirm, dataIndex) => {
- confirm()
- state.searchText = selectedKeys[0]
- state.searchedColumn = dataIndex
- }
- // 标题接口列搜索重置
- const handleReset = (clearFilters) => {
- clearFilters()
- state.searchText = ''
- }
- // 标题数据范围列radio-group事件
- const radioChange = (obj) => {
- loadDatas.value.forEach((data) => {
- data.dataScope.forEach((data) => {
- if (obj.target.value === data.value) {
- data.check = true
- } else {
- data.check = false
- }
- })
- })
- }
- // 调用这个函数将子组件的一些数据和方法暴露出去
- defineExpose({
- onOpen
- })
- </script>
- <style scoped>
- /* 重写复选框的样式 */
- .ant-checkbox-wrapper {
- margin-left: 0px !important;
- padding-top: 2px !important;
- padding-bottom: 2px !important;
- }
- </style>
|