From 84137c73642c7d0c6317dc8125855c6da05426d6 Mon Sep 17 00:00:00 2001 From: song-cc-rock Date: Fri, 21 Jul 2023 11:59:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=B5=8B=E8=AF=95=E8=B7=9F=E8=B8=AA):=20?= =?UTF-8?q?=E9=9D=9EMS=E5=B9=B3=E5=8F=B0=E9=9B=86=E6=88=90=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=B9=B3=E5=8F=B0=E7=8A=B6=E6=80=81=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --story=1012478 --user=宋昌昌 与JIRA集成,在MS列表中导出缺陷时,希望能够支持导出“平台状态”字段 https://www.tapd.cn/55049933/s/1396115 --- .../excel/constants/IssueExportHeadField.java | 1 + .../excel/domain/IssueExcelData.java | 2 + .../excel/domain/IssueExcelDataTw.java | 4 +- .../IssueTemplateHeadWriteHandler.java | 45 ++++- .../excel/listener/IssueExcelListener.java | 174 +++++++++++++++--- .../io/metersphere/service/IssuesService.java | 131 +++++++++++-- .../resources/i18n/messages_en_US.properties | 7 +- .../resources/i18n/messages_zh_CN.properties | 7 +- .../resources/i18n/messages_zh_TW.properties | 7 +- .../frontend/src/business/TestTrack.vue | 2 +- .../export/IssueExportFieldSelect.vue | 40 +++- .../src/business/utils/track-table-header.js | 4 +- 12 files changed, 358 insertions(+), 66 deletions(-) diff --git a/test-track/backend/src/main/java/io/metersphere/excel/constants/IssueExportHeadField.java b/test-track/backend/src/main/java/io/metersphere/excel/constants/IssueExportHeadField.java index 5f1b21ffd3..e8e47286d0 100644 --- a/test-track/backend/src/main/java/io/metersphere/excel/constants/IssueExportHeadField.java +++ b/test-track/backend/src/main/java/io/metersphere/excel/constants/IssueExportHeadField.java @@ -20,6 +20,7 @@ public enum IssueExportHeadField { COMMENT("comment", Translator.get("comment"), IssueExcelData::getComment), RESOURCE("resource", Translator.get("issue_resource"), IssueExcelData::getResourceName), PLATFORM("platform", Translator.get("issue_platform"), IssueExcelData::getPlatform), + PLATFORM_STATUS("platformStatus", Translator.get("platform_status"), IssueExcelData::getPlatformStatus), CREATE_TIME("createTime", Translator.get("create_time"), issueExcelData -> issueExcelData.getCreateTime() != null ? DateUtils.getTimeStr(issueExcelData.getCreateTime()) : null); private String id; diff --git a/test-track/backend/src/main/java/io/metersphere/excel/domain/IssueExcelData.java b/test-track/backend/src/main/java/io/metersphere/excel/domain/IssueExcelData.java index adaa61ee12..674f840759 100644 --- a/test-track/backend/src/main/java/io/metersphere/excel/domain/IssueExcelData.java +++ b/test-track/backend/src/main/java/io/metersphere/excel/domain/IssueExcelData.java @@ -66,6 +66,8 @@ public class IssueExcelData implements Serializable { private String priority; @ExcelIgnore Map customData = new LinkedHashMap<>(); + @ExcelIgnore + List tapdUsers = new ArrayList<>(); public List> getHead(Boolean isThirdTemplate, List customFields, IssueExportRequest request) { return new ArrayList<>(); diff --git a/test-track/backend/src/main/java/io/metersphere/excel/domain/IssueExcelDataTw.java b/test-track/backend/src/main/java/io/metersphere/excel/domain/IssueExcelDataTw.java index c5b98ce0b7..da2d745665 100644 --- a/test-track/backend/src/main/java/io/metersphere/excel/domain/IssueExcelDataTw.java +++ b/test-track/backend/src/main/java/io/metersphere/excel/domain/IssueExcelDataTw.java @@ -4,10 +4,10 @@ import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import io.metersphere.dto.CustomFieldDao; import io.metersphere.request.issues.IssueExportRequest; +import jakarta.validation.constraints.NotBlank; import lombok.Data; import org.hibernate.validator.constraints.Length; -import jakarta.validation.constraints.NotBlank; import java.util.List; import java.util.Locale; @@ -23,7 +23,7 @@ public class IssueExcelDataTw extends IssueExcelData{ @NotBlank(message = "{cannot_be_null}") @Length(max = 1000) @ColumnWidth(100) - @ExcelProperty("缺陷内容") + @ExcelProperty("缺陷描述") private String description; @Override diff --git a/test-track/backend/src/main/java/io/metersphere/excel/handler/IssueTemplateHeadWriteHandler.java b/test-track/backend/src/main/java/io/metersphere/excel/handler/IssueTemplateHeadWriteHandler.java index 93a164ce65..13ca593322 100644 --- a/test-track/backend/src/main/java/io/metersphere/excel/handler/IssueTemplateHeadWriteHandler.java +++ b/test-track/backend/src/main/java/io/metersphere/excel/handler/IssueTemplateHeadWriteHandler.java @@ -1,9 +1,16 @@ package io.metersphere.excel.handler; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.data.DataFormatData; +import com.alibaba.excel.metadata.data.WriteCellData; import com.alibaba.excel.util.BooleanUtils; +import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.handler.RowWriteHandler; import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.handler.context.RowWriteHandlerContext; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; import io.metersphere.commons.constants.CustomFieldScene; import io.metersphere.commons.constants.CustomFieldType; import io.metersphere.commons.utils.JSON; @@ -12,25 +19,23 @@ import io.metersphere.dto.CustomFieldOptionDTO; import io.metersphere.excel.constants.IssueExportHeadField; import io.metersphere.i18n.Translator; import org.apache.commons.lang3.StringUtils; -import org.apache.poi.ss.usermodel.Comment; -import org.apache.poi.ss.usermodel.Drawing; -import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFRichTextString; import org.jetbrains.annotations.NotNull; import java.util.*; -import java.util.stream.Collectors; /** * 表头, 单元格后置处理 */ -public class IssueTemplateHeadWriteHandler implements RowWriteHandler, SheetWriteHandler { +public class IssueTemplateHeadWriteHandler implements RowWriteHandler, SheetWriteHandler, CellWriteHandler { private Sheet sheet; private Drawing drawingPatriarch; private Map memberMap; private Map headCommentIndexMap = new HashMap<>(); + private Map dateFieldIndexMap = new HashMap<>(); public IssueTemplateHeadWriteHandler(Map memberMap, List> headList, List customFields) { this.memberMap = memberMap; @@ -56,7 +61,7 @@ public class IssueTemplateHeadWriteHandler implements RowWriteHandler, SheetWrit customFieldDao.setType(CustomFieldType.MEMBER.getValue()); } else { // 自定义字段 - List fields = customFields.stream().filter(field -> StringUtils.equals(field.getName(), head)).collect(Collectors.toList()); + List fields = customFields.stream().filter(field -> StringUtils.equals(field.getName(), head)).toList(); if (fields.size() > 0) { customFieldDao = fields.get(0); } else { @@ -79,6 +84,18 @@ public class IssueTemplateHeadWriteHandler implements RowWriteHandler, SheetWrit } } + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + Workbook workbook = writeSheetHolder.getSheet().getWorkbook(); + DataFormat dataFormat = workbook.createDataFormat(); + for (WriteCellData writeCellData : cellDataList) { + WriteCellStyle writeCellStyle = writeCellData.getOrCreateStyle(); + DataFormatData dataFormatData = new DataFormatData(); + dataFormatData.setIndex(dataFormat.getFormat("@")); + writeCellStyle.setDataFormatData(dataFormatData); + } + } + private String getCommentByCustomField(CustomFieldDao field) { String commentText = ""; if (StringUtils.equalsAnyIgnoreCase(field.getType(), @@ -86,6 +103,8 @@ public class IssueTemplateHeadWriteHandler implements RowWriteHandler, SheetWrit if (StringUtils.equalsAnyIgnoreCase(field.getScene(), CustomFieldScene.ISSUE.name()) && StringUtils.equalsAnyIgnoreCase(field.getName(), "状态", "严重程度")) { commentText = Translator.get("options").concat(JSON.toJSONString(getOptionValues(field))); + } else if (StringUtils.equalsAnyIgnoreCase(field.getName(), Translator.get("platform_status"))) { + commentText = Translator.get("options").concat(JSON.toJSONString(getOptionsLabel(field.getOptions()))); } else { commentText = Translator.get("options").concat(JSON.toJSONString(getOptionsText(field.getOptions()))); } @@ -159,6 +178,20 @@ public class IssueTemplateHeadWriteHandler implements RowWriteHandler, SheetWrit return options; } + private List getOptionsLabel(String optionStr) { + if (StringUtils.isEmpty(optionStr)) { + return Collections.emptyList(); + } + + List options = new ArrayList<>(); + List optionMapList = JSON.parseArray(optionStr, Map.class); + optionMapList.forEach(optionMap -> { + String optionText = optionMap.get("label").toString(); + options.add(optionText); + }); + return options; + } + private List getCascadSelect(String optionStr) { if (StringUtils.isEmpty(optionStr)) { return Collections.emptyList(); diff --git a/test-track/backend/src/main/java/io/metersphere/excel/listener/IssueExcelListener.java b/test-track/backend/src/main/java/io/metersphere/excel/listener/IssueExcelListener.java index 5d548fe309..40150981f9 100644 --- a/test-track/backend/src/main/java/io/metersphere/excel/listener/IssueExcelListener.java +++ b/test-track/backend/src/main/java/io/metersphere/excel/listener/IssueExcelListener.java @@ -22,6 +22,7 @@ import io.metersphere.excel.utils.ExcelValidateHelper; import io.metersphere.i18n.Translator; import io.metersphere.request.issues.IssueImportRequest; import io.metersphere.service.IssuesService; +import io.metersphere.xpack.track.dto.PlatformStatusDTO; import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; @@ -40,6 +41,18 @@ import java.util.stream.Collectors; public class IssueExcelListener extends AnalysisEventListener> { + /** + * dataClass: EXCEL数据实例class + * request: 导入参数 + * isThirdPlatform: 是否是第三方平台 + * headMap: excel表头字段集合 + * customFields: 自定义字段集合(模板自定义字段 + 平台自定义字段) + * issuesService: 业务类 + * memberMap: 成员集合 + * platformStatusList: 平台状态列表 + * excelHeadFieldMap: excel表头字段字典值 + * issueCustomFieldMap: 缺陷自定义字段KeyMap + */ private Class dataClass; private IssueImportRequest request; private Boolean isThirdPlatform; @@ -47,9 +60,8 @@ public class IssueExcelListener extends AnalysisEventListener customFields; private IssuesService issuesService; private Map memberMap; - /** - * excel表头字段字典值 - */ + private List platformStatusList; + private List tapdUsers; private Map headFieldTransferDic = new HashMap<>(); private Map> issueCustomFieldMap = new HashMap<>(); @@ -61,19 +73,21 @@ public class IssueExcelListener extends AnalysisEventListener insertList = new ArrayList<>(); protected List updateList = new ArrayList<>(); protected List> errList = new ArrayList<>(); - public IssueExcelListener(IssueImportRequest request, Class clazz, Boolean isThirdPlatform, List customFields, Map memberMap) { + public IssueExcelListener(IssueImportRequest request, Class clazz, Boolean isThirdPlatform, List customFields, Map memberMap, List platformStatusList, List tapdUsers) { this.request = request; this.dataClass = clazz; this.isThirdPlatform = isThirdPlatform; this.customFields = customFields; this.issuesService = CommonBeanFactory.getBean(IssuesService.class); this.memberMap = memberMap; + this.platformStatusList = platformStatusList; + this.tapdUsers = tapdUsers; } @Override @@ -85,9 +99,11 @@ public class IssueExcelListener extends AnalysisEventListener> customFieldMap = customFields.stream().collect(Collectors.groupingBy(CustomFieldDao::getName)); data.getCustomData().forEach((k, v) -> { @@ -210,6 +237,45 @@ public class IssueExcelListener extends AnalysisEventListener first = platformStatusList.stream().filter(status -> StringUtils.equals(status.getLabel(), platformStatus)).findFirst(); + if (first.isPresent()) { + data.setPlatformStatus(first.get().getValue()); + } else { + errMsg.append(IssueExportHeadField.PLATFORM_STATUS.getName()).append(Translator.get("options_not_exist")).append(";"); + } + } + } + + /** + * 校验TAPD处理人 + * @param data excel数据 + * @param errMsg 错误信息 + */ + public void validateTapdUsers(IssueExcelData data, StringBuilder errMsg) { + List tarTapdUsers = data.getTapdUsers(); + if (CollectionUtils.isNotEmpty(tarTapdUsers) && CollectionUtils.isNotEmpty(tapdUsers)) { + tarTapdUsers.forEach(tapdUser -> { + Optional first = tapdUsers.stream().filter(user -> StringUtils.equals(user, tapdUser)).findFirst(); + if (first.isEmpty()) { + errMsg.append(Translator.get("tapd_user")).append(Translator.get("options_not_exist")).append(";"); + } + }); + } + } + + /** + * 解析表格数据 -> excel数据 + * @param rowData 表格数据 + * @return excel数据 + */ private IssueExcelData parseDataToModel(Map rowData) { IssueExcelData data = new IssueExcelDataFactory().getIssueExcelDataLocal(); for (Map.Entry headEntry : headMap.entrySet()) { @@ -226,16 +292,28 @@ public class IssueExcelListener extends AnalysisEventListener dataList = Arrays.asList(org.springframework.util.StringUtils.trimAllWhitespace(value).split(",")); + List dataList = Arrays.stream(value.split(",")).map(String::trim).toList(); List formatDataList = dataList.stream().map(item -> "\"" + item + "\"").collect(Collectors.toList()); data.getCustomData().put(field, formatDataList); } else if (StringUtils.isNotEmpty(value) && (value.contains(";"))){ // 分号分隔 - List dataList = Arrays.asList(org.springframework.util.StringUtils.trimAllWhitespace(value).split(";")); + List dataList = Arrays.stream(value.split(";")).map(String::trim).toList(); List formatDataList = dataList.stream().map(item -> "\"" + item + "\"").collect(Collectors.toList()); data.getCustomData().put(field, formatDataList); } else { @@ -246,13 +324,20 @@ public class IssueExcelListener extends AnalysisEventListener issue请求数据 + * @param issueExcelData excel数据 + * @return issue请求数据 + */ private IssuesUpdateRequest convertToIssue(IssueExcelData issueExcelData) { IssuesUpdateRequest issuesUpdateRequest = new IssuesUpdateRequest(); + issuesUpdateRequest.setTapdUsers(issueExcelData.getTapdUsers()); issuesUpdateRequest.setWorkspaceId(request.getWorkspaceId()); issuesUpdateRequest.setProjectId(request.getProjectId()); issuesUpdateRequest.setThirdPartPlatform(isThirdPlatform); issuesUpdateRequest.setDescription(issueExcelData.getDescription()); issuesUpdateRequest.setTitle(issueExcelData.getTitle()); + issuesUpdateRequest.setPlatformStatus(issueExcelData.getPlatformStatus()); if (BooleanUtils.isTrue(issueExcelData.getAddFlag())) { issuesUpdateRequest.setCreator(SessionUtils.getUserId()); } else { @@ -285,10 +370,21 @@ public class IssueExcelListener extends AnalysisEventListener isInclude = new AtomicReference<>(Boolean.TRUE); if (value instanceof List) { @@ -443,11 +551,16 @@ public class IssueExcelListener extends AnalysisEventListener 值) + * @param options 选项 + * @param tarVal 文本 + * @return 值 + */ public String parseOptionText(String options, String tarVal) { if (StringUtils.isEmpty(options)) { return StringUtils.EMPTY; @@ -475,18 +594,23 @@ public class IssueExcelListener extends AnalysisEventListener 值) + * @param cascadingOption 级联选项 + * @param tarVal 文本 + * @return 值 + */ public String parseCascadingOptionText(String cascadingOption, String tarVal) { List values = new ArrayList<>(); if (StringUtils.isEmpty(cascadingOption)) { @@ -510,6 +634,12 @@ public class IssueExcelListener extends AnalysisEventListener userMap = baseUserService.getProjectMemberOption(projectId).stream().collect(Collectors.toMap(User::getId, User::getName)); + // 获取第三方平台自定义字段 + List pluginCustomFields = getPluginCustomFields(projectId); // 获取缺陷模板及自定义字段 IssueTemplateDao issueTemplate = getIssueTemplateByProjectId(projectId); List customFields = Optional.ofNullable(issueTemplate.getCustomFields()).orElse(new ArrayList<>()); + customFields.addAll(pluginCustomFields); + // TAPD暂时未拆分插件, 插件字段手动获取 + if (StringUtils.equals(issueTemplate.getPlatform(), IssuesManagePlatform.Tapd.name())) { + customFields.add(buildTapdUserCustomField(projectId)); + } // 根据自定义字段获取表头 List> heads = new IssueExcelDataFactory().getIssueExcelDataLocal().getHead(issueTemplate.getIsThirdTemplate(), customFields, null); // 导出空模板, heads->表头, headHandler->表头处理 - IssueTemplateHeadWriteHandler headHandler = new IssueTemplateHeadWriteHandler(userMap, heads, issueTemplate.getCustomFields()); + IssueTemplateHeadWriteHandler headHandler = new IssueTemplateHeadWriteHandler(userMap, heads, customFields); new EasyExcelExporter(new IssueExcelDataFactory().getExcelDataByLocal()) .exportByCustomWriteHandler(response, heads, null, Translator.get("issue_import_template_name"), Translator.get("issue_import_template_sheet"), headHandler); @@ -1687,10 +1691,23 @@ public class IssuesService { IssueTemplateDao issueTemplate = getIssueTemplateByProjectId(request.getProjectId()); List customFields = Optional.ofNullable(issueTemplate.getCustomFields()).orElse(new ArrayList<>()); customFields.addAll(pluginCustomFields); + // 非Local平台需要解析平台状态字段 + List platformStatus = new ArrayList<>(); + if (!IssuesManagePlatform.Local.equals(issueTemplate.getPlatform())) { + CustomFieldDao customFieldDao = buildPlatformStatusCustomField(request.getWorkspaceId(), request.getProjectId()); + platformStatus = JSON.parseArray(customFieldDao.getOptions(), PlatformStatusDTO.class); + } + // TAPD暂时未拆分插件, 插件字段手动获取 + List tapdUsers = new ArrayList<>(); + if (StringUtils.equals(issueTemplate.getPlatform(), IssuesManagePlatform.Tapd.name())) { + CustomFieldDao tapdField = buildTapdUserCustomField(request.getProjectId()); + List jsonObjects = JSON.parseArray(tapdField.getOptions(), JSONObject.class); + tapdUsers = jsonObjects.stream().map(item -> item.getString("value")).collect(Collectors.toList()); + } // 获取本地EXCEL数据对象 Class clazz = new IssueExcelDataFactory().getExcelDataByLocal(); // IssueExcelListener读取file内容 - IssueExcelListener issueExcelListener = new IssueExcelListener(request, clazz, issueTemplate.getIsThirdTemplate(), customFields, userMap); + IssueExcelListener issueExcelListener = new IssueExcelListener(request, clazz, issueTemplate.getIsThirdTemplate(), customFields, userMap, platformStatus, tapdUsers); try { EasyExcelFactory.read(importFile.getInputStream(), issueExcelListener).sheet().doRead(); } catch (IOException e) { @@ -1718,6 +1735,17 @@ public class IssuesService { IssueTemplateDao issueTemplate = getIssueTemplateByProjectId(request.getProjectId()); List customFields = Optional.ofNullable(issueTemplate.getCustomFields()).orElse(new ArrayList<>()); customFields.addAll(pluginCustomFields); + // 非Local平台需要展示平台状态字段 + List platformStatus = new ArrayList<>(); + if (!IssuesManagePlatform.Local.equals(issueTemplate.getPlatform())) { + CustomFieldDao customFieldDao = buildPlatformStatusCustomField(request.getWorkspaceId(), request.getProjectId()); + customFields.add(customFieldDao); + platformStatus = JSON.parseArray(customFieldDao.getOptions(), PlatformStatusDTO.class); + } + // TAPD暂时未拆分插件, 插件字段手动获取 + if (StringUtils.equals(issueTemplate.getPlatform(), IssuesManagePlatform.Tapd.name())) { + customFields.add(buildTapdUserCustomField(request.getProjectId())); + } // 根据自定义字段获取表头内容 List> heads = new IssueExcelDataFactory().getIssueExcelDataLocal().getHead(issueTemplate.getIsThirdTemplate(), customFields, request); // 获取导出缺陷列表 @@ -1725,9 +1753,9 @@ public class IssuesService { // 解析issue对象数据->excel对象数据 List excelDataList = parseIssueDataToExcelData(exportIssues); // 解析excel对象数据->excel列表数据 - List> data = parseExcelDataToList(heads, excelDataList); + List> data = parseExcelDataToList(heads, excelDataList, platformStatus); // 导出EXCEL - IssueTemplateHeadWriteHandler headHandler = new IssueTemplateHeadWriteHandler(userMap, heads, issueTemplate.getCustomFields()); + IssueTemplateHeadWriteHandler headHandler = new IssueTemplateHeadWriteHandler(userMap, heads, customFields); // heads-> 表头内容, data -> 导出EXCEL列表数据, headHandler -> 表头处理 new EasyExcelExporter(new IssueExcelDataFactory().getExcelDataByLocal()) .exportByCustomWriteHandler(response, heads, data, Translator.get("issue_list_export_excel"), @@ -1786,6 +1814,11 @@ public class IssuesService { List comments = commentDTOList.stream().map(IssueCommentDTO::getDescription).collect(Collectors.toList()); item.setComment(StringUtils.join(comments, ";")); } + + // TAPD平台需展示TAPD处理人 + if (IssuesManagePlatform.Tapd.name().equals(item.getPlatform())) { + item.setTapdUsers(getTapdIssueCurrentOwner(item.getId())); + } }); // 解析自定义字段 buildCustomField(issues, isThirdTemplate, customFields); @@ -1814,7 +1847,7 @@ public class IssuesService { } } - private List> parseExcelDataToList(List> heads, List excelDataList) { + private List> parseExcelDataToList(List> heads, List excelDataList, List platformStatus) { List> result = new ArrayList<>(); IssueExportHeadField[] exportHeadFields = IssueExportHeadField.values(); //转化excel头 @@ -1832,12 +1865,26 @@ public class IssuesService { boolean isSystemField = false; for (IssueExportHeadField exportHeadField : exportHeadFields) { if (StringUtils.equals(head, exportHeadField.getName())) { - rowData.add(exportHeadField.parseExcelDataValue(data)); + if (StringUtils.equals(head, IssueExportHeadField.PLATFORM_STATUS.getName())) { + String platformVal = exportHeadField.parseExcelDataValue(data); + Optional first = platformStatus.stream().filter(status -> StringUtils.equals(status.getValue(), platformVal)).findFirst(); + if (first.isPresent()) { + rowData.add(first.get().getLabel()); + } else { + rowData.add(StringUtils.EMPTY); + } + } else { + rowData.add(exportHeadField.parseExcelDataValue(data)); + } isSystemField = true; break; } } if (!isSystemField) { + if (StringUtils.equals(head, Translator.get("tapd_user"))) { + rowData.add(Joiner.on(";").join(data.getTapdUsers())); + continue; + } // 自定义字段 Object value = customData.get(head); if (value == null || StringUtils.equals(value.toString(), "null")) { @@ -1925,27 +1972,36 @@ public class IssuesService { } private String parseOptionValue(String options, String tarVal) { - if (StringUtils.isEmpty(options) || StringUtils.isEmpty(tarVal)) { + if (StringUtils.isEmpty(options) || StringUtils.isEmpty(tarVal) || StringUtils.equalsAny(tarVal, "null", "[]")) { return StringUtils.EMPTY; } + List tarVals = new ArrayList<>(); + List vals = JSON.parseArray(tarVal, String.class); List optionList = JSON.parseArray(options, Map.class); for (Map option : optionList) { String text = option.get("text").toString(); String value = option.get("value").toString(); - if (StringUtils.containsIgnoreCase(tarVal, value)) { - tarVal = tarVal.replaceAll(value, text); - } + vals.forEach(val -> { + if (StringUtils.equals(val, value)) { + tarVals.add(text); + } + }); } - return tarVal; + return tarVals.toString(); } public String parseCascadingOptionValue(String cascadingOption, String tarVal) { List values = new ArrayList<>(); - if (StringUtils.isEmpty(cascadingOption)) { + if (StringUtils.isEmpty(cascadingOption) || StringUtils.isEmpty(tarVal) || StringUtils.equalsAny(tarVal, "null", "[]")) { return StringUtils.EMPTY; } JSONArray options = JSONArray.parseArray(cascadingOption); - JSONArray talVals = JSONArray.parseArray(tarVal); + JSONArray talVals = new JSONArray(); + if (tarVal.contains("[") || tarVal.contains("]")) { + talVals = JSONArray.parseArray(tarVal); + } else { + talVals = JSONArray.parseArray("[" + tarVal + "]"); + } if (options.size() == 0 || talVals.size() == 0) { return StringUtils.EMPTY; } @@ -2086,6 +2142,43 @@ public class IssuesService { return tapdUsers; } + public CustomFieldDao buildPlatformStatusCustomField(String workspaceId, String projectId) { + PlatformIssueTypeRequest platformIssueTypeRequest = new PlatformIssueTypeRequest(); + platformIssueTypeRequest.setWorkspaceId(workspaceId); + platformIssueTypeRequest.setProjectId(projectId); + List platformStatus = issuesService.getPlatformStatus(platformIssueTypeRequest); + CustomFieldDao customFieldDao = new CustomFieldDao(); + customFieldDao.setName(Translator.get("platform_status")); + customFieldDao.setRequired(false); + customFieldDao.setType(CustomFieldType.SELECT.getValue()); + customFieldDao.setOptions(JSON.toJSONString(platformStatus)); + return customFieldDao; + } + + public CustomFieldDao buildTapdUserCustomField(String projectId) { + Project project = projectMapper.selectByPrimaryKey(projectId); + IssuesRequest request = new IssuesRequest(); + request.setProjectId(projectId); + request.setWorkspaceId(project.getWorkspaceId()); + List> tapdUsers = new ArrayList<>(); + List tapdProjectUsers = getTapdProjectUsers(request); + if (CollectionUtils.isNotEmpty(tapdProjectUsers)) { + tapdProjectUsers.forEach(tapdUser -> { + Map user = new HashMap<>(); + user.put("text", tapdUser.getUser()); + user.put("value", tapdUser.getUser()); + tapdUsers.add(user); + }); + } + CustomFieldDao customFieldDao = new CustomFieldDao(); + customFieldDao.setId(Translator.get("tapd_user")); + customFieldDao.setName(Translator.get("tapd_user")); + customFieldDao.setRequired(false); + customFieldDao.setType(CustomFieldType.MULTIPLE_SELECT.getValue()); + customFieldDao.setOptions(JSON.toJSONString(tapdUsers)); + return customFieldDao; + } + @MsAuditLog(module = OperLogModule.TRACK_TEST_CASE, type = OperLogConstants.ASSOCIATE_ISSUE, content = "#msClass.getIssueLogDetails(#caseId, #refId, #issuesId)", msClass = TestCaseIssueService.class) public void insertIssueRelateLog(String issuesId, String caseId, String refId, String refType) { testCaseIssueService.add(issuesId, caseId, refId, refType); diff --git a/test-track/backend/src/main/resources/i18n/messages_en_US.properties b/test-track/backend/src/main/resources/i18n/messages_en_US.properties index 722d59f997..23d0314dc2 100644 --- a/test-track/backend/src/main/resources/i18n/messages_en_US.properties +++ b/test-track/backend/src/main/resources/i18n/messages_en_US.properties @@ -46,8 +46,8 @@ issue_import_template_name=Issue_Template issue_import_template_sheet=Template issue_list_export_excel=Issue_Data_Export issue_list_export_excel_sheet=Data -date_import_cell_format_comment=The date cell format is YYYY/MM/DD (1999/10/01) -datetime_import_cell_format_comment=The date and time cell format is YYYY/MM/DD HH:MM:SS (1999/10/01 10:01:01) +date_import_cell_format_comment=The date cell format is YYYY-MM-DD (1999-10-01) +datetime_import_cell_format_comment=The date and time cell format is YYYY-MM-DD HH:MM:SS (1999-10-01 01:01:01) int_import_cell_format_comment=cell format: 100001 float_import_cell_format_comment=cell format: 24 multiple_input_import_cell_format_comment=This field has multiple values. Separate multiple values with commas or semicolons @@ -55,17 +55,20 @@ cascading_select_import_cell_format_comment=This cell is a cascade selection. Pl options_tips=(format{key:value}, please fill in the corresponding value)Option value: options_key_tips=(format{key:value},please fill in the corresponding key)Option value: # issue import and issue export +id=Issue ID title==Title description=Description case_count=Case count comment=Comment issue_resource=Issue resource issue_platform=Issue platform +platform_status=Platform status create_time=CreateTime can_not_be_null=Can not be null excel_field_not_exist=Not exist options_not_exist=Incorrect option value format_error=Format error +tapd_user=Tapd User # issue status new=new resolved=resolved diff --git a/test-track/backend/src/main/resources/i18n/messages_zh_CN.properties b/test-track/backend/src/main/resources/i18n/messages_zh_CN.properties index 27ebcd6fae..84ed79ba65 100644 --- a/test-track/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/test-track/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -23,8 +23,8 @@ issue_import_template_name=缺陷模版 issue_import_template_sheet=模版 issue_list_export_excel=缺陷数据导出 issue_list_export_excel_sheet=数据 -date_import_cell_format_comment=日期类型单元格格式为: YYYY/MM/DD (1999/10/01) -datetime_import_cell_format_comment=日期时间类型单元格格式为: YYYY/MM/DD HH:MM:SS (1999/10/01 10:01:01) +date_import_cell_format_comment=日期类型单元格格式为: YYYY-MM-DD (1999-10-01) +datetime_import_cell_format_comment=日期时间类型单元格格式为: YYYY-MM-DD HH:MM:SS (1999-10-01 01:01:01) int_import_cell_format_comment=整型单元格格式为: 100001 float_import_cell_format_comment=浮点单元格格式为: 24 multiple_input_import_cell_format_comment=该单元格可输入多个值,多个值请用逗号或分号隔开(v1;v2) @@ -32,17 +32,20 @@ cascading_select_import_cell_format_comment=该单元格为级联选择,选择 options_tips=(格式{key:value},请填写对应的value)选项: options_key_tips=(格式{key:value},请填写对应的key)选项: # issue import and issue export +id=缺陷ID title=缺陷标题 description=缺陷描述 case_count=用例数 comment=评论 issue_resource=缺陷来源 issue_platform=缺陷平台 +platform_status=平台状态 create_time=创建时间 can_not_be_null=不能为空 excel_field_not_exist=不存在该字段 options_not_exist=选项值有误 format_error=格式有误 +tapd_user=Tapd 处理人 # issue status new=新建 resolved=已解决 diff --git a/test-track/backend/src/main/resources/i18n/messages_zh_TW.properties b/test-track/backend/src/main/resources/i18n/messages_zh_TW.properties index 8430fcec3c..90c97dc97d 100644 --- a/test-track/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/test-track/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -23,8 +23,8 @@ issue_import_template_name=缺陷模版 issue_import_template_sheet=模版 issue_list_export_excel=缺陷數據導出 issue_list_export_excel_sheet=數據 -date_import_cell_format_comment=日期單元格格式爲: YYYY/MM/DD (1999/10/01) -datetime_import_cell_format_comment=日期時間單元格格式爲: YYYY/MM/DD HH:MM:SS (1999/10/01 10:01:01) +date_import_cell_format_comment=日期單元格格式爲: YYYY-MM-DD (1999-10-01) +datetime_import_cell_format_comment=日期時間單元格格式爲: YYYY-MM-DD HH:MM:SS (1999-10-01 01:01:01) int_import_cell_format_comment=單元格格式: 100001 float_import_cell_format_comment=單元格格式: 24 multiple_input_import_cell_format_comment=該單元格可輸入多個值,多個值請用逗號或分號隔開(v1;v2) @@ -32,17 +32,20 @@ cascading_select_import_cell_format_comment=該單元格爲級聯選擇,選擇 options_tips=(格式{key:value},請填寫對應value)選項: options_key_tips=(格式{key:value},請填寫對應key)選項: # issue import and issue export +id=缺陷ID title=缺陷標題 description=缺陷描述 case_count=用例數 comment=評論 issue_resource=缺陷來源 issue_platform=缺陷平臺 +platform_status=平台狀態 create_time=創建時間 can_not_be_null=不能爲空 excel_field_not_exist=不存在該字段 options_not_exist=選項值有誤 format_error=格式有誤 +tapd_user=Tapd 處理人 #issue status new=新建 resolved=已解決 diff --git a/test-track/frontend/src/business/TestTrack.vue b/test-track/frontend/src/business/TestTrack.vue index 7bde7f4352..a21749bbcc 100644 --- a/test-track/frontend/src/business/TestTrack.vue +++ b/test-track/frontend/src/business/TestTrack.vue @@ -385,6 +385,6 @@ span.ms-top.el-tag.el-tag--info.el-tag--small.el-tag--light span { .el-select__tags .el-tag .el-tag__close.el-icon-close::before { font-size: 24px; position: relative; - top: 9px; + top: -2px; } diff --git a/test-track/frontend/src/business/issue/components/export/IssueExportFieldSelect.vue b/test-track/frontend/src/business/issue/components/export/IssueExportFieldSelect.vue index 528903fe97..de9fc80e66 100644 --- a/test-track/frontend/src/business/issue/components/export/IssueExportFieldSelect.vue +++ b/test-track/frontend/src/business/issue/components/export/IssueExportFieldSelect.vue @@ -50,7 +50,8 @@