fix(测试跟踪): 修复测试计划及用例评审添加缺陷关联时附件上传的问题

--bug=1015225 --user=宋昌昌 【测试跟踪】测试计划/用例评审-功能用例-添加缺陷-上传附件,报500 https://www.tapd.cn/55049933/s/1212386
This commit is contained in:
song-cc-rock 2022-07-26 17:22:28 +08:00 committed by jianxing
parent 008c213346
commit 47dab7999c
8 changed files with 82 additions and 30 deletions

View File

@ -28,6 +28,7 @@ import io.metersphere.track.request.testcase.IssuesUpdateRequest;
import io.metersphere.track.service.IssuesService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
@ -62,13 +63,13 @@ public class IssuesController {
return PageUtils.setPageInfo(page, issuesService.relateList(request));
}
@PostMapping(value = "/add")
@PostMapping(value = "/add", consumes = {"multipart/form-data"})
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_ISSUE_READ_CREATE)
@MsAuditLog(module = OperLogModule.TRACK_BUG, type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#issuesRequest)", msClass = IssuesService.class)
@SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#issuesRequest",
event = NoticeConstants.Event.CREATE, subject = "缺陷通知")
public IssuesWithBLOBs addIssues(@RequestPart(value = "request") IssuesUpdateRequest issuesRequest) {
return issuesService.addIssues(issuesRequest);
public IssuesWithBLOBs addIssues(@RequestPart(value = "request") IssuesUpdateRequest issuesRequest, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
return issuesService.addIssues(issuesRequest, files);
}
@PostMapping(value = "/update")

View File

@ -210,14 +210,14 @@ public class TestCaseController {
@MsAuditLog(module = OperLogModule.TRACK_TEST_CASE, type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = TestCaseService.class)
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, targetClass = TestCaseMapper.class,
event = NoticeConstants.Event.CREATE, subject = "测试用例通知")
public TestCase addTestCase(@RequestPart("request") EditTestCaseRequest request) {
public TestCase addTestCase(@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
if (StringUtils.isBlank(request.getId())) {
//新增 后端生成 id
request.setId(UUID.randomUUID().toString());
} else {
//复制前端生成 id
}
return testCaseService.add(request);
return testCaseService.add(request, files);
}
@PostMapping("/edit/order")

View File

@ -41,6 +41,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.*;
@ -104,7 +105,7 @@ public class IssuesService {
}
public IssuesWithBLOBs addIssues(IssuesUpdateRequest issuesRequest) {
public IssuesWithBLOBs addIssues(IssuesUpdateRequest issuesRequest, List<MultipartFile> files) {
List<AbstractIssuePlatform> platformList = getAddPlatforms(issuesRequest);
IssuesWithBLOBs issues = null;
for (AbstractIssuePlatform platform : platformList) {
@ -118,13 +119,22 @@ public class IssuesService {
saveFollows(issuesRequest.getId(), issuesRequest.getFollows());
customFieldIssuesService.addFields(issuesRequest.getId(), issuesRequest.getAddFields());
customFieldIssuesService.editFields(issuesRequest.getId(), issuesRequest.getEditFields());
// 复制新增, 同步缺陷的MS附件
if (StringUtils.isNotEmpty(issuesRequest.getCopyIssueId())) {
// 复制新增, 同步缺陷的MS附件
AttachmentRequest attachmentRequest = new AttachmentRequest();
attachmentRequest.setCopyBelongId(issuesRequest.getCopyIssueId());
attachmentRequest.setBelongId(issues.getId());
attachmentRequest.setBelongType(AttachmentType.ISSUE.type());
attachmentService.copyAttachment(attachmentRequest);
} else {
// 新增, 需保存并同步所有待上传的附件
final String issueId = issues.getId();
files.forEach(file -> {
AttachmentRequest attachmentRequest = new AttachmentRequest();
attachmentRequest.setBelongId(issueId);
attachmentRequest.setBelongType(AttachmentType.ISSUE.type());
attachmentService.uploadAttachment(attachmentRequest, file);
});
}
return issues;
}

View File

@ -1957,15 +1957,23 @@ public class TestCaseService {
return false;
}
public TestCase add(EditTestCaseRequest request) {
public TestCase add(EditTestCaseRequest request, List<MultipartFile> files) {
final TestCaseWithBLOBs testCaseWithBLOBs = addTestCase(request);
// 复制用例时复制对应附件数据
if (StringUtils.isNotEmpty(request.getCopyCaseId())) {
// 复制用例时复制对应附件数据
AttachmentRequest attachmentRequest = new AttachmentRequest();
attachmentRequest.setCopyBelongId(request.getCopyCaseId());
attachmentRequest.setBelongId(testCaseWithBLOBs.getId());
attachmentRequest.setBelongType(AttachmentType.TEST_CASE.type());
attachmentService.copyAttachment(attachmentRequest);
} else {
// 新增需上传用例所有待上传的附件
files.forEach(file -> {
AttachmentRequest attachmentRequest = new AttachmentRequest();
attachmentRequest.setBelongId(testCaseWithBLOBs.getId());
attachmentRequest.setBelongType(AttachmentType.TEST_CASE.type());
attachmentService.uploadAttachment(attachmentRequest, file);
});
}
return testCaseWithBLOBs;
}

View File

@ -37,7 +37,7 @@
:width="70"
:label="$t('commons.status')">
<template v-slot:default="scope">
<span :class="scope.row.status === 'success' ? 'green' : scope.row.status === 'error' ? 'red' : ''">{{ scope.row.status | formatStatus}}</span>
<span :class="scope.row.status === 'success' ? 'green' : scope.row.status === 'error' ? 'red' : scope.row.status === 'toUpload' ? 'yellow' : ''">{{ scope.row.status | formatStatus}}</span>
</template>
</el-table-column>
<el-table-column
@ -55,7 +55,7 @@
<el-button @click="handleDownload(scope.row)" type="primary" :disabled="!scope.row.id"
v-if="scope.row.progress === 100"
icon="el-icon-download" size="mini" circle/>
<el-button :disabled="readOnly || !isDelete || isCopy || !scope.row.id"
<el-button :disabled="readOnly || !isDelete || isCopy || (!scope.row.id && scope.row.status !== 'toUpload')"
@click="handleDelete(scope.row, scope.$index)" type="danger"
v-if="scope.row.progress === 100"
icon="el-icon-delete" size="mini"
@ -132,7 +132,7 @@ export default {
filters: {
formatStatus(status) {
if (isNaN(status)) {
return status === 'success' ? '完成' : '失败'
return status === 'success' ? '完成' : status === 'toUpload' ? '待上传' : '失败'
}
return Math.floor(status * 100 / 100) + "%";
}
@ -165,4 +165,8 @@ export default {
.red {
color: red;
}
.yellow {
color: #E6A23C;
}
</style>

View File

@ -832,6 +832,11 @@ export default {
return key === "file" ? undefined : value
});
if (this.$refs.otherInfo.uploadFiles.length > 0) {
this.$refs.otherInfo.uploadFiles.forEach(f => {
formData.append("file", f);
});
}
formData.append('request', new Blob([requestJson], {
type: "application/json"
}));

View File

@ -73,8 +73,8 @@
:on-exceed="handleExceed"
:on-success="handleSuccess"
:on-error="handleError"
:disabled="(readOnly && isTestPlanEdit) || type === 'add' || isCopy">
<el-button :disabled="(readOnly && isTestPlanEdit) || type === 'add' || isCopy" type="primary" size="mini">{{$t('test_track.case.add_attachment')}}</el-button>
:disabled="(readOnly && isTestPlanEdit) || isCopy">
<el-button :disabled="(readOnly && isTestPlanEdit) || isCopy" type="primary" size="mini">{{$t('test_track.case.add_attachment')}}</el-button>
<span slot="tip" class="el-upload__tip"> {{ $t('test_track.case.upload_tip') }} </span>
</el-upload>
</el-col>
@ -174,6 +174,7 @@ export default {
},
intervalMap: new Map(),
cancelFileToken: [],
uploadFiles: []
};
},
computed: {
@ -258,12 +259,17 @@ export default {
name: file.name,
size: byteToSize(file.size),
updateTime: new Date().getTime(),
progress: 0,
status: 0,
progress: this.type === 'add' ? 100 : 0,
status: this.type === 'add' ? 'toUpload' : 0,
creator: user.name,
type: getTypeByFileName(file.name)
});
if (this.type === 'add') {
//
this.uploadFiles.push(file);
return false;
}
//
this.uploadFile(e, (param) => {
this.showProgress(e.file, param)
@ -358,10 +364,14 @@ export default {
}
this.fileList.splice(index, 1);
this.tableData.splice(index, 1);
this.$get('/attachment/delete/testcase/' + file.id , response => {
this.$success(this.$t('commons.delete_success'));
this.getFileMetaData();
});
if (this.type === 'add') {
this.uploadFiles.splice(index, 1);
} else {
this.$get('/attachment/delete/testcase/' + file.id , response => {
this.$success(this.$t('commons.delete_success'));
this.getFileMetaData();
});
}
},
handleCancel(file, index) {
this.fileList.splice(index, 1);

View File

@ -115,8 +115,8 @@
:on-exceed="handleExceed"
:on-success="handleSuccess"
:on-error="handleError"
:disabled="type === 'add' || type === 'copy' || isCaseEdit">
<el-button type="primary" :disabled="type === 'add' || type === 'copy' || isCaseEdit" size="mini">{{$t('test_track.case.add_attachment')}}</el-button>
:disabled="type === 'copy'">
<el-button type="primary" :disabled="type === 'copy'" size="mini">{{$t('test_track.case.add_attachment')}}</el-button>
<span slot="tip" class="el-upload__tip"> {{ $t('test_track.case.upload_tip') }} </span>
</el-upload>
</el-col>
@ -308,6 +308,7 @@ export default {
readOnly: false,
isDelete: true,
cancelFileToken: [],
uploadFiles: []
};
},
props: {
@ -574,9 +575,15 @@ export default {
return key === "file" ? undefined : value
});
if (this.uploadFiles.length > 0) {
this.uploadFiles.forEach(f => {
formData.append("file", f);
});
}
formData.append('request', new Blob([requestJson], {
type: "application/json"
}));
return {
method: 'POST',
url: this.url,
@ -639,13 +646,17 @@ export default {
name: file.name,
size: byteToSize(file.size),
updateTime: new Date().getTime(),
progress: 0,
status: 0,
progress: this.type === 'add' || this.isCaseEdit? 100 : 0,
status: this.type === 'add' || this.isCaseEdit? 'toUpload' : 0,
creator: user.name,
type: getTypeByFileName(file.name)
});
//
if (this.type === 'add' || this.isCaseEdit) {
//
this.uploadFiles.push(file);
return false;
}
this.uploadFile(e, (param) => {
this.showProgress(e.file, param)
})
@ -739,11 +750,14 @@ export default {
}
this.fileList.splice(index, 1);
this.tableData.splice(index, 1);
let data = {"belongId": this.issueId, "belongType": "issue"}
this.$get('/attachment/delete/issue/' + file.id , response => {
this.$success(this.$t('commons.delete_success'));
this.getFileMetaData(this.issueId);
});
if (this.type === 'add' || this.isCaseEdit) {
this.uploadFiles.splice(index, 1);
} else {
this.$get('/attachment/delete/issue/' + file.id , response => {
this.$success(this.$t('commons.delete_success'));
this.getFileMetaData(this.issueId);
});
}
},
handleCancel(file, index) {
this.fileList.splice(index, 1);