refactor(缺陷管理): 详情增加缺陷历史展示
This commit is contained in:
parent
4554dcec42
commit
52448dcb32
|
@ -211,3 +211,8 @@ export function batchAssociation(data: TableQueryParams) {
|
|||
export function cancelAssociation(id: string) {
|
||||
return MSR.get({ url: `${bugURL.getCancelDemandUrl}/${id}` });
|
||||
}
|
||||
|
||||
// 缺陷管理-变更历史-列表
|
||||
export function getChangeHistoryList(data: TableQueryParams) {
|
||||
return MSR.post({ url: bugURL.getChangeHistoryListUrl, data });
|
||||
}
|
||||
|
|
|
@ -64,3 +64,6 @@ export const getUnrelatedDemandListUrl = '/bug/case/un-relate/page';
|
|||
export const getUnrelatedModuleTreeUrl = '/bug/case/un-relate/module/tree';
|
||||
// 未关联的模块树 数量
|
||||
export const getUnrelatedModuleTreeCountUrl = '/bug/case/un-relate/module/count';
|
||||
|
||||
// 缺陷管理-变更历史-列表
|
||||
export const getChangeHistoryListUrl = '/bug/history/page';
|
||||
|
|
|
@ -0,0 +1,385 @@
|
|||
<template>
|
||||
<div class="flex flex-col">
|
||||
<div>
|
||||
<a-radio-group v-model:model-value="activeTab" type="button" size="small">
|
||||
<a-radio v-for="item of responseRadios" :key="item.value" :value="item.value">
|
||||
{{ t(item.label) }}
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<div v-if="activeTab === 'jsonPath'" class="mt-[16px]">
|
||||
<paramsTable
|
||||
v-model:params="innerParams.jsonPath"
|
||||
:selectable="false"
|
||||
:columns="jsonPathColumns"
|
||||
:scroll="{ minWidth: '700px' }"
|
||||
:default-param-item="jsonPathDefaultParamItem"
|
||||
@change="handleJsonPathChange"
|
||||
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
||||
>
|
||||
<template #expression="{ record }">
|
||||
<a-popover
|
||||
position="tl"
|
||||
:disabled="!record.expression || record.expression.trim() === ''"
|
||||
class="ms-params-input-popover"
|
||||
>
|
||||
<template #content>
|
||||
<div class="param-popover-title">
|
||||
{{ t('apiTestDebug.expression') }}
|
||||
</div>
|
||||
<div class="param-popover-value">
|
||||
{{ record.expression }}
|
||||
</div>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:model-value="record.expression"
|
||||
class="ms-params-input"
|
||||
:max-length="255"
|
||||
@input="handleExpressionChange"
|
||||
@change="handleExpressionChange"
|
||||
>
|
||||
<template #suffix>
|
||||
<a-tooltip :disabled="!disabledExpressionSuffix">
|
||||
<template #content>
|
||||
<div>{{ t('apiTestDebug.expressionTip1') }}</div>
|
||||
<div>{{ t('apiTestDebug.expressionTip2') }}</div>
|
||||
<div>{{ t('apiTestDebug.expressionTip3') }}</div>
|
||||
</template>
|
||||
<MsIcon
|
||||
type="icon-icon_flashlamp"
|
||||
:size="15"
|
||||
:class="
|
||||
disabledExpressionSuffix ? 'ms-params-input-suffix-icon--disabled' : 'ms-params-input-suffix-icon'
|
||||
"
|
||||
@click.stop="() => showFastExtraction(record, RequestExtractExpressionEnum.JSON_PATH)"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-popover>
|
||||
</template>
|
||||
<template #operationPre="{ record }">
|
||||
<a-popover
|
||||
v-model:popupVisible="record.moreSettingPopoverVisible"
|
||||
position="tl"
|
||||
trigger="click"
|
||||
:title="t('common.setting')"
|
||||
:content-style="{ width: '480px' }"
|
||||
>
|
||||
<template #content>
|
||||
<moreSetting v-model:config="activeRecord" is-popover class="mt-[12px]" />
|
||||
<div class="flex items-center justify-end gap-[8px]">
|
||||
<a-button type="secondary" size="mini" @click="record.moreSettingPopoverVisible = false">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="() => applyMoreSetting(record)">
|
||||
{{ t('common.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<span class="invisible relative"></span>
|
||||
</a-popover>
|
||||
</template>
|
||||
</paramsTable>
|
||||
</div>
|
||||
<div v-if="activeTab === 'xPath'" class="mt-[16px]">
|
||||
<div class="text-[var(--color-text-1)]">{{ t('ms.assertion.responseContentType') }}</div>
|
||||
<a-radio-group
|
||||
v-model:model-value="innerParams.xPath.responseFormat"
|
||||
class="mt-[16px]"
|
||||
type="button"
|
||||
size="small"
|
||||
>
|
||||
<a-radio value="XML">XML</a-radio>
|
||||
<a-radio value="HTML">HTML</a-radio>
|
||||
</a-radio-group>
|
||||
<paramsTable
|
||||
v-model:params="innerParams.xPath.data"
|
||||
class="mt-[16px]"
|
||||
:selectable="false"
|
||||
:columns="xPathColumns"
|
||||
:scroll="{ minWidth: '700px' }"
|
||||
:default-param-item="xPathDefaultParamItem"
|
||||
@change="handleXPathChange"
|
||||
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
||||
>
|
||||
<template #expression="{ record }">
|
||||
<a-popover
|
||||
position="tl"
|
||||
:disabled="!record.expression || record.expression.trim() === ''"
|
||||
class="ms-params-input-popover"
|
||||
>
|
||||
<template #content>
|
||||
<div class="param-popover-title">
|
||||
{{ t('apiTestDebug.expression') }}
|
||||
</div>
|
||||
<div class="param-popover-value">
|
||||
{{ record.expression }}
|
||||
</div>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:model-value="record.expression"
|
||||
class="ms-params-input"
|
||||
:max-length="255"
|
||||
@input="handleExpressionChange"
|
||||
@change="handleExpressionChange"
|
||||
>
|
||||
<template #suffix>
|
||||
<a-tooltip :disabled="!disabledExpressionSuffix">
|
||||
<template #content>
|
||||
<div>{{ t('apiTestDebug.expressionTip1') }}</div>
|
||||
<div>{{ t('apiTestDebug.expressionTip2') }}</div>
|
||||
<div>{{ t('apiTestDebug.expressionTip3') }}</div>
|
||||
</template>
|
||||
<MsIcon
|
||||
type="icon-icon_flashlamp"
|
||||
:size="15"
|
||||
:class="
|
||||
disabledExpressionSuffix ? 'ms-params-input-suffix-icon--disabled' : 'ms-params-input-suffix-icon'
|
||||
"
|
||||
@click.stop="() => showFastExtraction(record, RequestExtractExpressionEnum.JSON_PATH)"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-popover>
|
||||
</template>
|
||||
<template #operationPre="{ record }">
|
||||
<a-popover
|
||||
v-model:popupVisible="record.moreSettingPopoverVisible"
|
||||
position="tl"
|
||||
trigger="click"
|
||||
:title="t('common.setting')"
|
||||
:content-style="{ width: '480px' }"
|
||||
>
|
||||
<template #content>
|
||||
<moreSetting v-model:config="activeRecord" is-popover class="mt-[12px]" />
|
||||
<div class="flex items-center justify-end gap-[8px]">
|
||||
<a-button type="secondary" size="mini" @click="record.moreSettingPopoverVisible = false">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="() => applyMoreSetting(record)">
|
||||
{{ t('common.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<span class="invisible relative"></span>
|
||||
</a-popover>
|
||||
</template>
|
||||
</paramsTable>
|
||||
</div>
|
||||
</div>
|
||||
<fastExtraction v-model:visible="fastExtractionVisible" :config="activeRecord" @apply="handleFastExtractionApply" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineModel } from 'vue';
|
||||
|
||||
import { statusCodeOptions } from '@/components/pure/ms-advance-filter';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import fastExtraction from '@/views/api-test/components/fastExtraction/index.vue';
|
||||
import moreSetting from '@/views/api-test/components/fastExtraction/moreSetting.vue';
|
||||
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import {
|
||||
ExecuteConditionProcessor,
|
||||
ExpressionType,
|
||||
JSONPathExtract,
|
||||
RegexExtract,
|
||||
XPathExtract,
|
||||
} from '@/models/apiTest/debug';
|
||||
import {
|
||||
RequestExtractEnvType,
|
||||
RequestExtractExpressionEnum,
|
||||
RequestExtractExpressionRuleType,
|
||||
RequestExtractResultMatchingRule,
|
||||
RequestExtractScope,
|
||||
ResponseBodyXPathAssertionFormat,
|
||||
} from '@/enums/apiEnum';
|
||||
|
||||
interface Param {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:data', data: ExecuteConditionProcessor): void;
|
||||
(e: 'copy'): void;
|
||||
(e: 'delete', id: number): void;
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const innerParams = defineModel<Param>('modelValue', {
|
||||
default: { jsonPath: [], xPath: { responseFormat: 'XML', data: [] } },
|
||||
});
|
||||
const activeTab = ref('jsonPath');
|
||||
const extractParamsTableRef = ref<InstanceType<typeof paramsTable>>();
|
||||
const fastExtractionVisible = ref(false);
|
||||
const disabledExpressionSuffix = ref(false);
|
||||
export type ExpressionConfig = (RegexExtract | JSONPathExtract | XPathExtract) & Record<string, any>;
|
||||
|
||||
const defaultExtractParamItem: ExpressionConfig = {
|
||||
enable: true,
|
||||
variableName: '',
|
||||
variableType: RequestExtractEnvType.TEMPORARY,
|
||||
extractScope: RequestExtractScope.BODY,
|
||||
expression: '',
|
||||
extractType: RequestExtractExpressionEnum.REGEX,
|
||||
expressionMatchingRule: RequestExtractExpressionRuleType.EXPRESSION,
|
||||
resultMatchingRule: RequestExtractResultMatchingRule.RANDOM,
|
||||
resultMatchingRuleNum: 1,
|
||||
responseFormat: ResponseBodyXPathAssertionFormat.XML,
|
||||
moreSettingPopoverVisible: false,
|
||||
};
|
||||
|
||||
const activeRecord = ref({ ...defaultExtractParamItem }); // 用于暂存当前操作的提取参数表格项
|
||||
|
||||
const responseRadios = [
|
||||
{ label: 'ms.assertion.jsonPath', value: 'jsonPath' },
|
||||
{ label: 'ms.assertion.xpath', value: 'xPath' },
|
||||
{ label: 'ms.assertion.document', value: 'document' },
|
||||
{ label: 'ms.assertion.regular', value: 'regular' },
|
||||
{ label: 'ms.assertion.script', value: 'script' },
|
||||
];
|
||||
|
||||
const jsonPathColumns: ParamTableColumn[] = [
|
||||
{
|
||||
title: 'ms.assertion.expression',
|
||||
dataIndex: 'expression',
|
||||
slotName: 'expression',
|
||||
},
|
||||
{
|
||||
title: 'ms.assertion.matchCondition',
|
||||
dataIndex: 'matchCondition',
|
||||
slotName: 'matchCondition',
|
||||
options: statusCodeOptions,
|
||||
},
|
||||
{
|
||||
title: 'ms.assertion.matchValue',
|
||||
dataIndex: 'matchValue',
|
||||
slotName: 'matchValue',
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
slotName: 'operation',
|
||||
fixed: 'right',
|
||||
width: 130,
|
||||
hasDisable: true,
|
||||
moreAction: [
|
||||
{
|
||||
eventTag: 'copy',
|
||||
label: 'common.copy',
|
||||
},
|
||||
{
|
||||
eventTag: 'setting',
|
||||
label: 'common.setting',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const jsonPathDefaultParamItem = {
|
||||
expression: '',
|
||||
matchCondition: '',
|
||||
matchValue: '',
|
||||
enable: true,
|
||||
};
|
||||
const handleJsonPathChange = () => {
|
||||
console.log('jsonPath change');
|
||||
};
|
||||
function handleExpressionChange(val: string) {
|
||||
extractParamsTableRef.value?.addTableLine(val, 'expression');
|
||||
}
|
||||
|
||||
const xPathColumns: ParamTableColumn[] = [
|
||||
{
|
||||
title: 'ms.assertion.expression',
|
||||
dataIndex: 'expression',
|
||||
slotName: 'expression',
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
slotName: 'operation',
|
||||
fixed: 'right',
|
||||
width: 130,
|
||||
hasDisable: true,
|
||||
moreAction: [
|
||||
{
|
||||
eventTag: 'copy',
|
||||
label: 'common.copy',
|
||||
},
|
||||
{
|
||||
eventTag: 'setting',
|
||||
label: 'common.setting',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const xPathDefaultParamItem = {
|
||||
expression: '',
|
||||
matchCondition: '',
|
||||
matchValue: '',
|
||||
enable: true,
|
||||
};
|
||||
const handleXPathChange = () => {
|
||||
console.log('jsonPath change');
|
||||
};
|
||||
|
||||
/**
|
||||
* 提取参数表格-应用更多设置
|
||||
*/
|
||||
function applyMoreSetting(record: ExpressionConfig) {
|
||||
// condition.value.extractParams = condition.value.extractParams?.map((e) => {
|
||||
// if (e.id === activeRecord.value.id) {
|
||||
// record.moreSettingPopoverVisible = false;
|
||||
// return {
|
||||
// ...activeRecord.value,
|
||||
// moreSettingPopoverVisible: false,
|
||||
// } as any; // TOOD: 这里的后台类型应该是不对的,需要修改
|
||||
// }
|
||||
// return e;
|
||||
// });
|
||||
// emit('change');
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取参数表格-保存快速提取的配置
|
||||
*/
|
||||
function handleFastExtractionApply(config: RegexExtract | JSONPathExtract | XPathExtract) {
|
||||
// condition.value.extractParams = condition.value.extractParams?.map((e) => {
|
||||
// if (e.id === activeRecord.value.id) {
|
||||
// return {
|
||||
// ...e,
|
||||
// ...config,
|
||||
// };
|
||||
// }
|
||||
// return e;
|
||||
// });
|
||||
// fastExtractionVisible.value = false;
|
||||
// nextTick(() => {
|
||||
// extractParamsTableRef.value?.addTableLine();
|
||||
// });
|
||||
// emit('change');
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理提取参数表格更多操作
|
||||
*/
|
||||
function handleExtractParamMoreActionSelect(event: ActionsItem, record: ExpressionConfig) {
|
||||
activeRecord.value = { ...record };
|
||||
if (event.eventTag === 'copy') {
|
||||
emit('copy');
|
||||
} else if (event.eventTag === 'setting') {
|
||||
record.moreSettingPopoverVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
function showFastExtraction(record: ExpressionConfig, type: ExpressionType) {
|
||||
activeRecord.value = { ...record, extractType: type };
|
||||
fastExtractionVisible.value = true;
|
||||
}
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
|
@ -1,18 +1,13 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<a-radio-group v-model:model-value="innerParams.type" type="button" size="small">
|
||||
<a-radio v-for="item of responseRadios" :key="item.value" :value="item.value">
|
||||
{{ t(item.label) }}
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<div v-if="innerParams.type === 'jsonPath'">
|
||||
<MsJsonPathPicker data="" />
|
||||
</div>
|
||||
<div v-else-if="innerParams.type === 'xPath'">
|
||||
<MsXPathPicker :xml-string="innerParams.response" />
|
||||
</div>
|
||||
<paramsTable
|
||||
v-model:params="innerParams"
|
||||
:selectable="false"
|
||||
:columns="columns"
|
||||
:scroll="{ minWidth: '700px' }"
|
||||
:default-param-item="defaultParamItem"
|
||||
@change="handleParamTableChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -20,28 +15,77 @@
|
|||
import { defineModel } from 'vue';
|
||||
|
||||
import { statusCodeOptions } from '@/components/pure/ms-advance-filter/index';
|
||||
import MsJsonPathPicker from '@/components/pure/ms-jsonpath-picker/index.vue';
|
||||
import MsXPathPicker from '@/components/pure/ms-jsonpath-picker/xpath.vue';
|
||||
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
interface Param {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const innerParams = defineModel<Param>('modelValue', { default: { type: 'jsonPath' } });
|
||||
const innerParams = defineModel<Param[]>('modelValue', { default: [] });
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'change'): void; // 数据发生变化
|
||||
}>();
|
||||
const { t } = useI18n();
|
||||
|
||||
const responseRadios = [
|
||||
{ label: 'ms.assertion.jsonPath', value: 'jsonPath' },
|
||||
{ label: 'ms.assertion.xpath', value: 'xPath' },
|
||||
{ label: 'ms.assertion.document', value: 'document' },
|
||||
{ label: 'ms.assertion.regular', value: 'regular' },
|
||||
{ label: 'ms.assertion.script', value: 'script' },
|
||||
const defaultParamItem = {
|
||||
responseHeader: '',
|
||||
matchCondition: '',
|
||||
matchValue: '',
|
||||
enable: true,
|
||||
};
|
||||
|
||||
const responseHeaderOption = [
|
||||
{ label: 'Accept', value: 'accept' },
|
||||
{ label: 'Accept-Encoding', value: 'acceptEncoding' },
|
||||
{ label: 'Accept-Language', value: 'acceptLanguage' },
|
||||
{ label: 'Cache-Control', value: 'cacheControl' },
|
||||
{ label: 'Content-Type', value: 'contentType' },
|
||||
{ label: 'Content-Length', value: 'contentLength' },
|
||||
{ label: 'User-Agent', value: 'userAgent' },
|
||||
{ label: 'Referer', value: 'referer' },
|
||||
{ label: 'Cookie', value: 'cookie' },
|
||||
{ label: 'Authorization', value: 'authorization' },
|
||||
{ label: 'If-None-Match', value: 'ifNoneMatch' },
|
||||
{ label: 'If-Modified-Since', value: 'ifModifiedSince' },
|
||||
];
|
||||
|
||||
const columns: ParamTableColumn[] = [
|
||||
{
|
||||
title: 'ms.assertion.responseHeader', // 响应头
|
||||
dataIndex: 'responseHeader',
|
||||
slotName: 'responseHeader',
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
options: responseHeaderOption,
|
||||
},
|
||||
{
|
||||
title: 'ms.assertion.matchCondition', // 匹配条件
|
||||
dataIndex: 'matchCondition',
|
||||
slotName: 'matchCondition',
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
options: statusCodeOptions,
|
||||
},
|
||||
{
|
||||
title: 'ms.assertion.matchValue', // 匹配值
|
||||
dataIndex: 'matchValue',
|
||||
slotName: 'matchValue',
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
columnTitle: 'common.operation',
|
||||
slotName: 'operation',
|
||||
width: 50,
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
},
|
||||
];
|
||||
function handleParamTableChange(resultArr: any[], isInit?: boolean) {
|
||||
innerParams.value = [...resultArr];
|
||||
if (!isInit) {
|
||||
emit('change');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
v-model:statusCode="codeTabState.statusCode"
|
||||
/>
|
||||
<ResponseHeaderTab v-if="valueKey === 'responseHeader'" />
|
||||
<ResponseBodyTab v-if="valueKey === 'responseBody'" />
|
||||
<ResponseTimeTab v-if="valueKey === 'responseTime'" />
|
||||
<VariableTab v-if="valueKey === 'variable'" />
|
||||
<ScriptTab v-if="valueKey === 'script'" />
|
||||
|
@ -76,6 +77,7 @@
|
|||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import ResponseBodyTab from './comp/ResponseBodyTab.vue';
|
||||
import ResponseHeaderTab from './comp/ResponseHeaderTab.vue';
|
||||
import ResponseTimeTab from './comp/ResponseTimeTab.vue';
|
||||
import ScriptTab from './comp/ScriptTab.vue';
|
||||
|
|
|
@ -14,4 +14,6 @@ export default {
|
|||
'ms.assertion.document': '文档',
|
||||
'ms.assertion.regular': '正则',
|
||||
'ms.assertion.script': '脚本',
|
||||
'ms.assertion.expression': '表达式',
|
||||
'ms.assertion.responseContentType': '响应内容类型',
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
export { default as FilterForm } from './FilterForm.vue';
|
||||
export { default as MsAdvanceFilter } from './index.vue';
|
||||
|
||||
const IN = { label: 'advanceFilter.operator.in', value: 'in' };
|
||||
const NOT_IN = { label: 'advanceFilter.operator.not_in', value: 'not_in' };
|
||||
// const IN = { label: 'advanceFilter.operator.in', value: 'in' };
|
||||
// const NOT_IN = { label: 'advanceFilter.operator.not_in', value: 'not_in' };
|
||||
const LIKE = { label: 'advanceFilter.operator.like', value: 'like' };
|
||||
const NOT_LIKE = { label: 'advanceFilter.operator.not_like', value: 'not_like' };
|
||||
const GT = { label: 'advanceFilter.operator.gt', value: 'gt' };
|
||||
|
@ -14,18 +14,16 @@ const NOT_EQUAL = { label: 'advanceFilter.operator.notEqual', value: 'not_equal'
|
|||
const BETWEEN = { label: 'advanceFilter.operator.between', value: 'between' };
|
||||
|
||||
export const OPERATOR_MAP = {
|
||||
string: [LIKE, NOT_LIKE, IN, NOT_IN, EQUAL, NOT_EQUAL],
|
||||
string: [LIKE, NOT_LIKE, EQUAL, NOT_EQUAL],
|
||||
number: [GT, GE, LT, LE, EQUAL, NOT_EQUAL, BETWEEN],
|
||||
date: [GT, GE, LT, LE, EQUAL, NOT_EQUAL, BETWEEN],
|
||||
array: [IN, NOT_IN],
|
||||
array: [BETWEEN],
|
||||
};
|
||||
|
||||
export const timeSelectOptions = [GE, LE];
|
||||
|
||||
export const statusCodeOptions = [
|
||||
{ label: 'ms.assertion.noValidation', value: 'none' },
|
||||
IN,
|
||||
NOT_IN,
|
||||
EQUAL,
|
||||
NOT_EQUAL,
|
||||
GT,
|
||||
|
@ -133,7 +131,7 @@ export const CustomTypeMaps: Record<string, any> = {
|
|||
},
|
||||
};
|
||||
|
||||
export const MULTIPLE_OPERATOR_LIST = ['in', 'not_in', 'between'];
|
||||
export const MULTIPLE_OPERATOR_LIST = ['between'];
|
||||
|
||||
export function isMutipleOperator(operator: string) {
|
||||
return MULTIPLE_OPERATOR_LIST.includes(operator);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
@search="emit('keywordSearch', innerKeyword, filterResult)"
|
||||
@clear="handleClear"
|
||||
></a-input-search>
|
||||
<MsTag
|
||||
<!-- <MsTag
|
||||
:type="visible ? 'primary' : 'default'"
|
||||
:theme="visible ? 'lightOutLine' : 'outline'"
|
||||
size="large"
|
||||
|
@ -27,7 +27,7 @@
|
|||
{{ t('common.filter') }}
|
||||
</span>
|
||||
</span>
|
||||
</MsTag>
|
||||
</MsTag> -->
|
||||
<MsTag no-margin size="large" class="cursor-pointer" theme="outline" @click="handleRefresh">
|
||||
<MsIcon class="text-[var(color-text-4)]" :size="16" type="icon-icon_reset_outlined" />
|
||||
</MsTag>
|
||||
|
|
|
@ -206,6 +206,14 @@
|
|||
<a-checkbox v-model:model-value="record[columnConfig.dataIndex as string]" @change="(val) => addTableLine(val)" />
|
||||
</template>
|
||||
<template #operation="{ record, rowIndex, columnConfig }">
|
||||
<a-switch
|
||||
v-if="columnConfig.hasDisable"
|
||||
v-model:model-value="record.disable"
|
||||
size="small"
|
||||
type="line"
|
||||
class="mr-[8px]"
|
||||
@change="(val) => addTableLine(val, 'disable')"
|
||||
/>
|
||||
<slot name="operationPre" :record="record" :row-index="rowIndex" :column-config="columnConfig"></slot>
|
||||
<MsTableMoreAction
|
||||
v-if="columnConfig.moreAction"
|
||||
|
@ -226,19 +234,14 @@
|
|||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<a-switch
|
||||
v-if="columnConfig.hasDisable"
|
||||
v-model:model-value="record.disable"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(val) => addTableLine(val, 'disable')"
|
||||
/>
|
||||
<icon-minus-circle
|
||||
v-if="paramsLength > 1 && rowIndex !== paramsLength - 1"
|
||||
class="cursor-pointer text-[var(--color-text-4)]"
|
||||
size="20"
|
||||
@click="deleteParam(rowIndex)"
|
||||
/>
|
||||
<div>
|
||||
<icon-minus-circle
|
||||
v-if="paramsLength > 1 && rowIndex !== paramsLength - 1"
|
||||
class="ml-[8px] cursor-pointer text-[var(--color-text-4)]"
|
||||
size="20"
|
||||
@click="deleteParam(rowIndex)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #responseHeader="{ record, columnConfig }">
|
||||
<a-select v-model="record.responseHeader" class="param-input" @change="(val) => addTableLine(val as string)">
|
||||
|
|
|
@ -100,6 +100,12 @@
|
|||
</template>
|
||||
<CommentTab ref="commentRef" :bug-id="detailInfo.id" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="history">
|
||||
<template #title>
|
||||
{{ t('bugManagement.detail.changeHistory') }}
|
||||
</template>
|
||||
<BugHistoryTab :bug-id="detailInfo.id" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -166,6 +172,7 @@
|
|||
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
||||
import BugCaseTab from './bugCaseTab.vue';
|
||||
import BugDetailTab from './bugDetailTab.vue';
|
||||
import BugHistoryTab from './bugHistoryTab.vue';
|
||||
import CommentTab from './commentTab.vue';
|
||||
|
||||
import {
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<ms-base-table class="mt-[16px]" v-bind="propsRes" v-on="propsEvent">
|
||||
<template #changeNumber="{ record }">
|
||||
<span>{{ record.id }}</span>
|
||||
<!-- TODO: 先不上 -->
|
||||
<!-- <a-tag size="small" class="ml-[4px]">{{ t('bugManagement.history.current') }}</a-tag> -->
|
||||
</template>
|
||||
</ms-base-table>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
|
||||
import { getChangeHistoryList } from '@/api/modules/bug-management';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
const props = defineProps<{
|
||||
bugId: string;
|
||||
}>();
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'bugManagement.history.changeNumber',
|
||||
slotName: 'changeNumber',
|
||||
dataIndex: 'id',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.history.operationMan',
|
||||
dataIndex: 'createUserName',
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'bugManagement.history.updateTime',
|
||||
dataIndex: 'createTime',
|
||||
width: 200,
|
||||
},
|
||||
];
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getChangeHistoryList, {
|
||||
heightUsed: 240,
|
||||
columns,
|
||||
scroll: { x: '100%' },
|
||||
selectable: false,
|
||||
noDisable: false,
|
||||
pageSimple: true,
|
||||
debug: true,
|
||||
});
|
||||
|
||||
const fetchData = async (id: string) => {
|
||||
setLoadListParams({ sourceId: id, projectId: appStore.currentProjectId });
|
||||
await loadList();
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
fetchData(props.bugId);
|
||||
});
|
||||
</script>
|
|
@ -67,6 +67,7 @@ export default {
|
|||
tag: '标签',
|
||||
detail: '详情',
|
||||
case: '用例',
|
||||
changeHistory: '变更历史',
|
||||
comment: '评论',
|
||||
shareTip: '分享链接已复制到剪贴板',
|
||||
deleteTitle: '确认删除 {name} 吗?',
|
||||
|
@ -106,18 +107,12 @@ export default {
|
|||
deleteTime: '删除时间',
|
||||
deleteMan: '删除人',
|
||||
},
|
||||
severityO: {
|
||||
fatal: '致命',
|
||||
serious: '严重',
|
||||
general: '一般',
|
||||
reminder: '提醒',
|
||||
},
|
||||
statusO: {
|
||||
create: '新建',
|
||||
processing: '处理中',
|
||||
resolved: '已解决',
|
||||
closed: '已关闭',
|
||||
refused: '已拒绝',
|
||||
history: {
|
||||
changeNumber: '变更序号',
|
||||
operationMan: '操作人',
|
||||
updateTime: '更新时间',
|
||||
restore: '恢复',
|
||||
current: '当前',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue