feat(测试跟踪): 功能用例&缺陷管理附件功能改造

--story=1006991 --user=宋昌昌 【测试跟踪】功能用例&缺陷增加附件功能支持视频文件(1.20分支同步上) https://www.tapd.cn/55049933/s/1194201
This commit is contained in:
song-cc-rock 2022-07-04 16:43:18 +08:00 committed by jianxing
parent f08efd25bd
commit 4ccc8c0b03
33 changed files with 2468 additions and 82 deletions

View File

@ -0,0 +1,25 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class FileAttachmentMetadata implements Serializable {
private String id;
private String name;
private String type;
private Long size;
private Long createTime;
private Long updateTime;
private String creator;
private String filePath;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,730 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class FileAttachmentMetadataExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public FileAttachmentMetadataExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andNameIsNull() {
addCriterion("`name` is null");
return (Criteria) this;
}
public Criteria andNameIsNotNull() {
addCriterion("`name` is not null");
return (Criteria) this;
}
public Criteria andNameEqualTo(String value) {
addCriterion("`name` =", value, "name");
return (Criteria) this;
}
public Criteria andNameNotEqualTo(String value) {
addCriterion("`name` <>", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThan(String value) {
addCriterion("`name` >", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThanOrEqualTo(String value) {
addCriterion("`name` >=", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThan(String value) {
addCriterion("`name` <", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThanOrEqualTo(String value) {
addCriterion("`name` <=", value, "name");
return (Criteria) this;
}
public Criteria andNameLike(String value) {
addCriterion("`name` like", value, "name");
return (Criteria) this;
}
public Criteria andNameNotLike(String value) {
addCriterion("`name` not like", value, "name");
return (Criteria) this;
}
public Criteria andNameIn(List<String> values) {
addCriterion("`name` in", values, "name");
return (Criteria) this;
}
public Criteria andNameNotIn(List<String> values) {
addCriterion("`name` not in", values, "name");
return (Criteria) this;
}
public Criteria andNameBetween(String value1, String value2) {
addCriterion("`name` between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andNameNotBetween(String value1, String value2) {
addCriterion("`name` not between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andTypeIsNull() {
addCriterion("`type` is null");
return (Criteria) this;
}
public Criteria andTypeIsNotNull() {
addCriterion("`type` is not null");
return (Criteria) this;
}
public Criteria andTypeEqualTo(String value) {
addCriterion("`type` =", value, "type");
return (Criteria) this;
}
public Criteria andTypeNotEqualTo(String value) {
addCriterion("`type` <>", value, "type");
return (Criteria) this;
}
public Criteria andTypeGreaterThan(String value) {
addCriterion("`type` >", value, "type");
return (Criteria) this;
}
public Criteria andTypeGreaterThanOrEqualTo(String value) {
addCriterion("`type` >=", value, "type");
return (Criteria) this;
}
public Criteria andTypeLessThan(String value) {
addCriterion("`type` <", value, "type");
return (Criteria) this;
}
public Criteria andTypeLessThanOrEqualTo(String value) {
addCriterion("`type` <=", value, "type");
return (Criteria) this;
}
public Criteria andTypeLike(String value) {
addCriterion("`type` like", value, "type");
return (Criteria) this;
}
public Criteria andTypeNotLike(String value) {
addCriterion("`type` not like", value, "type");
return (Criteria) this;
}
public Criteria andTypeIn(List<String> values) {
addCriterion("`type` in", values, "type");
return (Criteria) this;
}
public Criteria andTypeNotIn(List<String> values) {
addCriterion("`type` not in", values, "type");
return (Criteria) this;
}
public Criteria andTypeBetween(String value1, String value2) {
addCriterion("`type` between", value1, value2, "type");
return (Criteria) this;
}
public Criteria andTypeNotBetween(String value1, String value2) {
addCriterion("`type` not between", value1, value2, "type");
return (Criteria) this;
}
public Criteria andSizeIsNull() {
addCriterion("`size` is null");
return (Criteria) this;
}
public Criteria andSizeIsNotNull() {
addCriterion("`size` is not null");
return (Criteria) this;
}
public Criteria andSizeEqualTo(Long value) {
addCriterion("`size` =", value, "size");
return (Criteria) this;
}
public Criteria andSizeNotEqualTo(Long value) {
addCriterion("`size` <>", value, "size");
return (Criteria) this;
}
public Criteria andSizeGreaterThan(Long value) {
addCriterion("`size` >", value, "size");
return (Criteria) this;
}
public Criteria andSizeGreaterThanOrEqualTo(Long value) {
addCriterion("`size` >=", value, "size");
return (Criteria) this;
}
public Criteria andSizeLessThan(Long value) {
addCriterion("`size` <", value, "size");
return (Criteria) this;
}
public Criteria andSizeLessThanOrEqualTo(Long value) {
addCriterion("`size` <=", value, "size");
return (Criteria) this;
}
public Criteria andSizeIn(List<Long> values) {
addCriterion("`size` in", values, "size");
return (Criteria) this;
}
public Criteria andSizeNotIn(List<Long> values) {
addCriterion("`size` not in", values, "size");
return (Criteria) this;
}
public Criteria andSizeBetween(Long value1, Long value2) {
addCriterion("`size` between", value1, value2, "size");
return (Criteria) this;
}
public Criteria andSizeNotBetween(Long value1, Long value2) {
addCriterion("`size` not between", value1, value2, "size");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;
}
public Criteria andCreateTimeIsNotNull() {
addCriterion("create_time is not null");
return (Criteria) this;
}
public Criteria andCreateTimeEqualTo(Long value) {
addCriterion("create_time =", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotEqualTo(Long value) {
addCriterion("create_time <>", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThan(Long value) {
addCriterion("create_time >", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("create_time >=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThan(Long value) {
addCriterion("create_time <", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThanOrEqualTo(Long value) {
addCriterion("create_time <=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeIn(List<Long> values) {
addCriterion("create_time in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotIn(List<Long> values) {
addCriterion("create_time not in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeBetween(Long value1, Long value2) {
addCriterion("create_time between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotBetween(Long value1, Long value2) {
addCriterion("create_time not between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNull() {
addCriterion("update_time is null");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNotNull() {
addCriterion("update_time is not null");
return (Criteria) this;
}
public Criteria andUpdateTimeEqualTo(Long value) {
addCriterion("update_time =", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotEqualTo(Long value) {
addCriterion("update_time <>", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThan(Long value) {
addCriterion("update_time >", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("update_time >=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThan(Long value) {
addCriterion("update_time <", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThanOrEqualTo(Long value) {
addCriterion("update_time <=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIn(List<Long> values) {
addCriterion("update_time in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotIn(List<Long> values) {
addCriterion("update_time not in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeBetween(Long value1, Long value2) {
addCriterion("update_time between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotBetween(Long value1, Long value2) {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andCreatorIsNull() {
addCriterion("creator is null");
return (Criteria) this;
}
public Criteria andCreatorIsNotNull() {
addCriterion("creator is not null");
return (Criteria) this;
}
public Criteria andCreatorEqualTo(String value) {
addCriterion("creator =", value, "creator");
return (Criteria) this;
}
public Criteria andCreatorNotEqualTo(String value) {
addCriterion("creator <>", value, "creator");
return (Criteria) this;
}
public Criteria andCreatorGreaterThan(String value) {
addCriterion("creator >", value, "creator");
return (Criteria) this;
}
public Criteria andCreatorGreaterThanOrEqualTo(String value) {
addCriterion("creator >=", value, "creator");
return (Criteria) this;
}
public Criteria andCreatorLessThan(String value) {
addCriterion("creator <", value, "creator");
return (Criteria) this;
}
public Criteria andCreatorLessThanOrEqualTo(String value) {
addCriterion("creator <=", value, "creator");
return (Criteria) this;
}
public Criteria andCreatorLike(String value) {
addCriterion("creator like", value, "creator");
return (Criteria) this;
}
public Criteria andCreatorNotLike(String value) {
addCriterion("creator not like", value, "creator");
return (Criteria) this;
}
public Criteria andCreatorIn(List<String> values) {
addCriterion("creator in", values, "creator");
return (Criteria) this;
}
public Criteria andCreatorNotIn(List<String> values) {
addCriterion("creator not in", values, "creator");
return (Criteria) this;
}
public Criteria andCreatorBetween(String value1, String value2) {
addCriterion("creator between", value1, value2, "creator");
return (Criteria) this;
}
public Criteria andCreatorNotBetween(String value1, String value2) {
addCriterion("creator not between", value1, value2, "creator");
return (Criteria) this;
}
public Criteria andFilePathIsNull() {
addCriterion("file_path is null");
return (Criteria) this;
}
public Criteria andFilePathIsNotNull() {
addCriterion("file_path is not null");
return (Criteria) this;
}
public Criteria andFilePathEqualTo(String value) {
addCriterion("file_path =", value, "filePath");
return (Criteria) this;
}
public Criteria andFilePathNotEqualTo(String value) {
addCriterion("file_path <>", value, "filePath");
return (Criteria) this;
}
public Criteria andFilePathGreaterThan(String value) {
addCriterion("file_path >", value, "filePath");
return (Criteria) this;
}
public Criteria andFilePathGreaterThanOrEqualTo(String value) {
addCriterion("file_path >=", value, "filePath");
return (Criteria) this;
}
public Criteria andFilePathLessThan(String value) {
addCriterion("file_path <", value, "filePath");
return (Criteria) this;
}
public Criteria andFilePathLessThanOrEqualTo(String value) {
addCriterion("file_path <=", value, "filePath");
return (Criteria) this;
}
public Criteria andFilePathLike(String value) {
addCriterion("file_path like", value, "filePath");
return (Criteria) this;
}
public Criteria andFilePathNotLike(String value) {
addCriterion("file_path not like", value, "filePath");
return (Criteria) this;
}
public Criteria andFilePathIn(List<String> values) {
addCriterion("file_path in", values, "filePath");
return (Criteria) this;
}
public Criteria andFilePathNotIn(List<String> values) {
addCriterion("file_path not in", values, "filePath");
return (Criteria) this;
}
public Criteria andFilePathBetween(String value1, String value2) {
addCriterion("file_path between", value1, value2, "filePath");
return (Criteria) this;
}
public Criteria andFilePathNotBetween(String value1, String value2) {
addCriterion("file_path not between", value1, value2, "filePath");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -0,0 +1,13 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class IssueFile implements Serializable {
private String issueId;
private String fileId;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,340 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class IssueFileExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public IssueFileExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIssueIdIsNull() {
addCriterion("issue_id is null");
return (Criteria) this;
}
public Criteria andIssueIdIsNotNull() {
addCriterion("issue_id is not null");
return (Criteria) this;
}
public Criteria andIssueIdEqualTo(String value) {
addCriterion("issue_id =", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdNotEqualTo(String value) {
addCriterion("issue_id <>", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdGreaterThan(String value) {
addCriterion("issue_id >", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdGreaterThanOrEqualTo(String value) {
addCriterion("issue_id >=", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdLessThan(String value) {
addCriterion("issue_id <", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdLessThanOrEqualTo(String value) {
addCriterion("issue_id <=", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdLike(String value) {
addCriterion("issue_id like", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdNotLike(String value) {
addCriterion("issue_id not like", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdIn(List<String> values) {
addCriterion("issue_id in", values, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdNotIn(List<String> values) {
addCriterion("issue_id not in", values, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdBetween(String value1, String value2) {
addCriterion("issue_id between", value1, value2, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdNotBetween(String value1, String value2) {
addCriterion("issue_id not between", value1, value2, "issueId");
return (Criteria) this;
}
public Criteria andFileIdIsNull() {
addCriterion("file_id is null");
return (Criteria) this;
}
public Criteria andFileIdIsNotNull() {
addCriterion("file_id is not null");
return (Criteria) this;
}
public Criteria andFileIdEqualTo(String value) {
addCriterion("file_id =", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdNotEqualTo(String value) {
addCriterion("file_id <>", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdGreaterThan(String value) {
addCriterion("file_id >", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdGreaterThanOrEqualTo(String value) {
addCriterion("file_id >=", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdLessThan(String value) {
addCriterion("file_id <", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdLessThanOrEqualTo(String value) {
addCriterion("file_id <=", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdLike(String value) {
addCriterion("file_id like", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdNotLike(String value) {
addCriterion("file_id not like", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdIn(List<String> values) {
addCriterion("file_id in", values, "fileId");
return (Criteria) this;
}
public Criteria andFileIdNotIn(List<String> values) {
addCriterion("file_id not in", values, "fileId");
return (Criteria) this;
}
public Criteria andFileIdBetween(String value1, String value2) {
addCriterion("file_id between", value1, value2, "fileId");
return (Criteria) this;
}
public Criteria andFileIdNotBetween(String value1, String value2) {
addCriterion("file_id not between", value1, value2, "fileId");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -0,0 +1,30 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.FileAttachmentMetadata;
import io.metersphere.base.domain.FileAttachmentMetadataExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface FileAttachmentMetadataMapper {
long countByExample(FileAttachmentMetadataExample example);
int deleteByExample(FileAttachmentMetadataExample example);
int deleteByPrimaryKey(String id);
int insert(FileAttachmentMetadata record);
int insertSelective(FileAttachmentMetadata record);
List<FileAttachmentMetadata> selectByExample(FileAttachmentMetadataExample example);
FileAttachmentMetadata selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") FileAttachmentMetadata record, @Param("example") FileAttachmentMetadataExample example);
int updateByExample(@Param("record") FileAttachmentMetadata record, @Param("example") FileAttachmentMetadataExample example);
int updateByPrimaryKeySelective(FileAttachmentMetadata record);
int updateByPrimaryKey(FileAttachmentMetadata record);
}

View File

@ -0,0 +1,258 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.FileAttachmentMetadataMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.FileAttachmentMetadata">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="type" jdbcType="VARCHAR" property="type" />
<result column="size" jdbcType="BIGINT" property="size" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="creator" jdbcType="VARCHAR" property="creator" />
<result column="file_path" jdbcType="VARCHAR" property="filePath" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, `name`, `type`, `size`, create_time, update_time, creator, file_path
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.FileAttachmentMetadataExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from file_attachment_metadata
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from file_attachment_metadata
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from file_attachment_metadata
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.FileAttachmentMetadataExample">
delete from file_attachment_metadata
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.FileAttachmentMetadata">
insert into file_attachment_metadata (id, `name`, `type`,
`size`, create_time, update_time,
creator, file_path)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
#{size,jdbcType=BIGINT}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{creator,jdbcType=VARCHAR}, #{filePath,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.FileAttachmentMetadata">
insert into file_attachment_metadata
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="name != null">
`name`,
</if>
<if test="type != null">
`type`,
</if>
<if test="size != null">
`size`,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="creator != null">
creator,
</if>
<if test="filePath != null">
file_path,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="type != null">
#{type,jdbcType=VARCHAR},
</if>
<if test="size != null">
#{size,jdbcType=BIGINT},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="creator != null">
#{creator,jdbcType=VARCHAR},
</if>
<if test="filePath != null">
#{filePath,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.FileAttachmentMetadataExample" resultType="java.lang.Long">
select count(*) from file_attachment_metadata
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update file_attachment_metadata
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.type != null">
`type` = #{record.type,jdbcType=VARCHAR},
</if>
<if test="record.size != null">
`size` = #{record.size,jdbcType=BIGINT},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.creator != null">
creator = #{record.creator,jdbcType=VARCHAR},
</if>
<if test="record.filePath != null">
file_path = #{record.filePath,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update file_attachment_metadata
set id = #{record.id,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
`type` = #{record.type,jdbcType=VARCHAR},
`size` = #{record.size,jdbcType=BIGINT},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
creator = #{record.creator,jdbcType=VARCHAR},
file_path = #{record.filePath,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.FileAttachmentMetadata">
update file_attachment_metadata
<set>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="type != null">
`type` = #{type,jdbcType=VARCHAR},
</if>
<if test="size != null">
`size` = #{size,jdbcType=BIGINT},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="creator != null">
creator = #{creator,jdbcType=VARCHAR},
</if>
<if test="filePath != null">
file_path = #{filePath,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.FileAttachmentMetadata">
update file_attachment_metadata
set `name` = #{name,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
`size` = #{size,jdbcType=BIGINT},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
creator = #{creator,jdbcType=VARCHAR},
file_path = #{filePath,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -0,0 +1,22 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.IssueFile;
import io.metersphere.base.domain.IssueFileExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface IssueFileMapper {
long countByExample(IssueFileExample example);
int deleteByExample(IssueFileExample example);
int insert(IssueFile record);
int insertSelective(IssueFile record);
List<IssueFile> selectByExample(IssueFileExample example);
int updateByExampleSelective(@Param("record") IssueFile record, @Param("example") IssueFileExample example);
int updateByExample(@Param("record") IssueFile record, @Param("example") IssueFileExample example);
}

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.IssueFileMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.IssueFile">
<result column="issue_id" jdbcType="VARCHAR" property="issueId" />
<result column="file_id" jdbcType="VARCHAR" property="fileId" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
issue_id, file_id
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.IssueFileExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from issue_file
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.IssueFileExample">
delete from issue_file
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.IssueFile">
insert into issue_file (issue_id, file_id)
values (#{issueId,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.IssueFile">
insert into issue_file
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="issueId != null">
issue_id,
</if>
<if test="fileId != null">
file_id,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="issueId != null">
#{issueId,jdbcType=VARCHAR},
</if>
<if test="fileId != null">
#{fileId,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.IssueFileExample" resultType="java.lang.Long">
select count(*) from issue_file
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update issue_file
<set>
<if test="record.issueId != null">
issue_id = #{record.issueId,jdbcType=VARCHAR},
</if>
<if test="record.fileId != null">
file_id = #{record.fileId,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update issue_file
set issue_id = #{record.issueId,jdbcType=VARCHAR},
file_id = #{record.fileId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
</mapper>

View File

@ -0,0 +1,17 @@
package io.metersphere.commons.constants;
public enum AttachmentType {
TEST_CASE("testcase"), ISSUE("issue");
// 附件类型名称
private String type;
AttachmentType(String type) {
this.type = type;
}
public String type() {
return this.type;
}
}

View File

@ -5,7 +5,8 @@ public enum FileType {
JPG(".jpg"), PNG(".png"), JPEG(".jpeg"), DOC(".doc"),
XLSX(".xlsx"), DOCX(".docx"), JAR(".jar"), JS(".js"), TXT(".txt"),
P12(".p12"), JKS(".jks"), PFX(".pfx"),
DER(".der"), CER(".cer"), PEM(".pem"), CRT(".crt"), SIDE(".side")
DER(".der"), CER(".cer"), PEM(".pem"), CRT(".crt"), SIDE(".side"),
MP4(".mp4"), MOV(".mov"), DCM(".dcm"), ZIP(".zip"), RAR(".rar")
;
// 保存后缀

View File

@ -26,6 +26,10 @@ public class FileUtils {
public static final String BODY_FILE_DIR = "/opt/metersphere/data/body";
public static final String MD_IMAGE_DIR = "/opt/metersphere/data/image/markdown";
public static final String UI_IMAGE_DIR = "/opt/metersphere/data/image/ui/screenshots";
public static final String ATTACHMENT_DIR = "/opt/metersphere/data/attachment";
public static final String TEST_CASE_ATTACHMENT_DIR = "/opt/metersphere/data/attachment/testcase";
public static final String ISSUE_ATTACHMENT_DIR = "/opt/metersphere/data/attachment/issue";
public static byte[] listBytesToZip(Map<String, byte[]> mapReport) {
try {
@ -339,6 +343,41 @@ public class FileUtils {
return buffer;
}
public static File byteToFile(byte[] buf, String filePath, String fileName){
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = null;
try{
File dir = new File(filePath);
if (!dir.exists()){
dir.mkdirs();
}
file = new File(filePath + "/" + fileName);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(buf);
}catch (Exception e){
e.printStackTrace();
}
finally{
if (bos != null){
try{
bos.close();
}catch (IOException e){
e.printStackTrace();
}
}
if (fos != null){
try{
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
return file;
}
public static String fileToStr(File tradeFile) {
String buffer = null;
try (FileInputStream fis = new FileInputStream(tradeFile);

View File

@ -80,6 +80,7 @@ public class ShiroUtils {
filterChainDefinitionMap.put("/", "apikey, authc"); // 跳转到 / 不用校验 csrf
filterChainDefinitionMap.put("/language", "apikey, authc");// 跳转到 /language 不用校验 csrf
filterChainDefinitionMap.put("/test/case/file/preview/**", "apikey, authc"); // 预览测试用例附件 不用校验 csrf
filterChainDefinitionMap.put("/test/case/attachment/preview/**", "apikey, authc"); // 预览测试用例附件 不用校验 csrf
filterChainDefinitionMap.put("/mock", "apikey, authc"); // 跳转到 /mock接口 不用校验 csrf
}

View File

@ -158,6 +158,7 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
initOnceOperate(mockConfigService::initExpectNum, "init.mock.expectNum");
initOnceOperate(customFieldResourceService::compatibleData, "init.custom.field.resource");
initOnceOperate(jarConfigService::initJarPath, "init.jar.path");
initOnceOperate(testCaseService::initAttachment, "init.attachment.test.case");
}
/**

View File

@ -1,14 +1,10 @@
package io.metersphere.service;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.FileContentMapper;
import io.metersphere.base.mapper.FileMetadataMapper;
import io.metersphere.base.mapper.TestCaseFileMapper;
import io.metersphere.base.mapper.*;
import io.metersphere.commons.constants.FileType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.RsaKey;
import io.metersphere.commons.utils.RsaUtil;
import io.metersphere.commons.utils.*;
import io.metersphere.performance.request.QueryProjectFileRequest;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
@ -32,9 +28,13 @@ public class FileService {
@Resource
private FileMetadataMapper fileMetadataMapper;
@Resource
private FileAttachmentMetadataMapper fileAttachmentMetadataMapper;
@Resource
private FileContentMapper fileContentMapper;
@Resource
private TestCaseFileMapper testCaseFileMapper;
@Resource
private IssueFileMapper issueFileMapper;
public byte[] loadFileAsBytes(String id) {
FileContent fileContent = fileContentMapper.selectByPrimaryKey(id);
@ -42,6 +42,12 @@ public class FileService {
return fileContent.getFile();
}
public byte[] getAttachmentBytes(String id) {
FileAttachmentMetadata fileAttachmentMetadata = fileAttachmentMetadataMapper.selectByPrimaryKey(id);
File attachmentFile = new File(fileAttachmentMetadata.getFilePath() + "/" + fileAttachmentMetadata.getName());
return FileUtils.fileToByte(attachmentFile);
}
public FileContent getFileContent(String fileId) {
return fileContentMapper.selectByPrimaryKey(fileId);
}
@ -70,6 +76,23 @@ public class FileService {
deleteFileByIds(ids);
}
public void deleteFileAttachmentByIds(List<String> ids) {
if (CollectionUtils.isEmpty(ids)) {
return;
}
FileAttachmentMetadataExample example = new FileAttachmentMetadataExample();
example.createCriteria().andIdIn(ids);
fileAttachmentMetadataMapper.deleteByExample(example);
}
public List<FileMetadata> getAllFileMeta() {
return fileMetadataMapper.selectByExample(new FileMetadataExample());
}
public List<FileContent> getAllFileContent() {
return fileContentMapper.selectByExampleWithBLOBs(new FileContentExample());
}
public FileMetadata saveFile(MultipartFile file, String projectId, String fileId) {
final FileMetadata fileMetadata = new FileMetadata();
if (StringUtils.isEmpty(fileId)) {
@ -98,6 +121,34 @@ public class FileService {
return fileMetadata;
}
public FileAttachmentMetadata saveAttachment(MultipartFile file, String attachmentType, String belongId) {
String uploadPath = FileUtils.ATTACHMENT_DIR + "/" + attachmentType + "/" + belongId;
FileUtils.uploadFile(file, uploadPath);
final FileAttachmentMetadata fileAttachmentMetadata = new FileAttachmentMetadata();
fileAttachmentMetadata.setId(UUID.randomUUID().toString());
fileAttachmentMetadata.setName(file.getOriginalFilename());
fileAttachmentMetadata.setType(getFileType(fileAttachmentMetadata.getName()).name());
fileAttachmentMetadata.setSize(file.getSize());
fileAttachmentMetadata.setCreateTime(System.currentTimeMillis());
fileAttachmentMetadata.setUpdateTime(System.currentTimeMillis());
fileAttachmentMetadata.setCreator(SessionUtils.getUser().getName());
fileAttachmentMetadata.setFilePath(uploadPath);
fileAttachmentMetadataMapper.insert(fileAttachmentMetadata);
return fileAttachmentMetadata;
}
public void deleteAttachment(List<String> ids) {
for (String id : ids) {
FileAttachmentMetadata fileAttachmentMetadata = fileAttachmentMetadataMapper.selectByPrimaryKey(id);
FileUtils.deleteFile(fileAttachmentMetadata.getFilePath() + "/" + fileAttachmentMetadata.getName());
}
}
public void deleteAttachment(String attachmentType, String belongId) {
String deletePath = FileUtils.ATTACHMENT_DIR + "/" + attachmentType + "/" + belongId;
FileUtils.deleteDir(deletePath);
}
public FileMetadata saveFile(MultipartFile file, String projectId) {
return saveFile(file, projectId, null);
}
@ -224,6 +275,26 @@ public class FileService {
return fileMetadata;
}
public FileAttachmentMetadata copyAttachment(String fileId, String attachmentType, String belongId) {
String copyPath = FileUtils.ATTACHMENT_DIR + "/" + attachmentType + "/" + belongId;
FileAttachmentMetadata fileAttachmentMetadata = fileAttachmentMetadataMapper.selectByPrimaryKey(fileId);
if (fileAttachmentMetadata != null) {
File copyFile = new File(copyPath);
if (!copyFile.exists()) {
FileUtils.copyFolder(fileAttachmentMetadata.getFilePath(), copyPath);
}
fileAttachmentMetadata.setId(UUID.randomUUID().toString());
fileAttachmentMetadata.setCreateTime(System.currentTimeMillis());
fileAttachmentMetadata.setUpdateTime(System.currentTimeMillis());
fileAttachmentMetadata.setCreator(SessionUtils.getUser().getName());
fileAttachmentMetadata.setFilePath(copyPath);
fileAttachmentMetadataMapper.insert(fileAttachmentMetadata);
}
return fileAttachmentMetadata;
}
private FileType getFileType(String filename) {
int s = filename.lastIndexOf(".") + 1;
String type = filename.substring(s);
@ -245,6 +316,38 @@ public class FileService {
return fileMetadataMapper.selectByExample(example);
}
public List<FileAttachmentMetadata> getFileAttachmentMetadataByCaseId(String caseId) {
TestCaseFileExample testCaseFileExample = new TestCaseFileExample();
testCaseFileExample.createCriteria().andCaseIdEqualTo(caseId);
final List<TestCaseFile> testCaseFiles = testCaseFileMapper.selectByExample(testCaseFileExample);
if (CollectionUtils.isEmpty(testCaseFiles)) {
return new ArrayList<>();
}
List<String> fileIds = testCaseFiles.stream().map(TestCaseFile::getFileId).collect(Collectors.toList());
FileAttachmentMetadataExample example = new FileAttachmentMetadataExample();
example.createCriteria().andIdIn(fileIds);
return fileAttachmentMetadataMapper.selectByExample(example);
}
public List<FileAttachmentMetadata> getFileAttachmentMetadataByIssueId(String issueId) {
IssueFileExample issueFileExample = new IssueFileExample();
issueFileExample.createCriteria().andIssueIdEqualTo(issueId);
final List<IssueFile> issueFiles = issueFileMapper.selectByExample(issueFileExample);
if (CollectionUtils.isEmpty(issueFiles)) {
return new ArrayList<>();
}
List<String> fileIds = issueFiles.stream().map(IssueFile::getFileId).collect(Collectors.toList());
FileAttachmentMetadataExample example = new FileAttachmentMetadataExample();
example.createCriteria().andIdIn(fileIds);
return fileAttachmentMetadataMapper.selectByExample(example);
}
public void deleteFileById(String fileId) {
deleteFileByIds(Collections.singletonList(fileId));
}

View File

@ -2,6 +2,7 @@ package io.metersphere.track.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.FileAttachmentMetadata;
import io.metersphere.base.domain.Issues;
import io.metersphere.base.domain.IssuesDao;
import io.metersphere.base.domain.IssuesWithBLOBs;
@ -14,6 +15,7 @@ import io.metersphere.commons.utils.Pager;
import io.metersphere.dto.IssueTemplateDao;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.FileService;
import io.metersphere.track.dto.DemandDTO;
import io.metersphere.track.dto.PlatformStatusDTO;
import io.metersphere.track.issue.domain.PlatformUser;
@ -27,6 +29,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;
@ -37,6 +40,8 @@ public class IssuesController {
@Resource
private IssuesService issuesService;
@Resource
private FileService fileService;
@PostMapping("/list/{goPage}/{pageSize}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_ISSUE_READ)
@ -59,22 +64,27 @@ public class IssuesController {
return PageUtils.setPageInfo(page, issuesService.relateList(request));
}
@PostMapping("/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(@RequestBody IssuesUpdateRequest issuesRequest) {
return issuesService.addIssues(issuesRequest);
public IssuesWithBLOBs addIssues(@RequestPart(value = "request") IssuesUpdateRequest issuesRequest, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
return issuesService.addIssuesRefactor(issuesRequest, files);
}
@PostMapping("/update")
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_ISSUE_READ_EDIT)
@MsAuditLog(module = OperLogModule.TRACK_BUG, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#issuesRequest.id)", content = "#msClass.getLogDetails(#issuesRequest.id)", msClass = IssuesService.class)
@SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#issuesRequest",
event = NoticeConstants.Event.UPDATE, subject = "缺陷通知")
public void updateIssues(@RequestBody IssuesUpdateRequest issuesRequest) {
issuesService.updateIssues(issuesRequest);
public void updateIssues(@RequestPart(value = "request") IssuesUpdateRequest issuesRequest, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
issuesService.updateIssuesRefactor(issuesRequest, files);
}
@GetMapping("/file/attachmentMetadata/{issueId}")
public List<FileAttachmentMetadata> getFileAttachmentMetadataByIssueId(@PathVariable String issueId) {
return fileService.getFileAttachmentMetadataByIssueId(issueId);
}
@GetMapping("/get/case/{refType}/{id}")

View File

@ -6,10 +6,7 @@ import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.TestCase;
import io.metersphere.base.domain.TestCaseWithBLOBs;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.TestCaseMapper;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
@ -224,7 +221,7 @@ public class TestCaseController {
} else {
//复制前端生成 id
}
return testCaseService.save(request, files);
return testCaseService.refactorSave(request, files);
}
@PostMapping("/edit/order")
@ -238,7 +235,7 @@ public class TestCaseController {
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, target = "#targetClass.getTestCase(#request.id)", targetClass = TestCaseService.class,
event = NoticeConstants.Event.UPDATE, subject = "测试用例通知")
public TestCase editTestCase(@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
return testCaseService.edit(request, files);
return testCaseService.refactorEdit(request, files);
}
@PostMapping(value = "/edit/testPlan", consumes = {"multipart/form-data"})
@ -374,6 +371,11 @@ public class TestCaseController {
return fileService.getFileMetadataByCaseId(caseId);
}
@GetMapping("/file/attachmentMetadata/{caseId}")
public List<FileAttachmentMetadata> getFileAttachmentMetadataByCaseId(@PathVariable String caseId) {
return fileService.getFileAttachmentMetadataByCaseId(caseId);
}
@PostMapping("/file/download")
public ResponseEntity<byte[]> download(@RequestBody FileOperationRequest fileOperationRequest) {
byte[] bytes = fileService.loadFileAsBytes(fileOperationRequest.getId());
@ -383,6 +385,15 @@ public class TestCaseController {
.body(bytes);
}
@PostMapping("/attachment/download")
public ResponseEntity<byte[]> attachmentDownload(@RequestBody FileOperationRequest fileOperationRequest) {
byte[] bytes = fileService.getAttachmentBytes(fileOperationRequest.getId());
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + URLEncoder.encode(fileOperationRequest.getName(), StandardCharsets.UTF_8) + "\"")
.body(bytes);
}
@GetMapping("/file/preview/{fileId}")
public ResponseEntity<byte[]> preview(@PathVariable String fileId) {
byte[] bytes = fileService.loadFileAsBytes(fileId);
@ -392,6 +403,15 @@ public class TestCaseController {
.body(bytes);
}
@GetMapping("/attachment/preview/{fileId}")
public ResponseEntity<byte[]> attachmentPreview(@PathVariable String fileId) {
byte[] bytes = fileService.getAttachmentBytes(fileId);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileId + "\"")
.body(bytes);
}
@PostMapping("/save")
@MsAuditLog(module = OperLogModule.TRACK_TEST_CASE, type = OperLogConstants.CREATE, title = "#testCaseWithBLOBs.name", content = "#msClass.getLogDetails(#testCaseWithBLOBs.id)", msClass = TestCaseService.class)
public TestCaseWithBLOBs saveTestCase(@RequestBody EditTestCaseRequest request) {

View File

@ -22,6 +22,10 @@ public class EditTestCaseRequest extends TestCaseWithBLOBs {
*/
private List<String> fileIds = new ArrayList<>();
private List<List<String>> selected = new ArrayList<>();
/**
* 复制测试用例时原始用例ID
*/
private String copyCaseId;
// 是否处理附件文件
private boolean handleAttachment = true;

View File

@ -1,8 +1,8 @@
package io.metersphere.track.request.testcase;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.IssuesWithBLOBs;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.track.issue.domain.jira.JiraTransitionsResponse;
import io.metersphere.track.dto.PlatformStatusDTO;
import lombok.Getter;
import lombok.Setter;
@ -41,4 +41,14 @@ public class IssuesUpdateRequest extends IssuesWithBLOBs {
private String devopsFields;
private PlatformStatusDTO transitions;
/**
* 缺陷附件上传更新的文件数据
*/
private List<FileMetadata> updatedFileList;
/**
* 复制缺陷时原始缺陷ID
*/
private String copyIssueId;
}

View File

@ -8,6 +8,7 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
import io.metersphere.commons.constants.AttachmentType;
import io.metersphere.commons.constants.IssueRefType;
import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.constants.IssuesStatus;
@ -34,11 +35,13 @@ import io.metersphere.track.request.testcase.IssuesRequest;
import io.metersphere.track.request.testcase.IssuesUpdateRequest;
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
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.lang.reflect.Constructor;
@ -84,6 +87,12 @@ public class IssuesService {
private CustomFieldIssuesMapper customFieldIssuesMapper;
@Resource
StringRedisTemplate stringRedisTemplate;
@Resource
FileService fileService;
@Resource
IssueFileMapper issueFileMapper;
@Resource
private FileAttachmentMetadataMapper fileAttachmentMetadataMapper;
private static final String SYNC_THIRD_PARTY_ISSUES_KEY = "ISSUE:SYNC";
@ -123,6 +132,90 @@ public class IssuesService {
// todo 缺陷更新事件
}
public IssuesWithBLOBs addIssuesRefactor(IssuesUpdateRequest issuesRequest, List<MultipartFile> files) {
List<AbstractIssuePlatform> platformList = getAddPlatforms(issuesRequest);
IssuesWithBLOBs issues = null;
for (AbstractIssuePlatform platform : platformList) {
issues = platform.addIssue(issuesRequest);
}
if (issuesRequest.getIsPlanEdit()) {
issuesRequest.getAddResourceIds().forEach(l -> {
testCaseIssueService.updateIssuesCount(l);
});
}
saveFollows(issuesRequest.getId(), issuesRequest.getFollows());
customFieldIssuesService.addFields(issuesRequest.getId(), issuesRequest.getAddFields());
// copy的附件
if (StringUtils.isNotEmpty(issuesRequest.getCopyIssueId())) {
final String addIssueId = issues.getId();
IssueFileExample example = new IssueFileExample();
example.createCriteria().andIssueIdEqualTo(issuesRequest.getCopyIssueId());
List<IssueFile> issueFiles = issueFileMapper.selectByExample(example);
if (issueFiles != null) {
issueFiles.forEach(issueFile -> {
FileAttachmentMetadata fileAttachmentMetadata = fileService.copyAttachment(issueFile.getFileId(), AttachmentType.ISSUE.type(), addIssueId);
IssueFile newIssueFile = new IssueFile();
newIssueFile.setIssueId(addIssueId);
newIssueFile.setFileId(fileAttachmentMetadata.getId());
issueFileMapper.insert(newIssueFile);
});
}
}
// 新的附件
if (files != null) {
files.forEach(file -> {
FileAttachmentMetadata fileAttachmentMetadata = fileService.saveAttachment(file, AttachmentType.ISSUE.type(), issuesRequest.getId());
IssueFile issueFile = new IssueFile();
issueFile.setIssueId(issuesRequest.getId());
issueFile.setFileId(fileAttachmentMetadata.getId());
issueFileMapper.insert(issueFile);
});
}
return issues;
}
public void updateIssuesRefactor(IssuesUpdateRequest issuesRequest, List<MultipartFile> files) {
issuesRequest.getId();
List<AbstractIssuePlatform> platformList = getUpdatePlatforms(issuesRequest);
platformList.forEach(platform -> {
platform.updateIssue(issuesRequest);
});
customFieldIssuesService.editFields(issuesRequest.getId(), issuesRequest.getEditFields());
customFieldIssuesService.addFields(issuesRequest.getId(), issuesRequest.getAddFields());
// todo 缺陷更新事件
// 删除原来的文件
List<FileMetadata> updatedFiles = issuesRequest.getUpdatedFileList();
List<FileAttachmentMetadata> originFiles = fileService.getFileAttachmentMetadataByIssueId(issuesRequest.getId());
List<String> updatedFileIds = updatedFiles.stream().map(FileMetadata::getId).collect(Collectors.toList());
List<String> originFileIds = originFiles.stream().map(FileAttachmentMetadata::getId).collect(Collectors.toList());
// 获得差异的附件ID
List<String> deleteFileIds = ListUtils.subtract(originFileIds, updatedFileIds);
// 删除差异附件记录, 目录下附件文件
fileService.deleteAttachment(deleteFileIds);
fileService.deleteFileAttachmentByIds(deleteFileIds);
//删除用例文件关联记录
if (!CollectionUtils.isEmpty(deleteFileIds)) {
IssueFileExample issueFileExample = new IssueFileExample();
issueFileExample.createCriteria().andFileIdIn(deleteFileIds);
issueFileMapper.deleteByExample(issueFileExample);
}
// 保存新的附件
if (files != null) {
files.forEach(file -> {
FileAttachmentMetadata fileAttachmentMetadata = fileService.saveAttachment(file, AttachmentType.ISSUE.type(), issuesRequest.getId());
IssueFile issueFile = new IssueFile();
issueFile.setIssueId(issuesRequest.getId());
issueFile.setFileId(fileAttachmentMetadata.getId());
issueFileMapper.insert(issueFile);
});
}
}
public void saveFollows(String issueId, List<String> follows) {
IssueFollowExample example = new IssueFollowExample();
example.createCriteria().andIssueIdEqualTo(issueId);
@ -321,6 +414,16 @@ public class IssuesService {
issuesRequest.setWorkspaceId(project.getWorkspaceId());
AbstractIssuePlatform platform = IssueFactory.createPlatform(issuesWithBLOBs.getPlatform(), issuesRequest);
platform.deleteIssue(id);
// 删除缺陷对应的附件
IssueFileExample issueFileExample = new IssueFileExample();
issueFileExample.createCriteria().andIssueIdEqualTo(id);
List<IssueFile> issueFiles = issueFileMapper.selectByExample(issueFileExample);
List<String> fileIds = issueFiles.stream().map(IssueFile::getFileId).collect(Collectors.toList());
FileAttachmentMetadataExample fileAttachmentMetadataExample = new FileAttachmentMetadataExample();
fileAttachmentMetadataExample.createCriteria().andIdIn(fileIds);
fileAttachmentMetadataMapper.deleteByExample(fileAttachmentMetadataExample);
issueFileMapper.deleteByExample(issueFileExample);
fileService.deleteAttachment(AttachmentType.ISSUE.type(), id);
}
public IssuesWithBLOBs get(String id) {

View File

@ -176,6 +176,8 @@ public class TestCaseService {
@Lazy
@Resource
private TestReviewTestCaseService testReviewTestCaseService;
@Resource
private FileAttachmentMetadataMapper fileAttachmentMetadataMapper;
private ThreadLocal<Integer> importCreateNum = new ThreadLocal<>();
private ThreadLocal<Integer> beforeImportCreateNum = new ThreadLocal<>();
@ -607,6 +609,16 @@ public class TestCaseService {
deleteFollows(testCaseId);
customFieldTestCaseService.deleteByResourceId(testCaseId); // 删除自定义字段关联关系
functionCaseExecutionInfoService.deleteBySourceId(testCaseId);
// 删除用例附件关联数据, 附件内容
TestCaseFileExample testCaseFileExample = new TestCaseFileExample();
testCaseFileExample.createCriteria().andCaseIdEqualTo(testCaseId);
List<TestCaseFile> testCaseFiles = testCaseFileMapper.selectByExample(testCaseFileExample);
List<String> fileIds = testCaseFiles.stream().map(TestCaseFile::getFileId).collect(Collectors.toList());
FileAttachmentMetadataExample fileAttachmentMetadataExample = new FileAttachmentMetadataExample();
fileAttachmentMetadataExample.createCriteria().andIdIn(fileIds);
fileAttachmentMetadataMapper.deleteByExample(fileAttachmentMetadataExample);
testCaseFileMapper.deleteByExample(testCaseFileExample);
fileService.deleteAttachment(AttachmentType.TEST_CASE.type(), testCaseId);
return testCaseMapper.deleteByPrimaryKey(testCaseId);
}
@ -1958,6 +1970,39 @@ public class TestCaseService {
return testCaseWithBLOBs;
}
public TestCase refactorSave(EditTestCaseRequest request, List<MultipartFile> files) {
final TestCaseWithBLOBs testCaseWithBLOBs = addTestCase(request);
// 复制用例时复制对应附件数据
if (StringUtils.isNotEmpty(request.getCopyCaseId())) {
TestCaseFileExample example = new TestCaseFileExample();
example.createCriteria().andCaseIdEqualTo(request.getCopyCaseId());
List<TestCaseFile> testCaseFiles = testCaseFileMapper.selectByExample(example);
if (testCaseFiles != null) {
testCaseFiles.forEach(testCaseFile -> {
FileAttachmentMetadata fileAttachmentMetadata = fileService.copyAttachment(testCaseFile.getFileId(), AttachmentType.TEST_CASE.type(), testCaseWithBLOBs.getId());
TestCaseFile newTestCaseFile = new TestCaseFile();
newTestCaseFile.setCaseId(testCaseWithBLOBs.getId());
newTestCaseFile.setFileId(fileAttachmentMetadata.getId());
testCaseFileMapper.insert(newTestCaseFile);
});
}
}
// 新的附件
if (files != null) {
files.forEach(file -> {
FileAttachmentMetadata fileAttachmentMetadata = fileService.saveAttachment(file, AttachmentType.TEST_CASE.type(), request.getId());
TestCaseFile testCaseFile = new TestCaseFile();
testCaseFile.setFileId(fileAttachmentMetadata.getId());
testCaseFile.setCaseId(request.getId());
testCaseFileMapper.insert(testCaseFile);
});
}
return testCaseWithBLOBs;
}
public TestCase edit(EditTestCaseRequest request, List<MultipartFile> files) {
TestCaseWithBLOBs testCaseWithBLOBs = testCaseMapper.selectByPrimaryKey(request.getId());
request.setNum(testCaseWithBLOBs.getNum());
@ -1996,6 +2041,47 @@ public class TestCaseService {
return editTestCase(request);
}
public TestCase refactorEdit(EditTestCaseRequest request, List<MultipartFile> files) {
TestCaseWithBLOBs testCaseWithBLOBs = testCaseMapper.selectByPrimaryKey(request.getId());
request.setNum(testCaseWithBLOBs.getNum());
if (testCaseWithBLOBs == null) {
MSException.throwException(Translator.get("edit_load_test_not_found") + request.getId());
}
if (BooleanUtils.isTrue(request.isHandleAttachment())) {
// 新选择了一个文件删除原来的文件
List<FileMetadata> updatedFiles = request.getUpdatedFileList();
List<FileAttachmentMetadata> originFiles = fileService.getFileAttachmentMetadataByCaseId(request.getId());
List<String> updatedFileIds = updatedFiles.stream().map(FileMetadata::getId).collect(Collectors.toList());
List<String> originFileIds = originFiles.stream().map(FileAttachmentMetadata::getId).collect(Collectors.toList());
// 获得差异的附件ID
List<String> deleteFileIds = ListUtils.subtract(originFileIds, updatedFileIds);
// 删除差异附件记录, 目录下附件文件
fileService.deleteAttachment(deleteFileIds);
fileService.deleteFileAttachmentByIds(deleteFileIds);
//删除用例文件关联记录
if (!CollectionUtils.isEmpty(deleteFileIds)) {
TestCaseFileExample testCaseFileExample = new TestCaseFileExample();
testCaseFileExample.createCriteria().andFileIdIn(deleteFileIds);
testCaseFileMapper.deleteByExample(testCaseFileExample);
}
// 保存新的附件
if (files != null) {
files.forEach(file -> {
FileAttachmentMetadata fileAttachmentMetadata = fileService.saveAttachment(file, AttachmentType.TEST_CASE.type(), request.getId());
TestCaseFile testCaseFile = new TestCaseFile();
testCaseFile.setFileId(fileAttachmentMetadata.getId());
testCaseFile.setCaseId(request.getId());
testCaseFileMapper.insert(testCaseFile);
});
}
}
this.setNode(request);
return editTestCase(request);
}
public String editTestCase(EditTestCaseRequest request, List<MultipartFile> files) {
String testCaseId = testPlanTestCaseMapper.selectByPrimaryKey(request.getId()).getCaseId();
request.setId(testCaseId);
@ -2505,6 +2591,45 @@ public class TestCaseService {
extTestCaseMapper::getIdsOrderByUpdateTime);
}
public void initAttachment() {
TestCaseFileExample example = new TestCaseFileExample();
List<TestCaseFile> testCaseFiles = testCaseFileMapper.selectByExample(example);
List<FileMetadata> allFileMeta = fileService.getAllFileMeta();
List<FileContent> allFileContent = fileService.getAllFileContent();
Map<String, List<TestCaseFile>> testCaseFileGroup = testCaseFiles.stream().collect(Collectors.groupingBy(TestCaseFile::getCaseId));
for(Map.Entry<String, List<TestCaseFile>> entry : testCaseFileGroup.entrySet()) {
final String caseId = entry.getKey();
final String uploadPath = FileUtils.ATTACHMENT_DIR + "/" + AttachmentType.TEST_CASE.type() + "/" + caseId;
entry.getValue().stream().forEach(testCaseFile -> {
String filename = "";
List<FileMetadata> fileMetadatas = allFileMeta.stream().filter(fileMetadata -> fileMetadata.getId().equals(testCaseFile.getFileId()))
.collect(Collectors.toList());
List<FileContent> fileContents = allFileContent.stream().filter(fileContent -> fileContent.getFileId().equals(testCaseFile.getFileId()))
.collect(Collectors.toList());
if (fileMetadatas.size() == 1) {
FileMetadata fileMetadata = fileMetadatas.get(0);
filename = fileMetadata.getName();
FileAttachmentMetadata fileAttachmentMetadata = new FileAttachmentMetadata();
BeanUtils.copyBean(fileAttachmentMetadata, fileMetadata);
fileAttachmentMetadata.setId(UUID.randomUUID().toString());
fileAttachmentMetadata.setCreator("");
fileAttachmentMetadata.setFilePath(uploadPath);
fileAttachmentMetadataMapper.insert(fileAttachmentMetadata);
TestCaseFile newTestCaseFile = new TestCaseFile();
newTestCaseFile.setFileId(fileAttachmentMetadata.getId());
TestCaseFileExample testCaseFileExample = new TestCaseFileExample();
testCaseFileExample.createCriteria().andCaseIdEqualTo(testCaseFile.getCaseId()).andFileIdEqualTo(testCaseFile.getFileId());
testCaseFileMapper.updateByExampleSelective(newTestCaseFile, testCaseFileExample);
}
if (StringUtils.isNotEmpty(filename) && fileContents.size() == 1) {
byte[] bytes = fileContents.get(0).getFile();
FileUtils.byteToFile(bytes, uploadPath, filename);
}
});
}
}
/**
* 用例自定义排序
*

View File

@ -6,16 +6,26 @@
<el-table-column
prop="name"
:label="$t('load_test.file_name')">
<template v-slot:default="scope">
<el-tooltip class="item" effect="dark" :content="scope.row.name" placement="top">
<el-progress
:color="scope.row.percentage >= 100 ? '' : uploadProgressColor"
type="line"
:format="clearPercentage(scope.row)"
:stroke-width="40"
:text-inside="true"
:percentage="scope.row.percentage >= 100 ? 100 : scope.row.percentage"
></el-progress>
</el-tooltip>
</template>
</el-table-column>
<el-table-column
prop="size"
:width="100"
:label="$t('load_test.file_size')">
</el-table-column>
<el-table-column
prop="type"
:label="$t('load_test.file_type')">
</el-table-column>
<el-table-column
:width="200"
:label="$t('test_track.case.upload_time')">
<template v-slot:default="scope">
<i class="el-icon-time"/>
@ -23,18 +33,36 @@
</template>
</el-table-column>
<el-table-column
prop="status"
:width="70"
:label="$t('commons.status')">
<template v-slot:default="scope">
<span :class="scope.row.status === '完成' ? 'green' : scope.row.status === '失败' ? 'red' : ''">{{ scope.row.status | formatProgressPercentage}}</span>
</template>
</el-table-column>
<el-table-column
prop="creator"
:width="120"
:label="$t('group.operator')">
</el-table-column>
<el-table-column
:width="140"
:label="$t('commons.operating')">
<template v-slot:default="scope">
<el-button @click="preview(scope.row)" :disabled="!scope.row.id" type="primary"
v-if="isPreview(scope.row)"
icon="el-icon-view"
size="mini" circle/>
v-if="scope.row.percentage === 100 && isPreview(scope.row)"
icon="el-icon-view" size="mini" circle/>
<el-button @click="handleDownload(scope.row)" type="primary" :disabled="!scope.row.id"
icon="el-icon-download"
size="mini" circle/>
<el-button :disabled="readOnly || !isDelete" @click="handleDelete(scope.row, scope.$index)" type="danger"
v-if="scope.row.percentage === 100"
icon="el-icon-download" size="mini" circle/>
<el-button :disabled="readOnly || !isDelete || isCopy" @click="handleDelete(scope.row, scope.$index)" type="danger"
v-if="scope.row.percentage === 100"
icon="el-icon-delete" size="mini"
circle/>
<el-button :disabled="readOnly || !isDelete" @click="handleCancel(scope.row, scope.$index)" type="danger"
v-if="scope.row.percentage < 100"
icon="el-icon-close" size="mini"
circle/>
</template>
</el-table-column>
</el-table>
@ -62,13 +90,23 @@ export default {
type: Boolean,
default: false
},
isCopy: {
type: Boolean,
default: false
}
},
data() {
return {
uploadProgressColor: '#d4f6d4',
uploadSuccessColor: '#FFFFFF'
}
},
methods: {
clearPercentage(row) {
return () => {
return row.name;
}
},
preview(row) {
this.$refs.testCaseFile.open(row);
},
@ -82,7 +120,7 @@ export default {
id: file.id,
};
let config = {
url: '/test/case/file/download',
url: '/test/case/attachment/download',
method: 'post',
data: data,
responseType: 'blob'
@ -109,10 +147,43 @@ export default {
handleDelete(file, index) {
this.$emit("handleDelete", file, index);
},
handleCancel(file, index) {
this.$emit("handleCancel", file, index);
},
},
filters: {
formatProgressPercentage(percentage) {
if (isNaN(percentage)) {
return percentage
}
return Math.floor(percentage * 100 / 100) + "%";
}
}
}
</script>
<style scoped>
.el-progress-bar__innerText {
color: black;
}
::v-deep .el-progress-bar__outer,
::v-deep .el-progress-bar__inner {
border-radius: inherit ;
background-color: transparent;
}
::v-deep .el-progress-bar__innerText {
float: left;
color: #606266;
margin-top: 15px;
}
.green {
color: green;
}
.red {
color: red;
}
</style>

View File

@ -104,6 +104,7 @@
<test-case-edit-other-info :read-only="readOnly" :project-id="projectIds" :form="form"
:is-copy="currentTestCaseInfo.isCopy"
:copy-case-id="copyCaseId"
:label-width="formLabelWidth" :case-id="form.id"
:type="type" :comments.sync="comments"
@openComment="openComment"
@ -141,6 +142,7 @@
import {TokenKey} from '@/common/js/constants';
import MsDialogFooter from '../../../common/components/MsDialogFooter';
import {
byteToSize,
getCurrentProjectID,
getCurrentUser,
getNodePath,
@ -287,6 +289,7 @@ export default {
{value: 'manual', label: this.$t('test_track.case.manual')}
],
testCase: {},
copyCaseId: "",
showInputTag: true,
tableType: "",
stepFilter: new STEP,
@ -302,7 +305,7 @@ export default {
selectedOtherInfo: null,
currentProjectId: "",
casePublic: false,
isClickAttachmentTab: false,
isClickAttachmentTab: false
};
},
props: {
@ -599,10 +602,12 @@ export default {
if (testCase) {
//
this.operationType = 'edit';
this.copyCaseId = '';
//
if (this.type === 'copy') {
this.showInputTag = false;
this.operationType = 'add';
this.copyCaseId = testCase.copyId;
this.setFormData(testCase);
this.setTestCaseExtInfo(testCase);
this.getSelectOptions();
@ -623,6 +628,7 @@ export default {
}
}
let user = JSON.parse(localStorage.getItem(TokenKey));
this.copyCaseId = '';
this.form.priority = 'P3';
this.form.type = 'functional';
this.form.method = 'manual';
@ -776,6 +782,7 @@ export default {
Object.assign(param, this.form);
param.steps = JSON.stringify(this.form.steps);
param.nodeId = this.form.module;
param.copyCaseId = this.copyCaseId
if (!this.publicEnable) {
param.nodePath = getNodePath(this.form.module, this.moduleOptions);
if (this.projectId) {

View File

@ -55,29 +55,31 @@
<el-tab-pane :label="$t('test_track.case.attachment')" name="attachment">
<el-row>
<el-col :span="20" :offset="1">
<el-col :span="22">
<el-upload
accept=".jpg,.jpeg,.png,.xlsx,.doc,.pdf,.docx,.txt,.json,.jmx,.side"
action=""
accept=".jpg,.jpeg,.png,.xlsx,.doc,.pdf,.docx,.txt,.json,.jmx,.side,.mp4,.mov,.dcm,.zip,.rar"
action="#"
:show-file-list="false"
:before-upload="beforeUpload"
:http-request="handleUpload"
:on-exceed="handleExceed"
multiple
:limit="8"
:disabled="readOnly && !isTestPlanEdit"
:disabled="readOnly && isTestPlanEdit"
:file-list="fileList">
<el-button icon="el-icon-plus" :disabled="readOnly && !isTestPlanEdit" size="mini"></el-button>
<el-button :disabled="readOnly && isTestPlanEdit" 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>
</el-row>
<el-row>
<el-col :span="19" :offset="2">
<el-col :span="22">
<test-case-attachment :table-data="tableData"
:read-only="readOnly"
:is-copy="isCopy"
:is-delete="!isTestPlan"
@handleDelete="handleDelete"/>
@handleDelete="handleDelete"
@handleCancel="handleCancel"/>
</el-col>
</el-row>
</el-tab-pane>
@ -128,6 +130,8 @@ import TabPaneCount from "@/business/components/track/plan/view/comonents/report
import {getRelationshipCountCase} from "@/network/testCase";
import TestCaseComment from "@/business/components/track/case/components/TestCaseComment";
import ReviewCommentItem from "@/business/components/track/review/commom/ReviewCommentItem";
import {byteToSize} from "@/common/js/utils";
import {TokenKey} from "@/common/js/constants";
export default {
name: "TestCaseEditOtherInfo",
@ -139,7 +143,7 @@ export default {
ReviewCommentItem,
FormRichTextItem, TestCaseIssueRelate, TestCaseAttachment, MsRichText, TestCaseRichText
},
props: ['form', 'labelWidth', 'caseId', 'readOnly', 'projectId', 'isTestPlan', 'planId', 'versionEnable', 'isCopy', 'isTestPlanEdit',
props: ['form', 'labelWidth', 'caseId', 'readOnly', 'projectId', 'isTestPlan', 'planId', 'versionEnable', 'isCopy', 'copyCaseId', 'isTestPlanEdit',
'type', 'comments', 'isClickAttachmentTab',
'defaultOpen'
],
@ -159,6 +163,7 @@ export default {
//lazy: true,
//lazyLoad:this.lazyLoad
},
intervalMap: new Map()
};
},
computed: {
@ -236,15 +241,17 @@ export default {
return false;
}
let type = file.name.substring(file.name.lastIndexOf(".") + 1);
let user = JSON.parse(localStorage.getItem(TokenKey));
this.tableData.push({
name: file.name,
size: file.size + ' Bytes', /// todo: ByteKBMB
type: type.toUpperCase(),
size: byteToSize(file.size),
updateTime: new Date().getTime(),
percentage: 0,
status: 0,
creator: user.name
});
this.handleProcess(file);
return true;
},
handleUpload(uploadResources) {
@ -290,6 +297,17 @@ export default {
}
});
},
handleCancel(file, index) {
this.fileList.splice(index, 1);
let i = this.uploadList.findIndex(upLoadFile => upLoadFile.name === file.name);
if (i > -1) {
this.uploadList.splice(i, 1);
}
let cancelFile = this.tableData.filter(f => f.name === file.name)[0];
clearInterval(this.intervalMap.get(cancelFile.name));
cancelFile.percentage = 100;
cancelFile.status = this.$t('notice.result.EXECUTE_FAILED');
},
_handleDelete(file, index) {
this.fileList.splice(index, 1);
this.tableData.splice(index, 1);
@ -301,6 +319,21 @@ export default {
handleExceed() {
this.$error(this.$t('load_test.file_size_limit'));
},
handleProcess(file) {
let currentUploadFile = this.tableData.filter(f => f.name === file.name)[0];
const interval = setInterval(() => {
let randomNum = Math.floor(Math.random() * 10);
if (currentUploadFile.percentage + randomNum > 100) {
clearInterval(interval)
currentUploadFile.percentage = 100;
currentUploadFile.status = this.$t('notice.result.EXECUTE_COMPLETED')
return
}
currentUploadFile.percentage += randomNum;
currentUploadFile.status += randomNum;
}, file.size > 1024 * 1024 ? 200 : 100)
this.intervalMap.set(currentUploadFile.name, interval);
},
getFileMetaData(id) {
this.$emit("update:isClickAttachmentTab", true);
// id
@ -310,9 +343,14 @@ export default {
this.fileList = [];
this.tableData = [];
this.uploadList = [];
let testCaseId = id ? id : this.caseId;
let testCaseId;
if (this.isCopy) {
testCaseId = this.copyCaseId
} else {
testCaseId = id ? id : this.caseId;
}
if (testCaseId) {
this.result = this.$get("test/case/file/metadata/" + testCaseId, response => {
this.result = this.$get("test/case/file/attachmentMetadata/" + testCaseId, response => {
let files = response.data;
if (!files) {
@ -322,7 +360,9 @@ export default {
this.fileList = JSON.parse(JSON.stringify(files));
this.tableData = JSON.parse(JSON.stringify(files));
this.tableData.map(f => {
f.size = f.size + ' Bytes';
f.size = byteToSize(f.size);
f.status = this.$t('notice.result.EXECUTE_COMPLETED');
f.percentage = 100
});
});
}

View File

@ -1,7 +1,7 @@
<template>
<el-dialog :visible.sync="dialogVisible" width="80%" :destroy-on-close="true" :before-close="close" :append-to-body="true">
<div>
<img :src="'/test/case/file/preview/' + file.id" :alt="$t('test_track.case.img_loading_fail')" style="width: 100%;height: 100%;"
<img :src="'/test/case/attachment/preview/' + file.id" :alt="$t('test_track.case.img_loading_fail')" style="width: 100%;height: 100%;"
v-if="file.type === 'JPG' || file.type === 'JPEG' || file.type === 'PNG'">
<div v-if="file.type === 'PDF'">
<test-case-pdf :file-id="file.id"/>

View File

@ -900,6 +900,7 @@ export default {
let testCase = response.data;
testCase.name = 'copy_' + testCase.name;
//
testCase.copyId = testCase.id;
testCase.id = getUUID();
testCase.refId = null;
testCase.versionId = null;

View File

@ -21,7 +21,7 @@ export default {
},
mounted() {
this.loading = true;
this.loadingTask = pdf.createLoadingTask("/test/case/file/preview/" + this.fileId);
this.loadingTask = pdf.createLoadingTask("/test/case/attachment/preview/" + this.fileId);
this.loadingTask.promise.then(pdf => {
this.numPages = pdf.numPages
this.loading = false;

View File

@ -3,6 +3,7 @@
<el-scrollbar>
<el-form :model="form" :rules="rules" label-position="right" label-width="80px" ref="form">
<ms-form-divider :title="$t('test_track.plan_view.base_info')"/>
<el-form-item v-if="!enableThirdPartTemplate" :label="$t('commons.title')" prop="title">
<el-row>
<el-col :span="22">
@ -89,35 +90,87 @@
</el-col>
</el-row>
<el-form-item v-if="!isCaseEdit">
<test-case-issue-list :issues-id="form.id"
ref="testCaseIssueList"/>
</el-form-item>
<!-- <form-rich-text-item :title="$t('commons.remark')" :data="form" prop="remark"/>-->
<el-row style="margin-top: 10px" v-if="type!=='add'">
<el-col :span="20" :offset="1">{{ $t('test_track.review.comment') }}:
<el-button icon="el-icon-plus" type="mini" @click="openComment"></el-button>
<el-row class="other-info-rows" style="margin-top: 20px">
<el-col :span="2">
<ms-form-divider :title="$t('test_track.case.other_info')"/>
</el-col>
</el-row>
<el-row>
<el-col :span="20" :offset="1">
<el-col :span="22">
<el-tabs class="other-info-tabs" v-loading="result.loading" v-model="tabActiveName">
<el-tab-pane :label="$t('test_track.review_view.relevance_case')" name="relateTestCase">
<el-form-item v-if="!isCaseEdit" style="margin-left: -80px">
<test-case-issue-list :issues-id="form.id"
ref="testCaseIssueList"/>
</el-form-item>
</el-tab-pane>
<review-comment-item v-for="(comment,index) in comments"
:key="index"
:comment="comment"
@refresh="getComments" api-url="/issues"/>
<div v-if="comments.length === 0" style="text-align: center">
<i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;">
<el-tab-pane :label="$t('test_track.case.attachment')" name="attachment">
<el-row>
<el-col :span="22">
<el-upload
accept=".jpg,.jpeg,.png,.xlsx,.doc,.pdf,.docx,.txt,.json,.jmx,.side,.mp4,.mov,.dcm,.zip,.rar"
action="#"
:show-file-list="false"
:before-upload="beforeUpload"
:http-request="handleUpload"
:on-exceed="handleExceed"
multiple
:limit="8"
:file-list="fileList">
<el-button 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>
</el-row>
<el-row style="margin-top: 10px">
<el-col :span="22">
<test-case-attachment :table-data="tableData"
:read-only="readOnly"
:is-delete="isDelete"
:is-copy="type === 'copy'"
@handleDelete="handleDelete"
@handleCancel="handleCancel"/>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane :label="$t('test_track.review.comment')" name="comment">
<el-tooltip class="item-tabs" effect="dark" :content="$t('test_track.review.comment')" placement="top-start"
slot="label">
<span>
{{ $t('test_track.review.comment') }}
<div class="el-step__icon is-text ms-api-col ms-header" v-if="comments && comments.length>0">
<div class="el-step__icon-inner">{{ comments.length }}</div>
</div>
</span>
</el-tooltip>
<el-row style="margin-top: 10px" v-if="type!=='add'">
<el-col :span="20" :offset="1">{{ $t('test_track.review.comment') }}:
<el-button icon="el-icon-plus" type="mini" @click="openComment"></el-button>
</el-col>
</el-row>
<el-row style="margin-top: 10px">
<el-col :span="20" :offset="1">
<review-comment-item v-for="(comment,index) in comments"
:key="index"
:comment="comment"
@refresh="getComments" api-url="/issues"/>
<div v-if="comments.length === 0" style="text-align: center">
<i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;">
<span style="font-size: 15px; color: #8a8b8d;">
{{ $t('test_track.comment.no_comment') }}
</span>
</i>
</div>
</i>
</div>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
<!-- <form-rich-text-item :title="$t('commons.remark')" :data="form" prop="remark"/>-->
<issue-comment :issues-id="form.id"
@getComments="getComments"
ref="issueComment"/>
@ -139,13 +192,21 @@ import {buildCustomFields, parseCustomField} from "@/common/js/custom_field";
import CustomFiledComponent from "@/business/components/project/template/CustomFiledComponent";
import TestCaseIssueList from "@/business/components/track/issue/TestCaseIssueList";
import IssueEditDetail from "@/business/components/track/issue/IssueEditDetail";
import {getCurrentProjectID, getCurrentUser, getCurrentUserId, getCurrentWorkspaceId,} from "@/common/js/utils";
import {
byteToSize,
getCurrentProjectID,
getCurrentUser,
getCurrentUserId,
getCurrentWorkspaceId,
} from "@/common/js/utils";
import {enableThirdPartTemplate, getIssuePartTemplateWithProject, getPlatformTransitions} from "@/network/Issue";
import CustomFiledFormItem from "@/business/components/common/components/form/CustomFiledFormItem";
import MsMarkDownText from "@/business/components/track/case/components/MsMarkDownText";
import IssueComment from "@/business/components/track/issue/IssueComment";
import ReviewCommentItem from "@/business/components/track/review/commom/ReviewCommentItem";
import {JIRA} from "@/common/js/constants";
import {TokenKey} from "@/common/js/constants";
import {Message} from "element-ui";
import TestCaseAttachment from "@/business/components/track/case/components/TestCaseAttachment";
const {getIssuesById} = require("@/network/Issue");
@ -163,7 +224,8 @@ export default {
TemplateComponentEditHeader,
MsMarkDownText,
IssueComment,
ReviewCommentItem
ReviewCommentItem,
TestCaseAttachment
},
data() {
return {
@ -196,7 +258,8 @@ export default {
tapdUsers:[],
zentaoBuilds:[],
zentaoAssigned: '',
platformStatus: null
platformStatus: null,
copyIssueId: ''
},
tapdUsers: [],
zentaoUsers: [],
@ -241,7 +304,14 @@ export default {
preview: false, //
},
comments: [],
richTextDefaultOpen: 'preview'
richTextDefaultOpen: 'preview',
tabActiveName: 'relateTestCase',
uploadList: [],
fileList: [],
tableData: [],
readOnly: false,
isDelete: true,
intervalMap: new Map()
};
},
props: {
@ -368,6 +438,9 @@ export default {
}
},
initEdit(data) {
this.tableData = [];
this.fileList = [];
this.uploadList = [];
if (data) {
Object.assign(this.form, data);
if (!(data.options instanceof Array)) {
@ -383,6 +456,7 @@ export default {
this.form.creator = getCurrentUserId();
}
this.form.title = data.title + '_copy';
this.form.copyIssueId = data.copyIssueId;
}
} else {
this.form = {
@ -400,6 +474,11 @@ export default {
if (this.$refs.testCaseIssueList) {
this.$refs.testCaseIssueList.initTableData();
}
if (this.type === 'copy' && data.copyIssueId != null) {
this.getFileMetaData(data.copyIssueId);
} else if (this.type === 'edit' && data.id != null) {
this.getFileMetaData(data.id);
}
this.getComments();
});
},
@ -465,7 +544,8 @@ export default {
_save() {
let param = this.buildPram();
this.parseOldFields(param);
this.result = this.$post(this.url, param, (response) => {
let option = this.getOption(param);
this.result = this.$request(option, (response) => {
this.$emit('close');
this.$success(this.$t('commons.save_success'));
this.$emit('refresh', response.data);
@ -482,6 +562,39 @@ export default {
});
}
},
getOption(param) {
let formData = new FormData();
if (this.uploadList) {
this.uploadList.forEach(f => {
formData.append("file", f);
});
}
if (this.fileList) {
// copyID TODO
param.updatedFileList = this.fileList;
} else {
param.fileIds = [];
param.updatedFileList = [];
}
let requestJson = JSON.stringify(param, function (key, value) {
return key === "file" ? undefined : value
});
formData.append('request', new Blob([requestJson], {
type: "application/json"
}));
return {
method: 'POST',
url: this.url,
data: formData,
headers: {
'Content-Type': undefined
}
};
},
saveFollow(){
if(!this.form.follows){
this.form.follows = [];
@ -513,6 +626,139 @@ export default {
}
}
},
fileValidator(file) {
/// todo:
return file.size > 0;
},
beforeUpload(file) {
if (!this.fileValidator(file)) {
/// todo:
return false;
}
if (this.tableData.filter(f => f.name === file.name).length > 0) {
this.$error(this.$t('load_test.delete_file') + ', name: ' + file.name);
return false;
}
let user = JSON.parse(localStorage.getItem(TokenKey));
this.tableData.push({
name: file.name,
size: byteToSize(file.size),
updateTime: new Date().getTime(),
percentage: 0,
status: 0,
creator: user.name
});
this.handleProcess(file);
return true;
},
handleUpload(uploadResources) {
this.uploadList.push(uploadResources.file);
},
handleDownload(file) {
let data = {
name: file.name,
id: file.id,
};
let config = {
url: '/test/case/file/download',
method: 'post',
data: data,
responseType: 'blob'
};
this.result = this.$request(config).then(response => {
const content = response.data;
const blob = new Blob([content]);
if ("download" in document.createElement("a")) {
// IE
// chrome/firefox
let aTag = document.createElement('a');
aTag.download = file.name;
aTag.href = URL.createObjectURL(blob);
aTag.click();
URL.revokeObjectURL(aTag.href);
} else {
// IE10+
navigator.msSaveBlob(blob, this.filename);
}
}).catch(e => {
Message.error({message: e.message, showClose: true});
});
},
handleDelete(file, index) {
this.$alert(this.$t('load_test.delete_file_confirm') + file.name + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this._handleDelete(file, index);
}
}
});
},
handleCancel(file, index) {
this.fileList.splice(index, 1);
let i = this.uploadList.findIndex(upLoadFile => upLoadFile.name === file.name);
if (i > -1) {
this.uploadList.splice(i, 1);
}
let cancelFile = this.tableData.filter(f => f.name === file.name)[0];
clearInterval(this.intervalMap.get(cancelFile.name));
cancelFile.percentage = 100;
cancelFile.status = this.$t('notice.result.EXECUTE_FAILED');
},
_handleDelete(file, index) {
this.fileList.splice(index, 1);
this.tableData.splice(index, 1);
let i = this.uploadList.findIndex(upLoadFile => upLoadFile.name === file.name);
if (i > -1) {
this.uploadList.splice(i, 1);
}
},
handleExceed() {
this.$error(this.$t('load_test.file_size_limit'));
},
handleProcess(file) {
let currentUploadFile = this.tableData.filter(f => f.name === file.name)[0];
const interval = setInterval(() => {
let randomNum = Math.floor(Math.random() * 10);
if (currentUploadFile.percentage + randomNum > 100) {
clearInterval(interval)
currentUploadFile.percentage = 100;
currentUploadFile.status = this.$t('notice.result.EXECUTE_COMPLETED')
return
}
currentUploadFile.percentage += randomNum;
currentUploadFile.status += randomNum;
}, file.size > 1024 * 1024 ? 200 : 100)
this.intervalMap.set(currentUploadFile.name, interval);
},
getFileMetaData(id) {
// id
if (this.uploadList && this.uploadList.length > 0 && !id) {
return;
}
this.fileList = [];
this.tableData = [];
this.uploadList = [];
if (id) {
this.result = this.$get("issues/file/attachmentMetadata/" + id, response => {
let files = response.data;
if (!files) {
return;
}
// deep copy
this.fileList = JSON.parse(JSON.stringify(files));
this.tableData = JSON.parse(JSON.stringify(files));
this.tableData.map(f => {
f.size = byteToSize(f.size);
f.status = this.$t('notice.result.EXECUTE_COMPLETED');
f.percentage = 100
});
});
}
},
openComment() {
if (!this.issueId) {
this.$warning(this.$t('test_track.issue.save_before_open_comment'));
@ -532,6 +778,10 @@ export default {
</script>
<style scoped>
.other-info-tabs >>> .el-tabs__content {
padding: 20px 0px;
}
.top-input-class{
width: 100%;
}
@ -543,4 +793,13 @@ export default {
.custom-field-row {
padding-left: 18px;
}
.ms-header {
background: #783887;
color: white;
height: 18px;
width: 18px;
font-size: xx-small;
border-radius: 50%;
}
</style>

View File

@ -359,7 +359,8 @@ export default {
},
handleCopy(data) {
let copyData = {};
Object.assign(copyData, data);
Object.assign(copyData, data)
copyData.copyIssueId = copyData.id
copyData.id = null;
copyData.name = data.name + '_copy';
this.$refs.issueEdit.open(copyData, 'copy');

View File

@ -1,6 +1,6 @@
<template>
<div>
<el-button type="primary" @click="relateTestCase">{{$t('test_track.review_view.relevance_case')}}</el-button>
<el-button type="primary" size="small" @click="relateTestCase">{{$t('test_track.review_view.relevance_case')}}</el-button>
<ms-table
v-loading="result.loading"

View File

@ -577,3 +577,15 @@ function _resizeTextarea(i, size, textareaList) {
}
}
}
export function byteToSize(bytes) {
if (bytes === 0) {
return '0 B';
}
let k = 1024,
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
i = Math.floor(Math.log(bytes) / Math.log(k));
return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];
}

View File

@ -2146,7 +2146,8 @@ export default {
cancel_relevance_project: "Disassociating the project will also cancel the associated test cases under the project",
img_loading_fail: "Image failed to load",
pdf_loading_fail: "PDF loading failed",
upload_tip: "Only jpg, jpeg, png, docx, doc, pdf, xlsx, txt, json, jmx, side files can be uploaded",
upload_tip: "Only jpg, jpeg, png, docx, doc, pdf, xlsx, txt, json, jmx, side, mp4, mov, dcm, zip, rar files can be uploaded",
add_attachment: "Add Attachment",
attachment: "Attachment",
upload_time: "Upload Time",
total: "Total Case",

View File

@ -2143,7 +2143,8 @@ export default {
cancel_relevance_project: "取消项目关联会同时取消该项目下已关联的测试用例",
img_loading_fail: "图片加载失败",
pdf_loading_fail: "PDF加载失败",
upload_tip: "只能上传jpg、jpeg、png、docx、doc、pdf、xlsx、txt、json、jmx、side文件",
upload_tip: "只能上传jpg、jpeg、png、docx、doc、pdf、xlsx、txt、json、jmx、side、mp4、mov、dcm、zip、rar文件",
add_attachment: "添加附件",
attachment: "附件",
upload_time: "上传时间",
total: "用例总数",

View File

@ -2138,7 +2138,8 @@ export default {
cancel_relevance_project: "取消項目關聯會同時取消該項目下已關聯的測試用例",
img_loading_fail: "圖片加載失敗",
pdf_loading_fail: "PDF加載失敗",
upload_tip: "只能上傳jpg、jpeg、png、docx、doc、pdf、xlsx、txt、json、jmx、side文件",
upload_tip: "只能上傳jpg、jpeg、png、docx、doc、pdf、xlsx、txt、json、jmx、side、mp4、mov、dcm、zip、rar文件",
add_attachment: "添加附件",
attachment: "附件",
upload_time: "上傳時間",
total: "用例總數",