feat(系统设置): 用户批量操作接口&部分单词拼写修正&部分组件调整
This commit is contained in:
parent
193b54a02c
commit
b18e2e85c4
|
@ -17,6 +17,11 @@ export default mergeConfig(
|
|||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/front/, ''),
|
||||
},
|
||||
'/base-display': {
|
||||
target: 'http://172.16.200.18:8081/',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: string) => path.replace(/^\/front\/base-display/, ''),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
|
|
|
@ -11,14 +11,13 @@
|
|||
import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn';
|
||||
import GlobalSetting from '@/components/pure/global-setting/index.vue';
|
||||
import useLocale from '@/locale/useLocale';
|
||||
import { saveBaseInfo, getBaseInfo } from '@/api/modules/setting/config';
|
||||
import { saveBaseInfo } from '@/api/modules/setting/config';
|
||||
import { getLocalStorage, setLocalStorage } from '@/utils/local-storage';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
import { watchStyle, watchTheme, setFavicon } from '@/utils/theme';
|
||||
import { GetPlatformIconUrl } from '@/api/requrls/setting/config';
|
||||
import { useUserStore } from '@/store';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
|
@ -39,30 +38,24 @@
|
|||
// 初始化平台风格和主题色
|
||||
watchStyle(appStore.pageConfig.style, appStore.pageConfig);
|
||||
watchTheme(appStore.pageConfig.theme, appStore.pageConfig);
|
||||
window.document.title = appStore.pageConfig.title;
|
||||
setFavicon(GetPlatformIconUrl);
|
||||
|
||||
onBeforeMount(async () => {
|
||||
try {
|
||||
appStore.initSystemversion(); // 初始化系统版本
|
||||
appStore.initSystemVersion(); // 初始化系统版本
|
||||
appStore.initPageConfig(); // 初始化页面配置
|
||||
licenseStore.getValidateLicense(); // 初始化校验license
|
||||
// 项目初始化时需要获取基础设置信息,看当前站点 url是否为系统内置默认地址,如果是需要替换为当前项目部署的 url 地址
|
||||
const isInitUrl = getLocalStorage('isInitUrl'); // 是否已经初始化过 url
|
||||
if (isInitUrl === 'true') return;
|
||||
const res = await getBaseInfo();
|
||||
if (res.url === 'http://127.0.0.1:8081') {
|
||||
await saveBaseInfo([
|
||||
{
|
||||
paramKey: 'base.url',
|
||||
paramValue: window.location.origin,
|
||||
type: 'string',
|
||||
},
|
||||
]);
|
||||
setLocalStorage('isInitUrl', 'true'); // 设置已经初始化过 url,避免重复初始化
|
||||
} else {
|
||||
setLocalStorage('isInitUrl', 'true'); // 设置已经初始化过 url,避免重复初始化
|
||||
}
|
||||
await saveBaseInfo([
|
||||
{
|
||||
paramKey: 'base.url',
|
||||
paramValue: window.location.origin,
|
||||
type: 'string',
|
||||
},
|
||||
]);
|
||||
setLocalStorage('isInitUrl', 'true'); // 设置已经初始化过 url,避免重复初始化
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
|
|
|
@ -9,6 +9,10 @@ import {
|
|||
GetSystemRoleUrl,
|
||||
ResetPasswordUrl,
|
||||
BatchAddUserGroupUrl,
|
||||
BatchAddOrgUrl,
|
||||
BatchAddProjectUrl,
|
||||
GetOrgsUrl,
|
||||
GetProjectsUrl,
|
||||
} from '@/api/requrls/setting/user';
|
||||
import type {
|
||||
UserListItem,
|
||||
|
@ -19,8 +23,9 @@ import type {
|
|||
ImportUserParams,
|
||||
SystemRole,
|
||||
ImportResult,
|
||||
BatchAddUserGroupParams,
|
||||
BatchAddParams,
|
||||
ResetUserPasswordParams,
|
||||
OrgsItem,
|
||||
} from '@/models/setting/user';
|
||||
import type { CommonList, TableQueryParams } from '@/models/common';
|
||||
|
||||
|
@ -65,6 +70,26 @@ export function resetUserPassword(data: ResetUserPasswordParams) {
|
|||
}
|
||||
|
||||
// 批量添加用户到多个用户组
|
||||
export function batchAddUserGroup(data: BatchAddUserGroupParams) {
|
||||
export function batchAddUserGroup(data: BatchAddParams) {
|
||||
return MSR.post({ url: BatchAddUserGroupUrl, data });
|
||||
}
|
||||
|
||||
// 批量添加用户到多个项目
|
||||
export function batchAddProject(data: BatchAddParams) {
|
||||
return MSR.post({ url: BatchAddProjectUrl, data });
|
||||
}
|
||||
|
||||
// 批量添加用户到多个组织
|
||||
export function batchAddOrg(data: BatchAddParams) {
|
||||
return MSR.post({ url: BatchAddOrgUrl, data });
|
||||
}
|
||||
|
||||
// 获取系统组织组
|
||||
export function getSystemOrgs() {
|
||||
return MSR.get<OrgsItem[]>({ url: GetOrgsUrl });
|
||||
}
|
||||
|
||||
// 获取系统项目
|
||||
export function getSystemProjects() {
|
||||
return MSR.get<OrgsItem[]>({ url: GetProjectsUrl });
|
||||
}
|
||||
|
|
|
@ -16,3 +16,11 @@ export const GetSystemRoleUrl = '/system/user/get/global/system/role';
|
|||
export const ResetPasswordUrl = '/system/user/reset/password';
|
||||
// 批量添加用户到多个用户组
|
||||
export const BatchAddUserGroupUrl = '/system/user/add/batch/user-role';
|
||||
// 批量添加用户到多个项目
|
||||
export const BatchAddProjectUrl = '/system/user/add-project-member';
|
||||
// 批量添加用户到多个组织
|
||||
export const BatchAddOrgUrl = '/system/user/add-org-member';
|
||||
// 查找组织
|
||||
export const GetOrgsUrl = '/system/user/get/organization';
|
||||
// 查找项目
|
||||
export const GetProjectsUrl = '/system/user/get/project';
|
||||
|
|
|
@ -84,11 +84,11 @@
|
|||
case 'batchAddProject':
|
||||
batchTitle.value = t('system.user.batchAddProject');
|
||||
break;
|
||||
case 'batchAddUsergroup':
|
||||
batchTitle.value = t('system.user.batchAddUsergroup');
|
||||
case 'batchAddUserGroup':
|
||||
batchTitle.value = t('system.user.batchAddUserGroup');
|
||||
break;
|
||||
case 'batchAddOrgnization':
|
||||
batchTitle.value = t('system.user.batchAddOrgnization');
|
||||
case 'batchAddOrganization':
|
||||
batchTitle.value = t('system.user.batchAddOrganization');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -182,10 +182,10 @@
|
|||
case 'batchAddProject':
|
||||
emit('addProject', target.value, 'project');
|
||||
break;
|
||||
case 'batchAddUsergroup':
|
||||
case 'batchAddUserGroup':
|
||||
emit('addUserGroup', target.value, 'usergroup');
|
||||
break;
|
||||
case 'batchAddOrgnization':
|
||||
case 'batchAddOrganization':
|
||||
emit('addOrgnization', target.value, 'orgnization');
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
:placeholder="props.placeholder"
|
||||
:loading="props.loading"
|
||||
@change="handleMsCascaderChange"
|
||||
@clear="clearValues"
|
||||
>
|
||||
<template #prefix>
|
||||
{{ props.prefix }}
|
||||
|
@ -224,6 +225,10 @@
|
|||
});
|
||||
}
|
||||
|
||||
function clearValues() {
|
||||
innerLevel.value = '';
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (cascader.value) {
|
||||
cascaderWidth.value = cascader.value.$el.nextElementSibling.getBoundingClientRect().width;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
<template v-if="fileList.length === 0">
|
||||
<div class="ms-upload-main-text">
|
||||
{{ t(props.mainText || 'ms.upload.importModalDragtext') }}
|
||||
{{ t(props.mainText || 'ms.upload.importModalDragText') }}
|
||||
</div>
|
||||
<div v-if="showSubText" class="ms-upload-sub-text">
|
||||
{{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export default {
|
||||
'ms.upload.changeFile': 'Change file',
|
||||
'ms.upload.overSize': 'The file size exceeds the limit, please reselect the file',
|
||||
'ms.upload.importModalDragtext': 'Drag or click this area to select a file',
|
||||
'ms.upload.importModalDragText': 'Drag or click this area to select a file',
|
||||
'ms.upload.importModalFileTip': 'Only {type} format files are supported, and the file size does not exceed {size} MB',
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export default {
|
||||
'ms.upload.changeFile': '更改文件',
|
||||
'ms.upload.overSize': '文件大小超出限制,请重新选择文件',
|
||||
'ms.upload.importModalDragtext': '拖拽或点击此区域选择文件',
|
||||
'ms.upload.importModalDragText': '拖拽或点击此区域选择文件',
|
||||
'ms.upload.importModalFileTip': '只支持 {type} 格式文件,文件大小不超过 {size} MB',
|
||||
};
|
||||
|
|
|
@ -34,18 +34,29 @@ export default function usePathMap() {
|
|||
/**
|
||||
* 根据路由的 key 进行路由跳转,自动携带配置的 routeQuery 和 传入的routeQuery
|
||||
* TODO: 权限校验待补充
|
||||
* @param key
|
||||
* @param key 路由的 key
|
||||
* @param routeQuery 路由的参数
|
||||
* @param openNewPage 是否在新页面打开
|
||||
*/
|
||||
const jumpRouteByMapKey = (key: typeof RouteEnum, routeQuery?: Record<string, any>) => {
|
||||
const jumpRouteByMapKey = (key: typeof RouteEnum, routeQuery?: Record<string, any>, openNewPage = false) => {
|
||||
const pathNode = findNodeByKey(pathMap, key as unknown as string);
|
||||
if (pathNode) {
|
||||
router.push({
|
||||
name: pathNode?.route,
|
||||
query: {
|
||||
...routeQuery,
|
||||
...pathNode?.routeQuery,
|
||||
},
|
||||
});
|
||||
if (openNewPage) {
|
||||
window.open(
|
||||
`${window.location.origin}#${router.resolve({ name: pathNode?.route }).fullPath}?${new URLSearchParams({
|
||||
...routeQuery,
|
||||
...pathNode?.routeQuery,
|
||||
}).toString()}`
|
||||
);
|
||||
} else {
|
||||
router.push({
|
||||
name: pathNode?.route,
|
||||
query: {
|
||||
...routeQuery,
|
||||
...pathNode?.routeQuery,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -97,6 +97,12 @@ export interface ImportResult {
|
|||
errorMessages: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface BatchAddUserGroupParams extends BatchApiParams {
|
||||
roleIds: string[]; // 用户组 id 集合
|
||||
export interface BatchAddParams extends BatchApiParams {
|
||||
roleIds: string[]; // 用户组/项目/组织 id 集合
|
||||
}
|
||||
|
||||
export interface OrgsItem {
|
||||
id: string;
|
||||
name: string;
|
||||
children?: OrgsItem[];
|
||||
}
|
||||
|
|
|
@ -197,7 +197,7 @@ const useAppStore = defineStore('app', {
|
|||
/**
|
||||
* 获取系统版本
|
||||
*/
|
||||
async initSystemversion() {
|
||||
async initSystemVersion() {
|
||||
try {
|
||||
this.version = await getSystemVersion();
|
||||
} catch (error) {
|
||||
|
@ -263,6 +263,7 @@ const useAppStore = defineStore('app', {
|
|||
if (hasThemeChange) {
|
||||
watchTheme(this.pageConfig.theme, this.pageConfig);
|
||||
}
|
||||
window.document.title = this.pageConfig.title;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
|
|
@ -221,8 +221,8 @@
|
|||
eventTag: 'batchAddProject',
|
||||
},
|
||||
{
|
||||
label: 'organization.member.batchActionAddUsergroup',
|
||||
eventTag: 'batchAddUsergroup',
|
||||
label: 'organization.member.batchActionAddUserGroup',
|
||||
eventTag: 'batchAddUserGroup',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -324,7 +324,7 @@
|
|||
treeData.value = [];
|
||||
batchAction.value = actionItem.eventTag;
|
||||
if (actionItem.eventTag === 'batchAddProject') getData(getProjectList);
|
||||
if (actionItem.eventTag === 'batchAddUsergroup') getData(getGlobalUserGroup);
|
||||
if (actionItem.eventTag === 'batchAddUserGroup') getData(getGlobalUserGroup);
|
||||
};
|
||||
// 列表编辑更新用户组和项目
|
||||
const updateUserOrProject = async (record: MemberItem) => {
|
||||
|
|
|
@ -5,7 +5,7 @@ export default {
|
|||
'organization.member.remove': 'Remove',
|
||||
'organization.member.edit': 'Edit',
|
||||
'organization.member.batchActionAddProject': 'Add to project',
|
||||
'organization.member.batchActionAddUsergroup': 'Add to usergroup',
|
||||
'organization.member.batchActionAddUserGroup': 'Add to usergroup',
|
||||
'organization.member.tableEnable': 'Enabled',
|
||||
'organization.member.tableDisable': 'Disabled',
|
||||
'organization.member.tableColunmEmail': 'Email',
|
||||
|
|
|
@ -5,7 +5,7 @@ export default {
|
|||
'organization.member.remove': '移除',
|
||||
'organization.member.edit': '编辑',
|
||||
'organization.member.batchActionAddProject': '添加至项目',
|
||||
'organization.member.batchActionAddUsergroup': '添加至用户组',
|
||||
'organization.member.batchActionAddUserGroup': '添加至用户组',
|
||||
'organization.member.tableEnable': '正常',
|
||||
'organization.member.tableDisable': '禁用',
|
||||
'organization.member.tableColunmEmail': '邮箱',
|
||||
|
|
|
@ -18,18 +18,19 @@
|
|||
</div>
|
||||
<MsDescription :descriptions="emailInfoDescs" :column="2">
|
||||
<template #value="{ item }">
|
||||
<div v-if="item.key && ['ssl', 'tsl'].includes(item.key)">
|
||||
<template v-if="item.key && ['ssl', 'tsl'].includes(item.key)">
|
||||
<div v-if="item.value === 'true'" class="flex items-center">
|
||||
<icon-check-circle-fill class="mr-[8px] text-[rgb(var(--success-6))]" />{{
|
||||
t('system.config.email.open')
|
||||
}}
|
||||
</div>
|
||||
<div v-else class="flex items-center">
|
||||
<div v-else-if="item.value === 'false'" class="flex items-center">
|
||||
<MsIcon type="icon-icon_disable" class="mr-[4px] text-[var(--color-text-4)]" />
|
||||
{{ t('system.config.email.close') }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="item.key === 'password' && item.value?.toString() !== ''">
|
||||
<div v-else>-</div>
|
||||
</template>
|
||||
<template v-else-if="item.key === 'password' && item.value !== null">
|
||||
<span v-if="pswInVisible">
|
||||
{{ item.value }}
|
||||
<icon-eye class="cursor-pointer text-[var(--color-text-4)]" @click="togglePswVisible" />
|
||||
|
@ -38,11 +39,14 @@
|
|||
{{ desensitize(item.value as string) }}
|
||||
<icon-eye-invisible class="cursor-pointer text-[var(--color-text-4)]" @click="togglePswVisible" />
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>{{ item.value?.toString() === '' ? '-' : item.value }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ item.value === undefined || item.value === null || item.value?.toString() === '' ? '-' : item.value }}
|
||||
</template>
|
||||
</template>
|
||||
</MsDescription>
|
||||
<a-button
|
||||
v-if="emailConfigForm.host !== null"
|
||||
type="outline"
|
||||
size="mini"
|
||||
class="arco-btn-outline--secondary"
|
||||
|
@ -451,12 +455,20 @@
|
|||
try {
|
||||
let params = {} as TestEmailParams;
|
||||
if (emailInfo === 'drawer') {
|
||||
drawerTestLoading.value = true;
|
||||
params = makeEmailTestParams({
|
||||
...emailConfigForm.value,
|
||||
ssl: emailConfigForm.value.ssl?.toString(),
|
||||
tsl: emailConfigForm.value.tsl?.toString(),
|
||||
let validError = false;
|
||||
await emailFormRef.value?.validate((errors: Record<string, ValidatedError> | undefined) => {
|
||||
if (!errors) {
|
||||
drawerTestLoading.value = true;
|
||||
params = makeEmailTestParams({
|
||||
...emailConfigForm.value,
|
||||
ssl: emailConfigForm.value.ssl?.toString(),
|
||||
tsl: emailConfigForm.value.tsl?.toString(),
|
||||
});
|
||||
} else {
|
||||
validError = true;
|
||||
}
|
||||
});
|
||||
if (validError) return;
|
||||
} else {
|
||||
testLoading.value = true;
|
||||
params = makeEmailTestParams({
|
||||
|
|
|
@ -168,10 +168,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
const defaultRange = props.mode === MENU_LEVEL[0] ? props.mode : MENU_LEVEL[2];
|
||||
const operateRange = ref<(string | number | Record<string, any>)[]>([defaultRange]); // 操作范围
|
||||
const operateRange = ref<(string | number | Record<string, any>)[]>([props.mode]); // 操作范围
|
||||
const rangeOptions = ref<CascaderOption[]>( // 系统级别才展示系统级别选项
|
||||
props.mode === 'SYSTEM'
|
||||
props.mode === MENU_LEVEL[0]
|
||||
? [
|
||||
{
|
||||
value: {
|
||||
|
@ -193,7 +192,7 @@
|
|||
try {
|
||||
rangeLoading.value = true;
|
||||
const res = await requestFuncMap[props.mode].optionsFunc(appStore.currentOrgId);
|
||||
if (props.mode === 'SYSTEM') {
|
||||
if (props.mode === MENU_LEVEL[0]) {
|
||||
// 系统级别才展示,组织和项目级别不展示
|
||||
rangeOptions.value.push({
|
||||
value: {
|
||||
|
@ -211,6 +210,14 @@
|
|||
isLeaf: true,
|
||||
})),
|
||||
});
|
||||
} else if (props.mode === MENU_LEVEL[1]) {
|
||||
rangeOptions.value.push({
|
||||
value: {
|
||||
level: 0,
|
||||
value: MENU_LEVEL[1], // 顶级范围-组织,单选
|
||||
},
|
||||
label: t('system.log.organization'),
|
||||
});
|
||||
}
|
||||
rangeOptions.value.push({
|
||||
value: {
|
||||
|
@ -235,7 +242,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
const level = ref<(typeof MENU_LEVEL)[number]>(defaultRange); // 操作范围级别,系统/组织/项目
|
||||
const level = ref<(typeof MENU_LEVEL)[number]>(props.mode); // 操作范围级别,系统/组织/项目
|
||||
const type = ref(''); // 操作类型
|
||||
const _module = ref(''); // 操作对象
|
||||
const content = ref(''); // 名称
|
||||
|
@ -438,7 +445,7 @@
|
|||
}
|
||||
|
||||
function handleNameClick(record: LogItem) {
|
||||
jumpRouteByMapKey(record.module, record.sourceId ? { id: record.sourceId } : {});
|
||||
jumpRouteByMapKey(record.module, record.sourceId ? { id: record.sourceId } : {}, true);
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
accept="jar"
|
||||
:max-size="50"
|
||||
size-unit="MB"
|
||||
main-text="system.user.importModalDragtext"
|
||||
main-text="system.user.importModalDragText"
|
||||
:sub-text="t('system.plugin.supportFormat')"
|
||||
:show-file-list="false"
|
||||
:auto-upload="false"
|
||||
|
|
|
@ -1,39 +1,38 @@
|
|||
<template>
|
||||
<a-modal
|
||||
v-model:visible="showBatchModal"
|
||||
title-align="start"
|
||||
class="ms-modal-upload ms-modal-medium"
|
||||
:loading="batchLoading"
|
||||
>
|
||||
<a-modal v-model:visible="showBatchModal" title-align="start" class="ms-modal-upload ms-modal-medium">
|
||||
<template #title>
|
||||
{{ batchTitle }}
|
||||
<div class="text-[var(--color-text-4)]">
|
||||
{{ t('system.user.batchModalSubTitle', { count: props.tableSelected.length }) }}
|
||||
</div>
|
||||
</template>
|
||||
<a-alert v-if="batchModalMode === 'project'" class="mb-[16px]">
|
||||
{{ t('system.user.batchModalTip') }}
|
||||
</a-alert>
|
||||
<a-transfer
|
||||
v-model="target"
|
||||
:title="[t('system.user.batchOptional'), t('system.user.batchChosen')]"
|
||||
:data="transferData"
|
||||
show-search
|
||||
>
|
||||
<template #source="{ data, selectedKeys, onSelect }">
|
||||
<a-tree
|
||||
:checkable="true"
|
||||
checked-strategy="child"
|
||||
:checked-keys="selectedKeys"
|
||||
:data="getTreeData(data)"
|
||||
block-node
|
||||
@check="onSelect"
|
||||
/>
|
||||
</template>
|
||||
</a-transfer>
|
||||
<a-spin :loading="loading">
|
||||
<a-alert v-if="batchModalMode === 'project'" class="mb-[16px]">
|
||||
{{ t('system.user.batchModalTip') }}
|
||||
</a-alert>
|
||||
<a-transfer
|
||||
v-model="target"
|
||||
:title="[t('system.user.batchOptional'), t('system.user.batchChosen')]"
|
||||
:data="transferData"
|
||||
show-search
|
||||
>
|
||||
<template #source="{ data, selectedKeys, onSelect }">
|
||||
<a-tree
|
||||
:checkable="true"
|
||||
checked-strategy="child"
|
||||
:checked-keys="selectedKeys"
|
||||
:data="getTreeData(data)"
|
||||
block-node
|
||||
@check="onSelect"
|
||||
/>
|
||||
</template>
|
||||
</a-transfer>
|
||||
</a-spin>
|
||||
<template #footer>
|
||||
<a-button type="secondary" @click="cancelBatch">{{ t('system.user.batchModalCancel') }}</a-button>
|
||||
<a-button type="primary" @click="confirmBatch">
|
||||
<a-button type="secondary" :disabled="batchLoading" @click="cancelBatch">{{
|
||||
t('system.user.batchModalCancel')
|
||||
}}</a-button>
|
||||
<a-button type="primary" :disabled="target.length === 0" :loading="batchLoading" @click="confirmBatch">
|
||||
{{ t('system.user.batchModalConfirm') }}
|
||||
</a-button>
|
||||
</template>
|
||||
|
@ -42,8 +41,18 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import {
|
||||
batchAddProject,
|
||||
batchAddOrg,
|
||||
batchAddUserGroup,
|
||||
getSystemOrgs,
|
||||
getSystemProjects,
|
||||
getSystemRoles,
|
||||
} from '@/api/modules/setting/user';
|
||||
|
||||
import type { OrgsItem } from '@/models/setting/user';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -64,7 +73,6 @@
|
|||
tableSelected: (string | number)[];
|
||||
visible: boolean;
|
||||
action: string;
|
||||
treeData: TreeDataItem[];
|
||||
}>(),
|
||||
{
|
||||
visible: false,
|
||||
|
@ -74,29 +82,82 @@
|
|||
const emit = defineEmits(['update:visible']);
|
||||
|
||||
const showBatchModal = ref(false);
|
||||
const batchLoading = ref(false);
|
||||
const batchTitle = ref('');
|
||||
const target = ref<string[]>([]);
|
||||
const batchModalMode = ref<'project' | 'usergroup' | 'organization'>('project');
|
||||
const batchModalMode = ref<'project' | 'userGroup' | 'organization'>('project');
|
||||
const treeData = ref<OrgsItem[]>([]);
|
||||
const loading = ref(false);
|
||||
const transferData = ref<TransferDataItem[]>([]);
|
||||
|
||||
function handleTableBatch(action: string) {
|
||||
switch (action) {
|
||||
case 'batchAddProject':
|
||||
batchModalMode.value = 'project';
|
||||
batchTitle.value = t('system.user.batchAddProject');
|
||||
break;
|
||||
case 'batchAddUsergroup':
|
||||
batchModalMode.value = 'usergroup';
|
||||
batchTitle.value = t('system.user.batchAddUsergroup');
|
||||
break;
|
||||
case 'batchAddOrgnization':
|
||||
batchModalMode.value = 'organization';
|
||||
batchTitle.value = t('system.user.batchAddOrgnization');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* 获取穿梭框数据,根据树结构获取
|
||||
* @param _treeData 树结构
|
||||
* @param transferDataSource 穿梭框数组
|
||||
*/
|
||||
const getTransferData = (_treeData: OrgsItem[], transferDataSource: TransferDataItem[]) => {
|
||||
_treeData.forEach((item) => {
|
||||
if (item.children) getTransferData(item.children, transferDataSource);
|
||||
else transferDataSource.push({ label: item.name, value: item.id, disabled: false });
|
||||
});
|
||||
return transferDataSource;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取树结构数据,根据穿梭框过滤的数据获取
|
||||
*/
|
||||
const getTreeData = (data: TransferDataItem[]) => {
|
||||
const values = data.map((item) => item.value);
|
||||
|
||||
const travel = (_treeData: OrgsItem[]) => {
|
||||
const treeDataSource: TreeDataItem[] = [];
|
||||
_treeData.forEach((item) => {
|
||||
// 需要判断当前父节点下的子节点是否全部选中,若选中则不会 push 进穿梭框数组内,否则会出现空的节点无法选中
|
||||
const allSelected = item.children?.every((child) => target.value.includes(child.id));
|
||||
if (!allSelected && (item.children || values.includes(item.id))) {
|
||||
treeDataSource.push({
|
||||
title: item.name,
|
||||
key: item.id,
|
||||
children: item.children ? travel(item.children) : [],
|
||||
});
|
||||
}
|
||||
});
|
||||
return treeDataSource;
|
||||
};
|
||||
|
||||
return travel(treeData.value);
|
||||
};
|
||||
|
||||
async function handleTableBatch(action: string) {
|
||||
showBatchModal.value = true;
|
||||
try {
|
||||
loading.value = true;
|
||||
let resTree: any[] = [];
|
||||
switch (action) {
|
||||
case 'batchAddProject':
|
||||
batchModalMode.value = 'project';
|
||||
batchTitle.value = t('system.user.batchAddProject');
|
||||
resTree = await getSystemProjects();
|
||||
break;
|
||||
case 'batchAddUserGroup':
|
||||
batchModalMode.value = 'userGroup';
|
||||
batchTitle.value = t('system.user.batchAddUserGroup');
|
||||
resTree = await getSystemRoles();
|
||||
break;
|
||||
case 'batchAddOrganization':
|
||||
batchModalMode.value = 'organization';
|
||||
batchTitle.value = t('system.user.batchAddOrganization');
|
||||
resTree = await getSystemOrgs();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
treeData.value = resTree;
|
||||
transferData.value = getTransferData(treeData.value, []);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
|
@ -114,71 +175,38 @@
|
|||
watch(
|
||||
() => showBatchModal.value,
|
||||
(val) => {
|
||||
if (!val) {
|
||||
target.value = [];
|
||||
}
|
||||
emit('update:visible', val);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 获取穿梭框数据,根据树结构获取
|
||||
* @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(props.treeData);
|
||||
};
|
||||
|
||||
const transferData = getTransferData(props.treeData, []);
|
||||
|
||||
function cancelBatch() {
|
||||
showBatchModal.value = false;
|
||||
target.value = [];
|
||||
}
|
||||
|
||||
async function batchAddProject() {}
|
||||
async function batchAddUsergroup() {}
|
||||
async function batchAddOrgnization() {}
|
||||
const batchLoading = ref(false);
|
||||
|
||||
async function confirmBatch() {
|
||||
batchLoading.value = true;
|
||||
try {
|
||||
const params = {
|
||||
selectIds: props.tableSelected as string[],
|
||||
selectAll: false,
|
||||
condition: {},
|
||||
roleIds: target.value,
|
||||
};
|
||||
switch (batchModalMode.value) {
|
||||
case 'project':
|
||||
await batchAddProject();
|
||||
await batchAddProject(params);
|
||||
break;
|
||||
case 'usergroup':
|
||||
await batchAddUsergroup();
|
||||
case 'userGroup':
|
||||
await batchAddUserGroup(params);
|
||||
break;
|
||||
case 'organization':
|
||||
await batchAddOrgnization();
|
||||
await batchAddOrg(params);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
v-model:model-value="keyword"
|
||||
:placeholder="t('system.user.searchUser')"
|
||||
class="w-[230px]"
|
||||
allow-clear
|
||||
@search="searchUser"
|
||||
@press-enter="searchUser"
|
||||
></a-input-search>
|
||||
|
@ -204,12 +205,7 @@
|
|||
</template>
|
||||
</a-modal>
|
||||
<inviteModal v-model:visible="inviteVisible" :user-group-options="userGroupOptions"></inviteModal>
|
||||
<batchModal
|
||||
v-model:visible="showBatchModal"
|
||||
:table-selected="tableSelected"
|
||||
:action="batchAction"
|
||||
:tree-data="treeData"
|
||||
></batchModal>
|
||||
<batchModal v-model:visible="showBatchModal" :table-selected="tableSelected" :action="batchAction"></batchModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -273,7 +269,7 @@
|
|||
showInTable: true,
|
||||
},
|
||||
{
|
||||
title: 'system.user.tableColumnUsergroup',
|
||||
title: 'system.user.tableColumnUserGroup',
|
||||
slotName: 'userRole',
|
||||
dataIndex: 'userRoleList',
|
||||
showInTable: true,
|
||||
|
@ -490,15 +486,19 @@
|
|||
eventTag: 'batchAddProject',
|
||||
},
|
||||
{
|
||||
label: 'system.user.batchActionAddUsergroup',
|
||||
eventTag: 'batchAddUsergroup',
|
||||
label: 'system.user.batchActionAddUserGroup',
|
||||
eventTag: 'batchAddUserGroup',
|
||||
},
|
||||
{
|
||||
label: 'system.user.batchActionAddOrgnization',
|
||||
eventTag: 'batchAddOrgnization',
|
||||
label: 'system.user.batchActionAddOrganization',
|
||||
eventTag: 'batchAddOrganization',
|
||||
},
|
||||
],
|
||||
moreAction: [
|
||||
{
|
||||
label: 'system.user.resetPassword',
|
||||
eventTag: 'resetPassword',
|
||||
},
|
||||
{
|
||||
label: 'system.user.disable',
|
||||
eventTag: 'disabled',
|
||||
|
@ -520,40 +520,6 @@
|
|||
|
||||
const showBatchModal = ref(false);
|
||||
const batchAction = ref(''); // 表格选中批量操作动作
|
||||
const treeData = ref([
|
||||
{
|
||||
title: 'Trunk 0-3',
|
||||
key: '0-3',
|
||||
},
|
||||
{
|
||||
title: 'Trunk 0-0',
|
||||
key: '0-0',
|
||||
children: [
|
||||
{
|
||||
title: 'Leaf 0-0-1',
|
||||
key: '0-0-1',
|
||||
},
|
||||
{
|
||||
title: 'Branch 0-0-2',
|
||||
key: '0-0-2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Trunk 0-1',
|
||||
key: '0-1',
|
||||
children: [
|
||||
{
|
||||
title: 'Branch 0-1-1',
|
||||
key: '0-1-1',
|
||||
},
|
||||
{
|
||||
title: 'Leaf 0-1-2',
|
||||
key: '0-1-2',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
/**
|
||||
* 处理表格选中后批量操作
|
||||
|
@ -562,11 +528,14 @@
|
|||
function handleTableBatch(event: BatchActionParams) {
|
||||
switch (event.eventTag) {
|
||||
case 'batchAddProject':
|
||||
case 'batchAddUsergroup':
|
||||
case 'batchAddOrgnization':
|
||||
case 'batchAddUserGroup':
|
||||
case 'batchAddOrganization':
|
||||
batchAction.value = event.eventTag;
|
||||
showBatchModal.value = true;
|
||||
break;
|
||||
case 'resetPassword':
|
||||
resetPassword(null, true);
|
||||
break;
|
||||
case 'disabled':
|
||||
disabledUser(null, true);
|
||||
break;
|
||||
|
@ -764,15 +733,18 @@
|
|||
|
||||
/**
|
||||
* 创建用户
|
||||
* @param isContinue 是否继续创建
|
||||
*/
|
||||
async function createUser() {
|
||||
async function createUser(isContinue?: boolean) {
|
||||
const params = {
|
||||
userInfoList: userForm.value.list,
|
||||
userRoleIdList: userForm.value.userGroup,
|
||||
};
|
||||
await batchCreateUser(params);
|
||||
Message.success(t('system.user.addUserSuccess'));
|
||||
visible.value = false;
|
||||
if (!isContinue) {
|
||||
visible.value = false;
|
||||
}
|
||||
loadList();
|
||||
}
|
||||
|
||||
|
@ -815,7 +787,7 @@
|
|||
*/
|
||||
function saveAndContinue() {
|
||||
userFormValidate(async () => {
|
||||
await createUser();
|
||||
await createUser(true);
|
||||
resetUserForm();
|
||||
});
|
||||
}
|
||||
|
@ -867,7 +839,7 @@
|
|||
loadList();
|
||||
break;
|
||||
case 'allFail':
|
||||
importResultTitle.value = t('system.user.importAllfailTitle');
|
||||
importResultTitle.value = t('system.user.importAllFailTitle');
|
||||
break;
|
||||
case 'fail':
|
||||
importResultTitle.value = t('system.user.importFailTitle');
|
||||
|
|
|
@ -51,8 +51,8 @@ export default {
|
|||
'system.user.createUserPhone': 'Phone',
|
||||
'system.user.createUserPhoneErr': 'Please enter 11 digit mobile number',
|
||||
'system.user.createUserPhonePlaceholder': 'Please enter an 11-digit mobile number',
|
||||
'system.user.createUserOrgnization': 'Orgnization',
|
||||
'system.user.createUserOrgnizationPlaceholder': 'Please select user organization',
|
||||
'system.user.createUserOrganization': 'Organization',
|
||||
'system.user.createUserOrganizationPlaceholder': 'Please select user organization',
|
||||
'system.user.createUserUserGroup': 'UserGroup',
|
||||
'system.user.createUserUserGroupPlaceholder': 'Please select a user group',
|
||||
'system.user.editUserModalTitle': 'Edit the user',
|
||||
|
@ -69,7 +69,7 @@ export default {
|
|||
'system.user.importModalTitle': 'Import user',
|
||||
'system.user.importDownload': 'Download the template',
|
||||
'system.user.importModalTip': 'User groups only support adding user groups that exist in the system',
|
||||
'system.user.importModalDragtext': 'Drag or click this area to select a file',
|
||||
'system.user.importModalDragText': 'Drag or click this area to select a file',
|
||||
'system.user.importModalFileTip': 'Only supports xls/xlsx format files, and the file size should not exceed 50M',
|
||||
'system.user.importModalCancel': 'Cancel',
|
||||
'system.user.importModalConfirm': 'Import',
|
||||
|
@ -77,7 +77,7 @@ export default {
|
|||
'system.user.importSuccessTitle': 'Import user',
|
||||
'system.user.importSuccess': 'Import succeeded',
|
||||
'system.user.importFailTitle': 'Some user information failed to import',
|
||||
'system.user.importAllfailTitle': 'User information import failed',
|
||||
'system.user.importAllFailTitle': 'User information import failed',
|
||||
'system.user.importResultContent': 'Successfully imported user {successNum} items, failed to import {failNum} items;',
|
||||
'system.user.importResultContentSubStart': 'You can',
|
||||
'system.user.importResultContentDownload': 'Download bug report',
|
||||
|
@ -87,23 +87,23 @@ export default {
|
|||
'system.user.importResultContinue': 'Continue importing',
|
||||
'system.user.importErrorFile': 'error report',
|
||||
'system.user.batchActionAddProject': 'Add to project',
|
||||
'system.user.batchActionAddUsergroup': 'Add to usergroup',
|
||||
'system.user.batchActionAddOrgnization': 'Add to org',
|
||||
'system.user.batchModalTip': 'Add project member usergroup as member by default',
|
||||
'system.user.batchActionAddUserGroup': 'Add to user group',
|
||||
'system.user.batchActionAddOrganization': 'Add to org',
|
||||
'system.user.batchModalTip': 'Add project member user group as member by default',
|
||||
'system.user.batchModalSubTitle': '(Selected {count} users)',
|
||||
'system.user.batchModalCancel': 'Cancel',
|
||||
'system.user.batchModalConfirm': 'Add',
|
||||
'system.user.batchModalSuccess': 'Successfully added',
|
||||
'system.user.batchAddProject': 'Batch add to project',
|
||||
'system.user.batchAddUsergroup': 'Batch add to user group',
|
||||
'system.user.batchAddOrgnization': 'Batch add to organization',
|
||||
'system.user.batchAddUserGroup': 'Batch add to user group',
|
||||
'system.user.batchAddOrganization': 'Batch add to organization',
|
||||
'system.user.batchOptional': 'Optional',
|
||||
'system.user.batchChosen': 'Chosen',
|
||||
'system.user.tableColumnEmail': 'Email',
|
||||
'system.user.tableColumnName': 'Name',
|
||||
'system.user.tableColumnPhone': 'Phone',
|
||||
'system.user.tableColumnOrg': 'Orgnization',
|
||||
'system.user.tableColumnUsergroup': 'UserGroup',
|
||||
'system.user.tableColumnOrg': 'Organization',
|
||||
'system.user.tableColumnUserGroup': 'UserGroup',
|
||||
'system.user.tableColumnStatus': 'Status',
|
||||
'system.user.tableColumnActions': 'Actions',
|
||||
};
|
||||
|
|
|
@ -50,8 +50,8 @@ export default {
|
|||
'system.user.createUserPhone': '手机',
|
||||
'system.user.createUserPhoneErr': '请输入11位手机号',
|
||||
'system.user.createUserPhonePlaceholder': '请输入 11 位手机号',
|
||||
'system.user.createUserOrgnization': '组织',
|
||||
'system.user.createUserOrgnizationPlaceholder': '请选择用户组织',
|
||||
'system.user.createUserOrganization': '组织',
|
||||
'system.user.createUserOrganizationPlaceholder': '请选择用户组织',
|
||||
'system.user.createUserUserGroup': '用户组',
|
||||
'system.user.createUserUserGroupPlaceholder': '请选择用户组',
|
||||
'system.user.editUserModalTitle': '编辑用户',
|
||||
|
@ -68,7 +68,7 @@ export default {
|
|||
'system.user.importModalTitle': '导入用户',
|
||||
'system.user.importModalTip': '用户组仅支持添加系统存在的用户组',
|
||||
'system.user.importDownload': '下载模板',
|
||||
'system.user.importModalDragtext': '拖拽或点击此区域选择文件',
|
||||
'system.user.importModalDragText': '拖拽或点击此区域选择文件',
|
||||
'system.user.importModalFileTip': '只支持 xls/xlsx格式文件,文件大小不超过 50M',
|
||||
'system.user.importModalCancel': '取消',
|
||||
'system.user.importModalConfirm': '导入',
|
||||
|
@ -76,7 +76,7 @@ export default {
|
|||
'system.user.importSuccessTitle': '导入用户',
|
||||
'system.user.importSuccess': '导入成功',
|
||||
'system.user.importFailTitle': '部分用户信息导入失败',
|
||||
'system.user.importAllfailTitle': '用户信息导入失败',
|
||||
'system.user.importAllFailTitle': '用户信息导入失败',
|
||||
'system.user.importResultContent': '成功导入用户 {successNum} 个,导入失败 {failNum} 个;',
|
||||
'system.user.importResultContentSubStart': '可',
|
||||
'system.user.importResultContentDownload': '下载错误报告',
|
||||
|
@ -86,23 +86,23 @@ export default {
|
|||
'system.user.importResultContinue': '继续导入',
|
||||
'system.user.importErrorFile': '错误报告',
|
||||
'system.user.batchActionAddProject': '添加至项目',
|
||||
'system.user.batchActionAddUsergroup': '添加至用户组',
|
||||
'system.user.batchActionAddOrgnization': '添加至组织',
|
||||
'system.user.batchActionAddUserGroup': '添加至用户组',
|
||||
'system.user.batchActionAddOrganization': '添加至组织',
|
||||
'system.user.batchModalTip': '默认为成员添加项目成员用户组',
|
||||
'system.user.batchModalSubTitle': '(已选 {count} 个用户)',
|
||||
'system.user.batchModalCancel': '取消',
|
||||
'system.user.batchModalConfirm': '添加',
|
||||
'system.user.batchModalSuccess': '添加成功',
|
||||
'system.user.batchAddProject': '批量添加至项目',
|
||||
'system.user.batchAddUsergroup': '批量添加至用户组',
|
||||
'system.user.batchAddOrgnization': '批量添加至组织',
|
||||
'system.user.batchAddUserGroup': '批量添加至用户组',
|
||||
'system.user.batchAddOrganization': '批量添加至组织',
|
||||
'system.user.batchOptional': '可选',
|
||||
'system.user.batchChosen': '已选',
|
||||
'system.user.tableColumnEmail': '邮箱',
|
||||
'system.user.tableColumnName': '姓名',
|
||||
'system.user.tableColumnPhone': '手机',
|
||||
'system.user.tableColumnOrg': '组织',
|
||||
'system.user.tableColumnUsergroup': '用户组',
|
||||
'system.user.tableColumnUserGroup': '用户组',
|
||||
'system.user.tableColumnStatus': '状态',
|
||||
'system.user.tableColumnActions': '操作',
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue