mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-12-05 05:29:29 +08:00
feat(接口测试): 场景 csv 文件删除提示
This commit is contained in:
parent
2cdc7f802a
commit
307f58d36f
@ -0,0 +1,189 @@
|
|||||||
|
<template>
|
||||||
|
<a-popover
|
||||||
|
v-model:popup-visible="visible"
|
||||||
|
trigger="click"
|
||||||
|
position="bl"
|
||||||
|
:disabled="inputFiles.length === 0"
|
||||||
|
content-class="ms-add-attachment-files-popover"
|
||||||
|
arrow-class="hidden"
|
||||||
|
:popup-offset="0"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
<template #content>
|
||||||
|
<div class="flex w-[200px] flex-col gap-[8px]">
|
||||||
|
<template v-if="alreadyDeleteFiles.length > 0">
|
||||||
|
<div class="flex items-center gap-[4px]">
|
||||||
|
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="18" />
|
||||||
|
<div class="text-[var(--color-text-4)]">{{ t('ms.add.attachment.alreadyDelete') }}</div>
|
||||||
|
<MsButton type="text" :disabled="props.disabled" @click="clearDeletedFiles">
|
||||||
|
{{ t('ms.add.attachment.quickClear') }}
|
||||||
|
</MsButton>
|
||||||
|
</div>
|
||||||
|
<div class="file-list">
|
||||||
|
<div v-for="file of alreadyDeleteFiles" :key="file.value" class="file-list-item">
|
||||||
|
<MsTag size="small" max-width="100%">
|
||||||
|
{{ file.label }}
|
||||||
|
</MsTag>
|
||||||
|
<a-tooltip :content="t('ms.add.attachment.remove')">
|
||||||
|
<MsButton type="text" status="secondary" :disabled="props.disabled" @click="handleClose(file)">
|
||||||
|
<MsIcon
|
||||||
|
type="icon-icon_unlink"
|
||||||
|
:class="props.disabled ? '' : 'hover:text-[rgb(var(--primary-5))]'"
|
||||||
|
size="16"
|
||||||
|
/>
|
||||||
|
</MsButton>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="otherFiles.length > 0">
|
||||||
|
<div v-if="alreadyDeleteFiles.length > 0" class="mt-[4px] text-[var(--color-text-4)]">
|
||||||
|
{{ t('ms.add.attachment.other') }}
|
||||||
|
</div>
|
||||||
|
<div class="file-list">
|
||||||
|
<div v-for="file of otherFiles" :key="file.value" class="file-list-item">
|
||||||
|
<MsTag size="small" max-width="100%">
|
||||||
|
{{ file.label }}
|
||||||
|
</MsTag>
|
||||||
|
<div v-if="file.local === true" class="flex items-center">
|
||||||
|
<template v-if="hasAnyPermission(['PROJECT_FILE_MANAGEMENT:READ+ADD'])">
|
||||||
|
<a-tooltip :content="t('ms.add.attachment.saveAs')">
|
||||||
|
<MsButton
|
||||||
|
type="text"
|
||||||
|
status="secondary"
|
||||||
|
class="!mr-0"
|
||||||
|
:disabled="props.disabled"
|
||||||
|
@click="handleOpenSaveAs(file)"
|
||||||
|
>
|
||||||
|
<MsIcon
|
||||||
|
type="icon-icon_unloading"
|
||||||
|
:class="props.disabled ? '' : 'hover:text-[rgb(var(--primary-5))]'"
|
||||||
|
size="16"
|
||||||
|
/>
|
||||||
|
</MsButton>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-divider direction="vertical" :margin="4"></a-divider>
|
||||||
|
</template>
|
||||||
|
<a-tooltip :content="t('ms.add.attachment.remove')">
|
||||||
|
<MsButton type="text" status="secondary" :disabled="props.disabled" @click="handleClose(file)">
|
||||||
|
<MsIcon
|
||||||
|
type="icon-icon_delete-trash_outlined1"
|
||||||
|
:class="props.disabled ? '' : 'hover:text-[rgb(var(--primary-5))]'"
|
||||||
|
size="16"
|
||||||
|
/>
|
||||||
|
</MsButton>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<a-tooltip v-else :content="t('ms.add.attachment.cancelAssociate')">
|
||||||
|
<MsButton type="text" status="secondary" :disabled="props.disabled" @click="handleClose(file)">
|
||||||
|
<MsIcon
|
||||||
|
type="icon-icon_unlink"
|
||||||
|
:class="props.disabled ? '' : 'hover:text-[rgb(var(--primary-5))]'"
|
||||||
|
size="16"
|
||||||
|
/>
|
||||||
|
</MsButton>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { TagData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
|
import MsTag, { Size } from '@/components/pure/ms-tag/ms-tag.vue';
|
||||||
|
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
disabled?: boolean;
|
||||||
|
inputClass?: string;
|
||||||
|
inputSize?: 'small' | 'medium' | 'large' | 'mini';
|
||||||
|
tagSize?: Size;
|
||||||
|
fields?: {
|
||||||
|
id: string; // 自定义文件的 id 字段名,用于详情展示,接口返回的字段名
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
fields: () => ({
|
||||||
|
id: 'uid',
|
||||||
|
name: 'name',
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'deleteFile', fileId?: string | number): void;
|
||||||
|
(e: 'openSaveAs', file: TagData): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const visible = defineModel<boolean>('visible', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
// 只做回显用
|
||||||
|
const inputFiles = defineModel<TagData[]>('inputFiles', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
const fileList = defineModel<MsFileItem[]>('fileList', {
|
||||||
|
// TODO:这里的文件含有组件内部定义的属性,应该继承MsFileItem类型并扩展声明组件定义的类型属性
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const alreadyDeleteFiles = computed(() => {
|
||||||
|
return inputFiles.value.filter((item) => item.delete);
|
||||||
|
});
|
||||||
|
const otherFiles = computed(() => {
|
||||||
|
return inputFiles.value.filter((item) => !item.delete);
|
||||||
|
});
|
||||||
|
|
||||||
|
function clearDeletedFiles() {
|
||||||
|
inputFiles.value = inputFiles.value.filter((item) => !item.delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClose(data: TagData) {
|
||||||
|
inputFiles.value = inputFiles.value.filter((item) => item.value !== data.value);
|
||||||
|
fileList.value = fileList.value.filter((item) => (item.uid || item[props.fields.id]) !== data.value);
|
||||||
|
if (inputFiles.value.length === 0) {
|
||||||
|
visible.value = false;
|
||||||
|
}
|
||||||
|
emit('deleteFile', data.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOpenSaveAs(file: TagData) {
|
||||||
|
emit('openSaveAs', file);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.ms-add-attachment-files-popover {
|
||||||
|
padding: 16px;
|
||||||
|
.arco-popover-content {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.file-list {
|
||||||
|
@apply flex flex-col overflow-y-auto overflow-x-hidden;
|
||||||
|
.ms-scroll-bar();
|
||||||
|
|
||||||
|
gap: 8px;
|
||||||
|
max-height: 200px;
|
||||||
|
.file-list-item {
|
||||||
|
@apply flex items-center justify-between;
|
||||||
|
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -70,14 +70,17 @@
|
|||||||
:file-module-options-api="props.fileModuleOptionsApi"
|
:file-module-options-api="props.fileModuleOptionsApi"
|
||||||
@finish="handleSaveFileFinish"
|
@finish="handleSaveFileFinish"
|
||||||
/>
|
/>
|
||||||
<a-popover
|
<filesPopover
|
||||||
v-model:popup-visible="inputFilesPopoverVisible"
|
v-model:visible="inputFilesPopoverVisible"
|
||||||
trigger="click"
|
v-model:file-list="fileList"
|
||||||
position="bl"
|
v-model:input-files="inputFiles"
|
||||||
:disabled="inputFiles.length === 0"
|
:disabled="props.disabled"
|
||||||
content-class="ms-add-attachment-files-popover"
|
:input-class="props.inputClass"
|
||||||
arrow-class="hidden"
|
:input-size="props.inputSize"
|
||||||
:popup-offset="0"
|
:fields="props.fields"
|
||||||
|
:tag-size="props.tagSize"
|
||||||
|
@open-save-as="handleOpenSaveAs"
|
||||||
|
@delete-file="emit('deleteFile', $event)"
|
||||||
>
|
>
|
||||||
<div class="h-full flex-1">
|
<div class="h-full flex-1">
|
||||||
<MsTagsInput
|
<MsTagsInput
|
||||||
@ -106,90 +109,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</MsTagsInput>
|
</MsTagsInput>
|
||||||
</div>
|
</div>
|
||||||
<template #content>
|
</filesPopover>
|
||||||
<div class="flex w-[200px] flex-col gap-[8px]">
|
|
||||||
<template v-if="alreadyDeleteFiles.length > 0">
|
|
||||||
<div class="flex items-center gap-[4px]">
|
|
||||||
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="18" />
|
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('ms.add.attachment.alreadyDelete') }}</div>
|
|
||||||
<MsButton type="text" :disabled="props.disabled" @click="clearDeletedFiles">
|
|
||||||
{{ t('ms.add.attachment.quickClear') }}
|
|
||||||
</MsButton>
|
|
||||||
</div>
|
|
||||||
<div class="file-list">
|
|
||||||
<div v-for="file of alreadyDeleteFiles" :key="file.value" class="file-list-item">
|
|
||||||
<a-tooltip :content="file.label" :mouse-enter-delay="300">
|
|
||||||
<MsTag size="small" max-width="100%">
|
|
||||||
{{ file.label }}
|
|
||||||
</MsTag>
|
|
||||||
</a-tooltip>
|
|
||||||
<a-tooltip :content="t('ms.add.attachment.remove')">
|
|
||||||
<MsButton type="text" status="secondary" :disabled="props.disabled" @click="handleClose(file)">
|
|
||||||
<MsIcon
|
|
||||||
type="icon-icon_unlink"
|
|
||||||
:class="props.disabled ? '' : 'hover:text-[rgb(var(--primary-5))]'"
|
|
||||||
size="16"
|
|
||||||
/>
|
|
||||||
</MsButton>
|
|
||||||
</a-tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-if="otherFiles.length > 0">
|
|
||||||
<div v-if="alreadyDeleteFiles.length > 0" class="mt-[4px] text-[var(--color-text-4)]">
|
|
||||||
{{ t('ms.add.attachment.other') }}
|
|
||||||
</div>
|
|
||||||
<div class="file-list">
|
|
||||||
<div v-for="file of otherFiles" :key="file.value" class="file-list-item">
|
|
||||||
<a-tooltip :content="file.label" :mouse-enter-delay="300">
|
|
||||||
<MsTag size="small" max-width="100%">
|
|
||||||
{{ file.label }}
|
|
||||||
</MsTag>
|
|
||||||
</a-tooltip>
|
|
||||||
<div v-if="file.local === true" class="flex items-center">
|
|
||||||
<template v-if="hasAnyPermission(['PROJECT_FILE_MANAGEMENT:READ+ADD'])">
|
|
||||||
<a-tooltip :content="t('ms.add.attachment.saveAs')">
|
|
||||||
<MsButton
|
|
||||||
type="text"
|
|
||||||
status="secondary"
|
|
||||||
class="!mr-0"
|
|
||||||
:disabled="props.disabled"
|
|
||||||
@click="handleOpenSaveAs(file)"
|
|
||||||
>
|
|
||||||
<MsIcon
|
|
||||||
type="icon-icon_unloading"
|
|
||||||
:class="props.disabled ? '' : 'hover:text-[rgb(var(--primary-5))]'"
|
|
||||||
size="16"
|
|
||||||
/>
|
|
||||||
</MsButton>
|
|
||||||
</a-tooltip>
|
|
||||||
<a-divider direction="vertical" :margin="4"></a-divider>
|
|
||||||
</template>
|
|
||||||
<a-tooltip :content="t('ms.add.attachment.remove')">
|
|
||||||
<MsButton type="text" status="secondary" :disabled="props.disabled" @click="handleClose(file)">
|
|
||||||
<MsIcon
|
|
||||||
type="icon-icon_delete-trash_outlined1"
|
|
||||||
:class="props.disabled ? '' : 'hover:text-[rgb(var(--primary-5))]'"
|
|
||||||
size="16"
|
|
||||||
/>
|
|
||||||
</MsButton>
|
|
||||||
</a-tooltip>
|
|
||||||
</div>
|
|
||||||
<a-tooltip v-else :content="t('ms.add.attachment.cancelAssociate')">
|
|
||||||
<MsButton type="text" status="secondary" :disabled="props.disabled" @click="handleClose(file)">
|
|
||||||
<MsIcon
|
|
||||||
type="icon-icon_unlink"
|
|
||||||
:class="props.disabled ? '' : 'hover:text-[rgb(var(--primary-5))]'"
|
|
||||||
size="16"
|
|
||||||
/>
|
|
||||||
</MsButton>
|
|
||||||
</a-tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="flex w-full items-center gap-[4px]">
|
<div v-else class="flex w-full items-center gap-[4px]">
|
||||||
<dropdownMenu
|
<dropdownMenu
|
||||||
@ -206,6 +126,11 @@
|
|||||||
allow-clear
|
allow-clear
|
||||||
readonly
|
readonly
|
||||||
>
|
>
|
||||||
|
<template v-if="fileList[0]?.delete" #prefix>
|
||||||
|
<a-tooltip :content="t('ms.add.attachment.fileDeletedTip')">
|
||||||
|
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="18" />
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
<template v-if="inputFileName" #suffix>
|
<template v-if="inputFileName" #suffix>
|
||||||
<div class="arco-icon-hover arco-input-icon-hover arco-input-clear-btn" @click.stop="handleFileClear">
|
<div class="arco-icon-hover arco-input-icon-hover arco-input-clear-btn" @click.stop="handleFileClear">
|
||||||
<icon-close />
|
<icon-close />
|
||||||
@ -229,7 +154,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { TagData } from '@arco-design/web-vue';
|
import { TagData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
|
||||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
import MsTag, { Size } from '@/components/pure/ms-tag/ms-tag.vue';
|
import MsTag, { Size } from '@/components/pure/ms-tag/ms-tag.vue';
|
||||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||||
@ -237,13 +161,13 @@
|
|||||||
import type { MsFileItem, UploadType } from '@/components/pure/ms-upload/types';
|
import type { MsFileItem, UploadType } from '@/components/pure/ms-upload/types';
|
||||||
import LinkFileDrawer from '@/components/business/ms-link-file/associatedFileDrawer.vue';
|
import LinkFileDrawer from '@/components/business/ms-link-file/associatedFileDrawer.vue';
|
||||||
import dropdownMenu from './dropdownMenu.vue';
|
import dropdownMenu from './dropdownMenu.vue';
|
||||||
|
import filesPopover from './filesPopover.vue';
|
||||||
import saveAsFilePopover from './saveAsFilePopover.vue';
|
import saveAsFilePopover from './saveAsFilePopover.vue';
|
||||||
|
|
||||||
import { getAssociatedFileListUrl } from '@/api/modules/case-management/featureCase';
|
import { getAssociatedFileListUrl } from '@/api/modules/case-management/featureCase';
|
||||||
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
|
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import { hasAnyPermission } from '@/utils/permission';
|
|
||||||
|
|
||||||
import { AssociatedList } from '@/models/caseManagement/featureCase';
|
import { AssociatedList } from '@/models/caseManagement/featureCase';
|
||||||
import { TableQueryParams, TransferFileParams } from '@/models/common';
|
import { TableQueryParams, TransferFileParams } from '@/models/common';
|
||||||
@ -399,13 +323,6 @@
|
|||||||
const alreadyDeleteFiles = computed(() => {
|
const alreadyDeleteFiles = computed(() => {
|
||||||
return inputFiles.value.filter((item) => item.delete);
|
return inputFiles.value.filter((item) => item.delete);
|
||||||
});
|
});
|
||||||
const otherFiles = computed(() => {
|
|
||||||
return inputFiles.value.filter((item) => !item.delete);
|
|
||||||
});
|
|
||||||
|
|
||||||
function clearDeletedFiles() {
|
|
||||||
inputFiles.value = inputFiles.value.filter((item) => !item.delete);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleClose(data: TagData) {
|
function handleClose(data: TagData) {
|
||||||
inputFiles.value = inputFiles.value.filter((item) => item.value !== data.value);
|
inputFiles.value = inputFiles.value.filter((item) => item.value !== data.value);
|
||||||
@ -455,28 +372,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
|
||||||
.ms-add-attachment-files-popover {
|
|
||||||
padding: 16px;
|
|
||||||
.arco-popover-content {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.file-list {
|
|
||||||
@apply flex flex-col overflow-y-auto overflow-x-hidden;
|
|
||||||
.ms-scroll-bar();
|
|
||||||
|
|
||||||
gap: 8px;
|
|
||||||
max-height: 200px;
|
|
||||||
.file-list-item {
|
|
||||||
@apply flex items-center justify-between;
|
|
||||||
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.arco-input-tag-has-prefix) {
|
:deep(.arco-input-tag-has-prefix) {
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
}
|
}
|
||||||
|
@ -12,4 +12,5 @@ export default {
|
|||||||
'ms.add.attachment.saveAsNamePlaceholder': 'Please enter file name',
|
'ms.add.attachment.saveAsNamePlaceholder': 'Please enter file name',
|
||||||
'ms.add.attachment.saveAsModulePlaceholder': 'Please select the transfer directory',
|
'ms.add.attachment.saveAsModulePlaceholder': 'Please select the transfer directory',
|
||||||
'ms.add.attachment.saveAsSuccess': 'File transfer successful',
|
'ms.add.attachment.saveAsSuccess': 'File transfer successful',
|
||||||
|
'ms.add.attachment.fileDeletedTip': 'The file has been deleted, please replace it',
|
||||||
};
|
};
|
||||||
|
@ -12,4 +12,5 @@ export default {
|
|||||||
'ms.add.attachment.saveAsNamePlaceholder': '请输入文件名称',
|
'ms.add.attachment.saveAsNamePlaceholder': '请输入文件名称',
|
||||||
'ms.add.attachment.saveAsModulePlaceholder': '请选择转存目录',
|
'ms.add.attachment.saveAsModulePlaceholder': '请选择转存目录',
|
||||||
'ms.add.attachment.saveAsSuccess': '文件转存成功',
|
'ms.add.attachment.saveAsSuccess': '文件转存成功',
|
||||||
|
'ms.add.attachment.fileDeletedTip': '该文件已被删除,请替换',
|
||||||
};
|
};
|
||||||
|
@ -113,7 +113,7 @@ export function getFileEnum(fileType?: string): keyof typeof UploadAcceptEnum {
|
|||||||
* @param status 文件状态
|
* @param status 文件状态
|
||||||
*/
|
*/
|
||||||
export function getFileIcon(item: MsFileItem, status?: UploadStatus) {
|
export function getFileIcon(item: MsFileItem, status?: UploadStatus) {
|
||||||
const fileType = item.file?.name.split('.').pop(); // 通过文件后缀判断文件类型
|
const fileType = item.file?.name?.split('.').pop(); // 通过文件后缀判断文件类型
|
||||||
const _status = status || item.status;
|
const _status = status || item.status;
|
||||||
if (_status === UploadStatus.done) {
|
if (_status === UploadStatus.done) {
|
||||||
return FileIconMap[getFileEnum(fileType)]?.[_status] ?? FileIconMap.unknown[UploadStatus.done];
|
return FileIconMap[getFileEnum(fileType)]?.[_status] ?? FileIconMap.unknown[UploadStatus.done];
|
||||||
|
@ -11,5 +11,6 @@ export type MsFileItem = FileItem & {
|
|||||||
enable?: boolean; // jar类型文件是否可用
|
enable?: boolean; // jar类型文件是否可用
|
||||||
uploadedTime?: string | number; // 上传完成时间
|
uploadedTime?: string | number; // 上传完成时间
|
||||||
errMsg?: string; // 上传失败的错误信息
|
errMsg?: string; // 上传失败的错误信息
|
||||||
|
delete?: boolean; // 是否删除
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div> quote </div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
|
@ -11,31 +11,85 @@
|
|||||||
{{ `CSV ${props.step.csvIds?.length}` }}
|
{{ `CSV ${props.step.csvIds?.length}` }}
|
||||||
</div>
|
</div>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="mb-[4px] font-medium text-[var(--color-text-4)]">
|
<template v-if="alreadyDeleteFiles.length > 0">
|
||||||
{{ `${t('apiScenario.csvQuote')}(${props.step.csvIds?.length})` }}
|
<div class="flex items-center">
|
||||||
|
<div class="flex flex-1 items-center gap-[4px] leading-[18px]">
|
||||||
|
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="14" />
|
||||||
|
<div class="text-[var(--color-text-4)]">{{ t('ms.add.attachment.alreadyDelete') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="csv of csvList" :key="csv.id" class="flex items-center justify-between px-[8px] py-[4px]">
|
<MsButton
|
||||||
|
type="text"
|
||||||
|
:disabled="props.disabled"
|
||||||
|
size="mini"
|
||||||
|
@click="
|
||||||
|
emit(
|
||||||
|
'removeDeleted',
|
||||||
|
alreadyDeleteFiles.map((e) => e.id)
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ t('ms.add.attachment.quickClear') }}
|
||||||
|
</MsButton>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="csv of alreadyDeleteFiles"
|
||||||
|
:key="csv.id"
|
||||||
|
class="flex items-center justify-between py-[4px] leading-[18px]"
|
||||||
|
>
|
||||||
<a-tooltip :content="csv.name">
|
<a-tooltip :content="csv.name">
|
||||||
<div class="one-line-text w-[142px] text-[var(--color-text-1)]">
|
<div class="one-line-text w-[142px] text-[var(--color-text-1)]">
|
||||||
{{ csv.name }}
|
{{ csv.name }}
|
||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center gap-[8px]">
|
||||||
<MsButton type="text" size="mini" class="!mr-0" @click="() => emit('replace', csv.id)">
|
<MsIcon
|
||||||
{{ t('common.replace') }}
|
type="icon-icon_update_rotatiorn"
|
||||||
</MsButton>
|
class="cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
||||||
<a-divider direction="vertical" :margin="8"></a-divider>
|
:size="14"
|
||||||
<MsButton type="text" size="mini" class="!mr-0" @click="() => emit('remove', csv.id)">
|
@click="() => emit('replace', csv.id)"
|
||||||
{{ t('common.remove') }}
|
/>
|
||||||
</MsButton>
|
<MsIcon
|
||||||
|
type="icon-icon_delete-trash_outlined1"
|
||||||
|
class="cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
||||||
|
:size="14"
|
||||||
|
@click="() => emit('remove', csv.id)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="otherFiles.length > 0">
|
||||||
|
<div v-if="alreadyDeleteFiles.length > 0" class="mt-[4px] text-[var(--color-text-4)]">
|
||||||
|
{{ t('ms.add.attachment.other') }}
|
||||||
|
</div>
|
||||||
|
<div v-for="csv of otherFiles" :key="csv.id" class="flex items-center justify-between py-[4px] leading-[18px]">
|
||||||
|
<a-tooltip :content="csv.name">
|
||||||
|
<div class="one-line-text w-[142px] text-[var(--color-text-1)]">
|
||||||
|
{{ csv.name }}
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
<div class="flex items-center gap-[8px]">
|
||||||
|
<MsIcon
|
||||||
|
type="icon-icon_update_rotatiorn"
|
||||||
|
class="cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
||||||
|
:size="14"
|
||||||
|
@click="() => emit('replace', csv.id)"
|
||||||
|
/>
|
||||||
|
<MsIcon
|
||||||
|
type="icon-icon_delete-trash_outlined1"
|
||||||
|
class="cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
||||||
|
:size="14"
|
||||||
|
@click="() => emit('remove', csv.id)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
@ -45,10 +99,12 @@
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
step: ScenarioStepItem;
|
step: ScenarioStepItem;
|
||||||
csvVariables: CsvVariable[];
|
csvVariables: CsvVariable[];
|
||||||
|
disabled: boolean;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'replace', id?: string): void;
|
(e: 'replace', id?: string): void;
|
||||||
(e: 'remove', id?: string): void;
|
(e: 'remove', id?: string): void;
|
||||||
|
(e: 'removeDeleted', ids: string[]): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -63,11 +119,27 @@
|
|||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const alreadyDeleteFiles = computed(() => {
|
||||||
|
return csvList.value.filter((item) => item.file.delete);
|
||||||
|
});
|
||||||
|
const otherFiles = computed(() => {
|
||||||
|
return csvList.value.filter((item) => !item.file.delete);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.step.csvIds,
|
||||||
|
(arr) => {
|
||||||
|
if (!arr || arr.length === 0) {
|
||||||
|
popoverVisible.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.csv-popover {
|
.csv-popover {
|
||||||
padding: 6px;
|
padding: 6px 12px;
|
||||||
.arco-popover-content {
|
.arco-popover-content {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
@ -100,8 +100,10 @@
|
|||||||
<csvTag
|
<csvTag
|
||||||
:step="step"
|
:step="step"
|
||||||
:csv-variables="scenario.scenarioConfig.variable.csvVariables"
|
:csv-variables="scenario.scenarioConfig.variable.csvVariables"
|
||||||
|
:disabled="!!step.isQuoteScenarioStep"
|
||||||
@remove="(id) => removeCsv(step, id)"
|
@remove="(id) => removeCsv(step, id)"
|
||||||
@replace="(id) => replaceCsv(step, id)"
|
@replace="(id) => replaceCsv(step, id)"
|
||||||
|
@remove-deleted="(ids) => removeDeletedCsv(step, ids)"
|
||||||
/>
|
/>
|
||||||
<!-- 自定义请求、API、CASE、场景步骤名称 -->
|
<!-- 自定义请求、API、CASE、场景步骤名称 -->
|
||||||
<template v-if="checkStepIsApi(step)">
|
<template v-if="checkStepIsApi(step)">
|
||||||
@ -889,6 +891,14 @@
|
|||||||
replaceCsvId.value = id || '';
|
replaceCsvId.value = id || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeDeletedCsv(step: ScenarioStepItem, ids: string[]) {
|
||||||
|
const realStep = findNodeByKey<ScenarioStepItem>(steps.value, step.uniqueId, 'uniqueId');
|
||||||
|
if (realStep) {
|
||||||
|
realStep.csvIds = realStep.csvIds.filter((item: string) => !ids.includes(item));
|
||||||
|
scenario.value.unSaved = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleQuoteCsvConfirm(keys: string[]) {
|
function handleQuoteCsvConfirm(keys: string[]) {
|
||||||
if (activeStep.value) {
|
if (activeStep.value) {
|
||||||
const realStep = findNodeByKey<ScenarioStepItem>(steps.value, activeStep.value.uniqueId, 'uniqueId');
|
const realStep = findNodeByKey<ScenarioStepItem>(steps.value, activeStep.value.uniqueId, 'uniqueId');
|
||||||
|
Loading…
Reference in New Issue
Block a user