fix(测试跟踪): 修复测试计划及用例评审添加缺陷关联时附件上传的问题
--bug=1015225 --user=宋昌昌 【测试跟踪】测试计划/用例评审-功能用例-添加缺陷-上传附件,报500 https://www.tapd.cn/55049933/s/1212386
This commit is contained in:
parent
008c213346
commit
47dab7999c
|
@ -28,6 +28,7 @@ import io.metersphere.track.request.testcase.IssuesUpdateRequest;
|
||||||
import io.metersphere.track.service.IssuesService;
|
import io.metersphere.track.service.IssuesService;
|
||||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -62,13 +63,13 @@ public class IssuesController {
|
||||||
return PageUtils.setPageInfo(page, issuesService.relateList(request));
|
return PageUtils.setPageInfo(page, issuesService.relateList(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/add")
|
@PostMapping(value = "/add", consumes = {"multipart/form-data"})
|
||||||
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_ISSUE_READ_CREATE)
|
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_ISSUE_READ_CREATE)
|
||||||
@MsAuditLog(module = OperLogModule.TRACK_BUG, type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#issuesRequest)", msClass = IssuesService.class)
|
@MsAuditLog(module = OperLogModule.TRACK_BUG, type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#issuesRequest)", msClass = IssuesService.class)
|
||||||
@SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#issuesRequest",
|
@SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#issuesRequest",
|
||||||
event = NoticeConstants.Event.CREATE, subject = "缺陷通知")
|
event = NoticeConstants.Event.CREATE, subject = "缺陷通知")
|
||||||
public IssuesWithBLOBs addIssues(@RequestPart(value = "request") IssuesUpdateRequest issuesRequest) {
|
public IssuesWithBLOBs addIssues(@RequestPart(value = "request") IssuesUpdateRequest issuesRequest, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
|
||||||
return issuesService.addIssues(issuesRequest);
|
return issuesService.addIssues(issuesRequest, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/update")
|
@PostMapping(value = "/update")
|
||||||
|
|
|
@ -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)
|
@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,
|
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, targetClass = TestCaseMapper.class,
|
||||||
event = NoticeConstants.Event.CREATE, subject = "测试用例通知")
|
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())) {
|
if (StringUtils.isBlank(request.getId())) {
|
||||||
//新增 后端生成 id
|
//新增 后端生成 id
|
||||||
request.setId(UUID.randomUUID().toString());
|
request.setId(UUID.randomUUID().toString());
|
||||||
} else {
|
} else {
|
||||||
//复制,前端生成 id
|
//复制,前端生成 id
|
||||||
}
|
}
|
||||||
return testCaseService.add(request);
|
return testCaseService.add(request, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/edit/order")
|
@PostMapping("/edit/order")
|
||||||
|
|
|
@ -41,6 +41,7 @@ import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.*;
|
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);
|
List<AbstractIssuePlatform> platformList = getAddPlatforms(issuesRequest);
|
||||||
IssuesWithBLOBs issues = null;
|
IssuesWithBLOBs issues = null;
|
||||||
for (AbstractIssuePlatform platform : platformList) {
|
for (AbstractIssuePlatform platform : platformList) {
|
||||||
|
@ -118,13 +119,22 @@ public class IssuesService {
|
||||||
saveFollows(issuesRequest.getId(), issuesRequest.getFollows());
|
saveFollows(issuesRequest.getId(), issuesRequest.getFollows());
|
||||||
customFieldIssuesService.addFields(issuesRequest.getId(), issuesRequest.getAddFields());
|
customFieldIssuesService.addFields(issuesRequest.getId(), issuesRequest.getAddFields());
|
||||||
customFieldIssuesService.editFields(issuesRequest.getId(), issuesRequest.getEditFields());
|
customFieldIssuesService.editFields(issuesRequest.getId(), issuesRequest.getEditFields());
|
||||||
// 复制新增, 同步缺陷的MS附件
|
|
||||||
if (StringUtils.isNotEmpty(issuesRequest.getCopyIssueId())) {
|
if (StringUtils.isNotEmpty(issuesRequest.getCopyIssueId())) {
|
||||||
|
// 复制新增, 同步缺陷的MS附件
|
||||||
AttachmentRequest attachmentRequest = new AttachmentRequest();
|
AttachmentRequest attachmentRequest = new AttachmentRequest();
|
||||||
attachmentRequest.setCopyBelongId(issuesRequest.getCopyIssueId());
|
attachmentRequest.setCopyBelongId(issuesRequest.getCopyIssueId());
|
||||||
attachmentRequest.setBelongId(issues.getId());
|
attachmentRequest.setBelongId(issues.getId());
|
||||||
attachmentRequest.setBelongType(AttachmentType.ISSUE.type());
|
attachmentRequest.setBelongType(AttachmentType.ISSUE.type());
|
||||||
attachmentService.copyAttachment(attachmentRequest);
|
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;
|
return issues;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1957,15 +1957,23 @@ public class TestCaseService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestCase add(EditTestCaseRequest request) {
|
public TestCase add(EditTestCaseRequest request, List<MultipartFile> files) {
|
||||||
final TestCaseWithBLOBs testCaseWithBLOBs = addTestCase(request);
|
final TestCaseWithBLOBs testCaseWithBLOBs = addTestCase(request);
|
||||||
// 复制用例时复制对应附件数据
|
|
||||||
if (StringUtils.isNotEmpty(request.getCopyCaseId())) {
|
if (StringUtils.isNotEmpty(request.getCopyCaseId())) {
|
||||||
|
// 复制用例时复制对应附件数据
|
||||||
AttachmentRequest attachmentRequest = new AttachmentRequest();
|
AttachmentRequest attachmentRequest = new AttachmentRequest();
|
||||||
attachmentRequest.setCopyBelongId(request.getCopyCaseId());
|
attachmentRequest.setCopyBelongId(request.getCopyCaseId());
|
||||||
attachmentRequest.setBelongId(testCaseWithBLOBs.getId());
|
attachmentRequest.setBelongId(testCaseWithBLOBs.getId());
|
||||||
attachmentRequest.setBelongType(AttachmentType.TEST_CASE.type());
|
attachmentRequest.setBelongType(AttachmentType.TEST_CASE.type());
|
||||||
attachmentService.copyAttachment(attachmentRequest);
|
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;
|
return testCaseWithBLOBs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
:width="70"
|
:width="70"
|
||||||
:label="$t('commons.status')">
|
:label="$t('commons.status')">
|
||||||
<template v-slot:default="scope">
|
<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>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
<el-button @click="handleDownload(scope.row)" type="primary" :disabled="!scope.row.id"
|
<el-button @click="handleDownload(scope.row)" type="primary" :disabled="!scope.row.id"
|
||||||
v-if="scope.row.progress === 100"
|
v-if="scope.row.progress === 100"
|
||||||
icon="el-icon-download" size="mini" circle/>
|
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"
|
@click="handleDelete(scope.row, scope.$index)" type="danger"
|
||||||
v-if="scope.row.progress === 100"
|
v-if="scope.row.progress === 100"
|
||||||
icon="el-icon-delete" size="mini"
|
icon="el-icon-delete" size="mini"
|
||||||
|
@ -132,7 +132,7 @@ export default {
|
||||||
filters: {
|
filters: {
|
||||||
formatStatus(status) {
|
formatStatus(status) {
|
||||||
if (isNaN(status)) {
|
if (isNaN(status)) {
|
||||||
return status === 'success' ? '完成' : '失败'
|
return status === 'success' ? '完成' : status === 'toUpload' ? '待上传' : '失败'
|
||||||
}
|
}
|
||||||
return Math.floor(status * 100 / 100) + "%";
|
return Math.floor(status * 100 / 100) + "%";
|
||||||
}
|
}
|
||||||
|
@ -165,4 +165,8 @@ export default {
|
||||||
.red {
|
.red {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.yellow {
|
||||||
|
color: #E6A23C;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -832,6 +832,11 @@ export default {
|
||||||
return key === "file" ? undefined : value
|
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], {
|
formData.append('request', new Blob([requestJson], {
|
||||||
type: "application/json"
|
type: "application/json"
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -73,8 +73,8 @@
|
||||||
:on-exceed="handleExceed"
|
:on-exceed="handleExceed"
|
||||||
:on-success="handleSuccess"
|
:on-success="handleSuccess"
|
||||||
:on-error="handleError"
|
:on-error="handleError"
|
||||||
:disabled="(readOnly && isTestPlanEdit) || type === 'add' || isCopy">
|
:disabled="(readOnly && isTestPlanEdit) || isCopy">
|
||||||
<el-button :disabled="(readOnly && isTestPlanEdit) || type === 'add' || isCopy" type="primary" size="mini">{{$t('test_track.case.add_attachment')}}</el-button>
|
<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>
|
<span slot="tip" class="el-upload__tip"> {{ $t('test_track.case.upload_tip') }} </span>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -174,6 +174,7 @@ export default {
|
||||||
},
|
},
|
||||||
intervalMap: new Map(),
|
intervalMap: new Map(),
|
||||||
cancelFileToken: [],
|
cancelFileToken: [],
|
||||||
|
uploadFiles: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -258,12 +259,17 @@ export default {
|
||||||
name: file.name,
|
name: file.name,
|
||||||
size: byteToSize(file.size),
|
size: byteToSize(file.size),
|
||||||
updateTime: new Date().getTime(),
|
updateTime: new Date().getTime(),
|
||||||
progress: 0,
|
progress: this.type === 'add' ? 100 : 0,
|
||||||
status: 0,
|
status: this.type === 'add' ? 'toUpload' : 0,
|
||||||
creator: user.name,
|
creator: user.name,
|
||||||
type: getTypeByFileName(file.name)
|
type: getTypeByFileName(file.name)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.type === 'add') {
|
||||||
|
// 新增上传
|
||||||
|
this.uploadFiles.push(file);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// 上传文件
|
// 上传文件
|
||||||
this.uploadFile(e, (param) => {
|
this.uploadFile(e, (param) => {
|
||||||
this.showProgress(e.file, param)
|
this.showProgress(e.file, param)
|
||||||
|
@ -358,10 +364,14 @@ export default {
|
||||||
}
|
}
|
||||||
this.fileList.splice(index, 1);
|
this.fileList.splice(index, 1);
|
||||||
this.tableData.splice(index, 1);
|
this.tableData.splice(index, 1);
|
||||||
this.$get('/attachment/delete/testcase/' + file.id , response => {
|
if (this.type === 'add') {
|
||||||
this.$success(this.$t('commons.delete_success'));
|
this.uploadFiles.splice(index, 1);
|
||||||
this.getFileMetaData();
|
} else {
|
||||||
});
|
this.$get('/attachment/delete/testcase/' + file.id , response => {
|
||||||
|
this.$success(this.$t('commons.delete_success'));
|
||||||
|
this.getFileMetaData();
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleCancel(file, index) {
|
handleCancel(file, index) {
|
||||||
this.fileList.splice(index, 1);
|
this.fileList.splice(index, 1);
|
||||||
|
|
|
@ -115,8 +115,8 @@
|
||||||
:on-exceed="handleExceed"
|
:on-exceed="handleExceed"
|
||||||
:on-success="handleSuccess"
|
:on-success="handleSuccess"
|
||||||
:on-error="handleError"
|
:on-error="handleError"
|
||||||
:disabled="type === 'add' || type === 'copy' || isCaseEdit">
|
:disabled="type === 'copy'">
|
||||||
<el-button type="primary" :disabled="type === 'add' || type === 'copy' || isCaseEdit" size="mini">{{$t('test_track.case.add_attachment')}}</el-button>
|
<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>
|
<span slot="tip" class="el-upload__tip"> {{ $t('test_track.case.upload_tip') }} </span>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -308,6 +308,7 @@ export default {
|
||||||
readOnly: false,
|
readOnly: false,
|
||||||
isDelete: true,
|
isDelete: true,
|
||||||
cancelFileToken: [],
|
cancelFileToken: [],
|
||||||
|
uploadFiles: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
@ -574,9 +575,15 @@ export default {
|
||||||
return key === "file" ? undefined : value
|
return key === "file" ? undefined : value
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.uploadFiles.length > 0) {
|
||||||
|
this.uploadFiles.forEach(f => {
|
||||||
|
formData.append("file", f);
|
||||||
|
});
|
||||||
|
}
|
||||||
formData.append('request', new Blob([requestJson], {
|
formData.append('request', new Blob([requestJson], {
|
||||||
type: "application/json"
|
type: "application/json"
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: this.url,
|
url: this.url,
|
||||||
|
@ -639,13 +646,17 @@ export default {
|
||||||
name: file.name,
|
name: file.name,
|
||||||
size: byteToSize(file.size),
|
size: byteToSize(file.size),
|
||||||
updateTime: new Date().getTime(),
|
updateTime: new Date().getTime(),
|
||||||
progress: 0,
|
progress: this.type === 'add' || this.isCaseEdit? 100 : 0,
|
||||||
status: 0,
|
status: this.type === 'add' || this.isCaseEdit? 'toUpload' : 0,
|
||||||
creator: user.name,
|
creator: user.name,
|
||||||
type: getTypeByFileName(file.name)
|
type: getTypeByFileName(file.name)
|
||||||
});
|
});
|
||||||
|
|
||||||
// 上传文件
|
if (this.type === 'add' || this.isCaseEdit) {
|
||||||
|
// 新增上传
|
||||||
|
this.uploadFiles.push(file);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
this.uploadFile(e, (param) => {
|
this.uploadFile(e, (param) => {
|
||||||
this.showProgress(e.file, param)
|
this.showProgress(e.file, param)
|
||||||
})
|
})
|
||||||
|
@ -739,11 +750,14 @@ export default {
|
||||||
}
|
}
|
||||||
this.fileList.splice(index, 1);
|
this.fileList.splice(index, 1);
|
||||||
this.tableData.splice(index, 1);
|
this.tableData.splice(index, 1);
|
||||||
let data = {"belongId": this.issueId, "belongType": "issue"}
|
if (this.type === 'add' || this.isCaseEdit) {
|
||||||
this.$get('/attachment/delete/issue/' + file.id , response => {
|
this.uploadFiles.splice(index, 1);
|
||||||
this.$success(this.$t('commons.delete_success'));
|
} else {
|
||||||
this.getFileMetaData(this.issueId);
|
this.$get('/attachment/delete/issue/' + file.id , response => {
|
||||||
});
|
this.$success(this.$t('commons.delete_success'));
|
||||||
|
this.getFileMetaData(this.issueId);
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleCancel(file, index) {
|
handleCancel(file, index) {
|
||||||
this.fileList.splice(index, 1);
|
this.fileList.splice(index, 1);
|
||||||
|
|
Loading…
Reference in New Issue