diff --git a/backend/src/main/java/io/metersphere/commons/constants/CustomFieldType.java b/backend/src/main/java/io/metersphere/commons/constants/CustomFieldType.java new file mode 100644 index 0000000000..080c65e286 --- /dev/null +++ b/backend/src/main/java/io/metersphere/commons/constants/CustomFieldType.java @@ -0,0 +1,21 @@ +package io.metersphere.commons.constants; + +public enum CustomFieldType { + INPUT("input"),TEXTAREA("textarea"), + SELECT("select"),MULTIPLE_SELECT("multipleSelect"), + RADIO("radio"),CHECKBOX("checkbox"), + MEMBER("member"), MULTIPLE_MEMBER("multipleMember"), + DATE("date"),DATETIME("datetime"), + INT("int"),FLOAT("float"), + MULTIPLE_INPUT("multipleInput"),RICH_TEXT("richText"); + + String value; + + CustomFieldType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/backend/src/main/java/io/metersphere/commons/utils/LicenseUtils.java b/backend/src/main/java/io/metersphere/commons/utils/LicenseUtils.java new file mode 100644 index 0000000000..834d77600e --- /dev/null +++ b/backend/src/main/java/io/metersphere/commons/utils/LicenseUtils.java @@ -0,0 +1,18 @@ +package io.metersphere.commons.utils; + +import java.lang.reflect.Method; + +public class LicenseUtils { + public static boolean valid() { + try { + Class aClass = Class.forName("io.metersphere.xpack.license.util.LicenseCache"); + Method get = aClass.getMethod("valid"); + System.out.println("===="); + return (boolean) get.invoke(null); + } catch (Exception e) { + LogUtil.error(e); + e.printStackTrace(); + return false; + } + } +} diff --git a/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java b/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java index 299e29b64d..4a3c9a2c65 100644 --- a/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java @@ -7,6 +7,7 @@ import io.metersphere.base.mapper.IssuesMapper; import io.metersphere.base.mapper.ProjectMapper; import io.metersphere.base.mapper.TestCaseIssuesMapper; import io.metersphere.base.mapper.ext.ExtIssuesMapper; +import io.metersphere.commons.constants.CustomFieldType; import io.metersphere.commons.constants.IssuesStatus; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.*; @@ -64,6 +65,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform { protected String workspaceId; protected String userId; protected String defaultCustomFields; + protected boolean isThirdPartTemplate; public String getKey() { @@ -366,13 +368,31 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform { protected String syncIssueCustomField(String customFieldsStr, JSONObject issue) { List customFields = CustomFieldService.getCustomFields(customFieldsStr); + Set names = issue.keySet(); customFields.forEach(item -> { String fieldName = item.getCustomData(); Object value = issue.get(fieldName); if (value != null) { - if (value instanceof JSONObject) { - if (!fieldName.equals("assignee") && !fieldName.equals("reporter")) { // 获取不到账号名 - item.setValue(((JSONObject)value).getString("id")); + if (value instanceof JSONObject) { + JSONObject valObj = ((JSONObject) value); + String accountId = valObj.getString("accountId"); + JSONObject child = valObj.getJSONObject("child"); + if (child != null) {// 级联框 + List values = new ArrayList<>(); + if (StringUtils.isNotBlank(valObj.getString("id"))) { + values.add(valObj.getString("id")); + } + if (StringUtils.isNotBlank(child.getString("id"))) { + values.add(child.getString("id")); + } + item.setValue(values); + } else if (StringUtils.isNotBlank(accountId)) { + // 用户选择框 + if (isThirdPartTemplate) { + item.setValue(accountId); + } + } else { + item.setValue(valObj.getString("id")); } } else if (value instanceof JSONArray) { List values = new ArrayList<>(); @@ -387,6 +407,12 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform { } else { item.setValue(value); } + } else if (names.contains(fieldName)) { + if (item.getType().equals(CustomFieldType.CHECKBOX.getValue())) { + item.setValue(new ArrayList<>()); + } else { + item.setValue(null); + } } }); return JSONObject.toJSONString(customFields); @@ -463,4 +489,12 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform { issue.setCreator(SessionUtils.getUserId()); issue.setNum(nextNum); } + + public boolean isThirdPartTemplate() { + Project project = projectService.getProjectById(projectId); + if (project.getThirdPartTemplate() != null && project.getThirdPartTemplate() && LicenseUtils.valid()) { + return true; + } + return false; + } } diff --git a/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java b/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java index c7cb031edb..72256d1b08 100644 --- a/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java @@ -294,6 +294,7 @@ public class JiraPlatform extends AbstractIssuePlatform { @Override public void syncIssues(Project project, List issues) { + isThirdPartTemplate = isThirdPartTemplate(); issues.forEach(item -> { try { IssuesWithBLOBs issuesWithBLOBs = issuesMapper.selectByPrimaryKey(item.getId()); diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index dae3bfa801..23fd955ff2 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit dae3bfa8015fefe44c0c7a7517a43a5da93e6950 +Subproject commit 23fd955ff25ccf19f115c9d37a970e0caba6986d diff --git a/frontend/src/business/components/project/menu/EditProject.vue b/frontend/src/business/components/project/menu/EditProject.vue index c80110a96f..00bfaa8b8c 100644 --- a/frontend/src/business/components/project/menu/EditProject.vue +++ b/frontend/src/business/components/project/menu/EditProject.vue @@ -18,7 +18,7 @@ - + @@ -231,7 +231,7 @@ export default { if (platforms.indexOf(platform) === -1) { for (let i = 0; i < this.platformOptions.length; i++) { if (this.platformOptions[i].value === platform) { - this.platformOptions.splice(1, i); + this.platformOptions.splice(i, 1); break; } } diff --git a/frontend/src/business/components/track/case/components/IssueRelateList.vue b/frontend/src/business/components/track/case/components/IssueRelateList.vue index cbd0918781..c61c1e8b92 100644 --- a/frontend/src/business/components/track/case/components/IssueRelateList.vue +++ b/frontend/src/business/components/track/case/components/IssueRelateList.vue @@ -66,14 +66,12 @@ import MsEditDialog from "@/business/components/common/components/MsEditDialog"; import MsTable from "@/business/components/common/components/table/MsTable"; import MsTableColumn from "@/business/components/common/components/table/MsTableColumn"; -import {getRelateIssues, testCaseIssueRelate} from "@/network/Issue"; +import {getRelateIssues, isThirdPartEnable, testCaseIssueRelate} from "@/network/Issue"; import IssueDescriptionTableItem from "@/business/components/track/issue/IssueDescriptionTableItem"; import {ISSUE_STATUS_MAP} from "@/common/js/table-constants"; import MsTablePagination from "@/business/components/common/pagination/TablePagination"; import {getPageInfo} from "@/common/js/tableUtils"; import {getCurrentProjectID} from "@/common/js/utils"; -import {getIssueTemplate} from "../../../../../network/custom-field-template"; -import {LOCAL} from "@/common/js/constants"; export default { name: "IssueRelateList", components: {MsTablePagination, IssueDescriptionTableItem, MsTableColumn, MsTable, MsEditDialog}, @@ -94,14 +92,9 @@ export default { }, props: ['caseId'], created() { - getIssueTemplate() - .then((template) => { - if (template.platform === LOCAL) { - this.isThirdPart = false; - } else { - this.isThirdPart = true; - } - }); + isThirdPartEnable((data) => { + this.isThirdPart = data; + }); }, methods: { open() { diff --git a/frontend/src/business/components/track/case/components/TestCaseEditOtherInfo.vue b/frontend/src/business/components/track/case/components/TestCaseEditOtherInfo.vue index fa61269529..fda4596f81 100644 --- a/frontend/src/business/components/track/case/components/TestCaseEditOtherInfo.vue +++ b/frontend/src/business/components/track/case/components/TestCaseEditOtherInfo.vue @@ -27,6 +27,7 @@ @@ -118,7 +119,9 @@ export default { if (this.tabActiveName === 'demand') { this.getDemandOptions(); } else if (this.tabActiveName === 'bug') { - this.$refs.issue.getIssues(); + if (this.$refs.issue) { + this.$refs.issue.getIssues(); + } } else if (this.tabActiveName === 'relationship') { this.$refs.relationship.open(); } else if (this.tabActiveName === 'attachment') { diff --git a/frontend/src/business/components/track/case/components/TestCaseIssueRelate.vue b/frontend/src/business/components/track/case/components/TestCaseIssueRelate.vue index 2dbf8e7671..577dee6829 100644 --- a/frontend/src/business/components/track/case/components/TestCaseIssueRelate.vue +++ b/frontend/src/business/components/track/case/components/TestCaseIssueRelate.vue @@ -97,8 +97,7 @@ import MsTableColumn from "@/business/components/common/components/table/MsTable import IssueDescriptionTableItem from "@/business/components/track/issue/IssueDescriptionTableItem"; import {ISSUE_STATUS_MAP} from "@/common/js/table-constants"; import IssueRelateList from "@/business/components/track/case/components/IssueRelateList"; -import {deleteIssueRelate, getIssuesByCaseId} from "@/network/Issue"; -import {getIssueTemplate} from "@/network/custom-field-template"; +import {deleteIssueRelate, getIssuePartTemplateWithProject, getIssuesByCaseId} from "@/network/Issue"; import {getCustomFieldValue, getTableHeaderWithCustomFields} from "@/common/js/tableUtils"; import {LOCAL} from "@/common/js/constants"; export default { @@ -132,34 +131,34 @@ export default { }, }, created() { - getIssueTemplate() - .then((template) => { - this.issueTemplate = template; - if (this.issueTemplate.platform === LOCAL) { - this.isThirdPart = false; - } else { - this.isThirdPart = true; - } - if (template) { - let customFields = template.customFields; - for (let fields of customFields) { - if (fields.name === '状态') { - this.status = fields.options; - break; - } + getIssuePartTemplateWithProject((template, project) => { + this.currentProject = project; + this.issueTemplate = template; + if (this.issueTemplate.platform === LOCAL) { + this.isThirdPart = false; + } else { + this.isThirdPart = true; + } + if (template) { + let customFields = template.customFields; + for (let fields of customFields) { + if (fields.name === '状态') { + this.status = fields.options; + break; } } - this.fields = getTableHeaderWithCustomFields('ISSUE_LIST', this.issueTemplate.customFields); - if (!this.isThirdPart) { - for (let i = 0; i < this.fields.length; i++) { - if (this.fields[i].id === 'platformStatus') { - this.fields.splice(i, 1); - break; - } + } + this.fields = getTableHeaderWithCustomFields('ISSUE_LIST', this.issueTemplate.customFields); + if (!this.isThirdPart) { + for (let i = 0; i < this.fields.length; i++) { + if (this.fields[i].id === 'platformStatus') { + this.fields.splice(i, 1); + break; } } - this.$refs.table.reloadTable(); - }); + } + this.$refs.table.reloadTable(); + }); }, methods: { statusChange(param) { diff --git a/frontend/src/business/components/track/issue/IssueEditDetail.vue b/frontend/src/business/components/track/issue/IssueEditDetail.vue index c3df76ca3e..d21f2d931a 100644 --- a/frontend/src/business/components/track/issue/IssueEditDetail.vue +++ b/frontend/src/business/components/track/issue/IssueEditDetail.vue @@ -3,7 +3,7 @@ - + @@ -81,12 +81,8 @@ import { getCurrentUser, getCurrentUserId, getCurrentWorkspaceId, - hasLicense } from "@/common/js/utils"; -import {getIssueTemplate} from "@/network/custom-field-template"; -import {getIssueThirdPartTemplate} from "@/network/Issue"; -import {getCurrentProject} from "@/network/project"; -import {JIRA} from "@/common/js/constants"; +import {enableThirdPartTemplate, getIssuePartTemplateWithProject} from "@/network/Issue"; import CustomFiledFormItem from "@/business/components/common/components/form/CustomFiledFormItem"; export default { @@ -154,26 +150,16 @@ export default { return getCurrentProjectID(); }, enableThirdPartTemplate() { - return hasLicense() && this.currentProject && this.currentProject.thirdPartTemplate && this.currentProject.platform === JIRA; + return enableThirdPartTemplate(this.currentProject); }, }, methods: { open(data) { this.result.loading = true; this.$nextTick(() => { - getCurrentProject((responseData) => { - this.currentProject = responseData; - if (hasLicense() && this.currentProject && this.currentProject.thirdPartTemplate && this.currentProject.platform === JIRA) { - getIssueThirdPartTemplate() - .then((template) => { - this.init(template, data); - }); - } else { - getIssueTemplate() - .then((template) => { - this.init(template, data); - }); - } + getIssuePartTemplateWithProject((template, project) => { + this.currentProject = project; + this.init(template, data); }); }); diff --git a/frontend/src/business/components/track/issue/IssueList.vue b/frontend/src/business/components/track/issue/IssueList.vue index a16425c551..e93ef64bb1 100644 --- a/frontend/src/business/components/track/issue/IssueList.vue +++ b/frontend/src/business/components/track/issue/IssueList.vue @@ -168,7 +168,7 @@ import { import MsTableHeader from "@/business/components/common/components/MsTableHeader"; import IssueDescriptionTableItem from "@/business/components/track/issue/IssueDescriptionTableItem"; import IssueEdit from "@/business/components/track/issue/IssueEdit"; -import {getIssues, getIssueThirdPartTemplate, syncIssues} from "@/network/Issue"; +import {getIssuePartTemplateWithProject, getIssues, syncIssues} from "@/network/Issue"; import { getCustomFieldValue, getCustomTableWidth, @@ -176,11 +176,9 @@ import { } from "@/common/js/tableUtils"; import MsContainer from "@/business/components/common/components/MsContainer"; import MsMainContainer from "@/business/components/common/components/MsMainContainer"; -import {getCurrentProjectID, getCurrentWorkspaceId, hasLicense} from "@/common/js/utils"; -import {getIssueTemplate} from "@/network/custom-field-template"; +import {getCurrentProjectID, getCurrentWorkspaceId} from "@/common/js/utils"; import {getProjectMember} from "@/network/user"; -import {JIRA, LOCAL} from "@/common/js/constants"; -import {getCurrentProject} from "@/network/project"; +import {LOCAL} from "@/common/js/constants"; export default { name: "IssueList", @@ -218,7 +216,6 @@ export default { members: [], isThirdPart: false, creatorFilters: [], - currentProject: null }; }, watch: { @@ -232,20 +229,8 @@ export default { getProjectMember((data) => { this.members = data; }); - - getCurrentProject((responseData) => { - this.currentProject = responseData; - if (hasLicense() && this.currentProject.thirdPartTemplate && this.currentProject.platform === JIRA) { - getIssueThirdPartTemplate() - .then((template) => { - this.initFields(template); - }); - } else { - getIssueTemplate() - .then((template) => { - this.initFields(template); - }); - } + getIssuePartTemplateWithProject((template) => { + this.initFields(template); }); this.getIssues(); }, diff --git a/frontend/src/business/components/xpack b/frontend/src/business/components/xpack index 992bf5c0bc..f806258070 160000 --- a/frontend/src/business/components/xpack +++ b/frontend/src/business/components/xpack @@ -1 +1 @@ -Subproject commit 992bf5c0bc50e23ced47cdb1aa87e3061c3a6a5d +Subproject commit f806258070e9ca2cda08e48aa47952d31eb2a60a diff --git a/frontend/src/common/js/tableUtils.js b/frontend/src/common/js/tableUtils.js index ec1be24498..effd955378 100644 --- a/frontend/src/common/js/tableUtils.js +++ b/frontend/src/common/js/tableUtils.js @@ -3,6 +3,7 @@ import {CUSTOM_TABLE_HEADER} from "@/common/js/default-table-header"; import {updateCustomFieldTemplate} from "@/network/custom-field-template"; import i18n from "@/i18n/i18n"; import Sortable from 'sortablejs' +import {timestampFormatDate} from "@/common/js/filter"; export function _handleSelectAll(component, selection, tableData, selectRows, condition) { if (selection.length > 0) { @@ -492,6 +493,8 @@ export function getCustomFieldValue(row, field, members) { } return values; } + } else if (field.type === 'datetime') { + return timestampFormatDate(item.value); } return item.value; } diff --git a/frontend/src/network/Issue.js b/frontend/src/network/Issue.js index 60c58f8645..f355b231b7 100644 --- a/frontend/src/network/Issue.js +++ b/frontend/src/network/Issue.js @@ -2,6 +2,9 @@ import {post, get} from "@/common/js/ajax"; import {getPageDate} from "@/common/js/tableUtils"; import {getCurrentProjectID, hasLicense} from "@/common/js/utils"; import {baseGet, basePost} from "@/network/base-network"; +import {getCurrentProject} from "@/network/project"; +import {JIRA, LOCAL} from "@/common/js/constants"; +import {getIssueTemplate} from "@/network/custom-field-template"; export function buildIssues(page) { let data = page.data; @@ -10,9 +13,6 @@ export function buildIssues(page) { if (data[i].customFields) { data[i].customFields = JSON.parse(data[i].customFields); } - // if (data[i].platform !== 'Local') { - // page.result = buildPlatformIssue(data[i]); - // } } } } @@ -108,3 +108,33 @@ export function getIssueThirdPartTemplate() { }) }); } + +export function getIssuePartTemplateWithProject(callback) { + getCurrentProject((project) => { + let currentProject = project; + if (enableThirdPartTemplate(currentProject)) { + getIssueThirdPartTemplate() + .then((template) => { + if (callback) + callback(template, currentProject); + }); + } else { + getIssueTemplate() + .then((template) => { + if (callback) + callback(template, currentProject); + }); + } + }); +} + +export function enableThirdPartTemplate(currentProject) { + return hasLicense() && currentProject && currentProject.thirdPartTemplate && currentProject.platform === JIRA; +} + +export function isThirdPartEnable(callback) { + getCurrentProject((project) => { + if (callback) + callback(project.platform !== LOCAL); + }); +}