feat(测试用例): excel和xmind导出

This commit is contained in:
teukkk 2024-08-08 19:23:18 +08:00 committed by Craftsman
parent 3c08ffeb9c
commit 455a85e98e
10 changed files with 363 additions and 251 deletions

View File

@ -17,6 +17,7 @@ import {
CancelAssociationDemandUrl,
cancelDisassociate,
cancelPreAndPostCaseUrl,
CheckCaseExportTaskUrl,
checkFileIsUpdateUrl,
CreateCaseModuleTreeUrl,
CreateCaseUrl,
@ -32,7 +33,9 @@ import {
DownloadXMindTemplateUrl,
dragSortUrl,
EditorUploadFileUrl,
ExportExcelCaseUrl,
exportExcelCheckUrl,
ExportXMindCaseUrl,
exportXMindCheckUrl,
FollowerCaseUrl,
GetAssociatedCaseIdsUrl,
@ -43,6 +46,8 @@ import {
GetAssociationPublicCaseModuleCountUrl,
GetAssociationPublicCasePageUrl,
GetAssociationPublicModuleTreeUrl,
GetCaseDownloadFileUrl,
GetCaseExportConfigUrl,
GetCaseListUrl,
GetCaseMinderTreeUrl,
GetCaseMinderUrl,
@ -74,6 +79,7 @@ import {
RecoverRecycleCaseListUrl,
RestoreCaseListUrl,
SaveCaseMinderUrl,
StopCaseExportUrl,
TransferFileUrl,
UpdateCaseModuleTreeUrl,
UpdateCaseUrl,
@ -446,7 +452,30 @@ export function importExcelOrXMindCase(data: { request: ImportExcelType; fileLis
''
);
}
// 导出excel
export function exportExcelCase(data: TableQueryParams) {
return MSR.post({ url: ExportExcelCaseUrl, data });
}
// 导出XMind
export function exportXMindCase(data: TableQueryParams) {
return MSR.post({ url: ExportXMindCaseUrl, data });
}
// 检查是否有导出任务
export function checkCaseExportTask() {
return MSR.get({ url: CheckCaseExportTaskUrl });
}
// 获取导出的文件
export function getCaseDownloadFile(projectId: string, fileId: string) {
return MSR.get({ url: `${GetCaseDownloadFileUrl}/${projectId}/${fileId}` });
}
// 停止导出
export function stopCaseExport(taskId: string) {
return MSR.get({ url: `${StopCaseExportUrl}/${taskId}` });
}
// 获取导出字段配置
export function getCaseExportConfig(projectId: string) {
return MSR.get({ url: `${GetCaseExportConfigUrl}/${projectId}` });
}
// 拖拽排序
export function dragSort(data: DragCase) {
return MSR.post({ url: dragSortUrl, data });

View File

@ -152,6 +152,18 @@ export const exportXMindCheckUrl = '/functional/case/pre-check/xmind';
export const importExcelCaseUrl = '/functional/case/import/excel';
// 导入xmind文件
export const importXMindCaseUrl = '/functional/case/import/xmind';
// 导出excel文件
export const ExportExcelCaseUrl = '/functional/case/export/excel';
// 导出XMind文件
export const ExportXMindCaseUrl = '/functional/case/export/xmind';
// 检查是否有导出任务
export const CheckCaseExportTaskUrl = '/functional/case/check/export-task';
// 导出字段配置
export const GetCaseExportConfigUrl = '/functional/case/export/columns';
// 下载导出的文件
export const GetCaseDownloadFileUrl = '/functional/case/download/file';
// 停止导出
export const StopCaseExportUrl = '/functional/case/stop';
// 用例拖拽排序
export const dragSortUrl = '/functional/case/edit/pos';
// 获取变更历史

View File

@ -14,7 +14,14 @@
@cancel="handleDrawerCancel"
>
<template #title>
<slot name="title"></slot>
<slot name="title">
<div v-if="props.drawerTitleProps">
<span class="text-[var(--color-text-1)]">{{ props.drawerTitleProps.title }}</span>
<span v-if="props.drawerTitleProps.count" class="ml-1 text-[var(--color-text-4)]">
{{ t('common.selectedCount', { count: props.drawerTitleProps.count }) }}
</span>
</div>
</slot>
</template>
<div class="panel-wrapper">
<div class="inner-wrapper">
@ -57,7 +64,7 @@
</div>
</div>
</a-checkbox-group>
<div class="text-[var(--color-text-4)]">
<div v-if="customList.length" class="text-[var(--color-text-4)]">
<a-checkbox
:model-value="isCheckedCustomAll"
:indeterminate="customIndeterminate"
@ -68,8 +75,12 @@
</span>
</a-checkbox>
</div>
<a-checkbox-group :model-value="selectedCustomIds" @change="(value) => handleGroupChange(value, 'custom')">
<div v-if="customList.length" class="mb-[32px]">
<a-checkbox-group
v-if="customList.length"
:model-value="selectedCustomIds"
@change="(value) => handleGroupChange(value, 'custom')"
>
<div class="mb-[32px]">
<div class="flex flex-row flex-wrap">
<a-checkbox
v-for="item in customList"
@ -84,7 +95,7 @@
</div>
</div>
</a-checkbox-group>
<div class="flex flex-row items-center gap-[4px]">
<div v-if="otherList.length" class="flex flex-row items-center gap-[4px]">
<div class="text-[var(--color-text-4)]">
<a-checkbox
:model-value="isCheckedOtherAll"
@ -102,8 +113,12 @@
</a-checkbox>
</div>
</div>
<a-checkbox-group :model-value="selectedOtherIds" @change="(value) => handleGroupChange(value, 'other')">
<div v-if="otherList.length" class="mb-[32px]">
<a-checkbox-group
v-if="otherList.length"
:model-value="selectedOtherIds"
@change="(value) => handleGroupChange(value, 'other')"
>
<div class="mb-[32px]">
<div class="flex flex-row flex-wrap">
<a-checkbox
v-for="item in otherList"
@ -206,6 +221,10 @@
systemTitle: string; // |
selectedTitle: string; // |
};
drawerTitleProps?: {
title: string;
count?: number;
};
disabledCancelKeys?: string[]; //
}

View File

@ -84,6 +84,10 @@ export default {
'common.quickAddMember': 'Quickly add members',
'common.filter': 'Filter',
'common.export': 'Export',
'common.exporting': 'Exporting',
'common.exportSuccessful': 'Export successful',
'common.exportFailed': 'Export failed',
'common.downloadFile': 'Download file',
'common.import': 'Import',
'common.collapseAll': 'Collapse all',
'common.expandAll': 'Expand all',

View File

@ -84,6 +84,10 @@ export default {
'common.pleaseSelect': '请选择',
'common.quickAddMember': '快速添加成员',
'common.export': '导出',
'common.exporting': '正在导出',
'common.exportSuccessful': '导出成功',
'common.exportFailed': '导出失败',
'common.downloadFile': '下载文件',
'common.import': '导入',
'common.collapseAll': '收起全部',
'common.expandAll': '展开全部',

View File

@ -128,17 +128,12 @@
:export-loading="exportLoading"
:all-data="exportOptionData"
:disabled-cancel-keys="['name']"
:drawer-title-props="{
title: t('bugManagement.exportBug'),
count: currentSelectParams.currentSelectCount,
}"
@confirm="exportConfirm"
>
<template #title>
<div>
<span class="text-[var(--color-text-1)]">{{ t('bugManagement.exportBug') }}</span>
<span v-if="currentSelectParams.currentSelectCount" class="text-[var(--color-text-4)]">
({{ t('bugManagement.exportBugCount', { count: currentSelectParams.currentSelectCount }) }})
</span>
</div>
</template>
</MsExportDrawer>
/>
<BugDetailDrawer
v-model:visible="detailVisible"
:detail-id="activeDetailId"

View File

@ -277,7 +277,50 @@
@case-node-select="caseNodeSelect"
></FeatureCaseTree>
</a-modal>
<ExportExcelDrawer v-model:visible="showExportExcelVisible" />
<MsExportDrawer
v-model:visible="showExportVisible"
:export-loading="exportLoading"
:all-data="
exportType === 'exportExcel'
? exportOptionData
: { systemColumns: exportOptionData.systemColumns, customColumns: exportOptionData.customColumns }
"
:disabled-cancel-keys="['name']"
:drawer-title-props="{
title:
exportType === 'exportExcel'
? t('caseManagement.featureCase.exportExcel')
: t('caseManagement.featureCase.exportXMindNoUnit'),
count: batchParams.currentSelectCount,
}"
@confirm="exportConfirm"
>
<template v-if="exportType === 'exportExcel'" #footerLeft>
<div class="flex items-center gap-[8px]">
<div>{{ t('caseManagement.featureCase.exportExcel.exportFormat') }}</div>
<a-radio-group v-model:model-value="isMerge">
<a-radio :value="false">
{{ t('common.default') }}
<a-tooltip :content="t('caseManagement.featureCase.exportExcel.defaultTip')">
<MsIcon
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-4))]"
type="icon-icon-maybe_outlined"
/>
</a-tooltip>
</a-radio>
<a-radio :value="true">
{{ t('caseManagement.featureCase.exportExcel.cellSplitting') }}
<a-tooltip :content="t('caseManagement.featureCase.exportExcel.cellSplittingTip')">
<MsIcon
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-4))]"
type="icon-icon-maybe_outlined"
/>
</a-tooltip>
</a-radio>
</a-radio-group>
</div>
</template>
</MsExportDrawer>
<BatchEditModal
v-model:visible="showEditModel"
:batch-params="batchParams"
@ -322,6 +365,7 @@
import { FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import { MsExportDrawerMap, MsExportDrawerOption } from '@/components/pure/ms-export-drawer/types';
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
@ -335,7 +379,6 @@
import BatchEditModal from './batchEditModal.vue';
import CaseDetailDrawer from './caseDetailDrawer.vue';
import FeatureCaseTree from './caseTree.vue';
import ExportExcelDrawer from './exportExcelDrawer.vue';
import AddDemandModal from './tabContent/tabDemand/addDemandModal.vue';
import ThirdDemandDrawer from './tabContent/tabDemand/thirdDemandDrawer.vue';
@ -344,14 +387,21 @@
batchCopyToModules,
batchDeleteCase,
batchMoveToModules,
checkCaseExportTask,
deleteCaseRequest,
dragSort,
exportExcelCase,
exportXMindCase,
getCaseDefaultFields,
getCaseDetail,
getCaseDownloadFile,
getCaseExportConfig,
getCaseList,
getCustomFieldsTable,
stopCaseExport,
updateCaseRequest,
} from '@/api/modules/case-management/featureCase';
import { getSocket } from '@/api/modules/project-management/commonScript';
import { getCaseRelatedInfo } from '@/api/modules/project-management/menuManagement';
import { getProjectOptions } from '@/api/modules/project-management/projectMember';
import { useI18n } from '@/hooks/useI18n';
@ -359,7 +409,15 @@
import { useAppStore, useTableStore } from '@/store';
import useFeatureCaseStore from '@/store/modules/case/featureCase';
import useMinderStore from '@/store/modules/components/minder-editor';
import { characterLimit, filterTreeNode, findNodeByKey, findNodePathByKey, mapTree } from '@/utils';
import {
characterLimit,
downloadByteFile,
filterTreeNode,
findNodeByKey,
findNodePathByKey,
getGenerateId,
mapTree,
} from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import type {
@ -378,6 +436,8 @@
import { executionResultMap, getCaseLevels, getTableFields, statusIconMap } from './utils';
import { LabelValue } from '@arco-design/web-vue/es/tree-select/interface';
const MsExportDrawer = defineAsyncComponent(() => import('@/components/pure/ms-export-drawer/index.vue'));
const { openModal } = useModal();
const { t } = useI18n();
const router = useRouter();
@ -638,20 +698,21 @@
const platformInfo = ref<Record<string, any>>({});
const tableBatchActions = {
baseAction: [
// {
// label: 'caseManagement.featureCase.export',
// eventTag: 'export',
// children: [
// {
// label: 'caseManagement.featureCase.exportExcel',
// eventTag: 'exportExcel',
// },
// {
// label: 'caseManagement.featureCase.exportXMind',
// eventTag: 'exportXMind',
// },
// ],
// },
{
label: 'caseManagement.featureCase.export',
eventTag: 'export',
permission: ['FUNCTIONAL_CASE:READ+EXPORT'],
children: [
{
label: 'caseManagement.featureCase.exportExcelXlsx',
eventTag: 'exportExcel',
},
{
label: 'caseManagement.featureCase.exportXMind',
eventTag: 'exportXMind',
},
],
},
{
label: 'common.edit',
eventTag: 'batchEdit',
@ -1010,11 +1071,187 @@
}
}
const showExportExcelVisible = ref<boolean>(false);
const exportType = ref<'exportExcel' | 'exportXMind'>('exportExcel');
const showExportVisible = ref<boolean>(false);
const exportLoading = ref(false);
const exportOptionData = ref<MsExportDrawerMap>({});
const isMerge = ref<boolean>(false);
async function getCaseExportData() {
try {
const res = await getCaseExportConfig(currentProjectId.value);
exportOptionData.value = res;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
// Excel
function handleShowExportExcel() {
showExportExcelVisible.value = true;
const websocket = ref<WebSocket>();
const reportId = ref('');
const taskId = ref('');
//
async function downloadFile() {
try {
const response = await getCaseDownloadFile(currentProjectId.value, reportId.value);
const fileName = response?.headers.get('content-disposition').split('filename=')[1];
downloadByteFile(response.blob(), fileName);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
//
function showExportSuccessfulMessage(count: number) {
Message.success({
content: () =>
h('div', { class: 'flex flex-col gap-[8px] items-start' }, [
h('div', { class: 'font-medium' }, t('common.exportSuccessful')),
h('div', { class: 'flex items-center gap-[12px]' }, [
h('div', t('caseManagement.featureCase.exportCaseCount', { number: count })),
h(
MsButton,
{
type: 'text',
onClick() {
downloadFile();
},
},
{ default: () => t('common.downloadFile') }
),
]),
]),
duration: 999999999, //
closable: true,
});
}
const isShowExportingMessage = ref(false); //
const exportingMessage = ref();
//
async function cancelExport() {
try {
await stopCaseExport(taskId.value);
exportingMessage.value.close();
websocket.value?.close();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
//
function showExportingMessage() {
if (isShowExportingMessage.value) return;
isShowExportingMessage.value = true;
exportingMessage.value = Message.loading({
content: () =>
h('div', { class: 'flex items-center gap-[12px]' }, [
h('div', t('common.exporting')),
h(
MsButton,
{
type: 'text',
onClick() {
cancelExport();
},
},
{ default: () => t('common.cancel') }
),
]),
duration: 999999999, //
closable: true,
onClose() {
isShowExportingMessage.value = false;
},
});
}
// websocket
function startWebsocketGetExportResult() {
websocket.value = getSocket(reportId.value, '/ws/export');
websocket.value.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') {
exportingMessage.value.close();
reportId.value = data.fileId;
taskId.value = data.taskId;
if (data.isSuccessful) {
showExportSuccessfulMessage(data.count);
} else {
Message.error({
content: t('common.exportFailed'),
duration: 999999999, //
closable: true,
});
}
websocket.value?.close();
}
});
}
function getConfirmFields(option: MsExportDrawerOption[], columnType: string) {
return option
.filter((optionItem) => optionItem.columnType === columnType)
.map((item) => ({ id: item.key, name: item.text }));
}
const exportConfirm = async (option: MsExportDrawerOption[]) => {
try {
exportLoading.value = true;
const { selectedIds, selectAll, excludeIds } = batchParams.value;
reportId.value = getGenerateId();
const params = {
projectId: currentProjectId.value,
selectIds: selectAll ? [] : selectedIds,
excludeIds: excludeIds || [],
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds],
condition: {
keyword: keyword.value,
filter: propsRes.value.filter,
combine: batchParams.value.condition,
},
selectAll,
systemFields: getConfirmFields(option, 'system'),
customFields: getConfirmFields(option, 'custom'),
fileId: reportId.value,
};
let res;
if (exportType.value === 'exportExcel') {
res = await exportExcelCase({
...params,
otherFields: getConfirmFields(option, 'other'),
isMerge: isMerge.value,
});
} else {
res = await exportXMindCase(params);
}
taskId.value = res.taskId;
startWebsocketGetExportResult();
showExportingMessage();
exportLoading.value = false;
showExportVisible.value = false;
resetSelector();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
exportLoading.value = false;
}
};
async function batchExport() {
try {
const res = await checkCaseExportTask();
if (!res.fileId.length) {
showExportVisible.value = true;
} else {
reportId.value = res.fileId;
taskId.value = res.taskId;
startWebsocketGetExportResult();
showExportingMessage();
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
const showEditModel = ref<boolean>(false);
@ -1166,11 +1403,13 @@
showThirdDrawer.value = true;
}
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
async function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
batchParams.value = params;
switch (event.eventTag) {
case 'exportExcel':
handleShowExportExcel();
case 'exportXMind':
exportType.value = event.eventTag;
batchExport();
break;
case 'batchEdit':
batchEdit();
@ -1513,6 +1752,7 @@
}
await initFilter();
initData();
getCaseExportData();
});
watch(
@ -1589,4 +1829,7 @@
padding: 4px 6px;
}
}
:deep(.arco-radio-group) {
display: flex;
}
</style>

View File

@ -1,208 +0,0 @@
<template>
<MsDrawer
v-model:visible="showDrawer"
:mask="false"
:title="t('caseManagement.featureCase.associatedFile')"
:ok-text="t('caseManagement.featureCase.associated')"
:ok-loading="drawerLoading"
:width="480"
unmount-on-close
:show-continue="false"
@confirm="handleDrawerConfirm"
@cancel="handleDrawerCancel"
>
<div class="header mb-6 flex justify-between">
<span class="font-medium">{{ t('caseManagement.featureCase.SelectExportRange') }}</span>
<span class="text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.clear') }}</span>
</div>
<div>
<a-checkbox class="mb-4" :model-value="checkedAll" :indeterminate="indeterminate" @change="handleChangeAll"
><div class="flex items-center">
<span class="mr-1">{{ t('caseManagement.featureCase.baseField') }}</span
><span
><icon-up
v-if="foldBaseFields"
class="text-[12px] text-[var(--color-text-brand)]"
@click="toggle('base')" /><icon-right
v-else
class="text-[12px] text-[var(--color-text-brand)]"
@click="toggle('base')"
/></span>
</div>
</a-checkbox>
</div>
<a-checkbox-group v-if="foldBaseFields" v-model="baseFields" class="checkboxContainer" @change="handleChange">
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
</a-checkbox-group>
<!-- 自定义字段 -->
<div>
<a-checkbox class="mb-4" :model-value="checkedAll" :indeterminate="indeterminate" @change="handleChangeAll"
><div class="flex items-center">
<span class="mr-1">{{ t('caseManagement.featureCase.customField') }}</span
><span
><icon-up
v-if="foldCustomFields"
class="text-[12px] text-[var(--color-text-brand)]"
@click="toggle('custom')" /><icon-right
v-else
class="text-[12px] text-[var(--color-text-brand)]"
@click="toggle('custom')"
/></span>
</div>
</a-checkbox>
</div>
<a-checkbox-group v-if="foldCustomFields" v-model="customFields" class="checkboxContainer" @change="handleChange">
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
</a-checkbox-group>
<!-- 其他字段 -->
<div>
<a-checkbox class="mb-4" :model-value="checkedAll" :indeterminate="indeterminate" @change="handleChangeAll"
><div class="flex items-center">
<span class="mr-1 flex items-center"
>{{ t('caseManagement.featureCase.otherFields') }}<span></span>
<a-tooltip
:content="t('caseManagement.featureCase.otherFieldsToolTip')"
position="top"
:mouse-enter-delay="500"
mini
>
<icon-question-circle
class="mx-1 text-[16px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]" /></a-tooltip
><icon-up
v-if="foldCustomFields"
class="text-[12px] text-[var(--color-text-brand)]"
@click="toggle('other')" /><icon-right
v-else
class="text-[12px] text-[var(--color-text-brand)]"
@click="toggle('other')"
/></span>
</div>
</a-checkbox>
</div>
<a-checkbox-group v-if="foldOtherFields" v-model="otherFields" class="checkboxContainer" @change="handleChange">
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
<div class="item checkbox">
<a-checkbox value="1">Option 1</a-checkbox>
</div>
</a-checkbox-group>
</MsDrawer>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import { useI18n } from '@/hooks/useI18n';
const { t } = useI18n();
const props = defineProps<{
visible: boolean;
}>();
const emit = defineEmits<{
(e: 'update:visible', val: boolean): void;
}>();
const showDrawer = ref<boolean>(false);
const drawerLoading = ref<boolean>(false);
const checkedAll = ref<boolean>(false);
const indeterminate = ref<boolean>(false);
function handleChangeAll() {}
function handleChange() {}
function handleDrawerConfirm() {}
function handleDrawerCancel() {
showDrawer.value = false;
}
const foldBaseFields = ref<boolean>(true); //
const baseFields = ref<string[]>([]);
const foldCustomFields = ref<boolean>(true);
const customFields = ref<string[]>([]);
const foldOtherFields = ref<boolean>(true);
const otherFields = ref<string[]>([]);
function toggle(foldType: string) {
if (foldType === 'base') {
foldBaseFields.value = !foldBaseFields.value;
} else if (foldType === 'custom') {
foldCustomFields.value = !foldCustomFields.value;
} else {
foldOtherFields.value = !foldOtherFields.value;
}
}
watch(
() => props.visible,
(val) => {
showDrawer.value = val;
}
);
watch(
() => showDrawer.value,
(val) => {
emit('update:visible', val);
}
);
</script>
<style scoped lang="less">
.checkboxContainer {
display: grid;
margin-bottom: 16px;
grid-template-columns: repeat(auto-fit, minmax(116px, 1fr));
grid-gap: 16px;
.checkbox {
width: 90px;
white-space: nowrap;
@apply overflow-hidden text-ellipsis;
}
}
</style>

View File

@ -54,8 +54,15 @@ export default {
'The deleted content will be put into the recycle bin, where data can be recovered',
'caseManagement.featureCase.deleteCaseTitle': 'Are you sure to delete the {name} use case?',
'caseManagement.featureCase.export': 'Export',
'caseManagement.featureCase.exportExcel': 'Export spreadsheet (xlsx)',
'caseManagement.featureCase.exportExcelXlsx': 'Export to Excel format (xlsx)',
'caseManagement.featureCase.exportExcel': 'Export as Excel',
'caseManagement.featureCase.exportExcel.exportFormat': 'Export Format',
'caseManagement.featureCase.exportExcel.cellSplitting': 'Cell Splitting',
'caseManagement.featureCase.exportExcel.cellSplittingTip': '1 step per cell, 1 test case occupies multiple rows',
'caseManagement.featureCase.exportExcel.defaultTip': '1 test case per row, multiple steps in one cell',
'caseManagement.featureCase.exportCaseCount': '{ number } test cases successfully exported',
'caseManagement.featureCase.exportXMind': 'Exporting Mind (xmind)',
'caseManagement.featureCase.exportXMindNoUnit': 'Exporting XMind',
'caseManagement.featureCase.moveTo': 'Move to',
'caseManagement.featureCase.copyTo': 'Copy to',
'caseManagement.featureCase.associatedDemand': 'Associated demand',

View File

@ -54,8 +54,15 @@ export default {
'caseManagement.featureCase.deleteCaseTitle': '确认删除 {name} 用例吗?',
'caseManagement.featureCase.completedDeleteCaseTitle': '确认彻底删除 {name} 用例吗?',
'caseManagement.featureCase.export': '导出',
'caseManagement.featureCase.exportExcel': '导出 Excel 表格 (xlsx)',
'caseManagement.featureCase.exportExcel': '导出 Excel 格式',
'caseManagement.featureCase.exportExcelXlsx': '导出 Excel 格式 (xlsx)',
'caseManagement.featureCase.exportExcel.exportFormat': '导出格式',
'caseManagement.featureCase.exportExcel.cellSplitting': '单元格拆分',
'caseManagement.featureCase.exportExcel.cellSplittingTip': '1 个步骤占用 1 个单元格1 条用例占用多行',
'caseManagement.featureCase.exportExcel.defaultTip': '1 条用例占 1 行,多个步骤在 1 个单元格内',
'caseManagement.featureCase.exportCaseCount': '{ number } 条用例已成功导出',
'caseManagement.featureCase.exportXMind': '导出思维导图 (xmind)',
'caseManagement.featureCase.exportXMindNoUnit': '导出思维导图',
'caseManagement.featureCase.moveTo': '移动到',
'caseManagement.featureCase.copyTo': '复制到',
'caseManagement.featureCase.associatedDemand': '关联需求',