feat: role member

This commit is contained in:
teukkk 2025-06-11 20:20:02 +08:00
parent ace03e5b5a
commit 569d16d735
7 changed files with 217 additions and 18 deletions

View File

@ -1,7 +1,7 @@
import { get, post, del } from '@/request/index'
import type { Ref } from 'vue'
import { Result } from '@/request/Result'
import type { RoleItem, RolePermissionItem, CreateOrUpdateParams, RoleMemberItem, CreateMemberParams } from '@/api/type/role'
import type { RoleItem, RolePermissionItem, CreateOrUpdateParams, PageList, RoleMemberItem, CreateMemberParamsItem } from '@/api/type/role'
import { RoleTypeEnum } from '@/enums/system'
import type { pageRequest } from '@/api/type/common'
@ -66,7 +66,7 @@ const getRoleMemberList: (
page: pageRequest,
param: any,
loading?: Ref<boolean>,
) => Promise<Result<RoleMemberItem>> = (role_id, page, param, loading) => {
) => Promise<Result<PageList<RoleMemberItem[]>>> = (role_id, page, param, loading) => {
return get(
`${prefix}/${role_id}/user_list/${page.current_page}/${page.page_size}`,
param,
@ -79,7 +79,7 @@ const getRoleMemberList: (
*/
const CreateMember: (
role_id: string,
data: CreateMemberParams,
data: { members: CreateMemberParamsItem[] },
loading?: Ref<boolean>,
) => Promise<Result<any>> = (role_id, data, loading) => {
return post(`${prefix}/${role_id}/add_member`, data, undefined, loading)

View File

@ -1,5 +1,5 @@
import { RoleTypeEnum } from '@/enums/system'
import type { FormItemRule } from 'element-plus'
interface RoleItem {
id: string,
role_name: string,
@ -49,8 +49,27 @@ interface RoleMemberItem {
workspace_name: string,
}
interface CreateMemberParams {
members: { user_ids: string[], workspace_ids: string[] }[]
interface CreateMemberParamsItem {
user_ids: string[],
workspace_ids: string[]
}
export type { RoleItem, RolePermissionItem, RoleTableDataItem, CreateOrUpdateParams, ChildrenPermissionItem, RoleMemberItem, CreateMemberParams }
interface PageList<T> {
current: number,
size: number,
total: number,
records: T
}
type Arrayable<T> = T | T[]
interface FormItemModel {
path: string
label?: string
rules?: Arrayable<FormItemRule>,
selectProps: {
options?: { label: string, value: string }[]
placeholder?: string
}
}
export type { RoleItem, FormItemModel, RolePermissionItem, RoleTableDataItem, CreateOrUpdateParams, PageList, ChildrenPermissionItem, RoleMemberItem, CreateMemberParamsItem }

View File

@ -26,7 +26,15 @@ const getProfile: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) =
// return get('/profile', undefined, loading)
// }
/**
*
*/
const getUserList: (loading?: Ref<boolean>) => Promise<Result<Record<string, any>[]>> = (loading) => {
return get('/user/list', undefined, loading)
}
export default {
getUserProfile,
getProfile
getProfile,
getUserList
}

View File

@ -0,0 +1,98 @@
<template>
<el-drawer v-model="visible" size="600" :destroy-on-close="true" :before-close="handleCancel">
<template #header>
<h4>{{ $t('views.role.member.add') }}</h4>
</template>
<template #default>
<MemberFormContent ref="memberFormContentRef" :models="formItemModel" v-model:form="list" />
</template>
<template #footer>
<div style="flex: auto">
<el-button @click="handleCancel">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="handleAdd()" :loading="loading">
{{ $t('common.add') }}
</el-button>
</div>
</template>
</el-drawer>
</template>
<script setup lang="ts">
import { onBeforeMount, ref } from 'vue'
import type { CreateMemberParamsItem, FormItemModel } from '@/api/type/role'
import RoleApi from '@/api/system/role'
import UserApi from '@/api/user/user'
import MemberFormContent from './MemberFormContent.vue'
import { t } from '@/locales'
import { MsgSuccess } from '@/utils/message'
const props = defineProps<{
roleId: string
}>()
const emit = defineEmits<{
(e: 'refresh'): void;
}>();
const loading = ref(false)
const visible = ref(false)
const list = ref<CreateMemberParamsItem[]>([]);
const formItemModel = ref<FormItemModel[]>([
{
path: 'user_ids',
label: t('views.role.member.title'),
rules: [
{
required: true,
message: `${t('common.selectPlaceholder')}${t('views.role.member.title')}`,
},
],
selectProps: {
options: [],
placeholder: `${t('common.selectPlaceholder')}${t('views.role.member.title')}`
}
},
{
path: 'workspace_ids',
label: t('views.role.member.workspace'),
rules: [
{
required: true,
message: `${t('common.selectPlaceholder')}${t('views.role.member.workspace')}`,
},
],
selectProps: {
options: [], // TODO
placeholder: `${t('common.selectPlaceholder')}${t('views.role.member.workspace')}`
}
},
]);
onBeforeMount(async () => {
const res = await UserApi.getUserList();
formItemModel.value[0].selectProps.options = res.data?.map(item => ({ label: item.nick_name, value: item.id }))
})
function open() {
visible.value = true
}
function handleCancel() {
visible.value = false
list.value = []
}
const memberFormContentRef = ref<InstanceType<typeof MemberFormContent>>()
function handleAdd() {
memberFormContentRef.value?.validate().then(async (valid) => {
if (valid) {
await RoleApi.CreateMember(props.roleId, { members: list.value }, loading)
MsgSuccess(t('common.addSuccess'))
handleCancel();
emit('refresh')
}
})
}
defineExpose({ open })
</script>

View File

@ -17,12 +17,10 @@
<el-table-column prop="nick_name" :label="$t('views.userManage.form.nick_name.label')" />
<el-table-column prop="username" :label="$t('views.userManage.form.username.label')" />
<el-table-column prop="workspace_name" :label="$t('views.role.member.workspace')" />
<!-- TODO -->
<el-table-column prop="nick_name" :label="$t('views.role.member.role')" />
<el-table-column :label="$t('common.operation')" width="100" fixed="right">
<template #default="{ row }">
<el-tooltip effect="dark" :content="`${$t('common.create')}${$t('views.role.customRole')}`" placement="top">
<el-button type="primary" text @click.stop="handleDelete(row)" :title="$t('common.edit')">
<el-tooltip effect="dark" :content="`${$t('views.role.member.delete.button')}`" placement="top">
<el-button type="primary" text @click.stop="handleDelete(row)">
<el-icon>
<EditPen />
</el-icon>
@ -32,7 +30,7 @@
</el-table-column>
</app-table>
</div>
<!-- <AddMemberDrawer ref="addMemberDrawerRef" /> -->
<AddMemberDrawer ref="addMemberDrawerRef" :role-id="props.currentRole?.id as string" @refresh="getList" />
</template>
<script setup lang="ts">
@ -41,6 +39,7 @@ import RoleApi from '@/api/system/role'
import type { RoleItem, RoleMemberItem } from '@/api/type/role'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import { t } from '@/locales'
import AddMemberDrawer from './AddMemberDrawer.vue'
const props = defineProps<{
currentRole?: RoleItem
@ -66,7 +65,8 @@ async function getList() {
[searchType.value]: searchForm.value[searchType.value],
}
const res = await RoleApi.getRoleMemberList(props.currentRole?.id as string, paginationConfig, params, loading)
console.log('🤔️ =>', res);
tableData.value = res.data.records
paginationConfig.total = res.data.total
} catch (error) {
console.error(error)
}
@ -85,8 +85,9 @@ watch(() => props.currentRole?.id, () => {
getList()
})
// TODO
const addMemberDrawerRef = ref<InstanceType<typeof AddMemberDrawer>>()
function handleAdd() {
addMemberDrawerRef.value?.open();
}
function handleDelete(row: RoleMemberItem) {

View File

@ -0,0 +1,72 @@
<template>
<el-form :model="form" ref="formRef" label-position="top" require-asterisk-position="right">
<el-scrollbar>
<div v-for="(element, index) in form" :key="index" class="flex w-full">
<el-form-item v-for="model of props.models" :key="model.path" :prop="`[${index}].${model.path}`"
:rules="model.rules" :label="index === 0 && model.label ? model.label : ''" class="mr-8" style="flex: 1">
<el-select v-model="element[model.path]"
:placeholder="model.selectProps.placeholder ?? $t('common.selectPlaceholder')" clearable filterable multiple
style="width: 100%">
<el-option v-for="opt in model.selectProps.options" :key="opt.value" :label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
<!-- 删除按钮 -->
<el-button @click="handleDelete(index)"
:style="{ 'margin-top': index === 0 && props.models.some((item) => item.label) ? '30px' : '' }">
<el-icon>
<Delete />
</el-icon>
</el-button>
</div>
</el-scrollbar>
<!-- 添加按钮 -->
<el-button type="primary" text class="mt-2" @click="handleAdd">
<el-icon class="mr-4">
<Plus />
</el-icon>
{{ $t('views.role.member.add') }}
</el-button>
</el-form>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import type { FormItemModel } from '@/api/type/role'
const props = defineProps<{
models: FormItemModel[];
}>()
const formRef = ref()
const formItem: Record<string, any> = {};
const form = defineModel<Record<string, any>[]>('form', {
default: [],
});
function handleAdd() {
form.value.push({ ...formItem });
}
watch(() => props.models, () => {
props.models.forEach((e) => {
formItem[e.path] = [];
});
handleAdd();
}, { immediate: true })
function handleDelete(index: number) {
form.value.splice(index, 1);
}
const validate = () => {
if (formRef.value) {
return formRef.value?.validate()
}
return Promise.resolve()
}
defineExpose({ validate })
</script>

View File

@ -69,7 +69,7 @@
<el-dropdown-item @click.stop="createOrUpdateRole(row)" class="p-8"> {{ $t('common.rename') }}
</el-dropdown-item>
<el-dropdown-item @click.stop="deleteRole(row)" class="border-t p-8"> {{ $t('common.delete')
}}
}}
</el-dropdown-item>
</el-dropdown-menu>
</template>
@ -85,12 +85,13 @@
</div>
<!-- 右边 -->
<div class="role-right">
<div class="role-right" v-loading="loading">
<div class="flex-between mb-16 p-24 pb-0">
<div class="flex align-center">
<span>
{{ currentRole?.role_name }}
<span v-if="currentRole?.type" class="color-input-placeholder ml-4">({{ roleTypeMap[currentRole?.type as
<span v-if="currentRole?.type && !currentRole.internal" class="color-input-placeholder ml-4">({{
roleTypeMap[currentRole?.type as
RoleTypeEnum] }})
</span>
</span>