fix(all): 修复bugs

This commit is contained in:
baiqi 2024-04-12 14:54:21 +08:00 committed by Craftsman
parent 9e3799b5f2
commit a5f51e6866
17 changed files with 174 additions and 127 deletions

View File

@ -6,6 +6,7 @@
:footer="true"
unmount-on-close
:ok-loading="props.confirmLoading"
:mask-closable="false"
save-continue-text="project.commonScript.saveAsDraft"
ok-text="project.commonScript.apply"
@confirm="handleDrawerConfirm"

View File

@ -9,7 +9,7 @@
props.autoHeight ? '' : 'h-full min-h-[500px]',
props.noContentPadding ? 'ms-card--noContentPadding' : 'p-[24px]',
props.noBottomRadius ? 'ms-card--noBottomRadius' : '',
!props.hideFooter && !props.simple ? 'pb-[80px]' : '',
!props.hideFooter && !props.simple ? 'pb-[24px]' : '',
]"
>
<a-scrollbar v-if="!props.simple" :style="{ overflow: 'auto' }">
@ -151,7 +151,7 @@
//
return props.noContentPadding ? 66 + _specialHeight : 114 + _specialHeight;
}
return 250 + _specialHeight;
return 230 + _specialHeight;
});
const getComputedContentStyle = computed(() => {

View File

@ -149,6 +149,7 @@
noTitle?: boolean; //
drawerStyle?: Record<string, string>; //
showFullScreen?: boolean; //
maskClosable?: boolean; //
}
const props = withDefaults(defineProps<DrawerProps>(), {
@ -160,6 +161,7 @@
popupContainer: 'body',
disabledWidthDrag: false,
showFullScreen: false,
maskClosable: true,
okPermission: () => [], //
});
const emit = defineEmits(['update:visible', 'confirm', 'cancel', 'continue', 'close']);

View File

@ -273,71 +273,73 @@
{{ t('apiTestDebug.introduceSource') }}
</MsButton>
</div>
<div class="mb-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.sqlScript') }}</div>
<div class="mb-[8px] h-[300px]">
<MsCodeEditor
v-model:model-value="condition.script"
:read-only="props.disabled"
theme="vs"
height="120px"
:language="LanguageEnum.SQL"
:show-full-screen="false"
:show-theme-change="false"
@change="() => emit('change')"
>
</MsCodeEditor>
</div>
<div class="mb-[8px]">
<div class="mb-[8px] flex items-center text-[var(--color-text-1)]">
{{ t('apiTestDebug.storageByCol') }}
<a-tooltip position="right" :content="t('apiTestDebug.storageColTip')">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
<template v-if="condition.dataSourceId">
<div class="mb-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.sqlScript') }}</div>
<div class="mb-[8px] h-[300px]">
<MsCodeEditor
v-model:model-value="condition.script"
:read-only="props.disabled"
theme="vs"
height="120px"
:language="LanguageEnum.SQL"
:show-full-screen="false"
:show-theme-change="false"
@change="() => emit('change')"
>
</MsCodeEditor>
</div>
<a-input
v-model:model-value="condition.variableNames"
:max-length="255"
:disabled="props.disabled"
:placeholder="
t('apiTestDebug.storageByColPlaceholder', { a: 'id', b: 'email', c: '${id_1}', d: '${email_1}' })
"
@input="() => emit('change')"
/>
</div>
<div class="sql-table-container">
<div class="mb-[8px] text-[var(--color-text-1)]">
{{ t('apiTestDebug.extractParameter') }}
<div class="mb-[8px]">
<div class="mb-[8px] flex items-center text-[var(--color-text-1)]">
{{ t('apiTestDebug.storageByCol') }}
<a-tooltip position="right" :content="t('apiTestDebug.storageColTip')">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
<a-input
v-model:model-value="condition.variableNames"
:max-length="255"
:disabled="props.disabled"
:placeholder="
t('apiTestDebug.storageByColPlaceholder', { a: 'id', b: 'email', c: '${id_1}', d: '${email_1}' })
"
@input="() => emit('change')"
/>
</div>
<paramTable
:params="condition.extractParams"
:disabled-except-param="props.disabled"
:columns="sqlSourceColumns"
:selectable="false"
:default-param-item="defaultKeyValueParamItem"
@change="handleSqlSourceParamTableChange"
/>
</div>
<div class="mt-[8px]">
<div class="mb-[8px] flex items-center text-[var(--color-text-1)]">
{{ t('apiTestDebug.storageByResult') }}
<a-tooltip position="right" :content="t('apiTestDebug.storageResultTip')">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
<div class="sql-table-container">
<div class="mb-[8px] text-[var(--color-text-1)]">
{{ t('apiTestDebug.extractParameter') }}
</div>
<paramTable
:params="condition.extractParams"
:disabled-except-param="props.disabled"
:columns="sqlSourceColumns"
:selectable="false"
:default-param-item="defaultKeyValueParamItem"
@change="handleSqlSourceParamTableChange"
/>
</div>
<a-input
v-model:model-value="condition.resultVariable"
:disabled="props.disabled"
:max-length="255"
:placeholder="t('apiTestDebug.storageByResultPlaceholder', { a: 'result', b: '${result}' })"
@input="() => emit('change')"
/>
</div>
<div class="mt-[8px]">
<div class="mb-[8px] flex items-center text-[var(--color-text-1)]">
{{ t('apiTestDebug.storageByResult') }}
<a-tooltip position="right" :content="t('apiTestDebug.storageResultTip')">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
<a-input
v-model:model-value="condition.resultVariable"
:disabled="props.disabled"
:max-length="255"
:placeholder="t('apiTestDebug.storageByResultPlaceholder', { a: 'result', b: '${result}' })"
@input="() => emit('change')"
/>
</div>
</template>
</template>
<!-- 等待时间 -->
<div v-else-if="condition.processorType === RequestConditionProcessor.TIME_WAITING">

View File

@ -119,7 +119,6 @@
import { cloneDeep } from 'lodash-es';
import result from '@/views/api-test/components/requestComposition/response/result.vue';
import loopPagination from '@/views/api-test/scenario/components/common/customApiDrawer.vue';
import { reportCaseStepDetail, reportStepDetail } from '@/api/modules/api-test/report';
import { useI18n } from '@/hooks/useI18n';
@ -292,6 +291,7 @@
}
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
loading.value = false;

View File

@ -97,6 +97,7 @@
/**
* @description 接口测试-接口调试
*/
import { useRoute } from 'vue-router';
import { cloneDeep } from 'lodash-es';
import MsCard from '@/components/pure/ms-card/index.vue';
@ -138,6 +139,7 @@
import { defaultBodyParams, defaultResponse } from '../components/config';
import { parseRequestBodyFiles } from '../components/utils';
const route = useRoute();
const { t } = useI18n();
const moduleTreeRef = ref<InstanceType<typeof moduleTree>>();
@ -235,8 +237,9 @@
activeDebug.value = debugTabs.value[debugTabs.value.length - 1];
}
async function openApiTab(apiInfo: ModuleTreeNode) {
const isLoadedTabIndex = debugTabs.value.findIndex((e) => e.id === apiInfo.id);
async function openApiTab(apiInfo: ModuleTreeNode | string) {
const id = typeof apiInfo === 'string' ? apiInfo : apiInfo.id;
const isLoadedTabIndex = debugTabs.value.findIndex((e) => e.id === id);
if (isLoadedTabIndex > -1) {
// tabtab
activeDebug.value = debugTabs.value[isLoadedTabIndex];
@ -244,17 +247,17 @@
}
try {
loading.value = true;
const res = await getDebugDetail(apiInfo.id);
const res = await getDebugDetail(id);
let parseRequestBodyResult;
if (res.protocol === 'HTTP') {
parseRequestBodyResult = parseRequestBodyFiles(res.request.body); // id
}
addDebugTab({
label: apiInfo.name,
...res,
response: cloneDeep(defaultResponse),
...res.request,
url: res.path,
label: res.name,
name: res.name, // requestnamenull
moduleId: res.moduleId, // requestmoduleIdnull
...parseRequestBodyResult,
@ -345,6 +348,12 @@
}
}
onMounted(() => {
if (route.query.id) {
openApiTab(route.query.id as string);
}
});
useLeaveTabUnSaveCheck(debugTabs.value, ['PROJECT_API_DEBUG:READ+ADD', 'PROJECT_API_DEBUG:READ+UPDATE']);
</script>

View File

@ -80,7 +80,7 @@
allow-clear
class="w-[200px]"
/> -->
<a-tooltip v-if="!props.isNew" position="left" :content="t('apiScenario.refreshRefScenario')">
<a-tooltip position="left" :content="t('apiScenario.refreshRefScenario')">
<a-button type="outline" class="arco-btn-outline--secondary !mr-0 !p-[8px]" @click="refreshStepInfo">
<template #icon>
<icon-refresh class="text-[var(--color-text-4)]" />
@ -149,9 +149,6 @@
import { ApiScenarioDebugRequest, Scenario, ScenarioStepItem } from '@/models/apiTest/scenario';
import { ScenarioExecuteStatus, ScenarioStepRefType, ScenarioStepType } from '@/enums/apiEnum';
const props = defineProps<{
isNew?: boolean; //
}>();
const emit = defineEmits<{
(e: 'batchDebug', data: Pick<ApiScenarioDebugRequest, 'steps' | 'stepDetails' | 'reportId'>): void;
}>();

View File

@ -527,7 +527,7 @@
getDefinitionDetail,
getModuleTreeOnlyModules,
} from '@/api/modules/api-test/management';
import { debugScenario, getScenarioStep } from '@/api/modules/api-test/scenario';
import { debugScenario, getScenarioDetail, getScenarioStep } from '@/api/modules/api-test/scenario';
import { getSocket } from '@/api/modules/project-management/commonScript';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
@ -834,8 +834,36 @@
};
}
/**
* 刷新引用场景的步骤数据
*/
async function refreshScenarioStepInfo(step: ScenarioStepItem, id: string | number) {
try {
loading.value = true;
const res = await getScenarioDetail(id);
if (step.children) {
step.children = mapTree(res.steps || [], (child) => {
child.uniqueId = getGenerateId();
child.isQuoteScenarioStep = true; //
child.isRefScenarioStep = true; //
child.draggable = false; //
if (selectedKeys.value.includes(step.uniqueId) && !selectedKeys.value.includes(child.uniqueId)) {
//
selectedKeys.value.push(child.uniqueId);
}
return child;
}) as ScenarioStepItem[];
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
loading.value = false;
}
}
//
function saveScenarioConfig() {
async function saveScenarioConfig() {
if (activeStep.value) {
const realStep = findNodeByKey<ScenarioStepItem>(steps.value, activeStep.value.uniqueId, 'uniqueId');
if (realStep) {
@ -844,16 +872,16 @@
...realStep.config,
...scenarioConfigForm.value,
};
realStep.children = mapTree<ScenarioStepItem>(realStep.children || [], (child) => {
//
if (scenarioConfigForm.value.refType === ScenarioStepRefType.REF) {
child.isRefScenarioStep = true;
child.enable = true;
} else {
if (scenarioConfigForm.value.refType === ScenarioStepRefType.REF) {
//
await refreshScenarioStepInfo(realStep as ScenarioStepItem, realStep.resourceId);
} else {
realStep.children = mapTree<ScenarioStepItem>(realStep.children || [], (child) => {
// -
child.isRefScenarioStep = false;
}
return child;
});
return child;
});
}
Message.success(t('apiScenario.setSuccess'));
scenario.value.unSaved = true;
cancelScenarioConfig();
@ -1138,7 +1166,7 @@
};
})[0]
),
name: `copy_${node.name}`,
name: `copy_${node.name}`.substring(0, 255),
copyFromStepId: stepDetail ? node.id : node.copyFromStepId,
sort: node.sort + 1,
isNew: true,
@ -1481,7 +1509,6 @@
delete scenario.value.stepResponses[realStep.uniqueId]; //
realStep.reportId = getGenerateId();
realStep.executeStatus = ScenarioExecuteStatus.EXECUTING;
const stepFileParam = scenario.value.stepFileParam[realStep.id];
request.executeLoading = true;
scenario.value.executeType = executeType;
realExecute({
@ -1491,7 +1518,10 @@
},
reportId: realStep.reportId,
stepFileParam: {
[realStep.uniqueId]: stepFileParam,
[realStep.uniqueId]: {
uploadFileIds: request.uploadFileIds || [],
linkFileIds: request.linkFileIds || [],
},
},
});
} else {

View File

@ -10,7 +10,6 @@
<step
v-if="activeKey === ScenarioCreateComposition.STEP"
v-model:scenario="scenario"
is-new
@batch-debug="emit('batchDebug', $event)"
/>
</a-tab-pane>

View File

@ -308,7 +308,7 @@
node.executeStatus = ScenarioExecuteStatus.EXECUTING;
waitingDebugStepDetails[node.id] = activeScenarioTab.value.stepDetails[node.id];
} else {
node.executeStatus = ScenarioExecuteStatus.UN_EXECUTE;
node.executeStatus = undefined;
}
return !!node.enable;
});

View File

@ -21,10 +21,9 @@
<style lang="less" scoped>
.banner-wrap {
width: 55%;
.img {
width: 100%;
object-fit: fill;
object-fit: cover;
}
}
</style>

View File

@ -19,13 +19,17 @@
{{ t('system.config.auth.edit') }}
</MsButton>
<MsButton
v-if="record.enable"
v-show="record.enable"
v-permission="['SYSTEM_PARAMETER_SETTING_AUTH:READ+UPDATE']"
@click="disabledAuth(record)"
>
{{ t('system.config.auth.disable') }}
</MsButton>
<MsButton v-else v-permission="['SYSTEM_PARAMETER_SETTING_AUTH:READ+UPDATE']" @click="enableAuth(record)">
<MsButton
v-show="!record.enable"
v-permission="['SYSTEM_PARAMETER_SETTING_AUTH:READ+UPDATE']"
@click="enableAuth(record)"
>
{{ t('system.config.auth.enable') }}
</MsButton>
<MsTableMoreAction
@ -49,7 +53,13 @@
show-description
>
<template #tbutton>
<a-button type="outline" size="mini" :disabled="detailDrawerLoading" @click="editAuth(activeAuthDetail, true)">
<a-button
v-permission="['SYSTEM_PARAMETER_SETTING_AUTH:READ+UPDATE']"
type="outline"
size="mini"
:disabled="detailDrawerLoading"
@click="editAuth(activeAuthDetail, true)"
>
{{ t('system.config.auth.edit') }}
</a-button>
</template>
@ -584,6 +594,7 @@
<script setup lang="ts">
import { computed, onBeforeMount, ref } from 'vue';
import { useRoute } from 'vue-router';
import { Message } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue';
@ -619,6 +630,7 @@
import type { FormInstance, ValidatedError } from '@arco-design/web-vue';
const route = useRoute();
const { t } = useI18n();
const { openModal } = useModal();
const loading = ref(false);
@ -703,6 +715,7 @@
Message.success(t('system.config.auth.enableSuccess'));
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
@ -730,6 +743,7 @@
Message.success(t('system.config.auth.disableSuccess'));
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
@ -939,7 +953,9 @@
}
activeAuthDesc.value = description;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
showDetailDrawer.value = false;
} finally {
detailDrawerLoading.value = false;
}
@ -1030,6 +1046,7 @@
});
Message.success(t('system.config.auth.testLinkSuccess'));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
LDAPTestLoading.value = false;
@ -1056,6 +1073,7 @@
});
Message.success(t('system.config.auth.testLinkSuccess'));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
LDAPTestLoading.value = false;
@ -1185,21 +1203,12 @@
authFormRef.value?.resetFields();
}
defineExpose({
openAuthDetail, // ID
onBeforeMount(() => {
if (route.query.id) {
openAuthDetail(route.query.id as string);
}
});
declare const _default: import('vue').DefineComponent<
unknown,
unknown,
import('vue').ComponentOptionsMixin,
import('vue').ComponentOptionsMixin,
{
openAuthDetail: (id: string) => void;
}
>;
export declare type AuthConfigInstance = InstanceType<typeof _default>;
await tableStore.initColumn(TableKeyEnum.SYSTEM_AUTH, columns, 'drawer');
</script>

View File

@ -2,7 +2,7 @@
<MsTabCard v-model:active-tab="activeTab" :title="t('system.config.parameterConfig')" :tab-list="tabList" />
<baseConfig v-if="activeTab === 'baseConfig'" v-show="activeTab === 'baseConfig'" />
<pageConfig v-if="isInitPageConfig" v-show="activeTab === 'pageConfig'" />
<authConfig v-if="isInitAuthConfig" v-show="activeTab === 'authConfig'" ref="authConfigRef" />
<authConfig v-if="isInitAuthConfig" v-show="activeTab === 'authConfig'" />
<memoryCleanup v-if="isInitMemoryCleanup" v-show="activeTab === 'memoryCleanup'" />
</template>
@ -10,7 +10,6 @@
/**
* @description 系统设置-系统参数
*/
import { onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import MsTabCard from '@/components/pure/ms-tab-card/index.vue';
@ -19,7 +18,6 @@
import useLicenseStore from '@/store/modules/setting/license';
import { hasAnyPermission } from '@/utils/permission';
import type { AuthConfigInstance } from './components/authConfig.vue';
//
const baseConfig = defineAsyncComponent(() => import('./components/baseConfig.vue'));
const pageConfig = defineAsyncComponent(() => import('./components/pageConfig.vue'));
@ -33,7 +31,6 @@
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 = ref([
{ key: 'baseConfig', title: t('system.config.baseConfig'), permission: ['SYSTEM_PARAMETER_SETTING_BASE:READ'] },
{ key: 'pageConfig', title: t('system.config.pageConfig'), permission: ['SYSTEM_PARAMETER_SETTING_DISPLAY:READ'] },
@ -73,13 +70,7 @@
onBeforeMount(() => {
getXpackTab();
const firstHasPermissionTab = tabList.value.find((item: any) => hasAnyPermission(item.permission));
activeTab.value = firstHasPermissionTab?.key || 'baseConfig';
});
onMounted(() => {
if (route.query.tab === 'authConfig' && route.query.id) {
authConfigRef.value?.openAuthDetail(route.query.id as string);
}
activeTab.value = (route.query.tab as string) || firstHasPermissionTab?.key || 'baseConfig';
});
</script>

View File

@ -19,9 +19,9 @@
<a-button type="text" class="px-0" @click="showPoolDetail(record.id)">{{ record.name }}</a-button>
</template>
<template #action="{ record }">
<MsButton v-permission="['SYSTEM_TEST_RESOURCE_POOL:READ+UPDATE']" @click="editPool(record)">{{
t('system.resourcePool.editPool')
}}</MsButton>
<MsButton v-permission="['SYSTEM_TEST_RESOURCE_POOL:READ+UPDATE']" @click="editPool(record)">
{{ t('system.resourcePool.editPool') }}
</MsButton>
<MsButton
v-if="record.enable"
v-permission="['SYSTEM_TEST_RESOURCE_POOL:READ+UPDATE']"
@ -30,9 +30,9 @@
>
{{ t('system.resourcePool.tableDisable') }}
</MsButton>
<MsButton v-else v-permission="['SYSTEM_TEST_RESOURCE_POOL:READ+UPDATE']" v-xpack @click="enablePool(record)">{{
t('system.resourcePool.tableEnable')
}}</MsButton>
<MsButton v-else v-permission="['SYSTEM_TEST_RESOURCE_POOL:READ+UPDATE']" v-xpack @click="enablePool(record)">
{{ t('system.resourcePool.tableEnable') }}
</MsButton>
<MsTableMoreAction
v-permission="['SYSTEM_TEST_RESOURCE_POOL:READ+DELETE']"
:list="tableActions"
@ -215,6 +215,7 @@
Message.success(t('system.resourcePool.disablePoolSuccess'));
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
@ -226,6 +227,10 @@
* 删除资源池
*/
function deletePool(record: any) {
if (propsRes.value.data.length === 1) {
Message.warning(t('system.resourcePool.atLeastOnePool'));
return;
}
openModal({
type: 'error',
title: t('system.resourcePool.deletePoolTip', { name: characterLimit(record.name) }),
@ -242,6 +247,7 @@
Message.success(t('system.resourcePool.deletePoolSuccess'));
loadList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},

View File

@ -121,4 +121,5 @@ export default {
'system.resourcePool.jobTemplateReset': 'Reset Template',
'system.resourcePool.addSuccess': 'Added resource pool successfully',
'system.resourcePool.updateSuccess': 'Resource pool updated successfully',
'system.resourcePool.atLeastOnePool': 'Reserve at least one resource pool',
};

View File

@ -116,4 +116,5 @@ export default {
'system.resourcePool.jobTemplateReset': '重置 Job 模板',
'system.resourcePool.addSuccess': '添加资源池成功',
'system.resourcePool.updateSuccess': '更新资源池成功',
'system.resourcePool.atLeastOnePool': '至少保留一个资源池',
};

View File

@ -322,7 +322,7 @@
import useLocale from '@/locale/useLocale';
import { useTableStore } from '@/store';
import { characterLimit, formatPhoneNumber } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
import { validateEmail, validatePhone } from '@/utils/validate';
import type { SimpleUserInfo, SystemRole, UserListItem } from '@/models/setting/user';
@ -387,7 +387,7 @@
{
tableKey: TableKeyEnum.SYSTEM_USER,
columns,
selectable: !!hasAnyPermission(['SYSTEM_USER:READ+ADD', 'SYSTEM_USER:READ+UPDATE', 'SYSTEM_USER:READ+DELETE']),
selectable: !!hasAnyPermission(['SYSTEM_USER:READ+UPDATE', 'SYSTEM_USER:READ+DELETE']),
showSetting: true,
heightUsed: 288,
},
@ -877,7 +877,7 @@
}
function handleTagClick(record: UserListItem & Record<string, any>) {
if (hasAnyPermission(['SYSTEM_USER:READ+UPDATE', 'SYSTEM_USER_ROLE:READ'])) {
if (hasAllPermission(['SYSTEM_USER:READ+UPDATE', 'SYSTEM_USER_ROLE:READ'])) {
record.selectUserGroupVisible = true;
}
}