fix(项目管理): 环境补充和部分bug修复

This commit is contained in:
xinxin.wu 2024-03-26 23:28:28 +08:00 committed by Craftsman
parent 451265b018
commit 71ae2fd9db
11 changed files with 215 additions and 156 deletions

View File

@ -6,7 +6,7 @@
height: 'calc(100vh - 490px)',
}"
>
<conditionContent v-model:data="condition" />
<conditionContent v-model:data="condition" :disabled="props.disabled" />
</a-scrollbar>
</div>
</template>
@ -26,7 +26,7 @@
interface ScriptTabProps {
data: any;
// disabled?: boolean;
disabled?: boolean;
}
const props = defineProps<ScriptTabProps>();

View File

@ -300,7 +300,7 @@ export default function useTableProps<T>(
// 当前是跨页全部选中状态,则取消当前页的选中项
propsRes.value.data.forEach((item) => {
propsRes.value.selectedKeys.delete(item.id);
propsRes.value.excludeKeys.add(item.id);
propsRes.value.excludeKeys.delete(item.id);
});
} else {
// 当前是当前页选中状态,则清空选中项

View File

@ -109,7 +109,7 @@
}
function validateTagsCountBlur() {
if (tagsLength.value >= 10) {
if (tagsLength.value > 10) {
Message.warning(t('common.tagCountMax'));
return false;
}

View File

@ -170,3 +170,12 @@ export interface EnvironmentItem {
description: string;
pos: number;
}
export interface PopVisibleItem {
id?: string;
visible: boolean;
defaultName: string;
}
export interface PopVisible {
[key: string]: PopVisibleItem;
}

View File

@ -604,7 +604,7 @@
}
Message.success(t('common.deleteSuccess'));
resetSelector();
loadList();
loadApiList();
if (typeof refreshModuleTree === 'function') {
refreshModuleTree();
}
@ -724,7 +724,7 @@
Message.success(t('common.updateSuccess'));
cancelBatch();
resetSelector();
loadList();
loadApiList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -764,8 +764,9 @@
} else {
activeApi.value = null;
}
loadList();
resetSelector();
loadList();
if (typeof refreshModuleTree === 'function') {
refreshModuleTree();
}

View File

@ -434,7 +434,6 @@
dataIndex: 'tags',
isTag: true,
isStringTag: true,
width: 150,
},
{
title: 'case.lastReportStatus',
@ -711,6 +710,7 @@
await deleteCase(record?.id as string);
}
Message.success(t('common.deleteSuccess'));
resetSelector();
loadCaseListAndResetSelector();
if (typeof refreshModuleTree === 'function') {
refreshModuleTree();
@ -832,6 +832,7 @@
});
Message.success(t('common.updateSuccess'));
cancelBatchEdit();
resetSelector();
loadCaseListAndResetSelector();
} catch (error) {
// eslint-disable-next-line no-console

View File

@ -1,6 +1,6 @@
<template>
<!-- class="tiled-wrap h-[calc(100vh - 374px)] p-4" -->
<div
class="tiled-wrap h-[calc(100vh - 374px)] p-4"
:class="{
'border border-solid border-[var(--color-text-n8)]': props.showType === 'API',
}"

View File

@ -176,10 +176,11 @@
customField.fieldId = item.field;
customField.value = Array.isArray(item.value) ? JSON.stringify(item.value) : item.value;
});
const { selectedIds, selectAll } = props.batchParams;
const { selectedIds, selectAll, excludeIds } = props.batchParams;
const params: TableQueryParams = {
selectIds: selectAll ? [] : selectedIds,
selectAll,
selectIds: selectedIds || [],
selectAll: !!selectAll,
excludeIds: excludeIds || [],
projectId: currentProjectId.value,
append: enable as boolean,
tags: form.value.tags,

View File

@ -65,14 +65,12 @@
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
import { getGroupDetailEnv, groupAddEnv, groupUpdateEnv } from '@/api/modules/project-management/envManagement';
import { getGroupDetailEnv, groupUpdateEnv } from '@/api/modules/project-management/envManagement';
import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store';
import useProjectEnvStore, { NEW_ENV_GROUP } from '@/store/modules/setting/useProjectEnvStore';
import { hasAnyPermission } from '@/utils/permission';
import { EnvListItem } from '@/models/projectManagement/environmental';
const { t } = useI18n();
const appStore = useAppStore();
@ -161,15 +159,8 @@
projectId: appStore.currentProjectId,
envGroupProject,
};
let res: EnvListItem;
if (id) {
res = await groupUpdateEnv(params);
Message.success(t('common.saveSuccess'));
initDetail(res.id);
} else {
res = await groupAddEnv(params);
}
emit('saveOrUpdate', res.id);
await groupUpdateEnv(params);
Message.success(t('common.saveSuccess'));
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
@ -187,6 +178,10 @@
initDetail(store.currentGroupId);
}
});
defineExpose({
initDetail,
});
</script>
<style lang="less" scoped>

View File

@ -1,30 +1,26 @@
<template>
<a-popover
<a-popconfirm
ref="popoverRef"
:popup-visible="currentVisible"
position="bl"
position="bottom"
trigger="click"
class="w-[277px]"
class="ms-pop-confirm--hidden-icon"
:content-class="props.id ? 'move-left' : ''"
:ok-loading="loading"
:cancel-button-props="{ disabled: loading }"
@popup-visible-change="reset"
>
<template #content>
<div class="mb-[1px] text-[14px] font-medium text-[var(--color-text-1)]">{{
props.id ? t('system.userGroup.rename') : t('system.userGroup.createUserGroup')
}}</div>
<div v-outer="handleOutsideClick">
<div class="form">
<a-form
ref="formRef"
:model="form"
size="large"
layout="vertical"
:label-col-props="{ span: 0 }"
:wrapper-col-props="{ span: 24 }"
>
<div class="mb-[8px] text-[14px] font-medium text-[var(--color-text-1)]">{{
props.id ? t('system.userGroup.rename') : t('system.userGroup.createUserGroup')
}}</div>
<a-form ref="formRef" :model="form" layout="vertical">
<a-form-item field="name" :rules="[{ validator: validateName }]">
<a-input
v-model="form.name"
class="w-[243px]"
class="w-[245px]"
:placeholder="t('system.userGroup.pleaseInputUserGroupName')"
allow-clear
:max-length="255"
@ -34,7 +30,7 @@
</a-form-item>
</a-form>
</div>
<div class="flex flex-row flex-nowrap justify-end gap-2">
<!-- <div class="mb-1 mt-4 flex flex-row flex-nowrap justify-end gap-2">
<a-button type="secondary" size="mini" :disabled="loading" @click="handleCancel">
{{ t('common.cancel') }}
</a-button>
@ -45,47 +41,52 @@
:disabled="form.name.length === 0"
@click="handleBeforeOk"
>
{{ props.id ? t('common.rename') : t('common.create') }}
{{ t('common.confirm') }}
</a-button>
</div>
</div> -->
</div>
</template>
<slot></slot>
</a-popover>
</a-popconfirm>
</template>
<script lang="ts" setup>
import { reactive, ref, watchEffect } from 'vue';
import { Message } from '@arco-design/web-vue';
import { updateOrAddProjectUserGroup } from '@/api/modules/project-management/usergroup';
import { updateOrAddOrgUserGroup, updateOrAddUserGroup } from '@/api/modules/setting/usergroup';
import {
getGroupDetailEnv,
groupAddEnv,
groupUpdateEnv,
updateOrAddEnv,
} from '@/api/modules/project-management/envManagement';
import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store';
import useProjectEnvStore, { NEW_ENV_GROUP } from '@/store/modules/setting/useProjectEnvStore';
import { EnvListItem } from '@/models/projectManagement/environmental';
import { EnvAuthScopeEnum, EnvAuthTypeEnum } from '@/enums/envEnum';
import { EnvAuthScopeEnum } from '@/enums/envEnum';
import type { FormInstance, ValidatedError } from '@arco-design/web-vue';
const { t } = useI18n();
const store = useProjectEnvStore();
const props = defineProps<{
id?: string;
list: EnvListItem[];
visible?: boolean;
defaultName?: string;
description?: string;
type: EnvAuthScopeEnum;
}>();
const systemType = ref(props.type);
const emit = defineEmits<{
(e: 'cancel', value: boolean): void;
(e: 'submit', currentId: string): void;
(e: 'success'): void;
}>();
const formRef = ref<FormInstance>();
const currentVisible = ref(props.visible);
// trigger
const form = reactive({
name: '',
@ -122,29 +123,33 @@
if (errors) {
return false;
}
// let res: EnvListItem;
try {
loading.value = true;
let res: EnvListItem | undefined;
if (systemType.value === EnvAuthScopeEnum.PROJECT) {
res = await updateOrAddUserGroup({ id: props.id, name: form.name });
} else if (systemType.value === EnvAuthScopeEnum.PROJECT_GROUP) {
//
res = await updateOrAddOrgUserGroup({
id: props.id,
name: form.name,
scopeId: appStore.currentOrgId,
});
if (props.type === EnvAuthScopeEnum.PROJECT) {
await updateOrAddEnv({ fileList: [], request: { ...store.currentEnvDetailInfo, name: form.name } });
} else {
//
res = await updateOrAddProjectUserGroup({ name: form.name });
}
if (res) {
Message.success(
props.id ? t('system.userGroup.updateUserGroupSuccess') : t('system.userGroup.addUserGroupSuccess')
);
emit('submit', res.id);
handleCancel();
const id = store.currentGroupId === NEW_ENV_GROUP ? undefined : store.currentGroupId;
if (id) {
const detail: Record<string, any> = await getGroupDetailEnv(id);
const envGroupProject = detail?.environmentGroupInfo.filter(
(item: any) => item.projectId && item.environmentId
);
const params = {
id,
name: form.name,
description: detail.description,
projectId: appStore.currentProjectId,
envGroupProject,
};
await groupUpdateEnv(params);
}
}
Message.success(t('project.fileManagement.renameSuccess'));
emit('success');
handleCancel();
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
@ -153,6 +158,7 @@
}
});
};
watchEffect(() => {
currentVisible.value = props.visible;
form.name = props.defaultName || '';
@ -163,6 +169,12 @@
handleCancel();
}
};
function reset(val: boolean) {
if (!val) {
form.name = '';
formRef.value?.resetFields();
}
}
</script>
<style lang="less">
@ -170,4 +182,7 @@
position: relative;
right: 22px;
}
:deep(.arco-trigger-content) {
padding: 16px;
}
</style>

View File

@ -45,6 +45,7 @@
<div class="env-row-extra">
<MsMoreAction
v-permission="['PROJECT_ENVIRONMENT:READ+IMPORT', 'PROJECT_ENVIRONMENT:READ+EXPORT']"
trigger="click"
:list="allMoreAction"
@select="(value) => handleMoreAction(value, 'all', EnvAuthTypeEnum.ENVIRONMENT)"
/>
@ -75,48 +76,47 @@
<div
v-for="element in envList"
:key="element.id"
class="env-item hover:bg-[rgb(var(--primary-1))]"
class="env-item"
:class="[activeKey === element.id ? 'env-item-focus' : '']"
@click="handleListItemClick(element)"
>
<RenamePop
:list="envList"
:type="(showType as EnvAuthScopeEnum)"
v-bind="popVisible[element.id]"
@cancel="handleRenameCancel(element)"
@submit="handleRenameCancel(element, true)"
>
<div class="flex max-w-[100%] grow flex-row items-center justify-between">
<a-tooltip :content="element.name">
<div
class="one-line-text"
:class="{ 'font-medium text-[rgb(var(--primary-5))]': element.id === activeKey }"
>{{ element.name }}</div
>
</a-tooltip>
<div class="node-extra">
<div class="flex max-w-[100%] grow flex-row items-center justify-between">
<a-tooltip :content="element.name">
<div
class="one-line-text"
:class="{ 'font-medium text-[rgb(var(--primary-5))]': element.id === activeKey }"
>{{ element.name }}</div
>
</a-tooltip>
<div class="env-item-actions">
<RenamePop
:list="envList"
:type="(showType as EnvAuthScopeEnum)"
v-bind="popVisible[element.id]"
@cancel="handleRenameCancel(element)"
@success="envSuccessHandler"
>
<div class="flex flex-row items-center gap-[8px]">
<MsButton
<icon-drag-dot-vertical
v-permission="['PROJECT_ENVIRONMENT:READ+UPDATE']"
type="icon"
class="drag-handle !mr-0 p-[2px]"
>
<MsIcon
type="icon-icon_drag"
size="16"
class="text-[rgb(var(--primary-5))] hover:text-[rgb(var(--primary-4))]"
/>
</MsButton>
class="drag-handle env-item-drag-icon"
/>
<MsMoreAction
v-permission="['PROJECT_ENVIRONMENT:READ+DELETE', 'PROJECT_ENVIRONMENT:READ+EXPORT']"
trigger="click"
:list="envMoreAction(element.mock || false)"
@select="
(value) => handleMoreAction(value, element.id, EnvAuthTypeEnum.ENVIRONMENT_PARAM)
"
/>
>
<MsButton type="icon" size="mini" class="env-item-actions-btn">
<MsIcon type="icon-icon_more_outlined" size="14" class="text-[var(--color-text-4)]" />
</MsButton>
</MsMoreAction>
</div>
</div>
</RenamePop>
</div>
</RenamePop>
</div>
</div>
</VueDraggable>
</div>
@ -156,46 +156,44 @@
<div
v-for="element in evnGroupList"
:key="element.id"
class="env-item hover:bg-[rgb(var(--primary-1))]"
class="env-item"
:class="[activeGroupKey === element.id ? 'env-item-focus' : '']"
@click="handleListItemClickGroup(element)"
>
<RenamePop
:list="evnGroupList"
:type="(showType as EnvAuthScopeEnum)"
v-bind="groupPopVisible[element.id]"
@cancel="handleRenameCancelGroup(element)"
@submit="handleRenameCancelGroup(element, true)"
>
<div class="flex max-w-[100%] grow flex-row items-center justify-between">
<a-tooltip :content="element.name">
<div
class="one-line-text"
:class="{ 'font-medium text-[rgb(var(--primary-5))]': element.id === activeGroupKey }"
>{{ element.name }}</div
>
</a-tooltip>
<div class="node-extra">
<div class="flex max-w-[100%] grow flex-row items-center justify-between">
<a-tooltip :content="element.name">
<div
class="one-line-text"
:class="{ 'font-medium text-[rgb(var(--primary-5))]': element.id === activeGroupKey }"
>{{ element.name }}</div
>
</a-tooltip>
<div class="env-item-actions">
<RenamePop
:list="evnGroupList"
:type="(showType as EnvAuthScopeEnum)"
v-bind="groupPopVisible[element.id]"
@cancel="handleRenameCancelGroup(element)"
@success="envSuccessCroupHandler(element)"
>
<div class="flex flex-row items-center gap-[8px]">
<MsButton
<icon-drag-dot-vertical
v-permission="['PROJECT_ENVIRONMENT:READ+UPDATE']"
type="icon"
class="drag-handle !mr-0 p-[2px]"
>
<MsIcon
type="icon-icon_drag"
size="16"
class="text-[rgb(var(--primary-5))] hover:text-[rgb(var(--primary-4))]"
/>
</MsButton>
class="env-item-drag-icon drag-handle"
/>
<MsMoreAction
v-permission="['PROJECT_ENVIRONMENT:READ+DELETE', 'PROJECT_ENVIRONMENT:READ+EXPORT']"
:list="groupMoreAction"
@select="(value) => handleMoreAction(value, element.id, EnvAuthTypeEnum.ENVIRONMENT_GROUP)"
/>
>
<MsButton type="icon" size="mini" class="env-item-actions-btn">
<MsIcon type="icon-icon_more_outlined" size="14" class="text-[var(--color-text-4)]" />
</MsButton>
</MsMoreAction>
</div>
</div>
</RenamePop>
</div>
</RenamePop>
</div>
</div>
</VueDraggable>
</div>
@ -216,7 +214,11 @@
@ok="successHandler"
/>
<!-- 环境组 -->
<EnvGroupBox v-else-if="showType === 'PROJECT_GROUP'" @save-or-update="handleUpdateEnvGroup" />
<EnvGroupBox
v-else-if="showType === 'PROJECT_GROUP'"
ref="envGroupBoxRef"
@save-or-update="handleUpdateEnvGroup"
/>
</template>
</MsSplitBox>
</div>
@ -263,7 +265,6 @@
groupListEnv,
listEnv,
} from '@/api/modules/project-management/envManagement';
import { deleteModule } from '@/api/modules/project-management/fileManagement';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import { useAppStore } from '@/store';
@ -273,10 +274,8 @@
NEW_ENV_PARAM,
} from '@/store/modules/setting/useProjectEnvStore';
import { downloadByteFile } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import { EnvListItem } from '@/models/projectManagement/environmental';
import { PopVisible } from '@/models/setting/usergroup';
import { EnvListItem, PopVisible } from '@/models/projectManagement/environmental';
import { EnvAuthScopeEnum, EnvAuthTypeEnum } from '@/enums/envEnum';
import { SortableEvent } from 'sortablejs';
@ -321,6 +320,11 @@
// MoreAction
const envMoreAction = (isMock: boolean | undefined) => {
return [
{
label: t('common.rename'),
eventTag: 'rename',
permission: ['PROJECT_ENVIRONMENT:READ+UPDATE'],
},
{
label: t('common.export'),
eventTag: 'export',
@ -355,6 +359,11 @@
// moreAction
const groupMoreAction: ActionsItem[] = [
{
label: t('common.rename'),
eventTag: 'rename',
permission: ['PROJECT_ENVIRONMENT:READ+UPDATE'],
},
{
label: t('common.delete'),
danger: true,
@ -589,24 +598,29 @@
function changeShowType(value: string | number | boolean) {
if (value === 'PROJECT_GROUP') {
initGroupList(keyword.value, true);
// store.setCurrentGroupId('');
}
}
const handleRenameCancel = (element: EnvListItem, shouldSearch?: boolean) => {
if (shouldSearch) {
initData();
}
const handleRenameCancel = async (element: EnvListItem) => {
popVisible.value[element.id].visible = false;
};
const handleRenameCancelGroup = (element: EnvListItem, shouldSearch?: boolean) => {
if (shouldSearch) {
initGroupList();
}
async function envSuccessHandler() {
initData();
store.initEnvDetail();
}
const envGroupBoxRef = ref();
const handleRenameCancelGroup = async (element: EnvListItem) => {
groupPopVisible.value[element.id].visible = false;
};
const envSuccessCroupHandler = async (element: EnvListItem) => {
await initGroupList();
envGroupBoxRef.value.initDetail(element.id);
};
const handleListItemClick = (element: EnvListItem) => {
const { id } = element;
store.setCurrentId(id);
@ -646,6 +660,17 @@
handleEnvImport();
}
break;
case 'rename':
if (scopeType === EnvAuthTypeEnum.ENVIRONMENT_GROUP) {
const tmpObj = evnGroupList.value.filter((ele) => ele.id === id)[0];
const visibleItem = { visible: true, defaultName: tmpObj.name, id };
groupPopVisible.value[id] = visibleItem;
} else if (scopeType === EnvAuthTypeEnum.ENVIRONMENT_PARAM) {
const tmpObj = envList.value.filter((ele) => ele.id === id)[0];
const visibleItem = { visible: true, defaultName: tmpObj.name, id };
popVisible.value[id] = visibleItem;
}
break;
default:
break;
}
@ -688,24 +713,36 @@
.env-item {
display: flex;
align-items: center;
padding: 7px 8px;
height: 38px;
padding: 8px 4px;
box-sizing: border-box;
border-radius: 4px;
border-radius: var(--border-radius-small);
cursor: pointer;
.node-extra {
opacity: 0;
&:hover {
opacity: 1;
}
}
&:hover {
.node-extra {
opacity: 1;
background-color: rgb(var(--primary-1));
.ms-list-drag-icon {
@apply visible;
}
.env-item-actions {
@apply visible;
}
}
:active {
color: rgb(var(--primary-5));
.ms-list-drag-icon {
@apply invisible cursor-move;
}
.env-item-actions {
@apply invisible flex items-center justify-end;
.env-item-actions-btn {
@apply !mr-0;
padding: 4px;
border-radius: var(--border-radius-mini);
}
}
}
.env-item-focus {
background-color: rgb(var(--primary-1));
.env-item-actions {
@apply visible;
}
}
.env-row {