601 lines
15 KiB
Vue
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>
|