feat(项目管理): 项目管理成员本地联调&封装公共组件tag&tagGroup

This commit is contained in:
xinxin.wu 2023-09-01 18:06:12 +08:00 committed by fit2-zhao
parent 2a24e2938d
commit c1108b48db
19 changed files with 670 additions and 296 deletions

View File

@ -0,0 +1,51 @@
import MSR from '@/api/http/index';
import {
GetProjectMemberListUrl,
AddMemberToProjectUrl,
EditProjectMemberUrl,
BatchAddUserGroup,
BatchRemoveMemberUrl,
RemoveProjectMemberUrl,
ProjectUserGroupUrl,
ProjectMemberOptions,
} from '@/api/requrls/project-management/projectMember';
import type { ProjectMemberItem, ActionProjectMember } from '@/models/projectManagement/projectAndPermission';
import type { TableQueryParams, CommonList } from '@/models/common';
// 获取项目成员列表
export function getProjectMemberList(data: TableQueryParams) {
return MSR.post<CommonList<ProjectMemberItem>>({ url: GetProjectMemberListUrl, data });
}
// 添加项目成员&编辑项目成员
export function addOrUpdateProjectMember(data: ActionProjectMember) {
if (data.userId) {
return MSR.post({ url: EditProjectMemberUrl, data });
}
return MSR.post({ url: AddMemberToProjectUrl, data });
}
// 添加项目成员到用户组
export function addProjectUserGroup(data: ActionProjectMember) {
return MSR.post({ url: BatchAddUserGroup, data });
}
// 批量移除项目成员
export function batchRemoveMember(data: ActionProjectMember) {
return MSR.post({ url: BatchRemoveMemberUrl, data });
}
// 移除项目成员
export function removeProjectMember(projectId: string, userId: string) {
return MSR.get({ url: RemoveProjectMemberUrl, params: `${projectId}/${userId}` });
}
// 获取用户组下拉
export function getProjectUserGroup(projectId: string) {
return MSR.get({ url: ProjectUserGroupUrl, params: projectId });
}
// 项目成员下拉选项
export function getProjectMemberOptions(projectId: string) {
return MSR.get({ url: ProjectMemberOptions, params: projectId });
}

View File

@ -0,0 +1,8 @@
export const GetProjectMemberListUrl = '/project/member/list';
export const AddMemberToProjectUrl = '/project/member/add';
export const EditProjectMemberUrl = '/project/member/update';
export const BatchRemoveMemberUrl = '/project/member/batch/remove';
export const RemoveProjectMemberUrl = '/project/member/remove';
export const BatchAddUserGroup = '/project/member/add-role';
export const ProjectUserGroupUrl = '/project/member/get-role/option';
export const ProjectMemberOptions = '/project/member/get-member/option';

View File

@ -618,18 +618,6 @@
font-weight: 500; font-weight: 500;
} }
/** 标签 **/
.arco-tag {
.arco-icon {
font-size: 14px;
}
.arco-tag-close-btn {
.arco-icon {
color: var(--color-text-brand);
}
}
}
/** 虚拟列表 **/ /** 虚拟列表 **/
.arco-virtual-list { .arco-virtual-list {
.ms-scroll-bar(); .ms-scroll-bar();

View File

@ -3,33 +3,28 @@
<template #title> <template #title>
{{ batchTitle }} {{ batchTitle }}
<div class="text-[var(--color-text-4)]"> <div class="text-[var(--color-text-4)]">
{{ t('msbatchmodal.batchModalSubTitle', { count: props.tableSelected.length }) }} {{ t('msBatchModal.batchModalSubTitle', { count: props.tableSelected.length }) }}
</div> </div>
</template> </template>
<a-alert v-if="props.action === 'batchAddProject'" class="mb-[16px]"> <a-spin :loading="loading">
{{ t('msbatchmodal.batchModalTip') }} <a-alert v-if="props.action === 'batchAddProject'" class="mb-[16px]">
</a-alert> {{ t('msBatchModal.batchModalTip') }}
<a-transfer </a-alert>
v-model="target" <MsTransfer
:title="[t('msbatchmodal.batchOptional'), t('msbatchmodal.batchChosen')]" v-model="target"
:data="transferData" :data="treeList"
show-search :tree-filed="{
> key: 'id',
<template #source="{ data, selectedKeys, onSelect }"> title: 'name',
<a-tree children: 'children',
:checkable="true" disabled: 'disabled',
checked-strategy="child" }"
:checked-keys="selectedKeys" />
:data="getTreeData(data)" </a-spin>
block-node
@check="onSelect"
/>
</template>
</a-transfer>
<template #footer> <template #footer>
<a-button type="secondary" @click="cancelBatch">{{ t('msbatchmodal.batchModalCancel') }}</a-button> <a-button type="secondary" @click="cancelBatch">{{ t('msBatchModal.batchModalCancel') }}</a-button>
<a-button type="primary" :loading="batchLoading" @click="confirmBatch"> <a-button type="primary" :loading="batchLoading" :disabled="target.length < 1" @click="confirmBatch">
{{ t('msbatchmodal.batchModalConfirm') }} {{ t('msBatchModal.batchModalConfirm') }}
</a-button> </a-button>
</template> </template>
</a-modal> </a-modal>
@ -40,6 +35,7 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import type { BatchModel } from './types'; import type { BatchModel } from './types';
import MsTransfer from '@/components/pure/ms-transfer/index.vue';
const { t } = useI18n(); const { t } = useI18n();
@ -49,18 +45,11 @@
children?: TreeDataItem[]; children?: TreeDataItem[];
} }
interface TransferDataItem {
value: string;
label: string;
disabled: boolean;
}
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
tableSelected: (string | number)[]; tableSelected: (string | number)[];
visible: boolean; visible: boolean;
action: string; action: string;
treeData: TreeDataItem[];
}>(), }>(),
{ {
visible: false, visible: false,
@ -70,7 +59,7 @@
(e: 'update:visible', val: boolean): void; (e: 'update:visible', val: boolean): void;
(e: 'addProject', targetValue: string[], type: string): void; (e: 'addProject', targetValue: string[], type: string): void;
(e: 'addUserGroup', targetValue: string[], type: string): void; (e: 'addUserGroup', targetValue: string[], type: string): void;
(e: 'addOrgnization', targetValue: string[], type: string): void; (e: 'addOrganization', targetValue: string[], type: string): void;
}>(); }>();
const showBatchModal = ref(false); const showBatchModal = ref(false);
@ -78,6 +67,7 @@
const batchTitle = ref(''); const batchTitle = ref('');
const target = ref<string[]>([]); const target = ref<string[]>([]);
const treeList = ref<TreeDataItem[]>([]); const treeList = ref<TreeDataItem[]>([]);
const loading = ref<boolean>(false);
function handleTableBatch(action: string) { function handleTableBatch(action: string) {
switch (action) { switch (action) {
@ -115,78 +105,38 @@
} }
); );
/**
* 获取穿梭框数据根据树结构获取
* @param _treeData 树结构
* @param transferDataSource 穿梭框数组
*/
const getTransferData = (_treeData: TreeDataItem[], transferDataSource: TransferDataItem[]) => {
_treeData.forEach((item) => {
if (item.children) getTransferData(item.children, transferDataSource);
else transferDataSource.push({ label: item.title, value: item.key, disabled: false });
});
return transferDataSource;
};
/**
* 获取树结构数据根据穿梭框过滤的数据获取
*/
const getTreeData = (data: TransferDataItem[]) => {
const values = data.map((item) => item.value);
const travel = (_treeData: TreeDataItem[]) => {
const treeDataSource: TreeDataItem[] = [];
_treeData.forEach((item) => {
// push 穿
const allSelected = item.children?.every((child) => target.value.includes(child.key));
if (!allSelected && (item.children || values.includes(item.key))) {
treeDataSource.push({
title: item.title,
key: item.key,
children: item.children ? travel(item.children) : [],
});
}
});
return treeDataSource;
};
return travel(treeList.value);
};
let transferData: TransferDataItem[] = [];
function cancelBatch() { function cancelBatch() {
showBatchModal.value = false; showBatchModal.value = false;
target.value = []; target.value = [];
} }
const batchRequestFun = async (reqFun: any, params: BatchModel) => { const batchRequestFun = async (reqFun: any, params: BatchModel) => {
batchLoading.value = true; batchLoading.value = true;
loading.value = true;
try { try {
await reqFun(params); await reqFun(params);
Message.success(t('organization.member.batchModalSuccess')); Message.success(t('msBatchModal.batchModalSuccess'));
showBatchModal.value = false; showBatchModal.value = false;
target.value = []; target.value = [];
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} finally { } finally {
batchLoading.value = false; batchLoading.value = false;
loading.value = false;
} }
}; };
const confirmBatch = async () => { const confirmBatch = async () => {
batchLoading.value = true;
if (target.value.length < 1) {
return;
}
try { try {
switch (props.action) { switch (props.action) {
case 'batchAddProject': case 'batchAddProject':
emit('addProject', target.value, 'project'); emit('addProject', target.value, 'project');
break; break;
case 'batchAddUserGroup': case 'batchAddUserGroup':
emit('addUserGroup', target.value, 'usergroup'); emit('addUserGroup', target.value, 'userGroup');
break; break;
case 'batchAddOrganization': case 'batchAddOrganization':
emit('addOrgnization', target.value, 'orgnization'); emit('addOrganization', target.value, 'organization');
break; break;
default: default:
break; break;
@ -195,17 +145,21 @@
console.log(error); console.log(error);
} }
}; };
watch(
() => props.treeData, const getTreeList = async (callBack: (orgId: string) => Promise<any>, orgId: string) => {
(newVal) => { loading.value = true;
treeList.value = newVal; try {
transferData = getTransferData(treeList.value, []); treeList.value = await callBack(orgId);
}, loading.value = false;
{ deep: true, immediate: true } } catch (error) {
); console.log(error);
}
};
defineExpose({ defineExpose({
batchLoading, batchLoading,
batchRequestFun, batchRequestFun,
getTreeList,
}); });
</script> </script>

View File

@ -1,8 +1,10 @@
export default { export default {
'msbatchmodal.batchModalSubTitle': '(Selected {count} users)', 'msBatchModal.batchModalSubTitle': '(Selected {count} users)',
'msbatchmodal.batchModalTip': 'Add project member usergroup as member by default', 'msBatchModal.batchModalTip': 'Add project member userGroup as member by default',
'msbatchmodal.batchOptional': 'Optional', 'msBatchModal.batchOptional': 'Optional',
'msbatchmodal.batchChosen': 'Chosen', 'msBatchModal.batchChosen': 'Chosen',
'msbatchmodal.batchModalCancel': 'Cancel', 'msBatchModal.batchModalCancel': 'Cancel',
'msbatchmodal.batchModalConfirm': 'Add', 'msBatchModal.batchModalConfirm': 'Add',
'msBatchModal.batchModalEmpty': 'The selection can not be empty',
'msBatchModal.batchModalSuccess': 'Successfully added',
}; };

View File

@ -1,8 +1,10 @@
export default { export default {
'msbatchmodal.batchModalSubTitle': '已选 {count} 个用户)', 'msBatchModal.batchModalSubTitle': '已选 {count} 个用户)',
'msbatchmodal.batchModalTip': '默认为成员添加项目成员用户组', 'msBatchModal.batchModalTip': '默认为成员添加项目成员用户组',
'msbatchmodal.batchOptional': '可选', 'msBatchModal.batchOptional': '可选',
'msbatchmodal.batchChosen': '已选', 'msBatchModal.batchChosen': '已选',
'msbatchmodal.batchModalCancel': '取消', 'msBatchModal.batchModalCancel': '取消',
'msbatchmodal.batchModalConfirm': '添加', 'msBatchModal.batchModalConfirm': '添加',
'msBatchModal.batchModalEmpty': '选择内容不能为空',
'msBatchModal.batchModalSuccess': '添加成功',
}; };

View File

@ -49,7 +49,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, useAttrs, watch } from 'vue'; import { ref, useAttrs, watch, watchEffect } from 'vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
const { t } = useI18n(); const { t } = useI18n();
@ -94,7 +94,11 @@
// //
const switchEnable = ref<boolean>(false); const switchEnable = ref<boolean>(false);
const dialogVisible = ref<boolean>(props.visible); const dialogVisible = ref<boolean>(false);
watchEffect(() => {
dialogVisible.value = props.visible;
});
watch( watch(
() => props.visible, () => props.visible,
@ -102,6 +106,12 @@
dialogVisible.value = val; dialogVisible.value = val;
} }
); );
watch(
() => dialogVisible.value,
(val) => {
emits('update:visible', val);
}
);
watch( watch(
() => props.switchProps?.enable, () => props.switchProps?.enable,

View File

@ -0,0 +1,29 @@
<template>
<a-tooltip :content="(props.tagList||[]).map((e: any) => e.name).join('')">
<div class="float-left flex min-h-[22px] max-w-[456px]">
<MsTag v-for="tag of props.tagList.slice(0, props.showNum)" :key="tag.id" v-bind="attrs">
<slot :tag="tag"> </slot>
</MsTag>
<MsTag v-if="props.tagList.length > props.showNum" v-bind="attrs"> +{{ props.showNum }}</MsTag>
</div>
</a-tooltip>
</template>
<script setup lang="ts">
import { useAttrs } from 'vue';
import MsTag from './ms-tag.vue';
const props = withDefaults(
defineProps<{
tagList: any;
showNum?: number;
}>(),
{
showNum: 2,
}
);
const attrs = useAttrs();
</script>
<style scoped lang="less"></style>

View File

@ -0,0 +1,121 @@
<template>
<a-tag
v-bind="attrs"
:type="props.type"
defer
:style="{ ...typeStyle, 'margin': tagMargin, 'max-width': '144px' }"
:size="props.size"
class="my-1"
>
<slot name="icon"></slot>
<span class="one-line-text"> <slot></slot></span>
</a-tag>
</template>
<script setup lang="ts">
import { computed, ref, useAttrs, watchEffect } from 'vue';
export type TagType = 'default' | 'primary' | 'danger' | 'warning' | 'success';
export type Size = 'small' | 'medium' | 'large';
export type Theme = 'dark' | 'light' | 'outline' | 'lightOutLine';
const attrs = useAttrs();
const props = withDefaults(
defineProps<{
type?: TagType; // tag
size?: Size; // tag
theme?: Theme; // tag
selfStyle?: any; //
}>(),
{
type: 'default',
theme: 'dark',
size: 'medium',
}
);
//
const tagMargin = computed(() => {
switch (props.size) {
case 'medium':
return '3px';
case 'large':
return '4px';
default:
return '2px';
}
});
//
const typeList: any = {
dark: {
'color': 'white',
'border-color': 'rgb(var(--#{}-5))',
'background': 'rgb(var(--#{}-5))',
},
light: {
color: 'rgb(var(--#{}-5))',
background: 'rgb(var(--#{}-1)',
},
outline: {
'border-color': 'rgb(var(--#{}-5))',
'color': 'rgb(var(--#{}-5))',
'background': 'transparent',
},
lightOutLine: {
'border-color': 'rgb(var(--#{}-5))',
'color': 'rgb(var(--#{}-5))',
'background': 'rgb(var(--#{}-1)',
},
default: {
'color': 'var(--color-text-1)',
'background': props.theme !== 'outline' ? 'var(--color-text-n8)' : 'white',
'border-color':
props.theme === 'lightOutLine' || props.theme === 'outline'
? 'var(--color-text-input-border)'
: 'var(--color-text-n8)',
},
};
const typeConst = ref<string>('');
const typeStyle = ref<string[]>();
// : > default >
const getTagType = (type: string, theme: string) => {
if (props.selfStyle && Object.keys(props.selfStyle).length > 0) {
typeStyle.value = props.selfStyle;
} else {
if (type === 'default') {
typeStyle.value = typeList.default;
return;
}
//
if (type === 'primary') {
typeConst.value = 'primary';
//
} else {
typeConst.value = type;
}
// style
if (theme !== 'default' && type !== 'default') {
const themeStyle = typeList[theme];
Object.keys(themeStyle).forEach((item) => {
themeStyle[item] = themeStyle[item].replace('#{}', typeConst.value);
});
typeStyle.value = themeStyle;
}
}
};
watchEffect(() => {
if (props.type && props.theme) {
getTagType(props.type, props.theme);
}
});
</script>
<style scoped lang="less">
:deep(.arco-icon) {
font-size: 14px;
color: var(--color-text-brand);
}
</style>

View File

@ -159,6 +159,51 @@ export const pathMap = [
route: RouteEnum.PROJECT_MANAGEMENT, route: RouteEnum.PROJECT_MANAGEMENT,
permission: [], permission: [],
level: MENU_LEVEL[2], level: MENU_LEVEL[2],
children: [], children: [
{
key: 'PROJECT_MANAGEMENT_PERMISSION', // 项目管理-项目与权限
locale: 'menu.projectManagement.projectPermission',
route: RouteEnum.PROJECT_MANAGEMENT_PERMISSION,
permission: [],
level: MENU_LEVEL[0],
children: [
{
key: 'PROJECT_MANAGEMENT_PERMISSION_BASIC_INFO', // 项目管理-项目与权限-基本信息
locale: 'project.permission.basicInfo',
route: RouteEnum.PROJECT_MANAGEMENT_PERMISSION_BASIC_INFO,
permission: [],
level: MENU_LEVEL[0],
},
{
key: 'PROJECT_MANAGEMENT_PERMISSION_MENU_MANAGEMENT', // 项目管理-项目与权限-菜单管理
locale: 'project.permission.menuManagement',
route: RouteEnum.PROJECT_MANAGEMENT_PERMISSION_MENU_MANAGEMENT,
permission: [],
level: MENU_LEVEL[0],
},
{
key: 'PROJECT_MANAGEMENT_PERMISSION_VERSION', // 项目管理-项目与权限-项目版本
locale: 'project.permission.projectVersion',
route: RouteEnum.PROJECT_MANAGEMENT_PERMISSION_VERSION,
permission: [],
level: MENU_LEVEL[0],
},
{
key: 'PROJECT_MANAGEMENT_PERMISSION_MEMBER', // 项目管理-项目与权限-成员
locale: 'project.permission.member',
route: RouteEnum.PROJECT_MANAGEMENT_PERMISSION_MEMBER,
permission: [],
level: MENU_LEVEL[0],
},
{
key: 'PROJECT_MANAGEMENT_PERMISSION_USER_GROUP', // 项目管理-项目与权限-用户组
locale: 'project.permission.userGroup',
route: RouteEnum.PROJECT_MANAGEMENT_PERMISSION_USER_GROUP,
permission: [],
level: MENU_LEVEL[0],
},
],
},
],
}, },
]; ];

View File

@ -3,3 +3,55 @@ export interface ProjectTreeData {
title: string; title: string;
children?: ProjectTreeData[]; children?: ProjectTreeData[];
} }
export interface UserGroupItem {
id: string;
name: string;
description: string;
internal: boolean;
type: string;
createTime: number | string;
updateTime: number | string;
createUser: string;
scopeId: string;
}
export interface ProjectMemberItem {
id?: string;
name: string;
email: string;
password: string;
enable: boolean; // 是否启用
createTime: number | string;
updateTime: number | string;
language: string;
lastOrganizationId: string; // 组织id
phone: string;
source: string;
lastProjectId: string; // 项目id
createUser: string;
updateUser: string;
deleted: true; // 是否被删除
userRoles: UserGroupItem[];
showUserSelect?: boolean; // 是否可以选择
selectUserList?: string[]; // 已选择项目用户组
}
export interface ActionProjectMember {
userId?: string;
projectId?: string; // 项目ID
userIds?: (string | number)[]; // 用户ID集合
roleIds?: string[]; // 用户组ID集合
}
export interface ProjectUserOption {
id: string;
name: string;
}
export interface SearchParams {
filter: {
roleIds: string[];
};
projectId: string;
keyword: '';
}

View File

@ -17,6 +17,7 @@ export interface UserState {
certification?: number; certification?: number;
role: RoleType; role: RoleType;
lastOrganizationId?: string; lastOrganizationId?: string;
lastProjectId?: string;
// 盐 // 盐
salt: string; salt: string;
} }

View File

@ -9,8 +9,8 @@
</MsTableMoreAction> </MsTableMoreAction>
</div> </div>
<div class="project-info mb-6 h-[112px] bg-white p-1"> <div class="project-info mb-6 h-[112px] bg-white p-1">
<div class="inner-wrapper p-4"> <div class="inner-wrapper rounded-md p-4">
<div class="detail-info flex flex-col justify-between p-4"> <div class="detail-info flex flex-col justify-between rounded-md p-4">
<div class="flex items-center"> <div class="flex items-center">
<span class="mr-1 font-medium text-[var(--color-text-000)]">具体的项目名称</span> <span class="mr-1 font-medium text-[var(--color-text-000)]">具体的项目名称</span>
<span v-if="!isDelete" class="button enable-button mr-1">{{ t('project.basicInfo.enable') }}</span> <span v-if="!isDelete" class="button enable-button mr-1">{{ t('project.basicInfo.enable') }}</span>
@ -55,6 +55,10 @@
label: 'project.basicInfo.edit', label: 'project.basicInfo.edit',
eventTag: 'edit', eventTag: 'edit',
}, },
{
label: 'project.basicInfo.enable',
eventTag: 'enable',
},
{ {
label: 'project.basicInfo.finish', label: 'project.basicInfo.finish',
eventTag: 'finish', eventTag: 'finish',

View File

@ -3,30 +3,30 @@
v-model:visible="visible" v-model:visible="visible"
dialog-size="medium" dialog-size="medium"
title="project.member.addMember" title="project.member.addMember"
:close="closeHandler"
:confirm="confirmFunHandler"
ok-text="project.member.add" ok-text="project.member.add"
:confirm="confirmHandler"
:close="closeHandler"
> >
<div class="form"> <div class="form">
<a-form ref="memberFormRef" :model="form" size="large" layout="vertical"> <a-form ref="memberFormRef" :model="form" size="large" layout="vertical">
<a-form-item <a-form-item
field="memberIds" field="userIds"
:label="t('project.member.member')" :label="t('project.member.member')"
asterisk-position="end" asterisk-position="end"
:rules="[{ required: true, message: t('project.member.selectMemberEmptyTip') }]" :rules="[{ required: true, message: t('project.member.selectMemberEmptyTip') }]"
> >
<a-select v-model="form.memberIds" multiple :placeholder="t('project.member.selectMemberScope')" allow-clear> <a-select v-model="form.userIds" multiple :placeholder="t('project.member.selectMemberScope')" allow-clear>
<a-option v-for="item of memberList" :key="item.id" :value="item.id">{{ item.name }}</a-option> <a-option v-for="item of memberList" :key="item.id" :value="item.id">{{ item.name }}</a-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item <a-form-item
field="userRoleIds" field="roleIds"
:label="t('project.member.tableColumnUserGroup')" :label="t('project.member.tableColumnUserGroup')"
asterisk-position="end" asterisk-position="end"
:rules="[{ required: true, message: t('project.member.selectUserEmptyTip') }]" :rules="[{ required: true, message: t('project.member.selectUserEmptyTip') }]"
> >
<a-select v-model="form.userRoleIds" multiple allow-clear :placeholder="t('project.member.selectUserScope')"> <a-select v-model="form.roleIds" multiple allow-clear :placeholder="t('project.member.selectUserScope')">
<a-option v-for="item of userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option> <a-option v-for="item of props.userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
</a-form> </a-form>
@ -35,49 +35,87 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref, watch } from 'vue';
import MsDialog from '@/components/pure/ms-dialog/index.vue'; import MsDialog from '@/components/pure/ms-dialog/index.vue';
import { getProjectMemberOptions, addOrUpdateProjectMember } from '@/api/modules/project-management/projectMember';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { useUserStore } from '@/store';
import { FormInstance, Message } from '@arco-design/web-vue'; import { FormInstance, Message } from '@arco-design/web-vue';
import type { ProjectUserOption, ActionProjectMember } from '@/models/projectManagement/projectAndPermission';
const { t } = useI18n(); const { t } = useI18n();
const userStore = useUserStore();
const lastProjectId = userStore.$state?.lastProjectId;
const props = defineProps<{
userGroupOptions: ProjectUserOption[];
}>();
const emits = defineEmits<{
(e: 'update:visible', visible: boolean): void;
(e: 'success'): void;
}>();
const visible = ref<boolean>(false); const visible = ref<boolean>(false);
const initFormValue = {
userRoleIds: [],
memberIds: [],
};
const form = ref({ ...initFormValue });
const memberList = ref([ const initFormValue: ActionProjectMember = {
{ roleIds: ['project_member'],
id: '', userIds: [],
name: '全部', projectId: lastProjectId,
}, };
]);
const userGroupOptions = ref([ const form = ref<ActionProjectMember>({ ...initFormValue });
{
id: '',
name: '全部',
},
]);
const memberFormRef = ref<FormInstance | null>(null); const memberFormRef = ref<FormInstance | null>(null);
const confirmFunHandler = async () => { const closeHandler = () => {
memberFormRef.value?.resetFields();
visible.value = false;
form.value = { ...initFormValue };
};
//
const confirmHandler = async () => {
await memberFormRef.value?.validate().then(async (error) => { await memberFormRef.value?.validate().then(async (error) => {
if (!error) { if (!error) {
console.log(error); try {
await addOrUpdateProjectMember(form.value);
Message.success(t('project.member.batchModalSuccess'));
closeHandler();
emits('success');
} catch (e) {
console.log(e);
}
} else { } else {
return false; return false;
} }
}); });
}; };
const closeHandler = () => { const memberList = ref<ProjectUserOption[]>([]);
memberFormRef.value?.resetFields();
visible.value = false; //
const initProjectMemberOptions = async () => {
try {
if (lastProjectId) {
const result = await getProjectMemberOptions(lastProjectId);
memberList.value = result;
}
} catch (error) {
console.log(error);
}
}; };
watch(
() => visible.value,
(val) => {
emits('update:visible', val);
}
);
defineExpose({
initProjectMemberOptions,
});
</script> </script>
<style scoped></style> <style scoped></style>

View File

@ -4,10 +4,8 @@
><a-button class="mr-3" type="primary" @click="addMember">{{ t('project.member.addMember') }}</a-button></div ><a-button class="mr-3" type="primary" @click="addMember">{{ t('project.member.addMember') }}</a-button></div
> >
<div> <div>
<a-select v-model="searchParams.userId"> <a-select v-model="roleIds" allow-search @change="changeSelect">
<a-option v-for="item of userGroupListOptions" :key="item.value" :value="item.value">{{ <a-option v-for="item of userGroupAll" :key="item.id" :value="item.id">{{ t(item.name) }}</a-option>
t(item.name)
}}</a-option>
<template #prefix <template #prefix
><span>{{ t('project.member.tableColumnUserGroup') }}</span></template ><span>{{ t('project.member.tableColumnUserGroup') }}</span></template
> >
@ -15,6 +13,7 @@
> >
<div> <div>
<a-input-search <a-input-search
v-model="searchParams.keyword"
:max-length="250" :max-length="250"
:placeholder="t('project.member.searchMember')" :placeholder="t('project.member.searchMember')"
allow-clear allow-clear
@ -31,25 +30,33 @@
@batch-action="handleTableBatch" @batch-action="handleTableBatch"
> >
<template #userRole="{ record }"> <template #userRole="{ record }">
<a-tooltip :content="(record.userRoleIdNameMap||[]).map((e: any) => e.name).join(',')"> <a-tooltip :content="(record.userRoles||[]).map((e: any) => e.name).join(',')">
<div v-if="!record.showUserSelect"> <div v-if="!record.showUserSelect">
<a-tag <a-tag
v-for="org of (record.userRoleIdNameMap || []).slice(0, 3)" v-for="org of (record.userRoles || []).slice(0, 3)"
:key="org" :key="org"
class="mr-[4px] border-[rgb(var(--primary-5))] bg-transparent !text-[rgb(var(--primary-5))]" class="mr-[4px] border-[rgb(var(--primary-5))] bg-transparent !text-[rgb(var(--primary-5))]"
bordered bordered
@click="changeUser(record)"
> >
{{ org.name }} {{ org.name }}
</a-tag> </a-tag>
<a-tag <a-tag
v-if="record.userRoleIdNameMap.length > 3" v-if="(record.userRoles || []).length > 3"
class="mr-[4px] border-[rgb(var(--primary-5))] bg-transparent !text-[rgb(var(--primary-5))]" class="mr-[4px] border-[rgb(var(--primary-5))] bg-transparent !text-[rgb(var(--primary-5))]"
bordered bordered
@click="changeUser(record)"
> >
+{{ record.userRoleIdNameMap.length - 3 }} +{{ (record.userRoles || []).length - 3 }}
</a-tag> </a-tag>
</div> </div>
<a-select v-else v-model="record.selectUserList" multiple :max-tag-count="2"> <a-select
v-else
v-model="record.selectUserList"
multiple
:max-tag-count="2"
@popup-visible-change="(value) => userGroupChange(value, record)"
>
<a-option v-for="item of userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option> <a-option v-for="item of userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
</a-select> </a-select>
</a-tooltip> </a-tooltip>
@ -69,28 +76,40 @@
position="br" position="br"
:title="t('project.member.deleteMemberTip', { name: characterLimit(record.name) })" :title="t('project.member.deleteMemberTip', { name: characterLimit(record.name) })"
:sub-title-tip="t('project.member.subTitle')" :sub-title-tip="t('project.member.subTitle')"
@ok="removeMember(record)"
/> />
</template> </template>
</ms-base-table> </ms-base-table>
<AddMemberModal v-model:visible="addMemberVisible" /> <AddMemberModal
ref="projectMemberRef"
v-model:visible="addMemberVisible"
:user-group-options="userGroupOptions"
@success="loadList()"
/>
<MSBatchModal <MSBatchModal
ref="batchModalRef" ref="batchModalRef"
v-model:visible="batchVisible" v-model:visible="batchVisible"
:table-selected="tableSelected" :table-selected="tableSelected"
:action="batchAction" :action="batchAction"
:tree-data="treeData"
:select-data="selectData" :select-data="selectData"
@add-user-group="addUserGroup" @add-user-group="addUserGroup"
/> />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onBeforeMount } from 'vue'; import { ref, onBeforeMount, onMounted } from 'vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsRemoveButton from '@/components/business/ms-remove-button/MsRemoveButton.vue'; import MsRemoveButton from '@/components/business/ms-remove-button/MsRemoveButton.vue';
import { getMemberList } from '@/api/modules/setting/member'; import {
getProjectMemberList,
getProjectUserGroup,
addOrUpdateProjectMember,
batchRemoveMember,
removeProjectMember,
addProjectUserGroup,
} from '@/api/modules/project-management/projectMember';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { useTableStore, useUserStore } from '@/store'; import { useTableStore, useUserStore } from '@/store';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
@ -98,27 +117,22 @@
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import AddMemberModal from './components/addMemberModal.vue'; import AddMemberModal from './components/addMemberModal.vue';
import MSBatchModal from '@/components/business/ms-batch-modal/index.vue'; import MSBatchModal from '@/components/business/ms-batch-modal/index.vue';
import type { ProjectTreeData } from '@/models/projectManagement/projectAndPermission'; import { Message } from '@arco-design/web-vue';
import type {
ProjectTreeData,
ProjectUserOption,
ActionProjectMember,
ProjectMemberItem,
SearchParams,
} from '@/models/projectManagement/projectAndPermission';
const { t } = useI18n(); const { t } = useI18n();
const { openModal } = useModal(); const { openModal } = useModal();
const tableStore = useTableStore(); const tableStore = useTableStore();
const userStore = useUserStore(); const userStore = useUserStore();
const lastOrganizationId = userStore?.$state.lastOrganizationId; const lastProjectId = userStore?.$state?.lastProjectId;
const userGroupListOptions = ref([
{
id: '',
name: '全部',
value: '',
},
{
id: '1001',
name: '用户组1',
value: '1001',
},
]);
const columns: MsTableColumn = [ const columns: MsTableColumn = [
{ {
title: 'project.member.tableColumnEmail', title: 'project.member.tableColumnEmail',
@ -180,7 +194,7 @@
tableSelected.value = selectArr; tableSelected.value = selectArr;
}; };
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getMemberList, { const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getProjectMemberList, {
tableKey: TableKeyEnum.PROJECT_MEMBER, tableKey: TableKeyEnum.PROJECT_MEMBER,
selectable: true, selectable: true,
showSetting: true, showSetting: true,
@ -189,19 +203,31 @@
}, },
}); });
const searchParams = ref<SearchParams>({
filter: {
roleIds: [],
},
projectId: lastProjectId as string,
keyword: '',
});
const roleIds = ref<string>('');
const initData = async () => { const initData = async () => {
setLoadListParams({ organizationId: lastOrganizationId }); setLoadListParams({ ...searchParams.value });
await loadList(); await loadList();
}; };
const searchParams = ref({ const searchHandler = () => {
userId: '', initData();
}); };
const searchHandler = () => {}; const changeSelect = () => {
searchParams.value.filter.roleIds = roleIds.value ? [roleIds.value] : [];
initData();
};
// //
const batchRemoveMember = () => { const batchRemoveHandler = () => {
openModal({ openModal({
type: 'error', type: 'error',
title: t('project.member.batchRemoveTip', { number: tableSelected.value.length }), title: t('project.member.batchRemoveTip', { number: tableSelected.value.length }),
@ -211,44 +237,128 @@
okButtonProps: { okButtonProps: {
status: 'danger', status: 'danger',
}, },
onBeforeOk: async () => {}, onBeforeOk: async () => {
try {
const params: ActionProjectMember = {
projectId: lastProjectId,
userIds: tableSelected.value,
};
await batchRemoveMember(params);
Message.success(t('project.member.deleteMemberSuccess'));
loadList();
} catch (error) {
console.log(error);
}
},
hideCancel: false, hideCancel: false,
}); });
}; };
//
const removeMember = async (record: ProjectMemberItem) => {
try {
if (lastProjectId && record.id) {
await removeProjectMember(lastProjectId, record.id);
Message.success(t('project.member.deleteMemberSuccess'));
loadList();
}
} catch (error) {
console.log(error);
}
};
const batchVisible = ref<boolean>(false); const batchVisible = ref<boolean>(false);
const selectData = ref<string[]>([]); const selectData = ref<string[]>([]);
const batchAction = ref(''); const batchAction = ref('');
const treeData = ref<ProjectTreeData[]>([]); const treeData = ref<ProjectTreeData[]>([]);
const userGroupOptions = ref<ProjectUserOption[]>([]);
const batchModalRef = ref();
// //
const addUserGroup = () => {}; const addUserGroup = async (target: string[]) => {
const params = {
projectId: lastProjectId,
userIds: tableSelected.value,
roleIds: target,
};
try {
await batchModalRef.value.batchRequestFun(addProjectUserGroup, params);
loadList();
} catch (error) {
console.log(error);
}
};
//
const handleTableBatch = (actionItem: any) => { const handleTableBatch = (actionItem: any) => {
if (actionItem.eventTag === 'batchActionRemove') { if (actionItem.eventTag === 'batchActionRemove') {
batchRemoveMember(); batchRemoveHandler();
} }
if (actionItem.eventTag === 'batchAddUserGroup') { if (actionItem.eventTag === 'batchAddUserGroup') {
batchVisible.value = true; batchVisible.value = true;
addUserGroup(); batchAction.value = actionItem.eventTag;
batchModalRef.value.getTreeList(getProjectUserGroup, lastProjectId);
} }
}; };
const userGroupOptions = ref([ //
{
id: '',
name: '',
},
]);
const addMemberVisible = ref<boolean>(false); const addMemberVisible = ref<boolean>(false);
const projectMemberRef = ref();
const addMember = () => { const addMember = () => {
addMemberVisible.value = true; addMemberVisible.value = true;
projectMemberRef.value.initProjectMemberOptions();
}; };
onBeforeMount(() => { //
const editProjectMember = async (record: ProjectMemberItem) => {
const params: ActionProjectMember = {
projectId: lastProjectId,
userId: record.id,
roleIds: record.selectUserList,
};
try {
await addOrUpdateProjectMember(params);
Message.success(t('project.member.batchUpdateSuccess'));
record.showUserSelect = false;
loadList();
} catch (error) {
console.log(error);
}
};
//
const changeUser = (record: ProjectMemberItem) => {
if (record.enable) {
record.showUserSelect = true;
record.selectUserList = (record.userRoles || []).map((item) => item.id);
}
};
//
const userGroupChange = (visible: boolean, record: ProjectMemberItem) => {
if (visible) {
return;
}
if ((record.selectUserList || []).length < 1) {
Message.warning(t('project.member.selectUserEmptyTip'));
return;
}
editProjectMember(record);
};
const userGroupAll = ref<ProjectUserOption[]>([]);
onBeforeMount(async () => {
initData(); initData();
userGroupOptions.value = await getProjectUserGroup(lastProjectId as string);
userGroupAll.value = [
{
id: '',
name: '全部',
},
...userGroupOptions.value,
];
}); });
</script> </script>

View File

@ -5,7 +5,6 @@ export default {
'project.member.remove': 'Remove', 'project.member.remove': 'Remove',
'project.member.edit': 'Edit', 'project.member.edit': 'Edit',
'project.member.add': 'Add', 'project.member.add': 'Add',
'project.member.batchActionAddProject': 'Add to project',
'project.member.batchActionAddUserGroup': 'Add to usergroup', 'project.member.batchActionAddUserGroup': 'Add to usergroup',
'project.member.tableEnable': 'Enabled', 'project.member.tableEnable': 'Enabled',
'project.member.tableDisable': 'Disabled', 'project.member.tableDisable': 'Disabled',
@ -28,7 +27,7 @@ export default {
'system.user.deleteUserTip': 'Are you sure to delete the user `{name}` ?', 'system.user.deleteUserTip': 'Are you sure to delete the user `{name}` ?',
'project.member.deleteMemberConfirm': 'Delete', 'project.member.deleteMemberConfirm': 'Delete',
'project.member.deleteMemberCancel': 'Cancel', 'project.member.deleteMemberCancel': 'Cancel',
'project.member.deleteMemberSuccess': 'Delete successful', 'project.member.deleteMemberSuccess': 'Remove successful',
'project.member.batchModalSuccess': 'Successfully added', 'project.member.batchModalSuccess': 'Successfully added',
'project.member.batchUpdateSuccess': 'Successfully updated', 'project.member.batchUpdateSuccess': 'Successfully updated',
'project.member.project': 'Project', 'project.member.project': 'Project',

View File

@ -5,7 +5,6 @@ export default {
'project.member.remove': '移除', 'project.member.remove': '移除',
'project.member.edit': '编辑', 'project.member.edit': '编辑',
'project.member.add': '添加', 'project.member.add': '添加',
'project.member.batchActionAddProject': '添加至项目',
'project.member.batchActionAddUserGroup': '添加至用户组', 'project.member.batchActionAddUserGroup': '添加至用户组',
'project.member.tableEnable': '正常', 'project.member.tableEnable': '正常',
'project.member.tableDisable': '禁用', 'project.member.tableDisable': '禁用',
@ -27,7 +26,7 @@ export default {
'project.member.deleteMemberTip': '确认移除 {name} 这个成员吗?', 'project.member.deleteMemberTip': '确认移除 {name} 这个成员吗?',
'project.member.deleteMemberConfirm': '确认删除', 'project.member.deleteMemberConfirm': '确认删除',
'project.member.deleteMemberCancel': '取消', 'project.member.deleteMemberCancel': '取消',
'project.member.deleteMemberSuccess': '除成功', 'project.member.deleteMemberSuccess': '除成功',
'project.member.batchModalSuccess': '添加成功', 'project.member.batchModalSuccess': '添加成功',
'project.member.batchUpdateSuccess': '更新成功', 'project.member.batchUpdateSuccess': '更新成功',
'project.member.project': '项目', 'project.member.project': '项目',

View File

@ -5,6 +5,7 @@
class="ms-modal-form ms-modal-medium" class="ms-modal-form ms-modal-medium"
:ok-text="t('organization.member.Confirm')" :ok-text="t('organization.member.Confirm')"
:cancel-text="t('organization.member.Cancel')" :cancel-text="t('organization.member.Cancel')"
@close="handleCancel"
> >
<template #title> <template #title>
{{ {{

View File

@ -24,71 +24,52 @@
@batch-action="handleTableBatch" @batch-action="handleTableBatch"
> >
<template #project="{ record }"> <template #project="{ record }">
<a-tooltip :content="(record.projectIdNameMap||[]).map((e: any) => e.name).join(',')"> <MsTagGroup
<div v-if="!record.showProjectSelect"> v-if="!record.showProjectSelect"
<a-tag :tag-list="record.projectIdNameMap || []"
v-for="pro of (record.projectIdNameMap || []).slice(0, 3)" :show-num="2"
:key="pro.id" theme="outline"
class="mr-[4px] bg-transparent" @click="changeUserOrProject(record, 'project')"
bordered >
@click="changeUserOrProject(record, 'project')" <template #default="{ tag }">
> {{ tag.name }}
{{ pro.name }} </template>
</a-tag> </MsTagGroup>
<a-tag <a-select
v-if="(record.projectIdNameMap || []).length > 3" v-else
class="mr-[4px] bg-transparent" v-model="record.selectProjectList"
bordered multiple
@click="changeUserOrProject(record, 'project')" :max-tag-count="2"
> size="small"
+{{ (record.projectIdNameMap || []).length - 3 }} @change="(value) => selectUserOrProject(value, record, 'project')"
</a-tag> @popup-visible-change="visibleChange($event, record, 'project')"
</div> >
<a-select <a-option v-for="item of projectOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
v-else </a-select>
v-model="record.selectProjectList"
multiple
:max-tag-count="2"
size="small"
@change="(value) => selectUserOrProject(value, record, 'project')"
@popup-visible-change="visibleChange($event, record, 'project')"
>
<a-option v-for="item of projectOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
</a-select>
</a-tooltip>
</template> </template>
<template #userRole="{ record }"> <template #userRole="{ record }">
<a-tooltip :content="(record.userRoleIdNameMap||[]).map((e: any) => e.name).join(',')"> <MsTagGroup
<div v-if="!record.showUserSelect"> v-if="!record.showUserSelect"
<a-tag :tag-list="record.userRoleIdNameMap || []"
v-for="org of (record.userRoleIdNameMap || []).slice(0, 3)" :show-num="2"
:key="org" type="primary"
class="mr-[4px] border-[rgb(var(--primary-5))] bg-transparent !text-[rgb(var(--primary-5))]" theme="outline"
bordered @click="changeUserOrProject(record, 'user')"
@click="changeUserOrProject(record, 'user')" >
> <template #default="{ tag }">
{{ org.name }} {{ tag.name }}
</a-tag> </template>
<a-tag </MsTagGroup>
v-if="record.userRoleIdNameMap.length > 3" <a-select
class="mr-[4px] border-[rgb(var(--primary-5))] bg-transparent !text-[rgb(var(--primary-5))]" v-else
bordered v-model="record.selectUserList"
@click="changeUserOrProject(record, 'user')" multiple
> :max-tag-count="2"
+{{ record.userRoleIdNameMap.length - 3 }} @change="(value) => selectUserOrProject(value, record, 'user')"
</a-tag> @popup-visible-change="(value) => visibleChange(value, record, 'user')"
</div> >
<a-select <a-option v-for="item of userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
v-else </a-select>
v-model="record.selectUserList"
multiple
:max-tag-count="2"
@change="(value) => selectUserOrProject(value, record, 'user')"
@popup-visible-change="(value) => visibleChange(value, record, 'user')"
>
<a-option v-for="item of userGroupOptions" :key="item.id" :value="item.id">{{ item.name }}</a-option>
</a-select>
</a-tooltip>
</template> </template>
<template #enable="{ record }"> <template #enable="{ record }">
<div v-if="record.enable" class="flex items-center"> <div v-if="record.enable" class="flex items-center">
@ -119,12 +100,10 @@
@success="initData()" @success="initData()"
/> />
<MSBatchModal <MSBatchModal
v-if="treeData.length > 0"
ref="batchModalRef" ref="batchModalRef"
v-model:visible="showBatchModal" v-model:visible="showBatchModal"
:table-selected="tableSelected" :table-selected="tableSelected"
:action="batchAction" :action="batchAction"
:tree-data="treeData"
:select-data="selectData" :select-data="selectData"
@add-project="addProjectOrAddUserGroup" @add-project="addProjectOrAddUserGroup"
@add-user-group="addProjectOrAddUserGroup" @add-user-group="addProjectOrAddUserGroup"
@ -154,19 +133,14 @@
import MSBatchModal from '@/components/business/ms-batch-modal/index.vue'; import MSBatchModal from '@/components/business/ms-batch-modal/index.vue';
import { useTableStore, useUserStore } from '@/store'; import { useTableStore, useUserStore } from '@/store';
import type { MsTableColumn } from '@/components/pure/ms-table/type'; import type { MsTableColumn } from '@/components/pure/ms-table/type';
import type { import type { MemberItem, AddorUpdateMemberModel, LinkList, BatchAddProjectModel } from '@/models/setting/member';
MemberItem,
AddorUpdateMemberModel,
LinkList,
LinkItem,
BatchAddProjectModel,
} from '@/models/setting/member';
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
const tableStore = useTableStore(); const tableStore = useTableStore();
const { t } = useI18n(); const { t } = useI18n();
const userStore = useUserStore(); const userStore = useUserStore();
const lastOrganizationId = userStore.$state?.lastOrganizationId as string; const lastOrganizationId = userStore.$state?.lastOrganizationId;
const columns: MsTableColumn = [ const columns: MsTableColumn = [
{ {
@ -237,13 +211,6 @@
const tableSelected = ref<(string | number)[]>([]); const tableSelected = ref<(string | number)[]>([]);
const selectData = ref<string[]>([]); const selectData = ref<string[]>([]);
interface TreeDataItem {
key: string;
title: string;
children?: TreeDataItem[];
}
const batchAction = ref('');
const initData = async () => { const initData = async () => {
setLoadListParams({ keyword: keyword.value, organizationId: lastOrganizationId }); setLoadListParams({ keyword: keyword.value, organizationId: lastOrganizationId });
await loadList(); await loadList();
@ -264,7 +231,7 @@
}; };
const deleteMember = async (record: MemberItem) => { const deleteMember = async (record: MemberItem) => {
try { try {
await deleteMemberReq(lastOrganizationId, record.id); if (lastOrganizationId) await deleteMemberReq(lastOrganizationId, record.id);
Message.success(t('organization.member.deleteMemberSuccess')); Message.success(t('organization.member.deleteMemberSuccess'));
initData(); initData();
} catch (error) { } catch (error) {
@ -275,23 +242,12 @@
tableSelected.value = selectArr; tableSelected.value = selectArr;
}; };
const treeData = ref<TreeDataItem[]>([]); const batchModalRef = ref();
const getData = async (callBack: any) => {
try { const getData = (callBack: any) => {
const links = await callBack(lastOrganizationId); batchModalRef.value.getTreeList(callBack, lastOrganizationId);
treeData.value = links.map((item: LinkItem) => {
return {
title: item.name,
key: item.id,
id: item.id,
};
});
} catch (error) {
console.log(error);
}
}; };
const batchModalRef = ref();
const showBatchModal = ref(false); const showBatchModal = ref(false);
const batchList = [ const batchList = [
@ -300,10 +256,13 @@
request: batchAddProject, request: batchAddProject,
}, },
{ {
type: 'usergroup', type: 'userGroup',
request: batchAddUserGroup, request: batchAddUserGroup,
}, },
]; ];
const batchAction = ref('');
// //
const addProjectOrAddUserGroup = async (target: string[], type: string) => { const addProjectOrAddUserGroup = async (target: string[], type: string) => {
const currentType = batchList.find((item) => item.type === type); const currentType = batchList.find((item) => item.type === type);
@ -322,7 +281,6 @@
// //
const handleTableBatch = (actionItem: any) => { const handleTableBatch = (actionItem: any) => {
showBatchModal.value = true; showBatchModal.value = true;
treeData.value = [];
batchAction.value = actionItem.eventTag; batchAction.value = actionItem.eventTag;
if (actionItem.eventTag === 'batchAddProject') getData(getProjectList); if (actionItem.eventTag === 'batchAddProject') getData(getProjectList);
if (actionItem.eventTag === 'batchAddUserGroup') getData(getGlobalUserGroup); if (actionItem.eventTag === 'batchAddUserGroup') getData(getGlobalUserGroup);
@ -383,8 +341,10 @@
const userGroupOptions = ref<LinkList>([]); const userGroupOptions = ref<LinkList>([]);
const projectOptions = ref<LinkList>([]); const projectOptions = ref<LinkList>([]);
const getLinkList = async () => { const getLinkList = async () => {
userGroupOptions.value = await getGlobalUserGroup(lastOrganizationId); if (lastOrganizationId) {
projectOptions.value = await getProjectList(lastOrganizationId); userGroupOptions.value = await getGlobalUserGroup(lastOrganizationId);
projectOptions.value = await getProjectList(lastOrganizationId);
}
}; };
onBeforeMount(() => { onBeforeMount(() => {
initData(); initData();