refactor: 用户组组织项目的用户选择&登录加密
This commit is contained in:
parent
7767502504
commit
9c34f9d3ad
|
@ -47,6 +47,7 @@
|
|||
"dayjs": "^1.11.8",
|
||||
"echarts": "^5.4.2",
|
||||
"hotbox-minder": "1.0.15",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"jsonpath-picker-vanilla": "^1.2.4",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
|
|
|
@ -12,7 +12,11 @@ export default function checkStatus(status: number, msg: string, errorMessageMod
|
|||
errMessage = `${msg}`;
|
||||
break;
|
||||
case 401: {
|
||||
if (msg.length > 100) {
|
||||
setSalt(msg);
|
||||
} else {
|
||||
errMessage = msg || t('api.errMsg401');
|
||||
}
|
||||
if (!isLoginPage()) {
|
||||
// 不是登录页再调用logout
|
||||
logout();
|
||||
|
|
|
@ -75,6 +75,11 @@ export function addUserToOrgOrProject(data: AddUserToOrgOrProjectParams) {
|
|||
export function getUserByOrganizationOrProject(sourceId: string) {
|
||||
return MSR.get({ url: `${orgUrl.getUserByOrgOrProjectUrl}${sourceId}` });
|
||||
}
|
||||
|
||||
// 系统-获取管理员下拉选项
|
||||
export function getAdminByOrganizationOrProject() {
|
||||
return MSR.get({ url: `${orgUrl.getAdminByOrgOrProjectUrl}` });
|
||||
}
|
||||
// 删除组织或项目成员
|
||||
export function deleteUserFromOrgOrProject(sourceId: string, userId: string, isOrg = true) {
|
||||
return MSR.get({
|
||||
|
@ -147,3 +152,13 @@ export function deleteProjectMemberByOrg(projectId: string, userId: string) {
|
|||
export function addProjectMemberByOrg(data: AddUserToOrgOrProjectParams) {
|
||||
return MSR.post({ url: orgUrl.postAddProjectMemberByOrgUrl, data });
|
||||
}
|
||||
|
||||
// 组织-获取项目下的管理员选项
|
||||
export function getAdminByProjectByOrg(organizationId: string) {
|
||||
return MSR.get({ url: `${orgUrl.getAdminByOrganizationOrProjectUrl}${organizationId}` });
|
||||
}
|
||||
|
||||
// 组织-获取成员下的成员选项
|
||||
export function getUserByProjectByOrg(organizationId: string, projectId: string) {
|
||||
return MSR.get({ url: `${orgUrl.getUserByOrganizationOrProjectUrl}${organizationId}/${projectId}` });
|
||||
}
|
||||
|
|
|
@ -67,6 +67,16 @@ export function saveGlobalUSetting(data: SaveGlobalUSettingData) {
|
|||
return MSR.post<UserGroupAuthSetting[]>({ url: ugUrl.editGlobalUSettingUrl, data });
|
||||
}
|
||||
|
||||
// 系统-获取需要关联的用户选项
|
||||
export function getSystemUserGroupOption(id: string) {
|
||||
return MSR.get<UserTableItem[]>({ url: `${ugUrl.getSystemUserGroupOptionUrl}${id}` });
|
||||
}
|
||||
|
||||
// 组织-获取需要关联的用户选项
|
||||
export function getOrgUserGroupOption(organizationId: string, roleId: string) {
|
||||
return MSR.get<UserTableItem[]>({ url: `${ugUrl.getOrgUserGroupOptionUrl}${organizationId}/${roleId}` });
|
||||
}
|
||||
|
||||
// 组织-编辑用户组对应的权限配置
|
||||
export function saveOrgUSetting(data: SaveGlobalUSettingData) {
|
||||
return MSR.post<UserGroupAuthSetting[]>({ url: ugUrl.editOrgUSettingUrl, data });
|
||||
|
@ -86,8 +96,8 @@ export function deleteUserFromUserGroup(id: string) {
|
|||
return MSR.get<string>({ url: `${ugUrl.deleteUserFromUserGroupUrl}${id}` });
|
||||
}
|
||||
// 组织-删除用户组对应的用户
|
||||
export function deleteOrgUserFromUserGroup(id: string) {
|
||||
return MSR.get<string>({ url: `${ugUrl.deleteOrgUserFromUserGroupUrl}${id}` });
|
||||
export function deleteOrgUserFromUserGroup(data: { userRoleId: string; userIds: string[]; organizationId: string }) {
|
||||
return MSR.post<CommonList<UserTableItem[]>>({ url: ugUrl.deleteOrgUserFromUserGroupUrl, data });
|
||||
}
|
||||
// 系统-添加用户到用户组
|
||||
export function addUserToUserGroup(data: { roleId: string; userIds: string[] }) {
|
||||
|
|
|
@ -48,7 +48,7 @@ export const getDeleteProjectUrl = '/system/project/delete/';
|
|||
// 系统-组织及项目,获取用户下拉选项
|
||||
export const getUserByOrgOrProjectUrl = '/system/organization/get-option/';
|
||||
// 系统-组织及项目,获取管理员下拉选项
|
||||
export const getAdminByOrgOrProjectUrl = '/system/organization/get-admin-option/';
|
||||
export const getAdminByOrgOrProjectUrl = '/system/project/user-list';
|
||||
// 启用项目
|
||||
export const getEnableProjectUrl = '/system/project/enable/';
|
||||
// 禁用项目
|
||||
|
@ -82,3 +82,7 @@ export const getEnableProjectByOrgUrl = '/organization/project/enable/';
|
|||
export const getDisableProjectByOrgUrl = '/organization/project/disable/';
|
||||
// 删除项目
|
||||
export const getDeleteProjectByOrgUrl = '/organization/project/delete/';
|
||||
// 获取成员下拉选项
|
||||
export const getUserByOrganizationOrProjectUrl = '/organization/project/user-member-list/';
|
||||
// 获取管理员下拉选项
|
||||
export const getAdminByOrganizationOrProjectUrl = '/organization/project/user-admin-list/';
|
||||
|
|
|
@ -20,6 +20,8 @@ export const postUserByUserGroupUrl = `/user/role/relation/global/list`;
|
|||
export const addUserToUserGroupUrl = `/user/role/relation/global/add`;
|
||||
/** 删除用户组用户 */
|
||||
export const deleteUserFromUserGroupUrl = `/user/role/relation/global/delete/`;
|
||||
/** 获取需要关联的用户选项 */
|
||||
export const getSystemUserGroupOptionUrl = `/user/role/relation//global/user/option/`;
|
||||
|
||||
/** 组织 */
|
||||
// 组织-修改用户组
|
||||
|
@ -41,4 +43,6 @@ export const postOrgUserByUserGroupUrl = `/user/role/organization/list-member`;
|
|||
/** 组织-用户组添加用户 */
|
||||
export const addOrgUserToUserGroupUrl = `/user/role/organization/add-member`;
|
||||
/** 组织-删除用户组用户 */
|
||||
export const deleteOrgUserFromUserGroupUrl = `/user/role/organization/delete/`;
|
||||
export const deleteOrgUserFromUserGroupUrl = `/user/role/organization/remove-member`;
|
||||
/** 组织-给用户组添加用户下拉选项 */
|
||||
export const getOrgUserGroupOptionUrl = `/user/role/organization/get-member/option/`;
|
||||
|
|
|
@ -1,100 +1,130 @@
|
|||
<template>
|
||||
<a-select
|
||||
v-model="currentValue"
|
||||
:disabled="props.disabled"
|
||||
:model-value="currentValue"
|
||||
:placeholder="t(props.placeholder || 'common.pleaseSelectMember')"
|
||||
multiple
|
||||
:placeholder="props.placeholder ? t(props.placeholder) : t('common.pleaseSelectMember')"
|
||||
value-key="id"
|
||||
@search="handleSearch"
|
||||
@change="handleChange"
|
||||
:value-key="props.valueKey"
|
||||
:disabled="props.disabled"
|
||||
allow-clear
|
||||
@change="change"
|
||||
@search="search"
|
||||
>
|
||||
<template #label="{ data }">
|
||||
<span class="option-name"> {{ data.value.name }} </span>
|
||||
<span class="text-[var(--color-text-1)]"> {{ data.value.name }} </span>
|
||||
</template>
|
||||
<a-option v-for="data in userOptions" :key="data.id" :disabled="(data.disabled as boolean)" :value="data">
|
||||
<span class="option-name"> {{ data.name }} </span>
|
||||
<span class="option-email"> {{ `(${data.email})` }} </span>
|
||||
<a-option v-for="data in currentOptions" :key="data.id" :disabled="data.disabled" :value="data">
|
||||
<span :class="data.disabled ? 'text-[var(--color-text-4)]' : 'text-[var(--color-text-1)]'">
|
||||
{{ data.name }}
|
||||
</span>
|
||||
<span v-if="data.email" class="text-[var(--color-text-4)]"> {{ `(${data.email})` }} </span>
|
||||
</a-option>
|
||||
</a-select>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import { getUserByOrganizationOrProject, getAllUser } from '@/api/modules/setting/organizationAndProject';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import initOptionsFunc, { UserRequesetTypeEnum } from './utils';
|
||||
|
||||
export interface MsUserSelectorProps {
|
||||
value: string[];
|
||||
disabled?: boolean;
|
||||
placeholder?: string;
|
||||
type?: 'organization' | 'usergroup';
|
||||
sourceId?: string;
|
||||
disabledKey?: string;
|
||||
}
|
||||
|
||||
export interface UserItem {
|
||||
export interface MsUserSelectorOption {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
[key: string]: boolean | string;
|
||||
disabled?: boolean;
|
||||
[key: string]: string | number | boolean | undefined;
|
||||
}
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = withDefaults(defineProps<MsUserSelectorProps>(), {
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
value: string[] | string; // 选中的值
|
||||
disabled?: boolean; // 是否禁用
|
||||
disabledKey?: string; // 禁用的key
|
||||
valueKey?: string; // value的key
|
||||
placeholder?: string;
|
||||
firstLabelKey?: string; // 首要的的字段key
|
||||
secondLabelKey?: string; // 次要的字段key
|
||||
loadOptionParams?: Record<string, any>; // 加载选项的参数
|
||||
type?: UserRequesetTypeEnum; // 加载选项的类型
|
||||
}>(),
|
||||
{
|
||||
disabled: false,
|
||||
type: 'usergroup',
|
||||
disabledKey: 'disabled',
|
||||
});
|
||||
valueKey: 'id',
|
||||
firstLabelKey: 'name',
|
||||
secondLabelKey: 'email',
|
||||
type: UserRequesetTypeEnum.SYSTEM_USER_GROUP,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:value', value: string[]): void;
|
||||
}>();
|
||||
const currentValue = ref(props.value);
|
||||
const { t } = useI18n();
|
||||
|
||||
const allOption = ref<UserItem[]>([]);
|
||||
const userOptions = ref<UserItem[]>([]);
|
||||
const currentOptions = ref<MsUserSelectorOption[]>([]);
|
||||
const oldOptions = ref<MsUserSelectorOption[]>([]);
|
||||
|
||||
const initUserList = async () => {
|
||||
let res: UserItem[] = [];
|
||||
if (props.type === 'organization') {
|
||||
if (!props.sourceId) {
|
||||
return;
|
||||
}
|
||||
res = await getUserByOrganizationOrProject(props.sourceId);
|
||||
} else {
|
||||
res = await getAllUser();
|
||||
}
|
||||
res.forEach((item) => {
|
||||
item.disabled = item[props.disabledKey as string];
|
||||
const currentValue = computed(() => {
|
||||
return currentOptions.value.filter((item) => props.value.includes(item.id)) || [];
|
||||
});
|
||||
allOption.value = [...res];
|
||||
userOptions.value = [...res];
|
||||
|
||||
const change = (value: string | number | Record<string, any> | (string | number | Record<string, any>)[]) => {
|
||||
const tmpArr = Array.isArray(value) ? value : [value];
|
||||
const { valueKey } = props;
|
||||
emit(
|
||||
'update:value',
|
||||
tmpArr.map((item) => item[valueKey])
|
||||
);
|
||||
};
|
||||
const loadList = async () => {
|
||||
try {
|
||||
const list = (await initOptionsFunc(props.type, props.loadOptionParams || {})) || [];
|
||||
const { firstLabelKey, secondLabelKey, disabledKey, valueKey } = props;
|
||||
list.forEach((item: MsUserSelectorOption) => {
|
||||
if (firstLabelKey) {
|
||||
item.name = (item[firstLabelKey] as string) || '';
|
||||
}
|
||||
if (secondLabelKey) {
|
||||
item.email = (item[secondLabelKey] as string) || '';
|
||||
}
|
||||
if (disabledKey) {
|
||||
item.disabled = item[disabledKey] as boolean;
|
||||
}
|
||||
if (valueKey) {
|
||||
item.id = item[valueKey] as string;
|
||||
}
|
||||
});
|
||||
currentOptions.value = [...list];
|
||||
oldOptions.value = [...list];
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
currentOptions.value = [];
|
||||
oldOptions.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
const handleSearch = (value: string) => {
|
||||
let timmer = null;
|
||||
const idInSelected = (id: string) => {
|
||||
return props.value.includes(id);
|
||||
};
|
||||
|
||||
const search = async (value: string) => {
|
||||
let timeout = null;
|
||||
if (value) {
|
||||
timmer = window.setTimeout(() => {
|
||||
userOptions.value = userOptions.value.filter(
|
||||
(item) => item.name.includes(value) || currentValue.value.includes(item.id)
|
||||
timeout = window.setTimeout(() => {
|
||||
currentOptions.value = currentOptions.value.filter(
|
||||
(item) => item.name.includes(value) || item.email.includes(value) || idInSelected(item.id)
|
||||
);
|
||||
}, 60);
|
||||
} else {
|
||||
if (timmer) window.clearTimeout(timmer);
|
||||
userOptions.value = allOption.value;
|
||||
if (timeout) {
|
||||
window.clearTimeout(timeout);
|
||||
}
|
||||
currentOptions.value = [...oldOptions.value];
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (value: string | number | Record<string, any> | (string | number | Record<string, any>)[]) => {
|
||||
emit('update:value', value as string[]);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initUserList();
|
||||
onMounted(async () => {
|
||||
await loadList();
|
||||
});
|
||||
watch(
|
||||
() => props.value,
|
||||
(value) => {
|
||||
currentValue.value = value;
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import {
|
||||
getAdminByOrganizationOrProject,
|
||||
getAdminByProjectByOrg,
|
||||
getUserByOrganizationOrProject,
|
||||
getUserByProjectByOrg,
|
||||
} from '@/api/modules/setting/organizationAndProject';
|
||||
import { getOrgUserGroupOption, getSystemUserGroupOption } from '@/api/modules/setting/usergroup';
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
export enum UserRequesetTypeEnum {
|
||||
SYSTEM_USER_GROUP = 'SYSTEM_USER_GROUP',
|
||||
SYSTEM_ORGANIZATION = 'SYSTEM_ORGANIZATION',
|
||||
SYSTEM_ORGANIZATION_ADMIN = 'SYSTEM_ORGANIZATION_ADMIN',
|
||||
SYSTEM_PROJECT = 'SYSTEM_PROJECT',
|
||||
SYSTEM_PROJECT_ADMIN = 'SYSTEM_PROJECT_ADMIN',
|
||||
ORGANIZATION_USER_GROUP = 'ORGANIZATION_USER_GROUP',
|
||||
ORGANIZATION_USER_GROUP_ADMIN = 'ORGANIZATION_USER_GROUP_ADMIN',
|
||||
ORGANIZATION_PROJECT = 'ORGANIZATION_PROJECT',
|
||||
ORGANIZATION_PROJECT_ADMIN = 'ORGANIZATION_PROJECT_ADMIN',
|
||||
}
|
||||
export default function initOptionsFunc(type: string, params: Record<string, any>) {
|
||||
if (type === UserRequesetTypeEnum.SYSTEM_USER_GROUP) {
|
||||
// 系统 - 用户组-添加成员-下拉选项
|
||||
return getSystemUserGroupOption(params.roleId);
|
||||
}
|
||||
if (type === UserRequesetTypeEnum.ORGANIZATION_USER_GROUP) {
|
||||
// 组织 - 用户组-添加成员-下拉选项
|
||||
return getOrgUserGroupOption(params.organizationId, params.roleId);
|
||||
}
|
||||
if (type === UserRequesetTypeEnum.SYSTEM_ORGANIZATION_ADMIN || type === UserRequesetTypeEnum.SYSTEM_PROJECT_ADMIN) {
|
||||
// 系统 - 【组织 或 项目】-添加管理员-下拉选项
|
||||
return getAdminByOrganizationOrProject();
|
||||
}
|
||||
if (type === UserRequesetTypeEnum.SYSTEM_ORGANIZATION || type === UserRequesetTypeEnum.SYSTEM_PROJECT) {
|
||||
// 系统 -【组织 或 项目】-添加成员-下拉选项
|
||||
return getUserByOrganizationOrProject(params.sourceId);
|
||||
}
|
||||
if (type === UserRequesetTypeEnum.ORGANIZATION_PROJECT) {
|
||||
// 组织 - 项目-添加成员-下拉选项
|
||||
return getUserByProjectByOrg(params.organizationId, params.projectId);
|
||||
}
|
||||
if (type === UserRequesetTypeEnum.ORGANIZATION_PROJECT_ADMIN) {
|
||||
// 组织 - 项目-添加管理员-下拉选项
|
||||
return getAdminByProjectByOrg(params.organizationId);
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ export default {
|
|||
'common.enable': 'Enable',
|
||||
'common.close': 'Close',
|
||||
'common.create': 'Create',
|
||||
'common.update': 'Update',
|
||||
'common.confirmEnable': 'Confirm enable',
|
||||
'common.confirmClose': 'Confirm close',
|
||||
'common.enableSuccess': 'Enable success',
|
||||
|
|
|
@ -14,6 +14,7 @@ export default {
|
|||
'common.enable': '启用',
|
||||
'common.close': '关闭',
|
||||
'common.create': '创建',
|
||||
'common.update': '更新',
|
||||
'common.confirmEnable': '确认启用',
|
||||
'common.confirmClose': '确认关闭',
|
||||
'common.enableSuccess': '启用成功',
|
||||
|
|
|
@ -120,4 +120,5 @@ export interface UserTableItem {
|
|||
createUser: string;
|
||||
updateUser: string;
|
||||
deleted: boolean;
|
||||
[key: string]: string | boolean | number;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
import { GetLoginLogoUrl } from '@/api/requrls/setting/config';
|
||||
import type { LoginData } from '@/models/user';
|
||||
import { WorkbenchRouteEnum } from '@/enums/routeEnum';
|
||||
import JSEncrypt from 'jsencrypt';
|
||||
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
|
@ -99,6 +100,13 @@
|
|||
password: 'metersphere',
|
||||
});
|
||||
|
||||
const encrypted = (input: string, publicKey: string) => {
|
||||
const encrypt = new JSEncrypt({ default_key_size: '1024' });
|
||||
debugger;
|
||||
encrypt.setPublicKey(publicKey);
|
||||
return encrypt.encrypt(input);
|
||||
};
|
||||
|
||||
const handleSubmit = async ({
|
||||
errors,
|
||||
values,
|
||||
|
@ -110,12 +118,15 @@
|
|||
if (!errors) {
|
||||
setLoading(true);
|
||||
try {
|
||||
await userStore.login(values as LoginData);
|
||||
const publicKey = userStore.salt;
|
||||
await userStore.login({
|
||||
username: encrypted(values.username, publicKey),
|
||||
password: encrypted(values.password, publicKey),
|
||||
authenticate: values.authenticate,
|
||||
} as LoginData);
|
||||
Message.success(t('login.form.login.success'));
|
||||
const { rememberPassword } = loginConfig.value;
|
||||
const { username, password } = values;
|
||||
// 实际生产环境需要进行加密存储。
|
||||
// The actual production environment requires encrypted storage.
|
||||
loginConfig.value.username = rememberPassword ? username : '';
|
||||
loginConfig.value.password = rememberPassword ? password : '';
|
||||
const { redirect, ...othersQuery } = router.currentRoute.value.query;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
class="ms-modal-form ms-modal-medium"
|
||||
:ok-text="isEdit ? t('common.update') : t('common.create')"
|
||||
unmount-on-close
|
||||
@cancel="handleCancel"
|
||||
@cancel="handleCancel(false)"
|
||||
>
|
||||
<template #title>
|
||||
<span v-if="isEdit">
|
||||
|
@ -39,7 +39,14 @@
|
|||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item field="userIds" :label="t('system.project.projectAdmin')">
|
||||
<MsUserSelector v-model:value="form.userIds" placeholder="system.project.projectAdminPlaceholder" />
|
||||
<MsUserSelector
|
||||
v-model:value="form.userIds"
|
||||
:type="UserRequesetTypeEnum.ORGANIZATION_PROJECT_ADMIN"
|
||||
placeholder="system.project.projectAdminPlaceholder"
|
||||
:load-option-params="{
|
||||
organizationId: currentOrgId,
|
||||
}"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="description" :label="t('system.organization.description')">
|
||||
<a-input v-model="form.description" :placeholder="t('system.organization.descriptionPlaceholder')" />
|
||||
|
@ -63,7 +70,7 @@
|
|||
</a-tooltip>
|
||||
</div>
|
||||
<div class="flex flex-row gap-[14px]">
|
||||
<a-button type="secondary" :loading="loading" @click="handleCancel">
|
||||
<a-button type="secondary" :loading="loading" @click="handleCancel(false)">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button type="primary" :loading="loading" @click="handleBeforeOk">
|
||||
|
@ -86,6 +93,7 @@
|
|||
import { CreateOrUpdateSystemProjectParams, SystemOrgOption } from '@/models/setting/system/orgAndProject';
|
||||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
import { useAppStore } from '@/store';
|
||||
import { UserRequesetTypeEnum } from '@/components/business/ms-user-selector/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
|
@ -112,7 +120,7 @@
|
|||
];
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel'): void;
|
||||
(e: 'cancel', shouldSearch: boolean): void;
|
||||
}>();
|
||||
|
||||
const form = reactive<CreateOrUpdateSystemProjectParams>({
|
||||
|
@ -133,9 +141,9 @@
|
|||
watchEffect(() => {
|
||||
currentVisible.value = props.visible;
|
||||
});
|
||||
const handleCancel = () => {
|
||||
const handleCancel = (shouldSearch: boolean) => {
|
||||
formRef.value?.resetFields();
|
||||
emit('cancel');
|
||||
emit('cancel', shouldSearch);
|
||||
};
|
||||
|
||||
const handleBeforeOk = async () => {
|
||||
|
@ -151,7 +159,7 @@
|
|||
? t('system.organization.updateOrganizationSuccess')
|
||||
: t('system.organization.createOrganizationSuccess')
|
||||
);
|
||||
handleCancel();
|
||||
handleCancel(true);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
class="ms-modal-form ms-modal-medium"
|
||||
:ok-text="t('system.organization.addMember')"
|
||||
unmount-on-close
|
||||
@cancel="handleCancel"
|
||||
@cancel="handleCancel(false)"
|
||||
>
|
||||
<template #title> {{ t('system.organization.addMember') }} </template>
|
||||
<div class="form">
|
||||
|
@ -15,12 +15,17 @@
|
|||
:label="t('system.organization.member')"
|
||||
:rules="[{ required: true, message: t('system.organization.addMemberRequired') }]"
|
||||
>
|
||||
<MsUserSelector v-model:value="form.name" type="organization" :source-id="projectId" />
|
||||
<MsUserSelector
|
||||
v-model:value="form.name"
|
||||
:type="UserRequesetTypeEnum.ORGANIZATION_PROJECT"
|
||||
:load-option-params="{ organizationId: currentOrgId, projectId: props.projectId }"
|
||||
disabled-key="memberFlag"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button type="secondary" :loading="loading" @click="handleCancel">
|
||||
<a-button type="secondary" :loading="loading" @click="handleCancel(false)">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button type="primary" :loading="loading" :disabled="form.name.length === 0" @click="handleAddMember">
|
||||
|
@ -32,20 +37,24 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { reactive, ref, watchEffect, onUnmounted } from 'vue';
|
||||
import { reactive, ref, watchEffect, onUnmounted, computed } from 'vue';
|
||||
import { addProjectMemberByOrg } from '@/api/modules/setting/organizationAndProject';
|
||||
import { Message, type FormInstance, type ValidatedError } from '@arco-design/web-vue';
|
||||
import MsUserSelector from '@/components/business/ms-user-selector/index.vue';
|
||||
import { UserRequesetTypeEnum } from '@/components/business/ms-user-selector/utils';
|
||||
import { useAppStore } from '@/store';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
projectId?: string;
|
||||
}>();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const currentOrgId = computed(() => appStore.currentOrgId);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel'): void;
|
||||
(e: 'submit', value: string[]): void;
|
||||
(e: 'cancel', shouldSearch: boolean): void;
|
||||
}>();
|
||||
|
||||
const currentVisible = ref(props.visible);
|
||||
|
@ -61,9 +70,9 @@
|
|||
currentVisible.value = props.visible;
|
||||
});
|
||||
|
||||
const handleCancel = () => {
|
||||
const handleCancel = (shouldSearch: boolean) => {
|
||||
form.name = [];
|
||||
emit('cancel');
|
||||
emit('cancel', shouldSearch);
|
||||
};
|
||||
|
||||
const handleAddMember = () => {
|
||||
|
@ -76,7 +85,7 @@
|
|||
loading.value = true;
|
||||
await addProjectMemberByOrg({ userIds: form.name, projectId });
|
||||
Message.success(t('system.organization.addSuccess'));
|
||||
handleCancel();
|
||||
handleCancel(true);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
|
|
|
@ -119,8 +119,11 @@
|
|||
userVisible.value = true;
|
||||
};
|
||||
|
||||
const handleHideUserModal = () => {
|
||||
const handleHideUserModal = (shouldSearch: boolean) => {
|
||||
userVisible.value = false;
|
||||
if (shouldSearch) {
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemove = async (record: TableData) => {
|
||||
|
|
|
@ -80,8 +80,8 @@
|
|||
import useModal from '@/hooks/useModal';
|
||||
import { CreateOrUpdateSystemProjectParams } from '@/models/setting/system/orgAndProject';
|
||||
import AddProjectModal from './components/addProjectModal.vue';
|
||||
import { UserItem } from '@/components/business/ms-user-selector/index.vue';
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import { UserItem } from '@/models/setting/log';
|
||||
|
||||
const { t } = useI18n();
|
||||
const tableStore = useTableStore();
|
||||
|
@ -255,13 +255,17 @@
|
|||
fetchData();
|
||||
};
|
||||
|
||||
const handleAddUserModalCancel = () => {
|
||||
const handleAddUserModalCancel = (shouldSearch: boolean) => {
|
||||
userVisible.value = false;
|
||||
if (shouldSearch) {
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
const handleAddProjectModalCancel = () => {
|
||||
const handleAddProjectModalCancel = (shouldSearch: boolean) => {
|
||||
addProjectVisible.value = false;
|
||||
if (shouldSearch) {
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const handleRevokeDelete = async (record: TableData) => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
text-align="start"
|
||||
:ok-text="t('system.userGroup.add')"
|
||||
unmount-on-close
|
||||
@cancel="handleCancel"
|
||||
@cancel="handleCancel(false)"
|
||||
>
|
||||
<template #title> {{ t('system.userGroup.addUser') }} </template>
|
||||
<div class="form">
|
||||
|
@ -16,12 +16,20 @@
|
|||
:label="t('system.userGroup.user')"
|
||||
:rules="[{ required: true, message: t('system.userGroup.pleaseSelectUser') }]"
|
||||
>
|
||||
<MsUserSelector v-model:value="form.name" />
|
||||
<MsUserSelector
|
||||
v-model:value="form.name"
|
||||
:type="UserRequesetTypeEnum.ORGANIZATION_USER_GROUP"
|
||||
:load-option-params="{
|
||||
roleId: store.currentId,
|
||||
organizationId: currentOrgId,
|
||||
}"
|
||||
disabled-key="checkRoleFlag"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button type="secondary" :loading="loading" @click="handleCancel">
|
||||
<a-button type="secondary" :loading="loading" @click="handleCancel(false)">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button type="primary" :loading="loading" :disabled="form.name.length === 0" @click="handleBeforeOk">
|
||||
|
@ -39,6 +47,7 @@
|
|||
import { addOrgUserToUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import { Message, type FormInstance, type ValidatedError } from '@arco-design/web-vue';
|
||||
import MsUserSelector from '@/components/business/ms-user-selector/index.vue';
|
||||
import { UserRequesetTypeEnum } from '@/components/business/ms-user-selector/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
|
@ -50,8 +59,7 @@
|
|||
const currentOrgId = computed(() => appStore.currentOrgId);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel'): void;
|
||||
(e: 'submit', value: string[]): void;
|
||||
(e: 'cancel', shouldSearch: boolean): void;
|
||||
}>();
|
||||
|
||||
const currentVisible = ref(props.visible);
|
||||
|
@ -69,10 +77,10 @@
|
|||
currentVisible.value = props.visible;
|
||||
});
|
||||
|
||||
const handleCancel = () => {
|
||||
const handleCancel = (shouldSearch = false) => {
|
||||
labelCache.clear();
|
||||
form.name = [];
|
||||
emit('cancel');
|
||||
emit('cancel', shouldSearch);
|
||||
};
|
||||
|
||||
const handleBeforeOk = () => {
|
||||
|
@ -87,7 +95,7 @@
|
|||
userIds: form.name,
|
||||
organizationId: currentOrgId.value,
|
||||
});
|
||||
handleCancel();
|
||||
handleCancel(true);
|
||||
Message.success(t('common.addSuccess'));
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
|
|
@ -70,7 +70,11 @@
|
|||
};
|
||||
const handleRemove = async (record: UserTableItem) => {
|
||||
try {
|
||||
await deleteOrgUserFromUserGroup(record.id);
|
||||
await deleteOrgUserFromUserGroup({
|
||||
organizationId: currentOrgId.value,
|
||||
userRoleId: store.currentId,
|
||||
userIds: [record.id],
|
||||
});
|
||||
await fetchData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -80,8 +84,10 @@
|
|||
const handleAddUser = () => {
|
||||
userVisible.value = true;
|
||||
};
|
||||
const handleAddUserModalCancel = () => {
|
||||
const handleAddUserModalCancel = (shouldSearch: boolean) => {
|
||||
if (shouldSearch) {
|
||||
fetchData();
|
||||
}
|
||||
userVisible.value = false;
|
||||
};
|
||||
watchEffect(() => {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
<MsUserSelector
|
||||
v-model:value="form.memberIds"
|
||||
placeholder="system.organization.organizationAdminPlaceholder"
|
||||
:type="UserRequesetTypeEnum.SYSTEM_ORGANIZATION_ADMIN"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="description" :label="t('system.organization.description')">
|
||||
|
@ -56,6 +57,7 @@
|
|||
import { createOrUpdateOrg } from '@/api/modules/setting/organizationAndProject';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { CreateOrUpdateSystemOrgParams } from '@/models/setting/system/orgAndProject';
|
||||
import { UserRequesetTypeEnum } from '@/components/business/ms-user-selector/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
|
@ -69,6 +71,7 @@
|
|||
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel'): void;
|
||||
(e: 'submit'): void;
|
||||
}>();
|
||||
|
||||
const form = reactive<{ name: string; memberIds: string[]; description: string }>({
|
||||
|
@ -86,6 +89,11 @@
|
|||
emit('cancel');
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
handleCancel();
|
||||
emit('submit');
|
||||
};
|
||||
|
||||
const handleBeforeOk = () => {
|
||||
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
|
||||
if (errors) {
|
||||
|
@ -99,7 +107,7 @@
|
|||
? t('system.organization.updateOrganizationSuccess')
|
||||
: t('system.organization.createOrganizationSuccess')
|
||||
);
|
||||
handleCancel();
|
||||
handleSubmit();
|
||||
return true;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -119,4 +127,3 @@
|
|||
});
|
||||
const isEdit = computed(() => !!props.currentOrganization?.id);
|
||||
</script>
|
||||
@/api/modules/setting/organizationAndProject
|
||||
|
|
|
@ -44,7 +44,11 @@
|
|||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item field="userIds" :label="t('system.project.projectAdmin')">
|
||||
<MsUserSelector v-model:value="form.userIds" placeholder="system.project.projectAdminPlaceholder" />
|
||||
<MsUserSelector
|
||||
v-model:value="form.userIds"
|
||||
:type="UserRequesetTypeEnum.SYSTEM_PROJECT_ADMIN"
|
||||
placeholder="system.project.projectAdminPlaceholder"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="description" :label="t('system.organization.description')">
|
||||
<a-input v-model="form.description" :placeholder="t('system.organization.descriptionPlaceholder')" />
|
||||
|
@ -90,6 +94,7 @@
|
|||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import { CreateOrUpdateSystemProjectParams, SystemOrgOption } from '@/models/setting/system/orgAndProject';
|
||||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
import { UserRequesetTypeEnum } from '@/components/business/ms-user-selector/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
|
@ -115,6 +120,7 @@
|
|||
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel'): void;
|
||||
(e: 'submit'): void;
|
||||
}>();
|
||||
|
||||
const form = reactive<CreateOrUpdateSystemProjectParams>({
|
||||
|
@ -153,7 +159,9 @@
|
|||
? t('system.organization.updateOrganizationSuccess')
|
||||
: t('system.organization.createOrganizationSuccess')
|
||||
);
|
||||
|
||||
handleCancel();
|
||||
emit('submit');
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
:label="t('system.organization.member')"
|
||||
:rules="[{ required: true, message: t('system.organization.addMemberRequired') }]"
|
||||
>
|
||||
<MsUserSelector v-model:value="form.name" type="organization" :source-id="organizationId || projectId" />
|
||||
<MsUserSelector
|
||||
v-model:value="form.name"
|
||||
:type="UserRequesetTypeEnum.SYSTEM_ORGANIZATION"
|
||||
:load-option-params="{ sourceId: props.organizationId || props.projectId }"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
|
@ -36,6 +40,7 @@
|
|||
import { addUserToOrgOrProject } from '@/api/modules/setting/organizationAndProject';
|
||||
import { Message, type FormInstance, type ValidatedError } from '@arco-design/web-vue';
|
||||
import MsUserSelector from '@/components/business/ms-user-selector/index.vue';
|
||||
import { UserRequesetTypeEnum } from '@/components/business/ms-user-selector/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
|
@ -46,7 +51,7 @@
|
|||
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel'): void;
|
||||
(e: 'submit', value: string[]): void;
|
||||
(e: 'submit'): void;
|
||||
}>();
|
||||
|
||||
const currentVisible = ref(props.visible);
|
||||
|
@ -78,6 +83,7 @@
|
|||
await addUserToOrgOrProject({ userIds: form.name, organizationId, projectId });
|
||||
Message.success(t('system.organization.addSuccess'));
|
||||
handleCancel();
|
||||
emit('submit');
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
|
|
|
@ -105,4 +105,3 @@
|
|||
}
|
||||
);
|
||||
</script>
|
||||
@/api/modules/setting/organizationAndProject
|
||||
|
|
|
@ -44,7 +44,12 @@
|
|||
:visible="orgVisible"
|
||||
@cancel="handleAddOrgModalCancel"
|
||||
/>
|
||||
<AddUserModal :organization-id="currentOrganizationId" :visible="userVisible" @cancel="handleAddUserModalCancel" />
|
||||
<AddUserModal
|
||||
:organization-id="currentOrganizationId"
|
||||
:visible="userVisible"
|
||||
@cancel="handleAddUserModalCancel"
|
||||
@submit="fetchData"
|
||||
/>
|
||||
<ProjectDrawer v-bind="currentProjectDrawer" @cancel="handleProjectDrawerCancel" />
|
||||
<UserDrawer v-bind="currentUserDrawer" @cancel="handleUserDrawerCancel" />
|
||||
</template>
|
||||
|
@ -254,7 +259,6 @@
|
|||
|
||||
const handleAddUserModalCancel = () => {
|
||||
userVisible.value = false;
|
||||
fetchData();
|
||||
};
|
||||
const handleAddOrgModalCancel = () => {
|
||||
orgVisible.value = false;
|
||||
|
|
|
@ -39,8 +39,14 @@
|
|||
:current-project="currentUpdateProject"
|
||||
:visible="addProjectVisible"
|
||||
@cancel="handleAddProjectModalCancel"
|
||||
@submit="fetchData"
|
||||
/>
|
||||
<AddUserModal
|
||||
:project-id="currentProjectId"
|
||||
:visible="userVisible"
|
||||
@submit="fetchData"
|
||||
@cancel="handleAddUserModalCancel"
|
||||
/>
|
||||
<AddUserModal :project-id="currentProjectId" :visible="userVisible" @cancel="handleAddUserModalCancel" />
|
||||
<UserDrawer :project-id="currentProjectId" v-bind="currentUserDrawer" @cancel="handleUserDrawerCancel" />
|
||||
</template>
|
||||
|
||||
|
@ -67,7 +73,7 @@
|
|||
import useModal from '@/hooks/useModal';
|
||||
import { CreateOrUpdateSystemProjectParams } from '@/models/setting/system/orgAndProject';
|
||||
import AddProjectModal from './addProjectModal.vue';
|
||||
import { UserItem } from '@/components/business/ms-user-selector/index.vue';
|
||||
import { UserItem } from '@/models/setting/log';
|
||||
|
||||
export interface SystemOrganizationProps {
|
||||
keyword: string;
|
||||
|
@ -235,16 +241,13 @@
|
|||
|
||||
const handleUserDrawerCancel = () => {
|
||||
currentUserDrawer.visible = false;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleAddUserModalCancel = () => {
|
||||
userVisible.value = false;
|
||||
fetchData();
|
||||
};
|
||||
const handleAddProjectModalCancel = () => {
|
||||
addProjectVisible.value = false;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleRevokeDelete = async (record: TableData) => {
|
||||
|
@ -278,4 +281,3 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@/api/modules/setting/organizationAndProject
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
:organization-id="props.organizationId"
|
||||
:visible="userVisible"
|
||||
@cancel="handleHideUserModal"
|
||||
@submit="fetchData"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
<SystemProject v-if="currentTable === 'project'" ref="projectTabeRef" :keyword="currentKeyword" />
|
||||
</div>
|
||||
</MsCard>
|
||||
<AddOrganizationModal :visible="organizationVisible" @cancel="handleAddOrganizationCancel" />
|
||||
<AddProjectModal :visible="projectVisible" @cancel="handleAddProjectCancel" />
|
||||
<AddOrganizationModal :visible="organizationVisible" @submit="tableSearch" @cancel="handleAddOrganizationCancel" />
|
||||
<AddProjectModal :visible="projectVisible" @submit="tableSearch" @cancel="handleAddProjectCancel" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
@ -89,11 +89,9 @@
|
|||
};
|
||||
|
||||
const handleAddProjectCancel = () => {
|
||||
tableSearch();
|
||||
projectVisible.value = false;
|
||||
};
|
||||
const handleAddOrganizationCancel = () => {
|
||||
tableSearch();
|
||||
organizationVisible.value = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,8 +15,13 @@
|
|||
field="name"
|
||||
:label="t('system.userGroup.user')"
|
||||
:rules="[{ required: true, message: t('system.userGroup.pleaseSelectUser') }]"
|
||||
asterisk-position="end"
|
||||
>
|
||||
<MsUserSelector v-model:value="form.name" />
|
||||
<MsUserSelector
|
||||
v-model:value="form.name"
|
||||
disabled-key="exclude"
|
||||
:load-option-params="{ roleId: store.currentId }"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
|
|
|
@ -159,4 +159,3 @@
|
|||
}
|
||||
}
|
||||
</style>
|
||||
@/store/modules/setting/system/usergroup
|
||||
|
|
Loading…
Reference in New Issue