feat(用例评审): 用例评审部分接口&部分组件调整
This commit is contained in:
parent
24f12d7b12
commit
c6723155a5
|
@ -5,10 +5,12 @@ import {
|
|||
GetAuthDetailUrl,
|
||||
GetAuthListUrl,
|
||||
GetBaseInfoUrl,
|
||||
GetCleanConfigUrl,
|
||||
GetEmailInfoUrl,
|
||||
GetPageConfigUrl,
|
||||
SaveBaseInfoUrl,
|
||||
SaveBaseUrlUrl,
|
||||
SaveCleanConfigUrl,
|
||||
SaveEmailInfoUrl,
|
||||
SavePageConfigUrl,
|
||||
TestEmailUrl,
|
||||
|
@ -23,6 +25,7 @@ import type {
|
|||
AuthItem,
|
||||
AuthParams,
|
||||
BaseConfig,
|
||||
CleanupConfig,
|
||||
EmailConfig,
|
||||
LDAPConfig,
|
||||
LDAPConnectConfig,
|
||||
|
@ -112,3 +115,13 @@ export function testLdapConnect(data: LDAPConnectConfig) {
|
|||
export function testLdapLogin(data: LDAPConfig) {
|
||||
return MSR.post({ url: TestLdapLoginUrl, data });
|
||||
}
|
||||
|
||||
// 保存内存清理配置
|
||||
export function saveCleanupConfig(data: SaveInfoParams) {
|
||||
return MSR.post({ url: SaveCleanConfigUrl, data });
|
||||
}
|
||||
|
||||
// 保存内存清理配置
|
||||
export function getCleanupConfig() {
|
||||
return MSR.get<CleanupConfig>({ url: GetCleanConfigUrl });
|
||||
}
|
||||
|
|
|
@ -30,6 +30,10 @@ export const DeleteAuthUrl = '/system/authsource/delete';
|
|||
export const TestLdapConnectUrl = '/system/authsource/ldap/test-connect';
|
||||
// 测试ldap登录
|
||||
export const TestLdapLoginUrl = '/system/authsource/ldap/test-login';
|
||||
// 内存清理配置保存
|
||||
export const SaveCleanConfigUrl = '/system/parameter/edit/clean-config';
|
||||
// 获取内存清理配置
|
||||
export const GetCleanConfigUrl = '/system/parameter/get/clean-config';
|
||||
|
||||
// 获取系统主页左上角图片
|
||||
export const GetTitleImgUrl = `${import.meta.env.VITE_API_BASE_URL}/base-display/get/logo-platform`;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<div :class="getFolderClass('all')" @click="setActiveFolder('all')">
|
||||
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
|
||||
<div class="folder-name">{{ t('caseManagement.caseReview.allReviews') }}</div>
|
||||
<div class="folder-count">({{ allFileCount }})</div>
|
||||
<div class="folder-count">({{ allCaseCount }})</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-divider class="my-[8px]" />
|
||||
|
@ -50,12 +50,23 @@
|
|||
</a-spin>
|
||||
</div>
|
||||
<div class="flex w-[calc(100%-293px)] flex-col p-[16px]">
|
||||
<div class="mb-[16px] flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<div class="mr-[4px] text-[var(--color-text-1)]">{{ activeFolderName }}</div>
|
||||
<div class="text-[var(--color-text-4)]">({{ activeFolderName }})</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-[8px]">
|
||||
<MsAdvanceFilter
|
||||
v-model:keyword="keyword"
|
||||
:filter-config-list="filterConfigList"
|
||||
:row-count="filterRowCount"
|
||||
:search-placeholder="t('caseManagement.caseReview.searchPlaceholder')"
|
||||
@keyword-search="searchCase"
|
||||
@adv-search="searchCase"
|
||||
>
|
||||
<template #left>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<div class="mr-[4px] text-[var(--color-text-1)]">{{ activeFolderName }}</div>
|
||||
<div class="text-[var(--color-text-4)]">({{ propsRes.msPagination?.total }})</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<a-select
|
||||
v-model:model-value="version"
|
||||
:options="versionOptions"
|
||||
|
@ -63,21 +74,9 @@
|
|||
class="w-[200px]"
|
||||
allow-clear
|
||||
/>
|
||||
<a-input-search
|
||||
v-model="keyword"
|
||||
:placeholder="t('ms.case.associate.searchPlaceholder')"
|
||||
allow-clear
|
||||
class="w-[200px]"
|
||||
@press-enter="searchCase"
|
||||
@search="searchCase"
|
||||
/>
|
||||
<a-button type="outline" class="arco-btn-outline--secondary px-[8px]">
|
||||
<MsIcon type="icon-icon-filter" class="mr-[4px] text-[var(--color-text-4)]" />
|
||||
<div class="text-[var(--color-text-4)]">{{ t('common.filter') }}</div>
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
|
||||
</template>
|
||||
</MsAdvanceFilter>
|
||||
<ms-base-table v-bind="propsRes" no-disable class="mt-[16px]" v-on="propsEvent">
|
||||
<template #caseLevel="{ record }">
|
||||
<caseLevel :case-level="record.caseLevel" />
|
||||
</template>
|
||||
|
@ -88,9 +87,9 @@
|
|||
</div>
|
||||
<div class="flex items-center">
|
||||
<slot name="footerRight">
|
||||
<a-button type="secondary" :disabled="loading" class="mr-[12px]" @click="cancel">{{
|
||||
t('common.cancel')
|
||||
}}</a-button>
|
||||
<a-button type="secondary" :disabled="loading" class="mr-[12px]" @click="cancel">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
|
@ -111,6 +110,8 @@
|
|||
import { computed, onBeforeMount, ref, watch } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import { MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
||||
import { FilterFormItem } from '@/components/pure/ms-advance-filter/type';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
|
@ -121,7 +122,6 @@
|
|||
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
||||
import caseLevel from './caseLevel.vue';
|
||||
|
||||
import { getModules } from '@/api/modules/project-management/fileManagement';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { mapTree } from '@/utils';
|
||||
|
@ -131,8 +131,10 @@
|
|||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
project: string;
|
||||
getModulesFunc: (params: any) => Promise<ModuleTreeNode[]>;
|
||||
modulesCount?: Record<string, number>; // 模块数量统计对象
|
||||
okButtonDisabled?: boolean; // 确认按钮是否禁用
|
||||
selectedKeys?: string[]; // 已选中的用例id
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', val: boolean): void;
|
||||
|
@ -187,7 +189,9 @@
|
|||
|
||||
const activeFolder = ref('all');
|
||||
const activeFolderName = ref(t('ms.case.associate.allCase'));
|
||||
const allFileCount = ref(0);
|
||||
const allCaseCount = ref(0);
|
||||
const filterRowCount = ref(0);
|
||||
const filterConfigList = ref<FilterFormItem[]>([]);
|
||||
|
||||
function getFolderClass(id: string) {
|
||||
return activeFolder.value === id ? 'folder-text folder-text--active' : 'folder-text';
|
||||
|
@ -213,7 +217,7 @@
|
|||
async function initModules(isSetDefaultKey = false) {
|
||||
try {
|
||||
moduleLoading.value = true;
|
||||
const res = await getModules(appStore.currentProjectId);
|
||||
const res = await props.getModulesFunc(appStore.currentProjectId);
|
||||
folderTree.value = res;
|
||||
if (isSetDefaultKey) {
|
||||
selectedModuleKeys.value = [folderTree.value[0].id];
|
||||
|
@ -259,7 +263,7 @@
|
|||
});
|
||||
|
||||
/**
|
||||
* 初始化模块文件数量
|
||||
* 初始化模块资源数量
|
||||
*/
|
||||
watch(
|
||||
() => props.modulesCount,
|
||||
|
@ -327,7 +331,7 @@
|
|||
isTag: true,
|
||||
},
|
||||
];
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||
() =>
|
||||
Promise.resolve({
|
||||
list: [
|
||||
|
@ -443,6 +447,7 @@
|
|||
Message.success(t('ms.case.associate.associateSuccess'));
|
||||
innerVisible.value = false;
|
||||
emit('success', Array.from(propsRes.value.selectedKeys));
|
||||
resetSelector();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
|
@ -453,6 +458,7 @@
|
|||
|
||||
function cancel() {
|
||||
innerVisible.value = false;
|
||||
resetSelector();
|
||||
emit('close');
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
:detail-id="props.detailId"
|
||||
:detail-index="props.detailIndex"
|
||||
:table-data="props.tableData"
|
||||
@loaded="(e) => emit('loaded', e)"
|
||||
@loaded="handleDetailLoaded"
|
||||
/>
|
||||
<div class="ml-auto flex items-center">
|
||||
<slot name="titleRight" :loading="loading" :detail="detail"></slot>
|
||||
|
@ -90,6 +90,11 @@
|
|||
prevNextButtonRef.value?.openNextDetail();
|
||||
}
|
||||
|
||||
function handleDetailLoaded(val: any) {
|
||||
detail.value = val;
|
||||
emit('loaded', val);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => innerVisible.value,
|
||||
(val) => {
|
||||
|
|
|
@ -60,9 +60,17 @@
|
|||
</a-form>
|
||||
<MsDescription v-else :descriptions="descriptions">
|
||||
<template #tag>
|
||||
<MsTag> 组织 1 </MsTag>
|
||||
<br />
|
||||
<MsTag size="small" class="mt-[8px] !bg-[rgb(var(--primary-1))] !text-[rgb(var(--primary-5))]"> 项目 1 </MsTag>
|
||||
<div v-for="org of orgList" :key="org.orgId" class="mb-[16px]">
|
||||
<MsTag class="h-[26px]"> {{ org.orgName }} </MsTag>
|
||||
<br />
|
||||
<MsTag
|
||||
v-for="project of org.projectList"
|
||||
:key="project.projectId"
|
||||
class="!mr-[8px] mt-[8px] !bg-[rgb(var(--primary-1))] !text-[rgb(var(--primary-5))]"
|
||||
>
|
||||
{{ project.projectName }}
|
||||
</MsTag>
|
||||
</div>
|
||||
</template>
|
||||
</MsDescription>
|
||||
<a-modal
|
||||
|
@ -131,6 +139,8 @@
|
|||
import useUserStore from '@/store/modules/user/index';
|
||||
import { validateEmail, validatePhone } from '@/utils/validate';
|
||||
|
||||
import { OrganizationProjectListItem } from '@/models/user';
|
||||
|
||||
import type { FormInstance } from '@arco-design/web-vue';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
@ -139,38 +149,43 @@
|
|||
|
||||
const loading = ref(false);
|
||||
const isEdit = ref(false);
|
||||
const descriptions = ref<Description[]>([
|
||||
{
|
||||
label: t('ms.personal.name'),
|
||||
value: userStore.name || '',
|
||||
},
|
||||
{
|
||||
label: t('ms.personal.email'),
|
||||
value: userStore.email || '',
|
||||
},
|
||||
{
|
||||
label: t('ms.personal.phone'),
|
||||
value: userStore.phone || '',
|
||||
},
|
||||
{
|
||||
label: t('ms.personal.org'),
|
||||
value: [],
|
||||
isTag: true,
|
||||
},
|
||||
]);
|
||||
const descriptions = ref<Description[]>([]);
|
||||
const baseInfoForm = ref({
|
||||
name: userStore.name,
|
||||
email: userStore.email,
|
||||
phone: userStore.phone,
|
||||
});
|
||||
const baseInfoFormRef = ref<FormInstance>();
|
||||
const orgList = ref([]);
|
||||
const orgList = ref<OrganizationProjectListItem[]>([]);
|
||||
|
||||
function initBaseInfo() {
|
||||
descriptions.value = [
|
||||
{
|
||||
label: t('ms.personal.name'),
|
||||
value: userStore.name || '',
|
||||
},
|
||||
{
|
||||
label: t('ms.personal.email'),
|
||||
value: userStore.email || '',
|
||||
},
|
||||
{
|
||||
label: t('ms.personal.phone'),
|
||||
value: userStore.phone || '',
|
||||
},
|
||||
{
|
||||
label: t('ms.personal.org'),
|
||||
value: [],
|
||||
isTag: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
initBaseInfo();
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await getBaseInfo(userStore.id || '');
|
||||
console.log(res);
|
||||
orgList.value = res.orgProjectList;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
|
@ -223,6 +238,7 @@
|
|||
});
|
||||
Message.success(t('common.updateSuccess'));
|
||||
await userStore.isLogin();
|
||||
initBaseInfo();
|
||||
isEdit.value = false;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
|
|
@ -100,10 +100,17 @@
|
|||
});
|
||||
Message.success({
|
||||
content: t('ms.personal.updatePswSuccess', { count: counting.value }),
|
||||
duration: 4000,
|
||||
duration: 1000,
|
||||
});
|
||||
setInterval(() => counting.value--, 1000);
|
||||
const timer = setInterval(() => {
|
||||
counting.value--;
|
||||
Message.success({
|
||||
content: t('ms.personal.updatePswSuccess', { count: counting.value }),
|
||||
duration: 1000,
|
||||
});
|
||||
}, 1000);
|
||||
setTimeout(() => {
|
||||
clearInterval(timer);
|
||||
logout();
|
||||
}, 3000);
|
||||
} catch (error) {
|
||||
|
|
|
@ -45,6 +45,7 @@ export interface MsSearchSelectSlots {
|
|||
header?: (() => JSX.Element) | Slot<any>;
|
||||
default?: () => JSX.Element[];
|
||||
footer?: Slot<any>;
|
||||
empty?: Slot<any>;
|
||||
}
|
||||
|
||||
export default defineComponent(
|
||||
|
@ -283,6 +284,9 @@ export default defineComponent(
|
|||
if (slots.footer) {
|
||||
_slots.footer = slots.footer;
|
||||
}
|
||||
if (slots.empty) {
|
||||
_slots.empty = slots.empty;
|
||||
}
|
||||
|
||||
return _slots;
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
v-bind="props"
|
||||
ref="treeRef"
|
||||
v-model:expanded-keys="expandedKeys"
|
||||
:selected-keys="selectedKeys"
|
||||
v-model:selected-keys="innerSelectedKeys"
|
||||
:data="treeData"
|
||||
class="ms-tree"
|
||||
@drop="onDrop"
|
||||
|
@ -355,17 +355,17 @@
|
|||
}
|
||||
);
|
||||
|
||||
const selectedKeys = ref(props.selectedKeys || []);
|
||||
const innerSelectedKeys = ref(props.selectedKeys || []);
|
||||
|
||||
watch(
|
||||
() => props.selectedKeys,
|
||||
(val) => {
|
||||
selectedKeys.value = val || [];
|
||||
innerSelectedKeys.value = val || [];
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => selectedKeys.value,
|
||||
() => innerSelectedKeys.value,
|
||||
(val) => {
|
||||
emit('update:selectedKeys', val);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<div class="flex flex-row justify-between">
|
||||
<slot name="left"></slot>
|
||||
<div class="flex flex-row gap-[8px]">
|
||||
<slot name="right"></slot>
|
||||
<a-input-search
|
||||
v-model="innerKeyword"
|
||||
size="small"
|
||||
|
@ -26,7 +27,6 @@
|
|||
</span>
|
||||
</span>
|
||||
</MsTag>
|
||||
<slot name="right"></slot>
|
||||
<MsTag no-margin size="large" class="cursor-pointer" theme="outline" @click="handleResetSearch">
|
||||
<MsIcon class="text-[var(color-text-4)]" :size="16" type="icon-icon_reset_outlined" />
|
||||
</MsTag>
|
||||
|
|
|
@ -145,3 +145,8 @@ export interface LDAPConfig extends LDAPConnectConfig {
|
|||
ldapUserOu: string;
|
||||
ldapUserMapping: string;
|
||||
}
|
||||
// 内存清理配置
|
||||
export interface CleanupConfig {
|
||||
operationLog: string;
|
||||
operationHistory: string;
|
||||
}
|
||||
|
|
|
@ -128,8 +128,14 @@ export interface PersonalOrganization {
|
|||
enable: boolean;
|
||||
moduleSetting: string;
|
||||
}
|
||||
export interface OrganizationProjectMap {
|
||||
[key: string]: PersonalOrganization[];
|
||||
export interface PersonalProject {
|
||||
projectId: string;
|
||||
projectName: string;
|
||||
}
|
||||
export interface OrganizationProjectListItem {
|
||||
orgId: string;
|
||||
orgName: string;
|
||||
projectList: PersonalProject[];
|
||||
}
|
||||
export interface PersonalInfo {
|
||||
id: string;
|
||||
|
@ -148,7 +154,7 @@ export interface PersonalInfo {
|
|||
updateUser: string;
|
||||
deleted: boolean;
|
||||
avatar: string;
|
||||
organizationProjectMap: OrganizationProjectMap;
|
||||
orgProjectList: OrganizationProjectListItem[];
|
||||
}
|
||||
export interface UpdateBaseInfo {
|
||||
id: string;
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
v-model:visible="innerVisible"
|
||||
v-model:project="innerProject"
|
||||
:ok-button-disabled="associateForm.reviewers.length === 0"
|
||||
:get-modules-func="getCaseModuleTree"
|
||||
@success="writeAssociateCases"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<template #footerLeft>
|
||||
<a-form ref="associateFormRef" :model="associateForm">
|
||||
|
@ -45,7 +45,17 @@
|
|||
allow-clear
|
||||
multiple
|
||||
class="w-[300px]"
|
||||
:loading="reviewerLoading"
|
||||
>
|
||||
<template #empty>
|
||||
<div class="p-[3px_8px] text-[var(--color-text-4)]">
|
||||
{{ t('caseManagement.caseReview.noMatchReviewer') }}
|
||||
<span class="cursor-pointer text-[rgb(var(--primary-5))]" @click="goProjectManagement">
|
||||
{{ t('menu.projectManagement') }}
|
||||
</span>
|
||||
<span v-if="currentLocale === 'zh-CN'" class="ml-[4px]">{{ t('common.setting') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</MsSelect>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
@ -55,12 +65,16 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router';
|
||||
import { FormInstance } from '@arco-design/web-vue';
|
||||
import { FormInstance, SelectOptionData } from '@arco-design/web-vue';
|
||||
|
||||
import MsCaseAssociate from '@/components/business/ms-case-associate/index.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
|
||||
import { getReviewUsers } from '@/api/modules/case-management/caseReview';
|
||||
import { getCaseModuleTree } from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useLocale from '@/locale/useLocale';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
import { ProjectManagementRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
|
@ -76,6 +90,8 @@
|
|||
}>();
|
||||
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const { currentLocale } = useLocale();
|
||||
const { t } = useI18n();
|
||||
|
||||
const innerVisible = ref(false);
|
||||
|
@ -125,24 +141,29 @@
|
|||
);
|
||||
}
|
||||
|
||||
const reviewersOptions = ref([
|
||||
{
|
||||
label: '张三',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '李四',
|
||||
value: '2',
|
||||
},
|
||||
{
|
||||
label: '王五',
|
||||
value: '3',
|
||||
},
|
||||
]);
|
||||
const reviewersOptions = ref<SelectOptionData[]>([]);
|
||||
const reviewerLoading = ref(false);
|
||||
|
||||
async function initReviewers() {
|
||||
try {
|
||||
reviewerLoading.value = true;
|
||||
const res = await getReviewUsers(appStore.currentProjectId, '');
|
||||
reviewersOptions.value = res.map((e) => ({ label: e.name, value: e.id }));
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
reviewerLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function writeAssociateCases(ids: string[]) {
|
||||
emit('success', ids);
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
initReviewers();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<MsIcon :type="isExpandAll ? 'icon-icon_folder_collapse1' : 'icon-icon_folder_expansion1'" />
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
<popConfirm mode="add" :all-names="rootModulesName" parent-id="none" @add-finish="initModules">
|
||||
<popConfirm mode="add" :all-names="rootModulesName" parent-id="NONE" @add-finish="initModules">
|
||||
<MsButton type="icon" class="!mr-0 p-[2px]">
|
||||
<MsIcon
|
||||
type="icon-icon_create_planarity"
|
||||
|
@ -33,7 +33,7 @@
|
|||
<a-spin class="min-h-[400px] w-full" :loading="loading">
|
||||
<MsTree
|
||||
v-model:focus-node-key="focusNodeKey"
|
||||
:selected-keys="selectedKeys"
|
||||
v-model:selected-keys="selectedKeys"
|
||||
:data="folderTree"
|
||||
:keyword="moduleKeyword"
|
||||
:node-more-actions="folderMoreActions"
|
||||
|
@ -83,7 +83,7 @@
|
|||
:field-config="{ field: renameFolderTitle }"
|
||||
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
|
||||
@close="resetFocusNodeKey"
|
||||
@rename-finish="(val) => (nodeData.name = val)"
|
||||
@rename-finish="initModules"
|
||||
>
|
||||
<span :id="`renameSpan${nodeData.id}`" class="relative"></span>
|
||||
</popConfirm>
|
||||
|
@ -139,6 +139,7 @@
|
|||
const allFileCount = ref(0);
|
||||
const isExpandAll = ref(props.isExpandAll);
|
||||
const rootModulesName = ref<string[]>([]); // 根模块名称列表
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
|
||||
watch(
|
||||
() => props.isExpandAll,
|
||||
|
@ -157,6 +158,9 @@
|
|||
|
||||
function setActiveFolder(id: string) {
|
||||
activeFolder.value = id;
|
||||
if (id === 'all') {
|
||||
selectedKeys.value = [];
|
||||
}
|
||||
emit('folderNodeSelect', [id], []);
|
||||
}
|
||||
|
||||
|
@ -182,8 +186,6 @@
|
|||
];
|
||||
const renamePopVisible = ref(false);
|
||||
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
|
||||
/**
|
||||
* 初始化模块树
|
||||
* @param isSetDefaultKey 是否设置第一个节点为选中节点
|
||||
|
@ -264,7 +266,7 @@
|
|||
offspringIds.push(e.id);
|
||||
return e;
|
||||
});
|
||||
|
||||
setActiveFolder(node.id);
|
||||
emit('folderNodeSelect', _selectedKeys, offspringIds);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,12 +51,7 @@
|
|||
import { ref, watch } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import {
|
||||
addModule,
|
||||
updateFile,
|
||||
updateModule,
|
||||
updateRepository,
|
||||
} from '@/api/modules/project-management/fileManagement';
|
||||
import { addReviewModule, updateReviewModule } from '@/api/modules/case-management/caseReview';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
|
@ -121,13 +116,14 @@
|
|||
);
|
||||
|
||||
function beforeConfirm(done?: (closed: boolean) => void) {
|
||||
if (loading.value) return;
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
try {
|
||||
loading.value = true;
|
||||
if (props.mode === 'add') {
|
||||
// 添加根级模块
|
||||
await addModule({
|
||||
await addReviewModule({
|
||||
projectId: appStore.currentProjectId,
|
||||
parentId: props.parentId || '',
|
||||
name: form.value.field,
|
||||
|
@ -136,31 +132,7 @@
|
|||
emit('addFinish', form.value.field);
|
||||
} else if (props.mode === 'rename') {
|
||||
// 模块重命名
|
||||
await updateModule({
|
||||
id: props.nodeId || '',
|
||||
name: form.value.field,
|
||||
});
|
||||
Message.success(t('project.fileManagement.renameSuccess'));
|
||||
emit('renameFinish', form.value.field);
|
||||
} else if (props.mode === 'fileRename') {
|
||||
// 文件重命名
|
||||
await updateFile({
|
||||
id: props.nodeId || '',
|
||||
name: form.value.field,
|
||||
});
|
||||
Message.success(t('project.fileManagement.renameSuccess'));
|
||||
emit('renameFinish', form.value.field);
|
||||
} else if (props.mode === 'fileUpdateDesc') {
|
||||
// 更新文件描述
|
||||
await updateFile({
|
||||
id: props.nodeId || '',
|
||||
description: form.value.field,
|
||||
});
|
||||
Message.success(t('project.fileManagement.updateDescSuccess'));
|
||||
emit('updateDescFinish', form.value.field);
|
||||
} else if (props.mode === 'repositoryRename') {
|
||||
// 模块重命名
|
||||
await updateRepository({
|
||||
await updateReviewModule({
|
||||
id: props.nodeId || '',
|
||||
name: form.value.field,
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
:row-count="filterRowCount"
|
||||
:search-placeholder="t('caseManagement.caseReview.searchPlaceholder')"
|
||||
@keyword-search="searchReview"
|
||||
@adv-search="searchReview"
|
||||
>
|
||||
<template #left>
|
||||
<div class="flex items-center">
|
||||
|
@ -92,7 +93,7 @@
|
|||
<template v-if="keyword.trim() === ''" #empty>
|
||||
<div class="flex items-center justify-center p-[8px] text-[var(--color-text-4)]">
|
||||
{{ t('caseManagement.caseReview.tableNoData') }}
|
||||
<MsButton class="ml-[8px]" @click="handleAddClick">
|
||||
<MsButton class="ml-[8px]" @click="() => emit('goCreate')">
|
||||
{{ t('caseManagement.caseReview.create') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
|
@ -213,6 +214,10 @@
|
|||
moduleTree: ModuleTreeNode[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'goCreate'): void;
|
||||
}>();
|
||||
|
||||
const appStore = useAppStore();
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
|
@ -491,6 +496,7 @@
|
|||
setLoadListParams({
|
||||
keyword: keyword.value,
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder],
|
||||
});
|
||||
loadList();
|
||||
}
|
||||
|
@ -527,7 +533,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* 拦截切换最新版确认
|
||||
* 删除确认
|
||||
* @param done 关闭弹窗
|
||||
*/
|
||||
async function handleDeleteConfirm(done: (closed: boolean) => void) {
|
||||
|
@ -679,9 +685,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
function handleAddClick() {
|
||||
console.log('handleAddClick');
|
||||
}
|
||||
watch(
|
||||
() => props.activeFolder,
|
||||
() => {
|
||||
searchReview();
|
||||
}
|
||||
);
|
||||
|
||||
function openDetail(id: string) {
|
||||
router.push({
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
:search-keys="['label']"
|
||||
allow-search
|
||||
multiple
|
||||
:loading="reviewerLoading"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="tags" :label="t('caseManagement.caseReview.tag')">
|
||||
|
@ -138,80 +139,38 @@
|
|||
</div>
|
||||
</template>
|
||||
</MsCard>
|
||||
<MsCaseAssociate
|
||||
<AssociateDrawer
|
||||
v-model:visible="caseAssociateVisible"
|
||||
v-model:project="caseAssociateProject"
|
||||
:ok-button-disabled="associateForm.reviewers.length === 0"
|
||||
@success="writeAssociateCases"
|
||||
>
|
||||
<template #footerLeft>
|
||||
<a-form ref="associateFormRef" :model="associateForm">
|
||||
<a-form-item
|
||||
field="reviewers"
|
||||
:rules="[{ required: true, message: t('caseManagement.caseReview.reviewerRequired') }]"
|
||||
class="mb-0"
|
||||
>
|
||||
<template #label>
|
||||
<div class="inline-flex items-center">
|
||||
{{ t('caseManagement.caseReview.reviewer') }}
|
||||
<a-tooltip position="right">
|
||||
<template #content>
|
||||
<div>{{ t('caseManagement.caseReview.switchProject') }}</div>
|
||||
<div>{{ t('caseManagement.caseReview.resetReviews') }}</div>
|
||||
<div>
|
||||
{{ t('caseManagement.caseReview.reviewsTip') }}
|
||||
<span class="cursor-pointer text-[rgb(var(--primary-4))]" @click="goProjectManagement">
|
||||
{{ t('menu.projectManagement') }}
|
||||
</span>
|
||||
{{ t('caseManagement.caseReview.reviewsTip2') }}
|
||||
</div>
|
||||
</template>
|
||||
<icon-question-circle
|
||||
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
|
||||
size="16"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<MsSelect
|
||||
v-model:modelValue="associateForm.reviewers"
|
||||
mode="static"
|
||||
:placeholder="t('caseManagement.caseReview.reviewerPlaceholder')"
|
||||
:options="reviewersOptions"
|
||||
:search-keys="['label']"
|
||||
allow-search
|
||||
allow-clear
|
||||
multiple
|
||||
class="w-[300px]"
|
||||
>
|
||||
</MsSelect>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
</MsCaseAssociate>
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* @description 功能测试-用例评审-创建评审
|
||||
*/
|
||||
import { onBeforeMount } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { Message, SelectOptionData } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
import MsCaseAssociate from '@/components/business/ms-case-associate/index.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
import AssociateDrawer from './components/create/associateDrawer.vue';
|
||||
|
||||
import { getReviewUsers } from '@/api/modules/case-management/caseReview';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
import { CaseManagementRouteEnum, ProjectManagementRouteEnum } from '@/enums/routeEnum';
|
||||
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
import type { FormInstance } from '@arco-design/web-vue';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const isEdit = ref(!!route.query.id);
|
||||
|
@ -239,20 +198,21 @@
|
|||
value: '2',
|
||||
},
|
||||
]);
|
||||
const reviewersOptions = ref([
|
||||
{
|
||||
label: '张三',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '李四',
|
||||
value: '2',
|
||||
},
|
||||
{
|
||||
label: '王五',
|
||||
value: '3',
|
||||
},
|
||||
]);
|
||||
const reviewersOptions = ref<SelectOptionData[]>([]);
|
||||
const reviewerLoading = ref(false);
|
||||
|
||||
async function initReviewers() {
|
||||
try {
|
||||
reviewerLoading.value = true;
|
||||
const res = await getReviewUsers(appStore.currentProjectId, '');
|
||||
reviewersOptions.value = res.map((e) => ({ label: e.name, value: e.id }));
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
reviewerLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const selectedAssociateCases = ref<string[]>([]);
|
||||
|
||||
|
@ -299,18 +259,10 @@
|
|||
|
||||
const caseAssociateVisible = ref<boolean>(false);
|
||||
const caseAssociateProject = ref('');
|
||||
const associateForm = ref({
|
||||
reviewers: [],
|
||||
});
|
||||
const associateFormRef = ref<FormInstance>();
|
||||
|
||||
function goProjectManagement() {
|
||||
window.open(
|
||||
`${window.location.origin}#${
|
||||
router.resolve({ name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_PERMISSION_USER_GROUP }).fullPath
|
||||
}`
|
||||
);
|
||||
}
|
||||
onBeforeMount(() => {
|
||||
initReviewers();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<ReviewTable :active-folder="activeFolderId" :module-tree="moduleTree" />
|
||||
<ReviewTable :active-folder="activeFolderId" :module-tree="moduleTree" @go-create="goCreateReview" />
|
||||
</template>
|
||||
</MsSplitBox>
|
||||
</div>
|
||||
|
|
|
@ -78,4 +78,55 @@ export default {
|
|||
'caseManagement.caseReview.reviewsTip2': 'can set permissions',
|
||||
'caseManagement.caseReview.clearSelectedCases': 'Clear selected use cases',
|
||||
'caseManagement.caseReview.selectedCases': '{count} use cases selected',
|
||||
'caseManagement.caseReview.onlyMine': 'See only Mine',
|
||||
'caseManagement.caseReview.createTestPlan': 'Create test plan',
|
||||
'caseManagement.caseReview.reviewedCase': 'Reviewed cases',
|
||||
'caseManagement.caseReview.createCase': 'Create cases',
|
||||
'caseManagement.caseReview.allCases': 'All cases',
|
||||
'caseManagement.caseReview.noCases': 'No matching case data yet',
|
||||
'caseManagement.caseReview.caseName': 'Case name',
|
||||
'caseManagement.caseReview.reviewResult': 'Review results',
|
||||
'caseManagement.caseReview.reviewResultTip':
|
||||
'When "See only mine" is turned on, you can view my review results on the list',
|
||||
'caseManagement.caseReview.disassociate': 'Disassociate',
|
||||
'caseManagement.caseReview.disassociateConfirmTitle':
|
||||
'Are you sure you want to cancel the selected {count} test cases?',
|
||||
'caseManagement.caseReview.version': 'Version',
|
||||
'caseManagement.caseReview.unReview': 'Unreviewed',
|
||||
'caseManagement.caseReview.reviewPass': 'Review passed',
|
||||
'caseManagement.caseReview.disassociateTip': 'Are you sure to cancel the association?',
|
||||
'caseManagement.caseReview.disassociateTipContent':
|
||||
'After cancellation, associate again, the review result is: Unreviewed',
|
||||
'caseManagement.caseReview.changeReviewer': 'Modify reviewer',
|
||||
'caseManagement.caseReview.batchReview': 'Batch review',
|
||||
'caseManagement.caseReview.selectedCase': '{count} use cases selected',
|
||||
'caseManagement.caseReview.reason': 'Reason',
|
||||
'caseManagement.caseReview.reasonRequired': 'Reason cannot be empty',
|
||||
'caseManagement.caseReview.reasonPlaceholder': 'Please enter the reason',
|
||||
'caseManagement.caseReview.commitResult': 'Submit results',
|
||||
'caseManagement.caseReview.batchReviewTip':
|
||||
'Modifying the review results means modifying the personal review results.',
|
||||
'caseManagement.caseReview.chooseReviewer': 'Select reviewers',
|
||||
'caseManagement.caseReview.batchChangeReviewer': 'Batch modify reviewers',
|
||||
'caseManagement.caseReview.append': 'Append',
|
||||
'caseManagement.caseReview.appendTip1': 'Open: Add reviewer',
|
||||
'caseManagement.caseReview.appendTip2': 'Close: Update reviewers',
|
||||
'caseManagement.caseReview.myReview': 'My reviews',
|
||||
'caseManagement.caseReview.caseLevel': 'Case level',
|
||||
'caseManagement.caseReview.caseVersion': 'Case version',
|
||||
'caseManagement.caseReview.caseStatus': 'Case status',
|
||||
'caseManagement.caseReview.responsiblePerson': 'Responsible person',
|
||||
'caseManagement.caseReview.createTime': 'Created time',
|
||||
'caseManagement.caseReview.caseBaseInfo': 'Basic info',
|
||||
'caseManagement.caseReview.caseDetail': 'Detail',
|
||||
'caseManagement.caseReview.caseDemand': 'Demand',
|
||||
'caseManagement.caseReview.startReview': 'Start review',
|
||||
'caseManagement.caseReview.autoNext': 'Automatically next',
|
||||
'caseManagement.caseReview.autoNextTip1': 'Open: After submitting the review results, jump to the next use case',
|
||||
'caseManagement.caseReview.autoNextTip2': 'Close: After submitting the review results, it is still current',
|
||||
'caseManagement.caseReview.suggestion': 'Suggestion',
|
||||
'caseManagement.caseReview.suggestionTip': 'Not as a result of the review',
|
||||
'caseManagement.caseReview.submitReview': 'Submit review',
|
||||
'caseManagement.caseReview.reviewHistory': 'Review history',
|
||||
'caseManagement.caseReview.noMatchReviewer': 'No matching handler, can be set in {menu}',
|
||||
};
|
||||
|
|
|
@ -118,4 +118,5 @@ export default {
|
|||
'caseManagement.caseReview.suggestionTip': '不作为评审结果',
|
||||
'caseManagement.caseReview.submitReview': '提交评审',
|
||||
'caseManagement.caseReview.reviewHistory': '评审历史',
|
||||
'caseManagement.caseReview.noMatchReviewer': '无匹配处理人,可在 ',
|
||||
};
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
:field-config="{ field: renameFolderTitle }"
|
||||
:all-names="(nodeData.children || []).map((e: ModuleTreeNode) => e.name || '')"
|
||||
@close="resetFocusNodeKey"
|
||||
@rename-finish="(val) => (nodeData.name = val)"
|
||||
@rename-finish="() => initModules()"
|
||||
>
|
||||
<span :id="`renameSpan${nodeData.id}`" class="relative"></span>
|
||||
</popConfirm>
|
||||
|
|
|
@ -121,6 +121,7 @@
|
|||
);
|
||||
|
||||
function beforeConfirm(done?: (closed: boolean) => void) {
|
||||
if (loading.value) return;
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
<template>
|
||||
<MsCard class="mb-[16px]" :loading="loading" simple auto-height>
|
||||
<div class="mb-[16px] flex justify-between">
|
||||
<div class="font-medium text-[var(--color-text-000)]">{{ t('system.config.memoryCleanup') }}</div>
|
||||
</div>
|
||||
<a-radio-group v-model:model-value="activeType" type="button">
|
||||
<a-radio value="log">{{ t('system.config.memoryCleanup.log') }}</a-radio>
|
||||
<a-radio value="history">{{ t('system.config.memoryCleanup.history') }}</a-radio>
|
||||
</a-radio-group>
|
||||
<template v-if="activeType === 'log'">
|
||||
<div class="mb-[8px] mt-[16px] flex items-center">
|
||||
<div class="text-[var(--color-text-000)]">{{ t('system.config.memoryCleanup.keepTime') }}</div>
|
||||
<a-tooltip :content="t('system.config.memoryCleanup.keepTimeTip')" position="right">
|
||||
<icon-question-circle
|
||||
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
|
||||
size="16"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<a-input-number
|
||||
v-model:model-value="timeCount"
|
||||
class="w-[130px]"
|
||||
:disabled="saveLoading"
|
||||
@blur="() => saveConfig()"
|
||||
>
|
||||
<template #append>
|
||||
<a-select
|
||||
v-model:model-value="activeTime"
|
||||
:options="timeOptions"
|
||||
class="time-input-append"
|
||||
:loading="saveLoading"
|
||||
@change="() => saveConfig()"
|
||||
/>
|
||||
</template>
|
||||
</a-input-number>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="mb-[8px] mt-[16px] flex items-center">
|
||||
<div class="text-[var(--color-text-000)]">{{ t('system.config.memoryCleanup.saveCount') }}</div>
|
||||
<a-tooltip :content="t('system.config.memoryCleanup.saveCountTip')" position="right">
|
||||
<icon-question-circle
|
||||
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
|
||||
size="16"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<a-input-number
|
||||
v-model:model-value="historyCount"
|
||||
class="w-[130px]"
|
||||
:disabled="saveLoading"
|
||||
@blur="() => saveConfig()"
|
||||
/>
|
||||
</template>
|
||||
</MsCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
|
||||
import { getCleanupConfig, saveCleanupConfig } from '@/api/modules/setting/config';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
const loading = ref(false);
|
||||
|
||||
const activeType = ref('log');
|
||||
|
||||
const timeCount = ref(6);
|
||||
const activeTime = ref('M');
|
||||
const timeOptions = [
|
||||
{
|
||||
label: t('system.config.memoryCleanup.day'),
|
||||
value: 'D',
|
||||
},
|
||||
{
|
||||
label: t('system.config.memoryCleanup.month'),
|
||||
value: 'M',
|
||||
},
|
||||
{
|
||||
label: t('system.config.memoryCleanup.year'),
|
||||
value: 'Y',
|
||||
},
|
||||
];
|
||||
const historyCount = ref(10);
|
||||
|
||||
onBeforeMount(async () => {
|
||||
loading.value = true;
|
||||
const res = await getCleanupConfig();
|
||||
if (res.operationLog) {
|
||||
const matches = res.operationLog.match(/(\d+)([MDY])$/);
|
||||
if (matches) {
|
||||
const [, number, letter] = matches;
|
||||
timeCount.value = Number(number);
|
||||
activeTime.value = letter;
|
||||
}
|
||||
}
|
||||
if (res.operationHistory) {
|
||||
historyCount.value = Number(res.operationHistory);
|
||||
}
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
const saveLoading = ref(false);
|
||||
|
||||
async function saveConfig() {
|
||||
saveLoading.value = true;
|
||||
await saveCleanupConfig([
|
||||
{
|
||||
paramKey: 'cleanConfig.operation.log',
|
||||
paramValue: `${timeCount.value}${activeTime.value}`,
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
paramKey: 'cleanConfig.operation.history',
|
||||
paramValue: historyCount.value.toString(),
|
||||
type: 'string',
|
||||
},
|
||||
]);
|
||||
saveLoading.value = false;
|
||||
Message.success(t('system.config.memoryCleanup.setSuccess'));
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.arco-input-append) {
|
||||
@apply border-none;
|
||||
}
|
||||
:deep(.time-input-append) {
|
||||
@apply z-10;
|
||||
|
||||
margin-left: -16px !important;
|
||||
border-radius: 0 4px 4px 0 !important;
|
||||
background-color: var(--color-text-n8) !important;
|
||||
&:hover {
|
||||
border-color: rgb(var(--primary-5)) !important;
|
||||
background-color: var(--color-text-n8) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -3,6 +3,7 @@
|
|||
<baseConfig v-show="activeTab === 'baseConfig'" />
|
||||
<pageConfig v-if="isInitPageConfig" v-show="activeTab === 'pageConfig'" />
|
||||
<authConfig v-if="isInitAuthConfig" v-show="activeTab === 'authConfig'" ref="authConfigRef" />
|
||||
<memoryCleanup v-if="isInitMemoryCleanup" v-show="activeTab === 'memoryCleanup'" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -15,6 +16,7 @@
|
|||
import MsTabCard from '@/components/pure/ms-tab-card/index.vue';
|
||||
import authConfig, { AuthConfigInstance } from './components/authConfig.vue';
|
||||
import baseConfig from './components/baseConfig.vue';
|
||||
import memoryCleanup from './components/memoryCleanup.vue';
|
||||
import pageConfig from './components/pageConfig.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -25,11 +27,13 @@
|
|||
const activeTab = ref((route.query.tab as string) || 'baseConfig');
|
||||
const isInitPageConfig = ref(activeTab.value === 'pageConfig');
|
||||
const isInitAuthConfig = ref(activeTab.value === 'authConfig');
|
||||
const isInitMemoryCleanup = ref(activeTab.value === 'memoryCleanup');
|
||||
const authConfigRef = ref<AuthConfigInstance | null>();
|
||||
const tabList = [
|
||||
{ key: 'baseConfig', title: t('system.config.baseConfig') },
|
||||
{ key: 'pageConfig', title: t('system.config.pageConfig') },
|
||||
{ key: 'authConfig', title: t('system.config.authConfig') },
|
||||
{ key: 'memoryCleanup', title: t('system.config.memoryCleanup') },
|
||||
];
|
||||
|
||||
watch(
|
||||
|
@ -39,6 +43,8 @@
|
|||
isInitPageConfig.value = true;
|
||||
} else if (val === 'authConfig' && !isInitAuthConfig.value) {
|
||||
isInitAuthConfig.value = true;
|
||||
} else if (val === 'memoryCleanup' && !isInitMemoryCleanup.value) {
|
||||
isInitMemoryCleanup.value = true;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -207,4 +207,16 @@ export default {
|
|||
'system.config.auth.testLoginPasswordNotNull': 'LDAP login password cannot be empty',
|
||||
'system.config.auth.testLoginSuccess': 'LDAP login successful',
|
||||
'system.config.auth.testLoginCancel': 'Cancel',
|
||||
'system.config.memoryCleanup': 'Memory cleanup',
|
||||
'system.config.memoryCleanup.log': 'Log',
|
||||
'system.config.memoryCleanup.history': 'Change history',
|
||||
'system.config.memoryCleanup.keepTime': 'Retention time',
|
||||
'system.config.memoryCleanup.keepTimeTip': 'The system will perform cleanup at 00:00 every day',
|
||||
'system.config.memoryCleanup.day': 'Day',
|
||||
'system.config.memoryCleanup.month': 'Month',
|
||||
'system.config.memoryCleanup.year': 'Year',
|
||||
'system.config.memoryCleanup.setSuccess': 'Setup successful',
|
||||
'system.config.memoryCleanup.saveCount': 'Reserved quantity',
|
||||
'system.config.memoryCleanup.saveCountTip':
|
||||
'It is effective for all projects in the system. Use case change history that exceeds the settings will be cleared and will take effect immediately after the update.',
|
||||
};
|
||||
|
|
|
@ -202,4 +202,15 @@ export default {
|
|||
'system.config.auth.testLoginPasswordNotNull': 'LDAP 登录密码不能为空',
|
||||
'system.config.auth.testLoginCancel': '取消测试',
|
||||
'system.config.auth.testLoginSuccess': 'LDAP 登录成功',
|
||||
'system.config.memoryCleanup': '内存清理',
|
||||
'system.config.memoryCleanup.log': '日志',
|
||||
'system.config.memoryCleanup.history': '变更历史',
|
||||
'system.config.memoryCleanup.keepTime': '保留时长',
|
||||
'system.config.memoryCleanup.keepTimeTip': '系统会在每天 00:00 执行清理',
|
||||
'system.config.memoryCleanup.day': '天',
|
||||
'system.config.memoryCleanup.month': '月',
|
||||
'system.config.memoryCleanup.year': '年',
|
||||
'system.config.memoryCleanup.setSuccess': '设置成功',
|
||||
'system.config.memoryCleanup.saveCount': '保留条数',
|
||||
'system.config.memoryCleanup.saveCountTip': '对系统内所有的项目生效,超出设置的用例变更历史会被清除,更新后立即生效',
|
||||
};
|
||||
|
|
|
@ -400,6 +400,10 @@
|
|||
label: 'system.log.operateType.logout',
|
||||
value: 'LOGOUT',
|
||||
},
|
||||
{
|
||||
label: 'system.log.operateType.associate',
|
||||
value: 'ASSOCIATE',
|
||||
},
|
||||
{
|
||||
label: 'system.log.operateType.disassociate',
|
||||
value: 'DISASSOCIATE',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'system.log.operateType.recover': 'Recover',
|
||||
'system.log.operateType.logout': 'Logout',
|
||||
'system.log.operateType.disassociate': 'Disassociate',
|
||||
'system.log.operateType.associate': 'Associate',
|
||||
'system.log.operateType.archived': 'Archived',
|
||||
'system.log.log': 'Operation log',
|
||||
'system.log.time': 'Operation time',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'system.log.operateType.recover': '恢复',
|
||||
'system.log.operateType.logout': '登出',
|
||||
'system.log.operateType.disassociate': '取消关联',
|
||||
'system.log.operateType.associate': '关联',
|
||||
'system.log.operateType.archived': '归档',
|
||||
'system.log.log': '操作日志',
|
||||
'system.log.time': '操作时间',
|
||||
|
|
Loading…
Reference in New Issue