feat 用户各项关联属性分配处理

This commit is contained in:
xxm
2022-11-10 16:59:22 +08:00
parent bdd16025ce
commit 7a169be898
12 changed files with 598 additions and 21 deletions

View File

@@ -10,6 +10,7 @@ import {
SelectOption,
List,
Tabs,
Alert,
Upload,
Checkbox,
Switch,
@@ -64,6 +65,7 @@ export function registerGlobComp(app: App) {
app.use(Tree)
app.use(TreeSelect)
app.use(Card)
app.use(Alert)
app.use(Menu)
app.use(Tooltip)
app.use(Descriptions)

View File

@@ -72,7 +72,6 @@
initFormModel(editType)
resetForm()
form.clientCode = clientCode
console.log(parentId)
form.parentId = parentId
getInfo(id, editType)
}

View File

@@ -148,13 +148,13 @@ export function deleteBatchUserAssign(obj) {
*/
export interface DataScope extends BaseEntity {
// 编码
code: string
code?: string
// 名称
name: string
name?: string
// 类型
type: number
type?: number
// 说明
remark: string
remark?: string
}
/**

View File

@@ -88,9 +88,9 @@ export function addUserRoleBatch(data) {
/**
* 获取用户拥有数据权限id集合
*/
export function findDataScopeIdsByUser(id) {
return defHttp.get<Result<string[]>>({
url: `/user/data/scope/findIdsByUser`,
export function getDataScopeIdByUser(id) {
return defHttp.get<Result<string>>({
url: `/user/data/scope/findDataScopeIdByUser`,
params: { id },
})
}
@@ -98,9 +98,9 @@ export function findDataScopeIdsByUser(id) {
/**
* 获取用户拥有数据权限集合
*/
export function getDataScopes(id) {
return defHttp.get<Result<DataScope[]>>({
url: `/user/data/scope/findAllByUser`,
export function getDataScopeByUser(id) {
return defHttp.get<Result<DataScope>>({
url: `/user/data/scope/findDataScopeByUser`,
params: { id },
})
}

View File

@@ -103,6 +103,11 @@
<user-edit ref="userEdit" @ok="queryPage" />
<user-show ref="userShow" />
<user-role-assign ref="userRoleAssign" />
<user-role-assign-batch ref="userRoleAssignBatch" />
<user-data-scope-assign ref="userDataScopeAssign" />
<user-data-scope-assign-batch ref="userDataScopeAssignBatch" />
<user-dept-assign ref="userDeptAssign" />
<user-dept-assign-batch ref="userDeptAssignBatch" />
</div>
</div>
</template>
@@ -122,6 +127,11 @@
import UserEdit from './UserEdit.vue'
import UserShow from './UserShow.vue'
import UserRoleAssign from './role/UserRoleAssign.vue'
import UserRoleAssignBatch from './role/UserRoleAssignBatch.vue'
import UserDataScopeAssign from './scope/UserDataScopeAssign.vue'
import UserDataScopeAssignBatch from './scope/UserDataScopeAssignBatch.vue'
import UserDeptAssign from './dept/UserDeptAssign.vue'
import UserDeptAssignBatch from './dept/UserDeptAssignBatch.vue'
// 使用hooks
const { handleTableChange, pageQueryResHandel, resetQueryParams, pagination, pages, model, loading, batchOperateFlag } =
@@ -237,7 +247,7 @@
function assignDept(record) {
userDeptAssign.init(record.id)
}
// 批量分配数据部门
// 批量分配部门
function assignDeptBatch() {
const userIds = xTable.getCheckboxRecords().map((o) => o.id)
userDeptAssignBatch.init(userIds)
@@ -246,7 +256,6 @@
userAdd.init()
}
function show(record) {
console.log('show')
userShow.init(record.id)
}
function edit(record) {

View File

@@ -35,7 +35,7 @@
<a-tag color="green" v-for="o in clientList" :key="o.id">{{ o.name }}</a-tag>
</a-form-item>
<a-form-item label="数据权限">
<a-tag color="green" v-for="o in dataScopes" :key="o.id">{{ o.name }}</a-tag>
<a-tag color="green" v-show="dataScope.name">{{ dataScope.name }}</a-tag>
</a-form-item>
<a-form-item label="部门列表">
<a-tag color="green" v-for="o in deptList" :key="o.id">{{ o.deptName }}</a-tag>
@@ -55,7 +55,7 @@
import { Client, findAll } from '/@/views/modules/system/client/Client.api'
import { Role } from '/@/views/modules/system/role/Role.api'
import { get, UserInfo } from '/@/views/modules/system/user/User.api'
import { getDataScopes, getDeptList, getRoles } from '/@/views/modules/system/user/UserAssign.api'
import { getDataScopeByUser, getDeptList, getRoles } from '/@/views/modules/system/user/UserAssign.api'
import { DataScope } from '/@/views/modules/system/scope/DataScope.api'
import { Dept } from '/@/views/modules/system/dept/Dept.api'
import { useDict } from '/@/hooks/bootx/useDict'
@@ -71,7 +71,7 @@
let roles = $ref<Role[]>([])
let clients = $ref<Client[]>([])
let clientList = $ref<Client[]>([])
let dataScopes = $ref<DataScope[]>([])
let dataScope = $ref<DataScope>({})
let deptList = $ref<Dept[]>([])
async function init(id) {
@@ -87,8 +87,8 @@
await getDeptList(id).then((res) => {
deptList = res.data
})
await getDataScopes(id).then((res) => {
dataScopes = res.data
await getDataScopeByUser(id).then((res) => {
dataScope = res.data
})
confirmLoading.value = false
}

View File

@@ -0,0 +1,154 @@
<template>
<basic-drawer showFooter v-bind="$attrs" title="用户部门分配" width="40%" :visible="visible" @close="handleCancel">
<a-spin :spinning="loading">
<a-input style="margin-bottom: 8px" placeholder="筛选" allowClear v-model:vallue="searchName" @change="search" />
<a-tree
ref="treeRef"
:checkable="true"
:checkStrictly="true"
v-model:checkedKeys="checkedKeys"
v-model:expandedKeys="expandedKeys"
:auto-expand-parent="autoExpandParent"
:tree-data="treeData"
@check="onCheck"
@expand="onExpand"
>
<template #title="{ title }">
<span v-if="title.indexOf(searchName) > -1">
{{ title.substr(0, title.indexOf(searchName)) }}
<span style="color: #f50">{{ searchName }}</span>
{{ title.substr(title.indexOf(searchName) + searchName.length) }}
</span>
<span v-else>{{ title }}</span>
</template>
</a-tree>
</a-spin>
<template #footer>
<a-dropdown :trigger="['click']">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="checkALL">全部勾选</a-menu-item>
<a-menu-item key="2" @click="cancelCheckALL">取消全选</a-menu-item>
<a-menu-item key="3" @click="expandAll">展开所有</a-menu-item>
<a-menu-item key="4" @click="closeAll">合并所有</a-menu-item>
</a-menu>
</template>
<a-button post-icon="ant-design:up-outlined"> 操作 </a-button>
</a-dropdown>
<a-button @click="handleCancel()">取消</a-button>
<a-button @click="handleSubmit()" type="primary" :loading="loading" style="margin-right: 0.8rem">保存</a-button>
</template>
</basic-drawer>
</template>
<script lang="ts" setup>
import BasicDrawer from '/@/components/Drawer/src/BasicDrawer.vue'
import { $ref } from 'vue/macros'
import XEUtils from 'xe-utils'
import { treeDataTranslate } from '/@/utils/dataUtil'
import { tree } from '/@/views/modules/system/dept/Dept.api'
import { addUserDept, findDeptIdsByUser } from '/@/views/modules/system/user/UserAssign.api'
let loading = $ref(false)
let visible = $ref(false)
let userId = $ref<string>()
let searchName = $ref<string>()
let allTreeKeys = $ref<string[]>([])
let expandedKeys = $ref<string[]>([])
let checkedKeys = $ref<any>([])
let tableData = $ref<string[]>([])
let autoExpandParent = $ref(false)
let treeData = $ref<any[]>([])
let treeList = $ref<any[]>([])
let treeRef = $ref<any>()
// 入口
async function init(id) {
visible = true
loading = true
userId = id
expandedKeys = []
// 权限树
await tree().then(({ data }) => {
treeData = treeDataTranslate(data, 'id', 'deptName')
generateTreeList(data)
})
// 当前用户已经分配的部门
await findDeptIdsByUser(userId).then(({ data }) => {
checkedKeys = data
})
// 所有的key值
allTreeKeys = treeList.map((item) => item.id)
loading = false
}
// 展开/收起节点时触发
function onExpand(keys) {
expandedKeys = keys
autoExpandParent = false
}
// 点击复选框触发
function onCheck(keys) {
checkedKeys = keys
}
// 展开全部
function expandAll() {
expandedKeys = allTreeKeys
}
// 合并全部
function closeAll() {
expandedKeys = []
}
// 全选
function checkALL() {
checkedKeys = allTreeKeys
}
// 全不选
function cancelCheckALL() {
checkedKeys = []
}
// 提交
function handleSubmit() {
loading = true
addUserDept({
userId,
deptIds: checkedKeys.checked,
}).then(() => {
handleCancel()
})
}
// 搜索
function search() {
const sn = XEUtils.toValueString(searchName).toLowerCase()
expandedKeys = treeList
.map((node) => {
if (sn && node.parentId && XEUtils.toValueString(node.deptName).toLowerCase().indexOf(sn) > -1) {
return node.parentId
}
})
.filter((item, i, self) => item && self.indexOf(item) === i)
}
// 树数据铺平
function generateTreeList(treeData) {
for (let i = 0; i < treeData.length; i++) {
const node = treeData[i]
treeList.push(node)
if (node.children) {
generateTreeList(node.children)
}
}
}
/**
* 关闭
*/
function handleCancel() {
visible = false
loading = false
}
defineExpose({
init,
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,151 @@
<template>
<basic-drawer showFooter v-bind="$attrs" title="用户部门批量分配" width="40%" :visible="visible" @close="handleCancel">
<a-spin :spinning="loading">
<a-alert style="margin-bottom: 15px" message="注意!会清空用户原有分配的部门" banner closable />
<a-input style="margin-bottom: 8px" placeholder="筛选" allowClear v-model:vallue="searchName" @change="search" />
<a-tree
ref="treeRef"
:checkable="true"
:checkStrictly="true"
v-model:checkedKeys="checkedKeys"
v-model:expandedKeys="expandedKeys"
:auto-expand-parent="autoExpandParent"
:tree-data="treeData"
@check="onCheck"
@expand="onExpand"
>
<template #title="{ title }">
<span v-if="title.indexOf(searchName) > -1">
{{ title.substr(0, title.indexOf(searchName)) }}
<span style="color: #f50">{{ searchName }}</span>
{{ title.substr(title.indexOf(searchName) + searchName.length) }}
</span>
<span v-else>{{ title }}</span>
</template>
</a-tree>
</a-spin>
<template #footer>
<a-dropdown :trigger="['click']">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="checkALL">全部勾选</a-menu-item>
<a-menu-item key="2" @click="cancelCheckALL">取消全选</a-menu-item>
<a-menu-item key="3" @click="expandAll">展开所有</a-menu-item>
<a-menu-item key="4" @click="closeAll">合并所有</a-menu-item>
</a-menu>
</template>
<a-button post-icon="ant-design:up-outlined"> 操作 </a-button>
</a-dropdown>
<a-button @click="handleCancel()">取消</a-button>
<a-button @click="handleSubmit()" type="primary" :loading="loading" style="margin-right: 0.8rem">保存</a-button>
</template>
</basic-drawer>
</template>
<script lang="ts" setup>
import BasicDrawer from '/@/components/Drawer/src/BasicDrawer.vue'
import { $ref } from 'vue/macros'
import XEUtils from 'xe-utils'
import { treeDataTranslate } from '/@/utils/dataUtil'
import { tree } from '/@/views/modules/system/dept/Dept.api'
import { addUserDeptBatch } from '/@/views/modules/system/user/UserAssign.api'
let loading = $ref(false)
let visible = $ref(false)
let userIds = $ref<string[]>()
let searchName = $ref<string>()
let allTreeKeys = $ref<string[]>([])
let expandedKeys = $ref<string[]>([])
let checkedKeys = $ref<any>([])
let tableData = $ref<string[]>([])
let autoExpandParent = $ref(false)
let treeData = $ref<any[]>([])
let treeList = $ref<any[]>([])
let treeRef = $ref<any>()
// 入口
async function init(ids) {
visible = true
loading = true
userIds = ids
expandedKeys = []
// 权限树
await tree().then(({ data }) => {
treeData = treeDataTranslate(data, 'id', 'deptName')
generateTreeList(data)
})
// 所有的key值
allTreeKeys = treeList.map((item) => item.id)
loading = false
}
// 展开/收起节点时触发
function onExpand(keys) {
expandedKeys = keys
autoExpandParent = false
}
// 点击复选框触发
function onCheck(keys) {
checkedKeys = keys
}
// 展开全部
function expandAll() {
expandedKeys = allTreeKeys
}
// 合并全部
function closeAll() {
expandedKeys = []
}
// 全选
function checkALL() {
checkedKeys = allTreeKeys
}
// 全不选
function cancelCheckALL() {
checkedKeys = []
}
// 提交
function handleSubmit() {
loading = true
addUserDeptBatch({
userIds,
deptIds: checkedKeys.checked,
}).then(() => {
handleCancel()
})
}
// 搜索
function search() {
const sn = XEUtils.toValueString(searchName).toLowerCase()
expandedKeys = treeList
.map((node) => {
if (sn && node.parentId && XEUtils.toValueString(node.deptName).toLowerCase().indexOf(sn) > -1) {
return node.parentId
}
})
.filter((item, i, self) => item && self.indexOf(item) === i)
}
// 树数据铺平
function generateTreeList(treeData) {
for (let i = 0; i < treeData.length; i++) {
const node = treeData[i]
treeList.push(node)
if (node.children) {
generateTreeList(node.children)
}
}
}
/**
* 关闭
*/
function handleCancel() {
visible = false
loading = false
}
defineExpose({
init,
})
</script>
<style scoped></style>

View File

@@ -14,7 +14,7 @@
<a-form-item label="账号" name="account">
<a-input :disabled="true" v-model:value="userInfo.username" />
</a-form-item>
<a-form-item label="用户" name="name">
<a-form-item label="用户名称" name="name">
<a-input :disabled="true" v-model:value="userInfo.name" />
</a-form-item>
<a-form-item label="角色" name="roleIds">
@@ -41,7 +41,11 @@
import { nextTick } from 'vue'
import { LabeledValue } from 'ant-design-vue/lib/select'
import { FormInstance } from 'ant-design-vue/lib/form'
import { addUserRole, getRoleIds } from '/@/views/modules/system/user/UserAssign.api'
import {
addUserDataScope,
addUserRole,
getRoleIds
} from "/@/views/modules/system/user/UserAssign.api";
import { findAll as roleList } from '/@/views/modules/system/role/Role.api'
import { dropdownTranslate } from '/@/utils/dataUtil'
import BasicModal from '/@/components/Modal/src/BasicModal.vue'
@@ -82,7 +86,7 @@
function handleOk() {
formRef.validate().then(async () => {
confirmLoading.value = true
await addUserRole(form)
await addUserDataScope(form)
createMessage.success('保存成功')
confirmLoading.value = false
visible.value = false

View File

@@ -0,0 +1,84 @@
<template>
<basic-modal
v-bind="$attrs"
title="用户角色批量分配"
:width="modalWidth"
:visible="visible"
:confirmLoading="confirmLoading"
:maskClosable="false"
@cancel="handleCancel"
@ok="handleOk"
>
<a-spin :spinning="confirmLoading">
<a-row>
<a-col span="16" offset="5">
<a-alert style="margin-bottom: 20px" message="注意!会清空用户原有分配的角色" banner closable />
</a-col>
</a-row>
<a-form class="small-from-item" ref="formRef" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="角色" name="roleIds">
<a-select
allowClear
mode="multiple"
v-model:value="form.roleIds"
:options="roles"
:filter-option="search"
style="width: 100%"
placeholder="选择角色"
/>
</a-form-item>
</a-form>
</a-spin>
</basic-modal>
</template>
<script lang="ts" setup>
import BasicModal from '/@/components/Modal/src/BasicModal.vue'
import { useMessage } from '/@/hooks/web/useMessage'
import useFormEdit from '/@/hooks/bootx/useFormEdit'
import { $ref } from 'vue/macros'
import { FormInstance } from 'ant-design-vue/lib/form'
import { LabeledValue } from 'ant-design-vue/lib/select'
import { findAll as roleList } from '/@/views/modules/system/role/Role.api'
import { dropdownTranslate } from '/@/utils/dataUtil'
import { nextTick } from 'vue'
import { addUserRoleBatch } from '/@/views/modules/system/user/UserAssign.api'
const { createMessage } = useMessage()
const { initFormModel, handleCancel, search, labelCol, wrapperCol, modalWidth, confirmLoading, visible } = useFormEdit()
const formRef = $ref<FormInstance>()
let roles = $ref<LabeledValue[]>([])
let form = $ref({
userIds: [] as string[],
roleIds: [] as string[],
})
async function init(ids) {
visible.value = true
confirmLoading.value = true
await nextTick(() => {
formRef.resetFields()
})
// 获取角色列表
await roleList().then(({ data }) => {
roles = dropdownTranslate(data, 'name', 'id')
})
form.userIds = ids
confirmLoading.value = false
}
function handleOk() {
formRef.validate().then(async () => {
confirmLoading.value = true
await addUserRoleBatch(form)
createMessage.success('批量分配角色成功')
confirmLoading.value = false
visible.value = false
})
}
defineExpose({ init })
</script>
<style scoped></style>

View File

@@ -0,0 +1,94 @@
<template>
<basic-modal
v-bind="$attrs"
title="用户角色分配"
:width="modalWidth"
:visible="visible"
:confirmLoading="confirmLoading"
:maskClosable="false"
@cancel="handleCancel"
@ok="handleOk"
>
<a-spin :spinning="confirmLoading">
<a-form class="small-from-item" ref="formRef" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="账号" name="account">
<a-input :disabled="true" v-model:value="userInfo.username" />
</a-form-item>
<a-form-item label="用户名称" name="name">
<a-input :disabled="true" v-model:value="userInfo.name" />
</a-form-item>
<a-form-item label="数据权限" name="dataScopeId">
<a-select
allowClear
v-model:value="form.dataScopeId"
style="width: 100%"
:default-value="form.dataScopeId"
:filter-option="search"
:options="dataScopes"
placeholder="选择数据权限"
/>
</a-form-item>
</a-form>
</a-spin>
</basic-modal>
</template>
<script lang="ts" setup>
import { useMessage } from '/@/hooks/web/useMessage'
import useFormEdit from '/@/hooks/bootx/useFormEdit'
import { $ref } from 'vue/macros'
import { FormInstance } from 'ant-design-vue/lib/form'
import { UserInfo } from '/@/views/modules/system/user/User.api'
import { LabeledValue } from 'ant-design-vue/lib/select'
import { nextTick } from 'vue'
import { dropdownTranslate } from '/@/utils/dataUtil'
import { addUserRole, getDataScopeIdByUser } from '/@/views/modules/system/user/UserAssign.api'
import BasicModal from '/@/components/Modal/src/BasicModal.vue'
import { findAll as dataScopeList } from '/@/views/modules/system/scope/DataScope.api'
const { createMessage } = useMessage()
const { initFormModel, handleCancel, search, labelCol, wrapperCol, modalWidth, confirmLoading, visible } = useFormEdit()
let formRef = $ref<FormInstance>()
let userInfo = $ref<UserInfo>({
name: '',
username: '',
})
let dataScopes = $ref<LabeledValue[]>([])
let form = $ref({
userId: '',
dataScopeId: undefined as undefined | string,
})
async function init(info: UserInfo) {
userInfo = info
visible.value = true
confirmLoading.value = true
await nextTick(() => {
formRef.resetFields()
})
form.userId = info.id as string
// 获取数据权限列表
await dataScopeList().then(({ data }) => {
dataScopes = dropdownTranslate(data, 'name', 'id')
})
// 获取关联权限信息
await getDataScopeIdByUser(userInfo.id).then(({ data }) => {
form.dataScopeId = data || undefined
})
confirmLoading.value = false
}
function handleOk() {
formRef.validate().then(async () => {
confirmLoading.value = true
await addUserRole(form)
createMessage.success('保存成功')
confirmLoading.value = false
visible.value = false
})
}
defineExpose({ init })
</script>
<style scoped></style>

View File

@@ -0,0 +1,80 @@
<template>
<basic-modal
v-bind="$attrs"
title="用户角色分配"
:width="modalWidth"
:visible="visible"
:confirmLoading="confirmLoading"
:maskClosable="false"
@cancel="handleCancel"
@ok="handleOk"
>
<a-spin :spinning="confirmLoading">
<a-row>
<a-col span="16" offset="4">
<a-alert style="margin-bottom: 20px" message="注意!会清空用户原有分配的数据权限" banner closable />
</a-col>
</a-row>
<a-form class="small-from-item" ref="formRef" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="数据权限" name="dataScopeId">
<a-select
allowClear
v-model:value="form.dataScopeId"
style="width: 100%"
:default-value="form.dataScopeId"
:filter-option="search"
:options="dataScopes"
placeholder="选择数据权限"
/>
</a-form-item>
</a-form>
</a-spin>
</basic-modal>
</template>
<script lang="ts" setup>
import BasicModal from '/@/components/Modal/src/BasicModal.vue'
import { useMessage } from '/@/hooks/web/useMessage'
import useFormEdit from '/@/hooks/bootx/useFormEdit'
import { $ref } from 'vue/macros'
import { FormInstance } from 'ant-design-vue/lib/form'
import { LabeledValue } from 'ant-design-vue/lib/select'
import { nextTick } from 'vue'
import { findAll as dataScopeList } from '/@/views/modules/system/scope/DataScope.api'
import { dropdownTranslate } from '/@/utils/dataUtil'
import { addUserDataScopeBatch } from '/@/views/modules/system/user/UserAssign.api'
const { createMessage } = useMessage()
const { initFormModel, handleCancel, search, labelCol, wrapperCol, modalWidth, confirmLoading, visible } = useFormEdit()
let formRef = $ref<FormInstance>()
let dataScopes = $ref<LabeledValue[]>([])
let form = $ref({
userIds: [],
dataScopeId: undefined as undefined | string,
})
async function init(ids) {
visible.value = true
confirmLoading.value = true
await nextTick(() => {
formRef.resetFields()
})
form.userIds = ids
// 获取数据权限列表
await dataScopeList().then(({ data }) => {
dataScopes = dropdownTranslate(data, 'name', 'id')
})
confirmLoading.value = false
}
function handleOk() {
formRef.validate().then(async () => {
confirmLoading.value = true
await addUserDataScopeBatch(form)
createMessage.success('保存成功')
confirmLoading.value = false
visible.value = false
})
}
defineExpose({ init })
</script>
<style scoped></style>