feat(系统设置): 用户批量操作接口&部分单词拼写修正&部分组件调整

This commit is contained in:
baiqi 2023-08-24 16:01:55 +08:00 committed by 刘瑞斌
parent 193b54a02c
commit b18e2e85c4
22 changed files with 303 additions and 230 deletions

View File

@ -17,6 +17,11 @@ export default mergeConfig(
changeOrigin: true, changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/front/, ''), 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: [ plugins: [

View File

@ -11,14 +11,13 @@
import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn'; import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn';
import GlobalSetting from '@/components/pure/global-setting/index.vue'; import GlobalSetting from '@/components/pure/global-setting/index.vue';
import useLocale from '@/locale/useLocale'; 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 { getLocalStorage, setLocalStorage } from '@/utils/local-storage';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useLicenseStore from '@/store/modules/setting/license'; import useLicenseStore from '@/store/modules/setting/license';
import { watchStyle, watchTheme, setFavicon } from '@/utils/theme'; import { watchStyle, watchTheme, setFavicon } from '@/utils/theme';
import { GetPlatformIconUrl } from '@/api/requrls/setting/config'; import { GetPlatformIconUrl } from '@/api/requrls/setting/config';
import { useUserStore } from '@/store'; import { useUserStore } from '@/store';
import { useRouter } from 'vue-router';
const appStore = useAppStore(); const appStore = useAppStore();
const userStore = useUserStore(); const userStore = useUserStore();
@ -39,19 +38,16 @@
// //
watchStyle(appStore.pageConfig.style, appStore.pageConfig); watchStyle(appStore.pageConfig.style, appStore.pageConfig);
watchTheme(appStore.pageConfig.theme, appStore.pageConfig); watchTheme(appStore.pageConfig.theme, appStore.pageConfig);
window.document.title = appStore.pageConfig.title;
setFavicon(GetPlatformIconUrl); setFavicon(GetPlatformIconUrl);
onBeforeMount(async () => { onBeforeMount(async () => {
try { try {
appStore.initSystemversion(); // appStore.initSystemVersion(); //
appStore.initPageConfig(); // appStore.initPageConfig(); //
licenseStore.getValidateLicense(); // license licenseStore.getValidateLicense(); // license
// url url // url url
const isInitUrl = getLocalStorage('isInitUrl'); // url const isInitUrl = getLocalStorage('isInitUrl'); // url
if (isInitUrl === 'true') return; if (isInitUrl === 'true') return;
const res = await getBaseInfo();
if (res.url === 'http://127.0.0.1:8081') {
await saveBaseInfo([ await saveBaseInfo([
{ {
paramKey: 'base.url', paramKey: 'base.url',
@ -60,9 +56,6 @@
}, },
]); ]);
setLocalStorage('isInitUrl', 'true'); // url setLocalStorage('isInitUrl', 'true'); // url
} else {
setLocalStorage('isInitUrl', 'true'); // url
}
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);

View File

@ -9,6 +9,10 @@ import {
GetSystemRoleUrl, GetSystemRoleUrl,
ResetPasswordUrl, ResetPasswordUrl,
BatchAddUserGroupUrl, BatchAddUserGroupUrl,
BatchAddOrgUrl,
BatchAddProjectUrl,
GetOrgsUrl,
GetProjectsUrl,
} from '@/api/requrls/setting/user'; } from '@/api/requrls/setting/user';
import type { import type {
UserListItem, UserListItem,
@ -19,8 +23,9 @@ import type {
ImportUserParams, ImportUserParams,
SystemRole, SystemRole,
ImportResult, ImportResult,
BatchAddUserGroupParams, BatchAddParams,
ResetUserPasswordParams, ResetUserPasswordParams,
OrgsItem,
} from '@/models/setting/user'; } from '@/models/setting/user';
import type { CommonList, TableQueryParams } from '@/models/common'; 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 }); 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 });
}

View File

@ -16,3 +16,11 @@ export const GetSystemRoleUrl = '/system/user/get/global/system/role';
export const ResetPasswordUrl = '/system/user/reset/password'; export const ResetPasswordUrl = '/system/user/reset/password';
// 批量添加用户到多个用户组 // 批量添加用户到多个用户组
export const BatchAddUserGroupUrl = '/system/user/add/batch/user-role'; 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';

View File

@ -84,11 +84,11 @@
case 'batchAddProject': case 'batchAddProject':
batchTitle.value = t('system.user.batchAddProject'); batchTitle.value = t('system.user.batchAddProject');
break; break;
case 'batchAddUsergroup': case 'batchAddUserGroup':
batchTitle.value = t('system.user.batchAddUsergroup'); batchTitle.value = t('system.user.batchAddUserGroup');
break; break;
case 'batchAddOrgnization': case 'batchAddOrganization':
batchTitle.value = t('system.user.batchAddOrgnization'); batchTitle.value = t('system.user.batchAddOrganization');
break; break;
default: default:
break; break;
@ -182,10 +182,10 @@
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 'batchAddOrgnization': case 'batchAddOrganization':
emit('addOrgnization', target.value, 'orgnization'); emit('addOrgnization', target.value, 'orgnization');
break; break;
default: default:

View File

@ -14,6 +14,7 @@
:placeholder="props.placeholder" :placeholder="props.placeholder"
:loading="props.loading" :loading="props.loading"
@change="handleMsCascaderChange" @change="handleMsCascaderChange"
@clear="clearValues"
> >
<template #prefix> <template #prefix>
{{ props.prefix }} {{ props.prefix }}
@ -224,6 +225,10 @@
}); });
} }
function clearValues() {
innerLevel.value = '';
}
onMounted(() => { onMounted(() => {
if (cascader.value) { if (cascader.value) {
cascaderWidth.value = cascader.value.$el.nextElementSibling.getBoundingClientRect().width; cascaderWidth.value = cascader.value.$el.nextElementSibling.getBoundingClientRect().width;

View File

@ -16,7 +16,7 @@
</div> </div>
<template v-if="fileList.length === 0"> <template v-if="fileList.length === 0">
<div class="ms-upload-main-text"> <div class="ms-upload-main-text">
{{ t(props.mainText || 'ms.upload.importModalDragtext') }} {{ t(props.mainText || 'ms.upload.importModalDragText') }}
</div> </div>
<div v-if="showSubText" class="ms-upload-sub-text"> <div v-if="showSubText" class="ms-upload-sub-text">
{{ {{

View File

@ -1,6 +1,6 @@
export default { export default {
'ms.upload.changeFile': 'Change file', 'ms.upload.changeFile': 'Change file',
'ms.upload.overSize': 'The file size exceeds the limit, please reselect the 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', 'ms.upload.importModalFileTip': 'Only {type} format files are supported, and the file size does not exceed {size} MB',
}; };

View File

@ -1,6 +1,6 @@
export default { export default {
'ms.upload.changeFile': '更改文件', 'ms.upload.changeFile': '更改文件',
'ms.upload.overSize': '文件大小超出限制,请重新选择文件', 'ms.upload.overSize': '文件大小超出限制,请重新选择文件',
'ms.upload.importModalDragtext': '拖拽或点击此区域选择文件', 'ms.upload.importModalDragText': '拖拽或点击此区域选择文件',
'ms.upload.importModalFileTip': '只支持 {type} 格式文件,文件大小不超过 {size} MB', 'ms.upload.importModalFileTip': '只支持 {type} 格式文件,文件大小不超过 {size} MB',
}; };

View File

@ -34,11 +34,21 @@ export default function usePathMap() {
/** /**
* key routeQuery routeQuery * key routeQuery routeQuery
* TODO: 权限校验待补充 * 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); const pathNode = findNodeByKey(pathMap, key as unknown as string);
if (pathNode) { if (pathNode) {
if (openNewPage) {
window.open(
`${window.location.origin}#${router.resolve({ name: pathNode?.route }).fullPath}?${new URLSearchParams({
...routeQuery,
...pathNode?.routeQuery,
}).toString()}`
);
} else {
router.push({ router.push({
name: pathNode?.route, name: pathNode?.route,
query: { query: {
@ -47,6 +57,7 @@ export default function usePathMap() {
}, },
}); });
} }
}
}; };
return { return {

View File

@ -97,6 +97,12 @@ export interface ImportResult {
errorMessages: Record<string, any>; errorMessages: Record<string, any>;
} }
export interface BatchAddUserGroupParams extends BatchApiParams { export interface BatchAddParams extends BatchApiParams {
roleIds: string[]; // 用户组 id 集合 roleIds: string[]; // 用户组/项目/组织 id 集合
}
export interface OrgsItem {
id: string;
name: string;
children?: OrgsItem[];
} }

View File

@ -197,7 +197,7 @@ const useAppStore = defineStore('app', {
/** /**
* *
*/ */
async initSystemversion() { async initSystemVersion() {
try { try {
this.version = await getSystemVersion(); this.version = await getSystemVersion();
} catch (error) { } catch (error) {
@ -263,6 +263,7 @@ const useAppStore = defineStore('app', {
if (hasThemeChange) { if (hasThemeChange) {
watchTheme(this.pageConfig.theme, this.pageConfig); watchTheme(this.pageConfig.theme, this.pageConfig);
} }
window.document.title = this.pageConfig.title;
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);

View File

@ -221,8 +221,8 @@
eventTag: 'batchAddProject', eventTag: 'batchAddProject',
}, },
{ {
label: 'organization.member.batchActionAddUsergroup', label: 'organization.member.batchActionAddUserGroup',
eventTag: 'batchAddUsergroup', eventTag: 'batchAddUserGroup',
}, },
], ],
}; };
@ -324,7 +324,7 @@
treeData.value = []; 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);
}; };
// //
const updateUserOrProject = async (record: MemberItem) => { const updateUserOrProject = async (record: MemberItem) => {

View File

@ -5,7 +5,7 @@ export default {
'organization.member.remove': 'Remove', 'organization.member.remove': 'Remove',
'organization.member.edit': 'Edit', 'organization.member.edit': 'Edit',
'organization.member.batchActionAddProject': 'Add to project', 'organization.member.batchActionAddProject': 'Add to project',
'organization.member.batchActionAddUsergroup': 'Add to usergroup', 'organization.member.batchActionAddUserGroup': 'Add to usergroup',
'organization.member.tableEnable': 'Enabled', 'organization.member.tableEnable': 'Enabled',
'organization.member.tableDisable': 'Disabled', 'organization.member.tableDisable': 'Disabled',
'organization.member.tableColunmEmail': 'Email', 'organization.member.tableColunmEmail': 'Email',

View File

@ -5,7 +5,7 @@ export default {
'organization.member.remove': '移除', 'organization.member.remove': '移除',
'organization.member.edit': '编辑', 'organization.member.edit': '编辑',
'organization.member.batchActionAddProject': '添加至项目', 'organization.member.batchActionAddProject': '添加至项目',
'organization.member.batchActionAddUsergroup': '添加至用户组', 'organization.member.batchActionAddUserGroup': '添加至用户组',
'organization.member.tableEnable': '正常', 'organization.member.tableEnable': '正常',
'organization.member.tableDisable': '禁用', 'organization.member.tableDisable': '禁用',
'organization.member.tableColunmEmail': '邮箱', 'organization.member.tableColunmEmail': '邮箱',

View File

@ -18,18 +18,19 @@
</div> </div>
<MsDescription :descriptions="emailInfoDescs" :column="2"> <MsDescription :descriptions="emailInfoDescs" :column="2">
<template #value="{ item }"> <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"> <div v-if="item.value === 'true'" class="flex items-center">
<icon-check-circle-fill class="mr-[8px] text-[rgb(var(--success-6))]" />{{ <icon-check-circle-fill class="mr-[8px] text-[rgb(var(--success-6))]" />{{
t('system.config.email.open') t('system.config.email.open')
}} }}
</div> </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)]" /> <MsIcon type="icon-icon_disable" class="mr-[4px] text-[var(--color-text-4)]" />
{{ t('system.config.email.close') }} {{ t('system.config.email.close') }}
</div> </div>
</div> <div v-else>-</div>
<div v-else-if="item.key === 'password' && item.value?.toString() !== ''"> </template>
<template v-else-if="item.key === 'password' && item.value !== null">
<span v-if="pswInVisible"> <span v-if="pswInVisible">
{{ item.value }} {{ item.value }}
<icon-eye class="cursor-pointer text-[var(--color-text-4)]" @click="togglePswVisible" /> <icon-eye class="cursor-pointer text-[var(--color-text-4)]" @click="togglePswVisible" />
@ -38,11 +39,14 @@
{{ desensitize(item.value as string) }} {{ desensitize(item.value as string) }}
<icon-eye-invisible class="cursor-pointer text-[var(--color-text-4)]" @click="togglePswVisible" /> <icon-eye-invisible class="cursor-pointer text-[var(--color-text-4)]" @click="togglePswVisible" />
</span> </span>
</div> </template>
<div v-else>{{ item.value?.toString() === '' ? '-' : item.value }}</div> <template v-else>
{{ item.value === undefined || item.value === null || item.value?.toString() === '' ? '-' : item.value }}
</template>
</template> </template>
</MsDescription> </MsDescription>
<a-button <a-button
v-if="emailConfigForm.host !== null"
type="outline" type="outline"
size="mini" size="mini"
class="arco-btn-outline--secondary" class="arco-btn-outline--secondary"
@ -451,12 +455,20 @@
try { try {
let params = {} as TestEmailParams; let params = {} as TestEmailParams;
if (emailInfo === 'drawer') { if (emailInfo === 'drawer') {
let validError = false;
await emailFormRef.value?.validate((errors: Record<string, ValidatedError> | undefined) => {
if (!errors) {
drawerTestLoading.value = true; drawerTestLoading.value = true;
params = makeEmailTestParams({ params = makeEmailTestParams({
...emailConfigForm.value, ...emailConfigForm.value,
ssl: emailConfigForm.value.ssl?.toString(), ssl: emailConfigForm.value.ssl?.toString(),
tsl: emailConfigForm.value.tsl?.toString(), tsl: emailConfigForm.value.tsl?.toString(),
}); });
} else {
validError = true;
}
});
if (validError) return;
} else { } else {
testLoading.value = true; testLoading.value = true;
params = makeEmailTestParams({ params = makeEmailTestParams({

View File

@ -168,10 +168,9 @@
} }
} }
const defaultRange = props.mode === MENU_LEVEL[0] ? props.mode : MENU_LEVEL[2]; const operateRange = ref<(string | number | Record<string, any>)[]>([props.mode]); //
const operateRange = ref<(string | number | Record<string, any>)[]>([defaultRange]); //
const rangeOptions = ref<CascaderOption[]>( // const rangeOptions = ref<CascaderOption[]>( //
props.mode === 'SYSTEM' props.mode === MENU_LEVEL[0]
? [ ? [
{ {
value: { value: {
@ -193,7 +192,7 @@
try { try {
rangeLoading.value = true; rangeLoading.value = true;
const res = await requestFuncMap[props.mode].optionsFunc(appStore.currentOrgId); const res = await requestFuncMap[props.mode].optionsFunc(appStore.currentOrgId);
if (props.mode === 'SYSTEM') { if (props.mode === MENU_LEVEL[0]) {
// //
rangeOptions.value.push({ rangeOptions.value.push({
value: { value: {
@ -211,6 +210,14 @@
isLeaf: true, 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({ rangeOptions.value.push({
value: { 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 type = ref(''); //
const _module = ref(''); // const _module = ref(''); //
const content = ref(''); // const content = ref(''); //
@ -438,7 +445,7 @@
} }
function handleNameClick(record: LogItem) { function handleNameClick(record: LogItem) {
jumpRouteByMapKey(record.module, record.sourceId ? { id: record.sourceId } : {}); jumpRouteByMapKey(record.module, record.sourceId ? { id: record.sourceId } : {}, true);
} }
onBeforeMount(() => { onBeforeMount(() => {

View File

@ -65,7 +65,7 @@
accept="jar" accept="jar"
:max-size="50" :max-size="50"
size-unit="MB" size-unit="MB"
main-text="system.user.importModalDragtext" main-text="system.user.importModalDragText"
:sub-text="t('system.plugin.supportFormat')" :sub-text="t('system.plugin.supportFormat')"
:show-file-list="false" :show-file-list="false"
:auto-upload="false" :auto-upload="false"

View File

@ -1,16 +1,12 @@
<template> <template>
<a-modal <a-modal v-model:visible="showBatchModal" title-align="start" class="ms-modal-upload ms-modal-medium">
v-model:visible="showBatchModal"
title-align="start"
class="ms-modal-upload ms-modal-medium"
:loading="batchLoading"
>
<template #title> <template #title>
{{ batchTitle }} {{ batchTitle }}
<div class="text-[var(--color-text-4)]"> <div class="text-[var(--color-text-4)]">
{{ t('system.user.batchModalSubTitle', { count: props.tableSelected.length }) }} {{ t('system.user.batchModalSubTitle', { count: props.tableSelected.length }) }}
</div> </div>
</template> </template>
<a-spin :loading="loading">
<a-alert v-if="batchModalMode === 'project'" class="mb-[16px]"> <a-alert v-if="batchModalMode === 'project'" class="mb-[16px]">
{{ t('system.user.batchModalTip') }} {{ t('system.user.batchModalTip') }}
</a-alert> </a-alert>
@ -31,9 +27,12 @@
/> />
</template> </template>
</a-transfer> </a-transfer>
</a-spin>
<template #footer> <template #footer>
<a-button type="secondary" @click="cancelBatch">{{ t('system.user.batchModalCancel') }}</a-button> <a-button type="secondary" :disabled="batchLoading" @click="cancelBatch">{{
<a-button type="primary" @click="confirmBatch"> t('system.user.batchModalCancel')
}}</a-button>
<a-button type="primary" :disabled="target.length === 0" :loading="batchLoading" @click="confirmBatch">
{{ t('system.user.batchModalConfirm') }} {{ t('system.user.batchModalConfirm') }}
</a-button> </a-button>
</template> </template>
@ -42,8 +41,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { useI18n } from '@/hooks/useI18n';
import { Message } from '@arco-design/web-vue'; 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(); const { t } = useI18n();
@ -64,7 +73,6 @@
tableSelected: (string | number)[]; tableSelected: (string | number)[];
visible: boolean; visible: boolean;
action: string; action: string;
treeData: TreeDataItem[];
}>(), }>(),
{ {
visible: false, visible: false,
@ -74,29 +82,82 @@
const emit = defineEmits(['update:visible']); const emit = defineEmits(['update:visible']);
const showBatchModal = ref(false); const showBatchModal = ref(false);
const batchLoading = ref(false);
const batchTitle = ref(''); const batchTitle = ref('');
const target = ref<string[]>([]); 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) { /**
* 获取穿梭框数据根据树结构获取
* @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) { switch (action) {
case 'batchAddProject': case 'batchAddProject':
batchModalMode.value = 'project'; batchModalMode.value = 'project';
batchTitle.value = t('system.user.batchAddProject'); batchTitle.value = t('system.user.batchAddProject');
resTree = await getSystemProjects();
break; break;
case 'batchAddUsergroup': case 'batchAddUserGroup':
batchModalMode.value = 'usergroup'; batchModalMode.value = 'userGroup';
batchTitle.value = t('system.user.batchAddUsergroup'); batchTitle.value = t('system.user.batchAddUserGroup');
resTree = await getSystemRoles();
break; break;
case 'batchAddOrgnization': case 'batchAddOrganization':
batchModalMode.value = 'organization'; batchModalMode.value = 'organization';
batchTitle.value = t('system.user.batchAddOrgnization'); batchTitle.value = t('system.user.batchAddOrganization');
resTree = await getSystemOrgs();
break; break;
default: default:
break; break;
} }
showBatchModal.value = true; treeData.value = resTree;
transferData.value = getTransferData(treeData.value, []);
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
} }
watch( watch(
@ -114,71 +175,38 @@
watch( watch(
() => showBatchModal.value, () => showBatchModal.value,
(val) => { (val) => {
if (!val) {
target.value = [];
}
emit('update:visible', val); 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() { function cancelBatch() {
showBatchModal.value = false; showBatchModal.value = false;
target.value = []; target.value = [];
} }
async function batchAddProject() {} const batchLoading = ref(false);
async function batchAddUsergroup() {}
async function batchAddOrgnization() {}
async function confirmBatch() { async function confirmBatch() {
batchLoading.value = true; batchLoading.value = true;
try { try {
const params = {
selectIds: props.tableSelected as string[],
selectAll: false,
condition: {},
roleIds: target.value,
};
switch (batchModalMode.value) { switch (batchModalMode.value) {
case 'project': case 'project':
await batchAddProject(); await batchAddProject(params);
break; break;
case 'usergroup': case 'userGroup':
await batchAddUsergroup(); await batchAddUserGroup(params);
break; break;
case 'organization': case 'organization':
await batchAddOrgnization(); await batchAddOrg(params);
break; break;
default: default:
break; break;

View File

@ -14,6 +14,7 @@
v-model:model-value="keyword" v-model:model-value="keyword"
:placeholder="t('system.user.searchUser')" :placeholder="t('system.user.searchUser')"
class="w-[230px]" class="w-[230px]"
allow-clear
@search="searchUser" @search="searchUser"
@press-enter="searchUser" @press-enter="searchUser"
></a-input-search> ></a-input-search>
@ -204,12 +205,7 @@
</template> </template>
</a-modal> </a-modal>
<inviteModal v-model:visible="inviteVisible" :user-group-options="userGroupOptions"></inviteModal> <inviteModal v-model:visible="inviteVisible" :user-group-options="userGroupOptions"></inviteModal>
<batchModal <batchModal v-model:visible="showBatchModal" :table-selected="tableSelected" :action="batchAction"></batchModal>
v-model:visible="showBatchModal"
:table-selected="tableSelected"
:action="batchAction"
:tree-data="treeData"
></batchModal>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -273,7 +269,7 @@
showInTable: true, showInTable: true,
}, },
{ {
title: 'system.user.tableColumnUsergroup', title: 'system.user.tableColumnUserGroup',
slotName: 'userRole', slotName: 'userRole',
dataIndex: 'userRoleList', dataIndex: 'userRoleList',
showInTable: true, showInTable: true,
@ -490,15 +486,19 @@
eventTag: 'batchAddProject', eventTag: 'batchAddProject',
}, },
{ {
label: 'system.user.batchActionAddUsergroup', label: 'system.user.batchActionAddUserGroup',
eventTag: 'batchAddUsergroup', eventTag: 'batchAddUserGroup',
}, },
{ {
label: 'system.user.batchActionAddOrgnization', label: 'system.user.batchActionAddOrganization',
eventTag: 'batchAddOrgnization', eventTag: 'batchAddOrganization',
}, },
], ],
moreAction: [ moreAction: [
{
label: 'system.user.resetPassword',
eventTag: 'resetPassword',
},
{ {
label: 'system.user.disable', label: 'system.user.disable',
eventTag: 'disabled', eventTag: 'disabled',
@ -520,40 +520,6 @@
const showBatchModal = ref(false); const showBatchModal = ref(false);
const batchAction = ref(''); // 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) { function handleTableBatch(event: BatchActionParams) {
switch (event.eventTag) { switch (event.eventTag) {
case 'batchAddProject': case 'batchAddProject':
case 'batchAddUsergroup': case 'batchAddUserGroup':
case 'batchAddOrgnization': case 'batchAddOrganization':
batchAction.value = event.eventTag; batchAction.value = event.eventTag;
showBatchModal.value = true; showBatchModal.value = true;
break; break;
case 'resetPassword':
resetPassword(null, true);
break;
case 'disabled': case 'disabled':
disabledUser(null, true); disabledUser(null, true);
break; break;
@ -764,15 +733,18 @@
/** /**
* 创建用户 * 创建用户
* @param isContinue 是否继续创建
*/ */
async function createUser() { async function createUser(isContinue?: boolean) {
const params = { const params = {
userInfoList: userForm.value.list, userInfoList: userForm.value.list,
userRoleIdList: userForm.value.userGroup, userRoleIdList: userForm.value.userGroup,
}; };
await batchCreateUser(params); await batchCreateUser(params);
Message.success(t('system.user.addUserSuccess')); Message.success(t('system.user.addUserSuccess'));
if (!isContinue) {
visible.value = false; visible.value = false;
}
loadList(); loadList();
} }
@ -815,7 +787,7 @@
*/ */
function saveAndContinue() { function saveAndContinue() {
userFormValidate(async () => { userFormValidate(async () => {
await createUser(); await createUser(true);
resetUserForm(); resetUserForm();
}); });
} }
@ -867,7 +839,7 @@
loadList(); loadList();
break; break;
case 'allFail': case 'allFail':
importResultTitle.value = t('system.user.importAllfailTitle'); importResultTitle.value = t('system.user.importAllFailTitle');
break; break;
case 'fail': case 'fail':
importResultTitle.value = t('system.user.importFailTitle'); importResultTitle.value = t('system.user.importFailTitle');

View File

@ -51,8 +51,8 @@ export default {
'system.user.createUserPhone': 'Phone', 'system.user.createUserPhone': 'Phone',
'system.user.createUserPhoneErr': 'Please enter 11 digit mobile number', 'system.user.createUserPhoneErr': 'Please enter 11 digit mobile number',
'system.user.createUserPhonePlaceholder': 'Please enter an 11-digit mobile number', 'system.user.createUserPhonePlaceholder': 'Please enter an 11-digit mobile number',
'system.user.createUserOrgnization': 'Orgnization', 'system.user.createUserOrganization': 'Organization',
'system.user.createUserOrgnizationPlaceholder': 'Please select user organization', 'system.user.createUserOrganizationPlaceholder': 'Please select user organization',
'system.user.createUserUserGroup': 'UserGroup', 'system.user.createUserUserGroup': 'UserGroup',
'system.user.createUserUserGroupPlaceholder': 'Please select a user group', 'system.user.createUserUserGroupPlaceholder': 'Please select a user group',
'system.user.editUserModalTitle': 'Edit the user', 'system.user.editUserModalTitle': 'Edit the user',
@ -69,7 +69,7 @@ export default {
'system.user.importModalTitle': 'Import user', 'system.user.importModalTitle': 'Import user',
'system.user.importDownload': 'Download the template', 'system.user.importDownload': 'Download the template',
'system.user.importModalTip': 'User groups only support adding user groups that exist in the system', '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.importModalFileTip': 'Only supports xls/xlsx format files, and the file size should not exceed 50M',
'system.user.importModalCancel': 'Cancel', 'system.user.importModalCancel': 'Cancel',
'system.user.importModalConfirm': 'Import', 'system.user.importModalConfirm': 'Import',
@ -77,7 +77,7 @@ export default {
'system.user.importSuccessTitle': 'Import user', 'system.user.importSuccessTitle': 'Import user',
'system.user.importSuccess': 'Import succeeded', 'system.user.importSuccess': 'Import succeeded',
'system.user.importFailTitle': 'Some user information failed to import', '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.importResultContent': 'Successfully imported user {successNum} items, failed to import {failNum} items;',
'system.user.importResultContentSubStart': 'You can', 'system.user.importResultContentSubStart': 'You can',
'system.user.importResultContentDownload': 'Download bug report', 'system.user.importResultContentDownload': 'Download bug report',
@ -87,23 +87,23 @@ export default {
'system.user.importResultContinue': 'Continue importing', 'system.user.importResultContinue': 'Continue importing',
'system.user.importErrorFile': 'error report', 'system.user.importErrorFile': 'error report',
'system.user.batchActionAddProject': 'Add to project', 'system.user.batchActionAddProject': 'Add to project',
'system.user.batchActionAddUsergroup': 'Add to usergroup', 'system.user.batchActionAddUserGroup': 'Add to user group',
'system.user.batchActionAddOrgnization': 'Add to org', 'system.user.batchActionAddOrganization': 'Add to org',
'system.user.batchModalTip': 'Add project member user group as member by default', 'system.user.batchModalTip': 'Add project member user group as member by default',
'system.user.batchModalSubTitle': '(Selected {count} users)', 'system.user.batchModalSubTitle': '(Selected {count} users)',
'system.user.batchModalCancel': 'Cancel', 'system.user.batchModalCancel': 'Cancel',
'system.user.batchModalConfirm': 'Add', 'system.user.batchModalConfirm': 'Add',
'system.user.batchModalSuccess': 'Successfully added', 'system.user.batchModalSuccess': 'Successfully added',
'system.user.batchAddProject': 'Batch add to project', 'system.user.batchAddProject': 'Batch add to project',
'system.user.batchAddUsergroup': 'Batch add to user group', 'system.user.batchAddUserGroup': 'Batch add to user group',
'system.user.batchAddOrgnization': 'Batch add to organization', 'system.user.batchAddOrganization': 'Batch add to organization',
'system.user.batchOptional': 'Optional', 'system.user.batchOptional': 'Optional',
'system.user.batchChosen': 'Chosen', 'system.user.batchChosen': 'Chosen',
'system.user.tableColumnEmail': 'Email', 'system.user.tableColumnEmail': 'Email',
'system.user.tableColumnName': 'Name', 'system.user.tableColumnName': 'Name',
'system.user.tableColumnPhone': 'Phone', 'system.user.tableColumnPhone': 'Phone',
'system.user.tableColumnOrg': 'Orgnization', 'system.user.tableColumnOrg': 'Organization',
'system.user.tableColumnUsergroup': 'UserGroup', 'system.user.tableColumnUserGroup': 'UserGroup',
'system.user.tableColumnStatus': 'Status', 'system.user.tableColumnStatus': 'Status',
'system.user.tableColumnActions': 'Actions', 'system.user.tableColumnActions': 'Actions',
}; };

View File

@ -50,8 +50,8 @@ export default {
'system.user.createUserPhone': '手机', 'system.user.createUserPhone': '手机',
'system.user.createUserPhoneErr': '请输入11位手机号', 'system.user.createUserPhoneErr': '请输入11位手机号',
'system.user.createUserPhonePlaceholder': '请输入 11 位手机号', 'system.user.createUserPhonePlaceholder': '请输入 11 位手机号',
'system.user.createUserOrgnization': '组织', 'system.user.createUserOrganization': '组织',
'system.user.createUserOrgnizationPlaceholder': '请选择用户组织', 'system.user.createUserOrganizationPlaceholder': '请选择用户组织',
'system.user.createUserUserGroup': '用户组', 'system.user.createUserUserGroup': '用户组',
'system.user.createUserUserGroupPlaceholder': '请选择用户组', 'system.user.createUserUserGroupPlaceholder': '请选择用户组',
'system.user.editUserModalTitle': '编辑用户', 'system.user.editUserModalTitle': '编辑用户',
@ -68,7 +68,7 @@ export default {
'system.user.importModalTitle': '导入用户', 'system.user.importModalTitle': '导入用户',
'system.user.importModalTip': '用户组仅支持添加系统存在的用户组', 'system.user.importModalTip': '用户组仅支持添加系统存在的用户组',
'system.user.importDownload': '下载模板', 'system.user.importDownload': '下载模板',
'system.user.importModalDragtext': '拖拽或点击此区域选择文件', 'system.user.importModalDragText': '拖拽或点击此区域选择文件',
'system.user.importModalFileTip': '只支持 xls/xlsx格式文件文件大小不超过 50M', 'system.user.importModalFileTip': '只支持 xls/xlsx格式文件文件大小不超过 50M',
'system.user.importModalCancel': '取消', 'system.user.importModalCancel': '取消',
'system.user.importModalConfirm': '导入', 'system.user.importModalConfirm': '导入',
@ -76,7 +76,7 @@ export default {
'system.user.importSuccessTitle': '导入用户', 'system.user.importSuccessTitle': '导入用户',
'system.user.importSuccess': '导入成功', 'system.user.importSuccess': '导入成功',
'system.user.importFailTitle': '部分用户信息导入失败', 'system.user.importFailTitle': '部分用户信息导入失败',
'system.user.importAllfailTitle': '用户信息导入失败', 'system.user.importAllFailTitle': '用户信息导入失败',
'system.user.importResultContent': '成功导入用户 {successNum} 个,导入失败 {failNum} 个;', 'system.user.importResultContent': '成功导入用户 {successNum} 个,导入失败 {failNum} 个;',
'system.user.importResultContentSubStart': '可', 'system.user.importResultContentSubStart': '可',
'system.user.importResultContentDownload': '下载错误报告', 'system.user.importResultContentDownload': '下载错误报告',
@ -86,23 +86,23 @@ export default {
'system.user.importResultContinue': '继续导入', 'system.user.importResultContinue': '继续导入',
'system.user.importErrorFile': '错误报告', 'system.user.importErrorFile': '错误报告',
'system.user.batchActionAddProject': '添加至项目', 'system.user.batchActionAddProject': '添加至项目',
'system.user.batchActionAddUsergroup': '添加至用户组', 'system.user.batchActionAddUserGroup': '添加至用户组',
'system.user.batchActionAddOrgnization': '添加至组织', 'system.user.batchActionAddOrganization': '添加至组织',
'system.user.batchModalTip': '默认为成员添加项目成员用户组', 'system.user.batchModalTip': '默认为成员添加项目成员用户组',
'system.user.batchModalSubTitle': '(已选 {count} 个用户)', 'system.user.batchModalSubTitle': '(已选 {count} 个用户)',
'system.user.batchModalCancel': '取消', 'system.user.batchModalCancel': '取消',
'system.user.batchModalConfirm': '添加', 'system.user.batchModalConfirm': '添加',
'system.user.batchModalSuccess': '添加成功', 'system.user.batchModalSuccess': '添加成功',
'system.user.batchAddProject': '批量添加至项目', 'system.user.batchAddProject': '批量添加至项目',
'system.user.batchAddUsergroup': '批量添加至用户组', 'system.user.batchAddUserGroup': '批量添加至用户组',
'system.user.batchAddOrgnization': '批量添加至组织', 'system.user.batchAddOrganization': '批量添加至组织',
'system.user.batchOptional': '可选', 'system.user.batchOptional': '可选',
'system.user.batchChosen': '已选', 'system.user.batchChosen': '已选',
'system.user.tableColumnEmail': '邮箱', 'system.user.tableColumnEmail': '邮箱',
'system.user.tableColumnName': '姓名', 'system.user.tableColumnName': '姓名',
'system.user.tableColumnPhone': '手机', 'system.user.tableColumnPhone': '手机',
'system.user.tableColumnOrg': '组织', 'system.user.tableColumnOrg': '组织',
'system.user.tableColumnUsergroup': '用户组', 'system.user.tableColumnUserGroup': '用户组',
'system.user.tableColumnStatus': '状态', 'system.user.tableColumnStatus': '状态',
'system.user.tableColumnActions': '操作', 'system.user.tableColumnActions': '操作',
}; };