feat(环境管理): 断言-请求体-文档
This commit is contained in:
parent
1ca47f0481
commit
18ac2c019d
|
@ -167,7 +167,7 @@
|
|||
</template>
|
||||
</paramsTable>
|
||||
</div>
|
||||
<div v-if="activeTab === 'document'">
|
||||
<div v-if="activeTab === 'document'" class="relative mt-[16px]">
|
||||
<paramsTable
|
||||
v-model:params="innerParams.document.data"
|
||||
:selectable="false"
|
||||
|
@ -175,7 +175,9 @@
|
|||
:scroll="{
|
||||
minWidth: '700px',
|
||||
}"
|
||||
:height-used="580"
|
||||
:default-param-item="documentDefaultParamItem"
|
||||
:span-method="documentSpanMethod"
|
||||
@change="handleChange"
|
||||
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
||||
>
|
||||
|
@ -183,17 +185,17 @@
|
|||
<a-tooltip v-if="['object', 'array'].includes(record.paramType)" :content="t('ms.assertion.addChild')">
|
||||
<div
|
||||
class="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-[rgb(var(--primary-5))] hover:bg-[rgb(var(--primary-1))]"
|
||||
@click="addChild"
|
||||
@click="addChild(record)"
|
||||
>
|
||||
<icon-plus size="14" />
|
||||
<icon-plus size="16" />
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<a-tooltip v-else :content="t('ms.assertion.validateChild')">
|
||||
<div
|
||||
class="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-[rgb(var(--primary-5))] hover:bg-[rgb(var(--primary-1))]"
|
||||
@click="addValidateChild"
|
||||
@click="addValidateChild(record)"
|
||||
>
|
||||
<icon-bookmark size="14" />
|
||||
<icon-bookmark size="16" />
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
|
@ -288,14 +290,18 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { TableColumnData, TableData } from '@arco-design/web-vue';
|
||||
|
||||
import { statusCodeOptions } from '@/components/pure/ms-advance-filter';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import { TableOperationColumn } from '../../ms-user-group-comp/authTable.vue';
|
||||
import conditionContent from '@/views/api-test/components/condition/content.vue';
|
||||
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 { findFirstByGroupId, insertTreeByCurrentId, insertTreeByGroupId } from '@/utils/tree';
|
||||
|
||||
import {
|
||||
ExecuteConditionProcessor,
|
||||
|
@ -359,7 +365,7 @@
|
|||
script: new Date().getTime().toString(),
|
||||
},
|
||||
});
|
||||
const activeTab = ref('jsonPath');
|
||||
const activeTab = ref('document');
|
||||
const extractParamsTableRef = ref<InstanceType<typeof paramsTable>>();
|
||||
const fastExtractionVisible = ref(false);
|
||||
const disabledExpressionSuffix = ref(false);
|
||||
|
@ -394,12 +400,14 @@
|
|||
title: 'ms.assertion.expression',
|
||||
dataIndex: 'expression',
|
||||
slotName: 'expression',
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: 'ms.assertion.matchCondition',
|
||||
dataIndex: 'matchCondition',
|
||||
slotName: 'matchCondition',
|
||||
options: statusCodeOptions,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: 'ms.assertion.matchValue',
|
||||
|
@ -473,6 +481,7 @@
|
|||
title: 'ms.assertion.paramsName',
|
||||
dataIndex: 'paramsName',
|
||||
slotName: 'key',
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: 'ms.assertion.mustInclude',
|
||||
|
@ -480,6 +489,7 @@
|
|||
slotName: 'mustContain',
|
||||
titleSlotName: 'documentMustIncludeTitle',
|
||||
align: 'left',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: 'ms.assertion.typeChecking',
|
||||
|
@ -487,6 +497,7 @@
|
|||
slotName: 'typeChecking',
|
||||
titleSlotName: 'documentTypeCheckingTitle',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'project.environmental.paramType',
|
||||
|
@ -522,7 +533,8 @@
|
|||
title: '',
|
||||
slotName: 'operation',
|
||||
fixed: 'right',
|
||||
width: 130,
|
||||
width: 60,
|
||||
align: 'right',
|
||||
},
|
||||
];
|
||||
const documentDefaultParamItem = {
|
||||
|
@ -602,21 +614,71 @@
|
|||
const addChild = (record: Record<string, any>) => {
|
||||
const children = record.children || [];
|
||||
const newRecord = {
|
||||
...documentDefaultParamItem,
|
||||
id: new Date().getTime(),
|
||||
parentId: record.id,
|
||||
rowIndex: children.length,
|
||||
};
|
||||
record.children = [...children, newRecord];
|
||||
};
|
||||
|
||||
// 添加验证子项
|
||||
const addValidateChild = (record: Record<string, any>) => {
|
||||
const children = record.children || [];
|
||||
const newRecord = {
|
||||
id: new Date().getTime(),
|
||||
parentId: record.id,
|
||||
rowIndex: children.length,
|
||||
};
|
||||
record.children = [...children, newRecord];
|
||||
if (record.groupId) {
|
||||
// 子项点击,找到父级
|
||||
const parent = innerParams.value.document.data.find((item: any) => item.id === record.groupId);
|
||||
insertTreeByCurrentId(innerParams.value.document.data, record.id, {
|
||||
...documentDefaultParamItem,
|
||||
id: new Date().getTime(),
|
||||
groupId: parent ? parent.id : record.groupId,
|
||||
});
|
||||
if (parent) {
|
||||
parent.rowSpan = parent.rowSpan ? parent.rowSpan + 1 : 2;
|
||||
} else {
|
||||
// 找到第一个子节点
|
||||
const fisrtChildNode = findFirstByGroupId(innerParams.value.document.data, record.groupId);
|
||||
if (fisrtChildNode) {
|
||||
fisrtChildNode.rowSpan = fisrtChildNode.rowSpan ? fisrtChildNode.rowSpan + 1 : 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 父级点击,直接添加到末尾
|
||||
insertTreeByCurrentId(innerParams.value.document.data, record.id, {
|
||||
...documentDefaultParamItem,
|
||||
id: new Date().getTime(),
|
||||
groupId: record.id,
|
||||
});
|
||||
}
|
||||
};
|
||||
const documentSpanMethod = (data: {
|
||||
record: TableData;
|
||||
column: TableColumnData | TableOperationColumn;
|
||||
rowIndex: number;
|
||||
columnIndex: number;
|
||||
}): { rowspan?: number; colspan?: number } | void => {
|
||||
// groupId 是后端传过来的id,然后根据这个id去找到对应的子项
|
||||
// 前端根据groupId 去过滤出rowspan的数量,然后返回
|
||||
const { record, column } = data;
|
||||
const currentColumn = column as TableColumnData;
|
||||
if (record.rowSpan > 1) {
|
||||
if (currentColumn.slotName === 'key') {
|
||||
return {
|
||||
rowspan: record.rowSpan,
|
||||
colspan: 1,
|
||||
};
|
||||
}
|
||||
if (currentColumn.slotName === 'operation') {
|
||||
return {
|
||||
rowspan: record.rowSpan,
|
||||
colspan: 1,
|
||||
};
|
||||
}
|
||||
if (currentColumn.slotName === 'mustContain') {
|
||||
return {
|
||||
rowspan: record.rowSpan,
|
||||
colspan: 3,
|
||||
};
|
||||
}
|
||||
}
|
||||
return { rowspan: record.rowSpan, colspan: 1 };
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -194,9 +194,11 @@
|
|||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
<template #expand-icon="{ expanded }">
|
||||
<MsIcon v-if="!expanded" :size="8" type="icon-icon_right_outlined" class="text-[var(--color-text-4)]" />
|
||||
<MsIcon v-else :size="8" class="text-[rgb(var(--primary-6))]" type="icon-icon_down_outlined" />
|
||||
<template #expand-icon="{ expanded, record }">
|
||||
<slot name="expand-icon" v-bind="{ expanded, record }">
|
||||
<MsIcon v-if="!expanded" :size="8" type="icon-icon_right_outlined" class="text-[var(--color-text-4)]" />
|
||||
<MsIcon v-else :size="8" class="text-[rgb(var(--primary-6))]" type="icon-icon_down_outlined" />
|
||||
</slot>
|
||||
</template>
|
||||
</a-table>
|
||||
<div
|
||||
|
@ -700,7 +702,7 @@
|
|||
height: 16px;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: var(--color-text-n8) !important;
|
||||
background: var(--color-text-n8);
|
||||
}
|
||||
:deep(.arco-table .arco-table-expand-btn:hover) {
|
||||
border-color: transparent;
|
||||
|
|
|
@ -166,6 +166,14 @@
|
|||
loadColumn(props.tableKey);
|
||||
}
|
||||
});
|
||||
watch(
|
||||
() => props.visible,
|
||||
(value) => {
|
||||
if (value) {
|
||||
hasChange.value = false;
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -23,7 +23,7 @@ export default {
|
|||
drawer: 'Drawer',
|
||||
newWindow: 'New Window',
|
||||
header: 'Header Settings',
|
||||
resetDefault: 'Reset default',
|
||||
resetDefault: 'Undo Changes',
|
||||
nonSort: 'The above properties cannot be sorted',
|
||||
tooltipContentDrawer: 'Drawer: open a new page as a drawer',
|
||||
tooltipContentWindow: 'New Window: open a new page with a new page',
|
||||
|
|
|
@ -23,7 +23,7 @@ export default {
|
|||
drawer: '抽屉',
|
||||
newWindow: '新窗口',
|
||||
header: '表头设置',
|
||||
resetDefault: '恢复默认',
|
||||
resetDefault: '撤销修改',
|
||||
nonSort: '以上属性不可排序',
|
||||
tooltipContentDrawer: '抽屉:以抽屉形式打开新页面',
|
||||
tooltipContentWindow: '新窗口:以新开网页打开新页面',
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
interface TreeData {
|
||||
id: number;
|
||||
groupId?: number;
|
||||
children?: TreeData[];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export function insertTreeByCurrentId(tree: TreeData[], currentId: number, newData: TreeData) {
|
||||
const stack: Array<{ node: TreeData; parent: TreeData | null }> = tree.map((node) => ({ node, parent: null }));
|
||||
|
||||
while (stack.length > 0) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const { node, parent } = stack.pop()!;
|
||||
|
||||
if (parent && parent.children) {
|
||||
const index = parent.children.findIndex((child) => child.id === currentId);
|
||||
if (index !== -1) {
|
||||
// 在目标节点后面插入新数据
|
||||
parent.children.splice(index + 1, 0, newData);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.children) {
|
||||
node.children.forEach((child) => {
|
||||
stack.push({ node: child, parent: node });
|
||||
});
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function insertTreeByGroupId(tree: TreeData[], currentId: number, newData: TreeData) {
|
||||
const stack: Array<{ node: TreeData; parent: TreeData | null }> = tree.map((node) => ({ node, parent: null }));
|
||||
|
||||
while (stack.length > 0) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const { node, parent } = stack.pop()!;
|
||||
|
||||
if (parent && parent.children) {
|
||||
const index = parent.children.findIndex((child) => child.groupId === currentId);
|
||||
if (index !== -1) {
|
||||
// 在目标节点后面插入新数据
|
||||
parent.children.splice(index + 1, 0, newData);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.children) {
|
||||
node.children.forEach((child) => {
|
||||
stack.push({ node: child, parent: node });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function findFirstByGroupId(tree: TreeData[], groupId: number): TreeData | null {
|
||||
const queue: TreeData[] = [...tree];
|
||||
while (queue.length > 0) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const node = queue.shift()!; // 取出队列的第一个元素
|
||||
if (node.groupId === groupId) {
|
||||
return node; // 如果匹配,返回当前节点
|
||||
}
|
||||
if (node.children) {
|
||||
queue.push(...node.children);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
|
@ -1,5 +1,19 @@
|
|||
<template>
|
||||
<MsBaseTable v-bind="propsRes" :hoverable="false" no-disable is-simple-setting v-on="propsEvent">
|
||||
<MsBaseTable
|
||||
v-bind="propsRes"
|
||||
:hoverable="false"
|
||||
no-disable
|
||||
is-simple-setting
|
||||
:span-method="props.spanMethod"
|
||||
v-on="propsEvent"
|
||||
>
|
||||
<!-- 展开行-->
|
||||
<template #expand-icon="{ record }">
|
||||
<div class="flex flex-row items-center gap-[2px] text-[var(--color-text-4)]">
|
||||
<icon-branch class="scale-y-[-1]" />
|
||||
<span v-if="record.children">{{ record.children.length }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 表格头 slot -->
|
||||
<template #encodeTitle>
|
||||
<div class="flex items-center text-[var(--color-text-3)]">
|
||||
|
@ -224,42 +238,49 @@
|
|||
@change="() => addTableLine(rowIndex)"
|
||||
/>
|
||||
</template>
|
||||
<template #mustContain="{ record, columnConfig, rowIndex }">
|
||||
<template #mustContain="{ record, columnConfig }">
|
||||
<a-checkbox
|
||||
v-model:model-value="record[columnConfig.dataIndex as string]"
|
||||
@change="() => addTableLine(rowIndex)"
|
||||
@change="handleMustContainColChange(false)"
|
||||
/>
|
||||
</template>
|
||||
<template #typeChecking="{ record, columnConfig }">
|
||||
<a-checkbox
|
||||
v-model:model-value="record[columnConfig.dataIndex as string]"
|
||||
@change="handleTypeCheckingColChange(false)"
|
||||
/>
|
||||
</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="() => addTableLine(rowIndex)"
|
||||
/>
|
||||
<slot name="operationPre" :record="record" :row-index="rowIndex" :column-config="columnConfig"></slot>
|
||||
<MsTableMoreAction
|
||||
v-if="columnConfig.moreAction"
|
||||
:list="getMoreActionList(columnConfig.moreAction, record)"
|
||||
@select="(e) => handleMoreActionSelect(e, record)"
|
||||
/>
|
||||
<a-trigger v-if="columnConfig.format === RequestBodyFormat.FORM_DATA" trigger="click" position="br">
|
||||
<MsButton type="icon" class="mr-[8px]"><icon-more /></MsButton>
|
||||
<template #content>
|
||||
<div class="content-type-trigger-content">
|
||||
<div class="mb-[8px] text-[var(--color-text-1)]">Content-Type</div>
|
||||
<a-select
|
||||
v-model:model-value="record.contentType"
|
||||
:options="Object.values(RequestContentTypeEnum).map((e) => ({ label: e, value: e }))"
|
||||
allow-create
|
||||
@change="() => addTableLine(rowIndex)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<div>
|
||||
<div class="flex flex-row items-center">
|
||||
<a-switch
|
||||
v-if="columnConfig.hasDisable"
|
||||
v-model:model-value="record.disable"
|
||||
size="small"
|
||||
type="line"
|
||||
class="mr-[8px]"
|
||||
@change="(val) => addTableLine(val as number)"
|
||||
/>
|
||||
<slot name="operationPre" :record="record" :row-index="rowIndex" :column-config="columnConfig"></slot>
|
||||
<MsTableMoreAction
|
||||
v-if="columnConfig.moreAction"
|
||||
:list="getMoreActionList(columnConfig.moreAction, record)"
|
||||
@select="(e) => handleMoreActionSelect(e, record)"
|
||||
/>
|
||||
<a-trigger v-if="columnConfig.format === RequestBodyFormat.FORM_DATA" trigger="click" position="br">
|
||||
<MsButton type="icon" class="mr-[8px]"><icon-more /></MsButton>
|
||||
<template #content>
|
||||
<div class="content-type-trigger-content">
|
||||
<div class="mb-[8px] text-[var(--color-text-1)]">Content-Type</div>
|
||||
<a-select
|
||||
v-model:model-value="record.contentType"
|
||||
:options="Object.values(RequestContentTypeEnum).map((e) => ({ label: e, value: e }))"
|
||||
allow-create
|
||||
@change="(val) => addTableLine(val as number)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
|
||||
<icon-minus-circle
|
||||
v-if="paramsLength > 1 && rowIndex !== paramsLength - 1"
|
||||
class="ml-[8px] cursor-pointer text-[var(--color-text-4)]"
|
||||
|
@ -273,13 +294,28 @@
|
|||
<a-option v-for="item in columnConfig.options" :key="item.value">{{ t(item.label) }}</a-option>
|
||||
</a-select>
|
||||
</template>
|
||||
<template #matchCondition="{ record, columnConfig, rowIndex }">
|
||||
<a-select v-model="record.condition" class="param-input" @change="() => addTableLine(rowIndex)">
|
||||
<template #matchCondition="{ record, columnConfig }">
|
||||
<a-select v-model="record.condition" class="param-input">
|
||||
<a-option v-for="item in columnConfig.options" :key="item.value">{{ t(item.label) }}</a-option>
|
||||
</a-select>
|
||||
</template>
|
||||
<template #matchValue="{ record, rowIndex }">
|
||||
<a-input v-model="record.matchValue" class="param-input" @change="() => addTableLine(rowIndex)" />
|
||||
<template #matchValue="{ record, rowIndex, columnConfig }">
|
||||
<a-tooltip
|
||||
v-if="columnConfig.hasRequired"
|
||||
:content="t(record.required ? 'apiTestDebug.paramRequired' : 'apiTestDebug.paramNotRequired')"
|
||||
>
|
||||
<MsButton
|
||||
type="icon"
|
||||
:class="[
|
||||
record.required ? '!text-[rgb(var(--danger-5))]' : '!text-[var(--color-text-brand)]',
|
||||
'!mr-[4px] !p-[4px]',
|
||||
]"
|
||||
@click="toggleRequired(record, rowIndex)"
|
||||
>
|
||||
<div>*</div>
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
<a-input v-model="record.matchValue" class="param-input" />
|
||||
</template>
|
||||
<template #project="{ record, columnConfig, rowIndex }">
|
||||
<a-select
|
||||
|
@ -346,7 +382,8 @@
|
|||
</template>
|
||||
|
||||
<script async setup lang="ts">
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { TableColumnData, TableData } from '@arco-design/web-vue';
|
||||
import { cloneDeep, isEqual } from 'lodash-es';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||
|
@ -366,6 +403,8 @@
|
|||
|
||||
import { RequestBodyFormat, RequestContentTypeEnum, RequestParamsType } from '@/enums/apiEnum';
|
||||
import { SelectAllEnum, TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
import { TableOperationColumn } from '@arco-design/web-vue/es/table/interface';
|
||||
// 异步加载组件
|
||||
const MsAddAttachment = defineAsyncComponent(() => import('@/components/business/ms-add-attachment/index.vue'));
|
||||
const MsParamsInput = defineAsyncComponent(() => import('@/components/business/ms-params-input/index.vue'));
|
||||
|
@ -400,6 +439,12 @@
|
|||
showSelectorAll?: boolean; // 是否显示全选
|
||||
isSimpleSetting?: boolean; // 是否简单Column设置
|
||||
response?: string; // 响应内容
|
||||
spanMethod?: (data: {
|
||||
record: TableData;
|
||||
column: TableColumnData | TableOperationColumn;
|
||||
rowIndex: number;
|
||||
columnIndex: number;
|
||||
}) => { rowspan?: number; colspan?: number } | void;
|
||||
uploadTempFileApi?: (...args) => Promise<any>; // 上传临时文件接口
|
||||
}>(),
|
||||
{
|
||||
|
@ -496,6 +541,69 @@
|
|||
emit('change', propsRes.value.data);
|
||||
}
|
||||
|
||||
/** 断言-文档-Begin */
|
||||
// 断言-文档-必须包含-全选
|
||||
const mustIncludeAllChecked = ref(false);
|
||||
const mustIncludeIndeterminate = ref(false);
|
||||
const handleMustIncludeChange = (val: boolean) => {
|
||||
mustIncludeAllChecked.value = val;
|
||||
mustIncludeIndeterminate.value = false;
|
||||
const { data } = propsRes.value;
|
||||
data.forEach((e: any) => {
|
||||
e.mustInclude = val;
|
||||
});
|
||||
propsRes.value.data = data;
|
||||
emit('change', propsRes.value.data);
|
||||
};
|
||||
const handleMustContainColChange = (notEmit?: boolean) => {
|
||||
const { data } = propsRes.value;
|
||||
const checkedList = data.filter((e: any) => e.mustInclude).map((e: any) => e.id);
|
||||
if (checkedList.length === data.length) {
|
||||
mustIncludeAllChecked.value = true;
|
||||
mustIncludeIndeterminate.value = false;
|
||||
} else if (checkedList.length === 0) {
|
||||
mustIncludeAllChecked.value = false;
|
||||
mustIncludeIndeterminate.value = false;
|
||||
} else {
|
||||
mustIncludeAllChecked.value = false;
|
||||
mustIncludeIndeterminate.value = true;
|
||||
}
|
||||
if (!notEmit) {
|
||||
emit('change', propsRes.value.data);
|
||||
}
|
||||
};
|
||||
|
||||
const typeCheckingAllChecked = ref(false);
|
||||
const typeCheckingIndeterminate = ref(false);
|
||||
const handleTypeCheckingChange = (val: boolean) => {
|
||||
typeCheckingAllChecked.value = val;
|
||||
typeCheckingIndeterminate.value = false;
|
||||
const { data } = propsRes.value;
|
||||
data.forEach((e: any) => {
|
||||
e.typeChecking = val;
|
||||
});
|
||||
propsRes.value.data = data;
|
||||
emit('change', propsRes.value.data);
|
||||
};
|
||||
const handleTypeCheckingColChange = (notEmit?: boolean) => {
|
||||
const { data } = propsRes.value;
|
||||
const checkedList = data.filter((e: any) => e.typeChecking).map((e: any) => e.id);
|
||||
if (checkedList.length === data.length) {
|
||||
typeCheckingAllChecked.value = true;
|
||||
typeCheckingIndeterminate.value = false;
|
||||
} else if (checkedList.length === 0) {
|
||||
typeCheckingAllChecked.value = false;
|
||||
typeCheckingIndeterminate.value = false;
|
||||
} else {
|
||||
typeCheckingAllChecked.value = false;
|
||||
typeCheckingIndeterminate.value = true;
|
||||
}
|
||||
if (!notEmit) {
|
||||
emit('change', propsRes.value.data);
|
||||
}
|
||||
};
|
||||
/** 断言-文档-end */
|
||||
|
||||
/**
|
||||
* 当表格输入框变化时,给参数表格添加一行数据行
|
||||
* @param val 输入值
|
||||
|
@ -513,6 +621,8 @@
|
|||
} as any);
|
||||
emit('change', propsRes.value.data);
|
||||
}
|
||||
handleMustContainColChange(true);
|
||||
handleTypeCheckingColChange(true);
|
||||
}
|
||||
|
||||
watch(
|
||||
|
@ -667,30 +777,6 @@
|
|||
addTableLine(rowIndex);
|
||||
}
|
||||
|
||||
/** 断言-文档-Begin */
|
||||
// 断言-文档-必须包含-全选
|
||||
const mustIncludeList = ref([]);
|
||||
const mustIncludeAllChecked = ref(false);
|
||||
const mustIncludeIndeterminate = ref(false);
|
||||
const handleMustIncludeChange = (val: boolean) => {
|
||||
mustIncludeAllChecked.value = val;
|
||||
mustIncludeIndeterminate.value = false;
|
||||
const data = propsRes.value;
|
||||
mustIncludeList.value = val ? data.map((e: any) => e.id) : [];
|
||||
};
|
||||
|
||||
// 断言-文档-类型校验-存储用户勾选的id
|
||||
const typeCheckingList = ref([]);
|
||||
const typeCheckingAllChecked = ref(false);
|
||||
const typeCheckingIndeterminate = ref(false);
|
||||
const handleTypeCheckingChange = (val: boolean) => {
|
||||
typeCheckingAllChecked.value = val;
|
||||
typeCheckingIndeterminate.value = false;
|
||||
const data = propsRes.value;
|
||||
typeCheckingList.value = val ? data.map((e: any) => e.id) : [];
|
||||
};
|
||||
/** 断言-文档-end */
|
||||
|
||||
defineExpose({
|
||||
addTableLine,
|
||||
});
|
||||
|
@ -774,4 +860,7 @@
|
|||
line-height: 16px;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
:deep(.arco-table-expand-btn) {
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -188,57 +188,57 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {useRoute} from 'vue-router';
|
||||
import {Message} from '@arco-design/web-vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import {FormItem, FormRuleItem} from '@/components/pure/ms-form-create/types';
|
||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
import MsFileList from "@/components/pure/ms-upload/fileList.vue";
|
||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||
import {MsFileItem} from '@/components/pure/ms-upload/types';
|
||||
import RelateFileDrawer from '@/components/business/ms-link-file/associatedFileDrawer.vue';
|
||||
import TransferModal from '@/views/case-management/caseManagementFeature/components/tabContent/transferModal.vue';
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||
import { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
|
||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||
import RelateFileDrawer from '@/components/business/ms-link-file/associatedFileDrawer.vue';
|
||||
import TransferModal from '@/views/case-management/caseManagementFeature/components/tabContent/transferModal.vue';
|
||||
|
||||
import {
|
||||
checkFileIsUpdateRequest,
|
||||
createOrUpdateBug,
|
||||
downloadFileRequest,
|
||||
editorUploadFile,
|
||||
getAssociatedFileList,
|
||||
getBugDetail,
|
||||
getTemplateById,
|
||||
getTemplateOption,
|
||||
previewFile,
|
||||
transferFileRequest,
|
||||
updateFile,
|
||||
} from '@/api/modules/bug-management';
|
||||
import {getModules, getModulesCount} from '@/api/modules/project-management/fileManagement';
|
||||
import {useI18n} from '@/hooks/useI18n';
|
||||
import useVisit from '@/hooks/useVisit';
|
||||
import router from '@/router';
|
||||
import {useAppStore} from '@/store';
|
||||
import {downloadByteFile} from '@/utils';
|
||||
import {scrollIntoView} from '@/utils/dom';
|
||||
import {
|
||||
checkFileIsUpdateRequest,
|
||||
createOrUpdateBug,
|
||||
downloadFileRequest,
|
||||
editorUploadFile,
|
||||
getAssociatedFileList,
|
||||
getBugDetail,
|
||||
getTemplateById,
|
||||
getTemplateOption,
|
||||
previewFile,
|
||||
transferFileRequest,
|
||||
updateFile,
|
||||
} from '@/api/modules/bug-management';
|
||||
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useVisit from '@/hooks/useVisit';
|
||||
import router from '@/router';
|
||||
import { useAppStore } from '@/store';
|
||||
import { downloadByteFile } from '@/utils';
|
||||
import { scrollIntoView } from '@/utils/dom';
|
||||
|
||||
import {
|
||||
BugEditCustomField,
|
||||
BugEditCustomFieldItem,
|
||||
BugEditFormObject,
|
||||
BugTemplateRequest
|
||||
} from '@/models/bug-management';
|
||||
import {AssociatedList, AttachFileInfo} from '@/models/caseManagement/featureCase';
|
||||
import {TableQueryParams} from '@/models/common';
|
||||
import {SelectValue} from '@/models/projectManagement/menuManagement';
|
||||
import {BugManagementRouteEnum} from '@/enums/routeEnum';
|
||||
import {
|
||||
BugEditCustomField,
|
||||
BugEditCustomFieldItem,
|
||||
BugEditFormObject,
|
||||
BugTemplateRequest,
|
||||
} from '@/models/bug-management';
|
||||
import { AssociatedList, AttachFileInfo } from '@/models/caseManagement/featureCase';
|
||||
import { TableQueryParams } from '@/models/common';
|
||||
import { SelectValue } from '@/models/projectManagement/menuManagement';
|
||||
import { BugManagementRouteEnum } from '@/enums/routeEnum';
|
||||
|
||||
import {convertToFile} from '../case-management/caseManagementFeature/components/utils';
|
||||
import {convertToFileByBug} from './utils';
|
||||
import { convertToFile } from '../case-management/caseManagementFeature/components/utils';
|
||||
import { convertToFileByBug } from './utils';
|
||||
|
||||
defineOptions({ name: 'BugEditPage' });
|
||||
defineOptions({ name: 'BugEditPage' });
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -356,9 +356,9 @@ defineOptions({ name: 'BugEditPage' });
|
|||
const templateChange = async (v: SelectValue, request?: BugTemplateRequest) => {
|
||||
if (v) {
|
||||
try {
|
||||
let param = {projectId: appStore.currentProjectId, id: v}
|
||||
let param = { projectId: appStore.currentProjectId, id: v };
|
||||
if (request) {
|
||||
param = {...param, ...request}
|
||||
param = { ...param, ...request };
|
||||
}
|
||||
const res = await getTemplateById(param);
|
||||
getFormRules(res.customFields);
|
||||
|
@ -555,7 +555,7 @@ defineOptions({ name: 'BugEditPage' });
|
|||
// 复制, 只需返回初始状态
|
||||
await templateChange(templateId);
|
||||
} else {
|
||||
await templateChange(templateId, {fromStatusId: res.status, platformBugKey: res.platformBugId})
|
||||
await templateChange(templateId, { fromStatusId: res.status, platformBugKey: res.platformBugId });
|
||||
}
|
||||
if (attachments && attachments.length) {
|
||||
attachmentsList.value = attachments;
|
||||
|
|
|
@ -192,6 +192,7 @@
|
|||
<style lang="less" scoped>
|
||||
.page {
|
||||
transform: scale3d(1, 1, 1);
|
||||
padding-bottom: 180px;
|
||||
.header {
|
||||
padding: 24px 24px 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue