Files
SPDM/src/views/task/execution/components/taskDetailPage/components/experimentResult.vue
2026-01-29 18:58:07 +08:00

601 lines
15 KiB
Vue

<template>
<div class="result-page">
<BaseTable
ref="baseTableRef"
tableName="EXPERIMENT_RESULT_TABLE"
:showCheckbox="true"
:action-list="showLeftOptions ? actionList : []"
:api="listExperimentResultApi"
:show-overflow="false"
:params="tableParams"
>
<template v-if="showLeftOptions" #leftOptions>
<el-button type="primary" @click="uploadResultFun">上传结果</el-button>
<el-button type="danger" @click="batchDeleteFun">删除结果</el-button>
</template>
<template #imageId="{ row }">
<img
v-if="row.imageId"
:src="getImgPathFun(row.imageId)"
@click="previewFileFun({ id: row.imageId })"
width="150"
class="mr10"
alt=""
/>
</template>
<template #fileId="{ row }">
<el-icon class="icon-style" v-if="row.fileId" @click="showfileTableFun(row.fileId)"
><View
/></el-icon>
<span v-else>--</span>
</template>
</BaseTable>
<el-drawer
v-model="visible"
:title="`试验结果上传`"
:size="600"
:close-on-click-modal="false"
@close="closeFun"
>
<div class="content">
<TableForm ref="tableFormRef" tableName="EXPERIMENT_RESULT_TABLE" />
<el-form>
<el-form-item label="试验截图">
<div v-show="imageUrl" class="img-box">
<el-icon class="icon-style-delete" @click="removeFileFun"><Delete /></el-icon>
<img :src="imageUrl" class="avatar" />
</div>
<el-upload
v-show="!imageUrl"
class="upload-demo2"
ref="uploadImgRef"
v-model:file-list="imageFileList"
:auto-upload="false"
:on-change="handleChangeFun"
:accept="accept"
list-type="picture-card"
>
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
<el-form-item label="附件文件" v-if="resultInfo?.id && attachmentFileList?.length">
<div class="file-list">
<div class="file-content" v-for="item in attachmentFileList" :key="item.id">
<div class="file-name" :title="item.originalName">
<el-icon class="icon-style"><Document /></el-icon> {{ item.originalName }}
</div>
<div class="file-operate">
<el-icon @click="deleteAttachmentFileFun(item)"><Close /></el-icon>
</div>
</div>
</div>
</el-form-item>
<!-- 试验结果上传 -->
<el-form-item label="试验附件" v-if="!resultInfo?.id">
<el-upload
v-model:file-list="fileList"
class="upload-demo"
multiple
:auto-upload="false"
>
<el-button type="primary">上传附件</el-button>
</el-upload>
</el-form-item>
<!-- 试验结果编辑 -->
<el-form-item label="试验附件" v-else>
<el-upload
v-model:file-list="fileList"
class="upload-demo"
multiple
:auto-upload="false"
>
<el-button type="primary">上传附件</el-button>
</el-upload>
</el-form-item>
</el-form>
</div>
<template #footer>
<div>
<el-button @click="closeFun">关闭</el-button>
<el-button type="primary" @click="submitFun">确定</el-button>
</div>
</template>
</el-drawer>
<FilePreview v-model="previewVisible" :fileId="currentRow?.id" />
<Dialog
v-model="diaVisible"
diaTitle="试验附件"
top="5vh"
width="70%"
@close="diaVisible = false"
>
<BaseTable
ref="baseFileTableRef"
table-name="RUN_RESULT_FILE_TABLE"
:hide-pagination="true"
:full-height="true"
:action-list="fileActionList"
>
<template #fileSize="{ row }">
<span>{{ formatFileSize(row.fileSize) }}</span>
</template>
</BaseTable>
</Dialog>
</div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref, watch } from 'vue';
import BaseTable from '@/components/common/table/baseTable.vue';
import TableForm from '@/components/common/table/tableForm.vue';
import { cloneDeep } from 'lodash-es';
import {
batchAddExperimentResultApi,
deleteExperimentResultApi,
editExperimentResultApi,
listExperimentResultApi,
} from '@/api/project/run';
import emitter from '@/utils/eventBus';
import { ElMessage, ElMessageBox } from 'element-plus';
import FilePreview from '@/components/common/filePreview/index.vue';
import { getFileBaseInfoApi } from '@/api/data/data';
import Dialog from '@/components/common/dialog/index.vue';
import { downloadFileById, fileUploadAllocationTypeFun, formatFileSize } from '@/utils/file';
import { useI18n } from 'vue-i18n';
import { updateTaskStatusApi } from '@/api/project/task';
const env = import.meta.env;
const props = defineProps({
taskInfo: {
type: Object,
default: () => {},
},
showLeftOptions: {
type: Boolean,
default: true,
},
});
const baseTableRef = ref();
const tableFormRef = ref();
const visible = ref(false);
const imageUrl = ref<any>('');
const fileList = ref<any>([]);
const imageFileList = ref<any>([]);
const diaVisible = ref(false);
const baseFileTableRef = ref();
const tableParams = ref({
taskId: props.taskInfo.uuid,
});
const uploadImgRef = ref();
const { t } = useI18n();
const accept = ref('.jpg,.jpeg,.png,.gif');
watch(
() => props.taskInfo,
(val: any) => {
tableParams.value.taskId = val.uuid;
},
{
deep: true,
}
);
const uploadResultFun = () => {
resultInfo.value = {};
visible.value = true;
imageFileList.value = [];
fileList.value = [];
imageUrl.value = '';
deleteFileIds.value = [];
deleteImageId.value = '';
nextTick(() => {
tableFormRef.value.resetFun();
});
};
const closeFun = () => {
visible.value = false;
};
const tableData = ref<any>([]);
const fileIds = ref<any>([]);
const showfileTableFun = async (ids: any) => {
fileIds.value = ids.split(',');
tableData.value = [];
for (let i = 0; i < fileIds.value.length; i++) {
const res: any = await getFileBaseInfoApi({ fileId: fileIds.value[i] });
if (res && res.code === 200) {
if (res.data.dataType === 2) {
tableData.value.push(res.data);
}
}
}
diaVisible.value = true;
nextTick(() => {
baseFileTableRef.value.setDataFun(tableData.value);
});
};
const resultInfo = ref<any>({});
const attachmentFileList = ref<any>([]);
const actionList = ref([
{
title: '编辑',
type: 'primary',
click: async (row: any) => {
visible.value = true;
resultInfo.value = cloneDeep(row);
const ids = resultInfo.value?.fileId ? resultInfo.value?.fileId?.split(',') || [] : '';
attachmentFileList.value = [];
deleteFileIds.value = [];
deleteImageId.value = '';
fileList.value = [];
if (resultInfo.value.imageId) {
imageUrl.value = getImgPathFun(resultInfo.value.imageId);
}
for (let i = 0; i < ids.length; i++) {
const res: any = await getFileBaseInfoApi({ fileId: ids[i] });
if (res && res.code === 200) {
if (res.data.dataType === 2) {
attachmentFileList.value.push(res.data);
}
}
}
nextTick(() => {
tableFormRef.value.setFormDataFun(resultInfo.value);
});
},
},
{
title: '删除',
type: 'danger',
needConfirm: true,
confirmTip: '确认删除吗?',
click: (row: any) => {
deleteFun(row.id);
},
},
]);
const currentRow = ref();
const previewVisible = ref(false);
const previewFileFun = (row: any) => {
currentRow.value = row;
previewVisible.value = true;
};
const handleChangeFun = (uploadFile: any) => {
imageUrl.value = URL.createObjectURL(uploadFile.raw);
};
const fileActionList = ref([
{
title: t('通用.预览'),
type: 'primary',
click: (row: any) => {
previewFileFun(row);
},
hide: (row: any) => {
return row.dataType !== 2;
},
},
{
title: t('通用.下载'),
type: 'primary',
click: (row: any) => {
downloadFileById(row.id);
},
hide: (row: any) => {
return row.dataType !== 2;
},
},
]);
const deleteFun = async (id: any) => {
const res: any = await deleteExperimentResultApi({ id });
if (res && res.code === 200) {
ElMessage.success('删除成功!');
}
baseTableRef.value.resetFun();
};
const deleteFileIds = ref<any>([]);
const deleteAttachmentFileFun = (file: any) => {
deleteFileIds.value.push(file.id);
attachmentFileList.value = attachmentFileList.value.filter((item: any) => {
return item.id != file.id;
});
};
const apiParams = ref([
'fileInfoList',
'imageFileInfo',
'expName',
'expData',
'expDesc',
'uploadTaskId',
'taskId',
'id',
'addFileInfoList',
'addImageInfo',
'deleteFileIds',
'deleteImageId',
]);
const submitFun = async () => {
const valid = await tableFormRef.value.validateFun();
if (valid) {
const fromData = tableFormRef.value.getFormDataFun();
const files = fileList.value.concat(imageFileList.value);
const obj: any = cloneDeep(fromData);
if (fileList.value.length) {
if (obj?.id) {
obj.addFileInfoList = fileList.value.map((item: any) => {
return {
fileName: item.name,
fileSize: item.size,
fileType: fileUploadAllocationTypeFun(item.name),
};
});
} else {
obj.fileInfoList = fileList.value.map((item: any) => {
return {
fileName: item.name,
fileSize: item.size,
fileType: fileUploadAllocationTypeFun(item.name),
};
});
}
}
if (imageFileList.value.length) {
if (obj?.id) {
obj.addImageInfo = {
fileName: imageFileList.value[0].name,
fileSize: imageFileList.value[0].size,
fileType: fileUploadAllocationTypeFun(imageFileList.value[0].name),
};
} else {
obj.imageFileInfo = {
fileName: imageFileList.value[0].name,
fileSize: imageFileList.value[0].size,
fileType: fileUploadAllocationTypeFun(imageFileList.value[0].name),
};
}
}
if (deleteFileIds.value.length) {
obj.deleteFileIds = deleteFileIds.value;
}
if (deleteImageId.value) {
obj.deleteImageId = Number(deleteImageId.value);
}
obj.uploadTaskId = new Date().getTime();
obj.taskId = props.taskInfo.uuid;
for (const key in obj) {
if (!apiParams.value.includes(key)) {
delete obj[key];
}
}
const res: any = obj?.id
? await editExperimentResultApi(obj)
: await batchAddExperimentResultApi(obj);
if (res && res.code === 200) {
if (res.data instanceof Array) {
res?.data?.forEach((item: any, index: any) => {
emitter.emit('ADD_UPLOAD_FILE', {
file: files[index].raw,
data: {
// 接口返回的文件目录信息,包括配置信息
...item,
isApprove: 0, // 0否 1是
taskType: 4, // 5实验数据
},
});
});
}
if (props.taskInfo.exeStatus != 8) {
await updateTaskExeStatusFun();
}
closeFun();
}
}
};
const updateTaskExeStatusFun = async () => {
const task = cloneDeep(props.taskInfo);
delete task.children;
const param = {
taskIds: [props.taskInfo.uuid],
req: {
// ...task,
exeStatus: '8',
},
};
try {
const res: any = await updateTaskStatusApi(param);
if (res && res.code === 200) {
}
} catch {}
};
const getImgPathFun = (fileId: any) => {
const url = `${env.VITE_API_IMAGE_PREVIEW_URL}/data/previewImage?fileId=${fileId}`;
return url;
};
const deleteImageId = ref<any>('');
const removeFileFun = () => {
imageFileList.value = [];
if (imageUrl.value.includes('data/previewImage')) {
const id = imageUrl.value.split('=').at(-1);
deleteImageId.value = id;
}
imageUrl.value = '';
};
const batchDeleteFun = async () => {
const files = baseTableRef.value.tableRef.getCheckboxRecords();
if (files.length) {
ElMessageBox.confirm('确认要删除选中的试验结果?', '警告', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
for (let i = 0; i < files.length; i++) {
await deleteFun(files[i].id);
}
baseTableRef.value.resetFun();
})
.catch(() => {
baseTableRef.value.resetFun();
});
} else {
ElMessage.warning('请勾选后再删除');
}
};
onMounted(() => {});
</script>
<style lang="scss" scoped>
.result-page {
width: 100%;
height: 100%;
.upload-demo {
width: 100%;
}
.upload-demo2 {
width: 148px;
height: 148px;
display: flex;
justify-content: center !important;
align-items: center !important;
cursor: pointer;
border-radius: 3px;
border: 1px dashed var(--el-color-primary);
position: relative;
:deep(.el-upload) {
width: 148px;
height: 148px;
display: flex;
justify-content: center !important;
align-items: center !important;
}
:deep(.el-upload-list__item-preview) {
display: none;
}
}
.mr10 {
cursor: pointer;
}
.icon-style {
color: var(--el-color-primary);
font-size: 16px;
cursor: pointer;
}
.file-list {
width: 100%;
.file-content {
width: 100%;
height: 32px;
font-size: 14px;
display: flex;
align-items: center;
justify-content: space-between;
.file-name {
width: 80%;
display: flex;
align-items: center;
text-overflow: ellipsis;
/* 当内容溢出容器时显示省略号 */
overflow: hidden;
/* 隐藏溢出容器的内容 */
white-space: nowrap;
color: #606266;
.icon-style {
margin-right: 5px;
color: #606266;
}
}
.file-operate {
display: none;
cursor: pointer;
padding-right: 10px;
}
}
.file-content:hover {
background-color: #f5f7fa;
.file-operate {
display: block;
}
}
}
.img-box {
width: 148px;
height: 148px;
display: flex;
align-items: center;
justify-content: center;
border: 1px dashed var(--el-color-primary);
position: relative;
.icon-style-delete {
display: none;
position: absolute;
top: 5px;
right: 5px;
font-size: 24px;
color: var(--el-color-danger);
cursor: pointer;
}
.avatar {
width: 146px;
}
}
.img-box:hover {
.icon-style-delete {
display: block;
}
}
}
</style>