feat(系统设置): 禅道插件化改造

This commit is contained in:
chenjianxing 2022-12-06 16:12:20 +08:00 committed by 刘瑞斌
parent 0a01ed4903
commit 39defe8a3b
15 changed files with 51 additions and 331 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -1,35 +0,0 @@
<template>
<el-form label-position="right" label-width="115px" size="small">
<el-form-item :label="'Jira '+ $t('commons.information')">
<ms-instructions-icon size="10" :content="$t('organization.integration.jira_prompt_information')"/>
</el-form-item>
<el-form-item :label="'Jira ' + $t('organization.integration.account')" prop="account">
<el-input v-model="data.jiraAccount" :placeholder="$t('organization.integration.input_api_account')"/>
</el-form-item>
<el-form-item label="Token" prop="password">
<el-input v-model="data.jiraPassword" auto-complete="new-password"
:placeholder="$t('organization.integration.input_api_password')" show-password/>
</el-form-item>
<el-form-item>
<el-button type="primary" style="float: right" @click="$emit('auth', 'Jira')" size="mini">
{{ $t('commons.validate') }}
</el-button>
</el-form-item>
</el-form>
</template>
<script>
import MsInstructionsIcon from "../MsInstructionsIcon";
export default {
name: "JiraUserInfo",
components: {MsInstructionsIcon},
props: ['data'],
}
</script>
<style scoped>
.instructions-icon {
margin-left: -5px;
}
</style>

View File

@ -27,10 +27,6 @@ import MsDialogFooter from "../MsDialogFooter";
import {removeGoBackListener} from "../../utils";
import MsTableOperatorButton from "../MsTableOperatorButton";
import {EMAIL_REGEX, PHONE_REGEX} from "../../utils/regex";
import JiraUserInfo from "./JiraUserInfo";
import TapdUserInfo from "./TapdUserInfo";
import ZentaoUserInfo from "./ZentaoUserInfo";
import AzureDevopsUserInfo from "./AzureDevopsUserInfo";
import {useUserStore} from "@/store";
import {updateInfo} from "../../api/user";
@ -38,7 +34,7 @@ const userStore = useUserStore();
export default {
name: "MsPersonFromSetting",
components: {ZentaoUserInfo, TapdUserInfo, JiraUserInfo, AzureDevopsUserInfo, MsDialogFooter, MsTableOperatorButton},
components: {MsDialogFooter, MsTableOperatorButton},
inject: [
'reload',
'reloadTopMenus'

View File

@ -12,7 +12,7 @@
class="setting-item"></el-tab-pane>
<el-tab-pane
v-if="hasPermission('PERSONAL_INFORMATION:READ+THIRD_ACCOUNT')
&&(platformAccountConfigs.length > 0 || hasTapd || hasZentao || hasAzure) && hasPermission('WORKSPACE_SERVICE:READ')"
&&(platformAccountConfigs.length > 0 || hasTapd || hasAzure) && hasPermission('WORKSPACE_SERVICE:READ')"
name="third_account" :label="$t('commons.third_account')" class="setting-item"></el-tab-pane>
<el-tab-pane v-if="hasPermission('PERSONAL_INFORMATION:READ+UI_SETTING') && isXpack" name="commons.ui_setting"
:label="$t('commons.ui_setting')"
@ -33,7 +33,6 @@
/>
</div>
<tapd-user-info @auth="handleAuth" v-if="hasTapd" :data="currentPlatformInfo"/>
<zentao-user-info @auth="handleAuth" v-if="hasZentao" :data="currentPlatformInfo"/>
<azure-devops-user-info @auth="handleAuth" v-if="hasAzure" :data="currentPlatformInfo"/>
<el-form-item class="el-form-item-class">
<el-button size="small" @click="cancel">{{ $t('commons.cancel') }}</el-button>
@ -56,7 +55,6 @@ import PasswordInfo from "./PasswordInfo";
import UiSetting from "./UiSetting";
import {getCurrentUser, getCurrentWorkspaceId} from "../../utils/token";
import {hasLicense, hasPermission} from "../../utils/permission";
import ZentaoUserInfo from "./ZentaoUserInfo";
import TapdUserInfo from "./TapdUserInfo";
import AzureDevopsUserInfo from "./AzureDevopsUserInfo";
import {getIntegrationService} from "../../api/workspace";
@ -77,7 +75,6 @@ export default {
MsPersonFromSetting,
MsApiKeys,
PasswordInfo,
ZentaoUserInfo,
TapdUserInfo,
AzureDevopsUserInfo,
UiSetting
@ -90,7 +87,6 @@ export default {
activeIndex: '',
ruleForm: {},
hasTapd: false,
hasZentao: false,
hasAzure: false,
isXpack: false,
updatePath: '/user/update/current',
@ -131,15 +127,7 @@ export default {
},
handleAuth(type) {
let param = {...this.currentPlatformInfo};
if (type === 'Zentao') {
if (!param.zentaoUserName) {
this.$error(this.$t('organization.integration.input_api_account'));
return
} else if (!param.zentaoPassword) {
this.$error(this.$t('organization.integration.input_api_password'));
return
}
} else if (type === 'AzureDevops') {
if (type === 'AzureDevops') {
if (!param.azureDevopsPat) {
this.$error(this.$t('organization.integration.input_azure_pat'));
return
@ -171,9 +159,6 @@ export default {
if (platforms.indexOf("Tapd") !== -1) {
this.hasTapd = true;
}
if (platforms.indexOf("Zentao") !== -1) {
this.hasZentao = true;
}
if (platforms.indexOf("AzureDevops") !== -1) {
this.hasAzure = true;
}

View File

@ -52,9 +52,15 @@
<el-input v-model="form.phone" autocomplete="off"/>
</el-form-item>
</el-form>
<jira-user-info @auth="handleAuth" v-if="hasJira" :data="currentPlatformInfo"/>
<div v-for="config in platformAccountConfigs" :key="config.key">
<platform-account-config
:config="config"
:account-config="currentPlatformInfo"
v-if="showPlatformConfig(config.key)"
/>
</div>
<tapd-user-info @auth="handleAuth" v-if="hasTapd" :data="currentPlatformInfo"/>
<zentao-user-info @auth="handleAuth" v-if="hasZentao" :data="currentPlatformInfo"/>
<azure-devops-user-info @auth="handleAuth" v-if="hasAzure" :data="currentPlatformInfo"/>
<template v-slot:footer>
<ms-dialog-footer
@ -94,19 +100,20 @@ import {listenGoBack, removeGoBackListener} from "../../utils";
import {getCurrentUser, getCurrentWorkspaceId} from "../../utils/token";
import MsTableOperatorButton from "../MsTableOperatorButton";
import {EMAIL_REGEX, PHONE_REGEX} from "../../utils/regex";
import JiraUserInfo from "./JiraUserInfo";
import TapdUserInfo from "./TapdUserInfo";
import {getIntegrationService} from "../../api/workspace";
import ZentaoUserInfo from "./ZentaoUserInfo";
import AzureDevopsUserInfo from "./AzureDevopsUserInfo";
import {useUserStore} from "@/store";
import {handleAuth as _handleAuth, updateInfo, updatePassword} from "../../api/user";
import {getPlatformAccountInfo} from "../../api/platform-plugin";
import {ISSUE_PLATFORM_OPTION} from "../../utils/table-constants";
import PlatformAccountConfig from "./PlatformAccountConfig";
const userStore = useUserStore();
export default {
name: "MsPersonSetting",
components: {ZentaoUserInfo, TapdUserInfo, JiraUserInfo, AzureDevopsUserInfo, MsDialogFooter, MsTableOperatorButton},
components: {TapdUserInfo, AzureDevopsUserInfo, MsDialogFooter, MsTableOperatorButton, PlatformAccountConfig},
inject: [
'reload'
],
@ -128,10 +135,9 @@ export default {
zentaoPassword: '',
azureDevopsPat: ''
},
platformAccountConfigs: [],
ruleForm: {},
hasJira: false,
hasTapd: false,
hasZentao: false,
hasAzure: false,
rule: {
name: [
@ -188,6 +194,10 @@ export default {
},
activated() {
getPlatformAccountInfo()
.then((r) => {
this.platformAccountConfigs = r.data;
});
this.initTableData();
// remove router query _token _csrf
if (this.$route.query && Object.keys(this.$route.query).length > 0) {
@ -198,6 +208,9 @@ export default {
currentUser: () => {
return getCurrentUser();
},
showPlatformConfig(platform) {
return ISSUE_PLATFORM_OPTION.map(item => item.value).indexOf(platform) < 0;
},
edit: function (row) {
this.updateVisible = true;
this.form = Object.assign({}, row);
@ -221,12 +234,6 @@ export default {
if (platforms.indexOf("Tapd") !== -1) {
this.hasTapd = true;
}
if (platforms.indexOf("Jira") !== -1) {
this.hasJira = true;
}
if (platforms.indexOf("Zentao") !== -1) {
this.hasZentao = true;
}
if (platforms.indexOf("AzureDevops") !== -1) {
this.hasAzure = true;
}

View File

@ -1,35 +0,0 @@
<template>
<el-form label-position="right" label-width="115px" size="small">
<el-form-item :label="$t('organization.integration.zentao_info')">
<ms-instructions-icon size="10" :content="$t('organization.integration.zentao_prompt_information')"/>
</el-form-item>
<el-form-item :label="$t('organization.integration.zentao_account')" prop="account">
<el-input v-model="data.zentaoUserName" :placeholder="$t('organization.integration.input_api_account')"/>
</el-form-item>
<el-form-item :label="$t('organization.integration.zentao_password')" prop="password">
<el-input v-model="data.zentaoPassword" auto-complete="new-password"
:placeholder="$t('organization.integration.input_api_password')" show-password/>
</el-form-item>
<el-form-item>
<el-button type="primary" style="float: right" @click="$emit('auth', 'Zentao')" size="mini">
{{ $t('commons.validate') }}
</el-button>
</el-form-item>
</el-form>
</template>
<script>
import MsInstructionsIcon from "../MsInstructionsIcon";
export default {
name: "ZentaoUserInfo",
components: {MsInstructionsIcon},
props: ['data'],
}
</script>
<style scoped>
.instructions-icon {
margin-left: -5px;
}
</style>

View File

@ -68,7 +68,6 @@ export function CASE_TYPE_OPTION(){
export const ISSUE_PLATFORM_OPTION = [
{value: LOCAL, text: 'Local'},
{value: TAPD, text: 'Tapd'},
{value: ZEN_TAO, text: 'Zentao'},
{value: AZURE_DEVOPS, text: 'Azure Devops'},
];

View File

@ -25,11 +25,11 @@
<el-form-item :label-width="labelWidth"
:label="$t('workspace.issue_template_manage')" prop="issueTemplateId">
<template-select :platform="form.platform" :data="form" scene="ISSUE" prop="issueTemplateId"
:disabled="form.platform === 'Jira' && form.thirdPartTemplate"
:disabled="thirdPartTemplateSupport && form.thirdPartTemplate"
:platformOptions="platformOptions" :project-id="form.id"
ref="issueTemplate"/>
<el-checkbox @change="thirdPartTemplateChange" v-if="form.platform === 'Jira' && thirdPartTemplateSupport"
<el-checkbox @change="thirdPartTemplateChange" v-if="thirdPartTemplateSupport"
v-model="form.thirdPartTemplate" style="margin-left: 10px">
{{ $t('test_track.issue.use_third_party') }}
</el-checkbox>
@ -61,20 +61,6 @@
ref="platformConfig"
/>
<el-form-item :label-width="labelWidth" :label="$t('project.zentao_id')" v-if="zentao">
<el-input v-model="form.zentaoId" autocomplete="off"></el-input>
<el-button @click="check" type="primary" class="checkButton">
{{ $t('test_track.issue.check_id_exist') }}
</el-button>
<ms-instructions-icon effect="light">
<template>
禅道流程产品-项目 | 产品-迭代 | 产品-冲刺 | 项目-迭代 | 项目-冲刺 <br/><br/>
根据 "后台 -> 自定义 -> 流程" 查看对应流程根据流程填写ID <br/><br/>
产品-项目 | 产品-迭代 | 产品-冲刺 需要填写产品ID <br/><br/>
项目-迭代 | 项目-冲刺 需要填写项目ID
</template>
</ms-instructions-icon>
</el-form-item>
<el-form-item :label-width="labelWidth" :label="$t('project.azureDevops_id')" v-if="azuredevops">
<el-input v-model="form.azureDevopsId" autocomplete="off"></el-input>
</el-form-item>
@ -198,9 +184,6 @@ export default {
tapd() {
return this.showPlatform(TAPD);
},
zentao() {
return this.showPlatform(ZEN_TAO);
},
azuredevops() {
return this.showPlatform(AZURE_DEVOPS);
},

View File

@ -1,84 +0,0 @@
<template>
<div>
<el-form-item :label-width="labelWidth" :label="$t('project.jira_key')">
<el-input v-model="form.jiraKey" autocomplete="off" @blur="getIssueTypeOption"/>
<slot name="checkBtn"></slot>
<ms-instructions-icon effect="light">
<template>
<img class="jira-image" src="assets/jira-key.png"/>
</template>
</ms-instructions-icon>
</el-form-item>
<el-form-item :label-width="labelWidth" :label="$t('organization.integration.jira_issuetype')" prop="issuetype">
<el-select filterable v-model="form.issueConfigObj.jiraIssueTypeId">
<el-option v-for="item in issueTypes" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label-width="labelWidth" :label="$t('organization.integration.jira_storytype')" prop="storytype">
<el-select filterable v-model="form.issueConfigObj.jiraStoryTypeId">
<el-option v-for="item in issueTypes" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item>
</div>
</template>
<script>
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
import {getJiraIssueType} from "../../api/project";
import {getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
export default {
name: "ProjectJiraConfig",
components: {MsInstructionsIcon},
props: ['labelWidth', 'form', 'result'],
data() {
return {
issueTypes: []
}
},
mounted() {
this.getIssueTypeOption();
},
methods: {
getIssueTypeOption() {
this.issueTypes = [];
this.result.loading = true;
let param = {
projectId: this.form.id,
workspaceId: getCurrentWorkspaceId(),
jiraKey: this.form.jiraKey
}
getJiraIssueType(param)
.then((response) => {
this.issueTypes = response.data;
let hasJiraIssueType = false;
let hasJiraStoryType = false;
if (response.data) {
response.data.forEach(item => {
if (this.form.issueConfigObj.jiraIssueTypeId === item.id) {
hasJiraIssueType = true;
} else if (this.form.issueConfigObj.jiraStoryTypeId === item.id) {
hasJiraStoryType = true;
}
});
}
if (!hasJiraIssueType) {
this.form.issueConfigObj.jiraIssueTypeId = null;
}
if (!hasJiraStoryType) {
this.form.issueConfigObj.jiraStoryTypeId = null;
}
this.result.loading = false;
});
}
}
}
</script>
<style scoped>
.el-input, .el-textarea {
width: 80%;
}
</style>

View File

@ -19,10 +19,13 @@
class="checkButton">
{{ $t('test_track.issue.check_id_exist') }}
</el-button>
<ms-instructions-icon v-if="item.instructionsIcon" effect="light">
<ms-instructions-icon v-if="item.instructionsIcon || item.instructionsTip" effect="light">
<template>
<img class="jira-image"
<img v-if="item.instructionsIcon"
:src="getPlatformImageUrl(config, item)"/>
<span v-if="item.instructionsTip">
{{ item.instructionsTip }}
</span>
</template>
</ms-instructions-icon>
</el-form-item>

View File

@ -11,9 +11,6 @@
<el-radio label="Tapd">
<img class="platform" src="/assets/tapd.png" alt="Tapd"/>
</el-radio>
<el-radio label="Zentao">
<img class="zentao_platform" src="/assets/zentao.jpg" alt="Zentao"/>
</el-radio>
<el-radio label="AzureDevops" v-xpack>
<img class="platform" src="/assets/AzureDevops.png" alt="AzureDevops"/>
</el-radio>
@ -21,7 +18,6 @@
</div>
<tapd-setting v-if="tapdEnable" ref="tapdSetting"/>
<zentao-setting v-if="zentaoEnable" ref="zentaoSetting"/>
<azuredevops-setting v-if="azuredevopsEnable" ref="azureDevopsSetting"/>
<div v-for="config in platformConfigs" :key="config.key">
@ -36,7 +32,6 @@
<script>
import TapdSetting from '@/business/workspace/integration/TapdSetting';
import JiraSetting from '@/business/workspace/integration/JiraSetting';
import ZentaoSetting from '@/business/workspace/integration/ZentaoSetting';
import AzuredevopsSetting from '@/business/workspace/integration/AzureDevopsSetting';
import {AZURE_DEVOPS, TAPD, ZEN_TAO} from "metersphere-frontend/src/utils/constants";
import PlatformConfig from "@/business/workspace/integration/PlatformConfig";
@ -44,7 +39,7 @@ import {generatePlatformResourceUrl, getIntegrationInfo} from "@/api/platform-pl
export default {
name: "BugManagement",
components: {PlatformConfig, TapdSetting, JiraSetting, ZentaoSetting, AzuredevopsSetting},
components: {PlatformConfig, TapdSetting, JiraSetting, AzuredevopsSetting},
data() {
return {
loading: false,
@ -66,9 +61,6 @@ export default {
tapdEnable() {
return this.platform === TAPD;
},
zentaoEnable() {
return this.platform === ZEN_TAO;
},
azuredevopsEnable() {
return this.platform === AZURE_DEVOPS;
}
@ -90,9 +82,4 @@ export default {
height: 80px;
vertical-align: middle
}
.zentao_platform {
height: 100px;
vertical-align: middle
}
</style>

View File

@ -11,6 +11,15 @@
<custom-filed-component :form="form"
:data="item"
prop="defaultValue"/>
<ms-instructions-icon v-if="item.instructionsIcon || item.instructionsTip" effect="light">
<template>
<img v-if="item.instructionsIcon"
:src="getPlatformImageUrl(config, item)"/>
<span v-if="item.instructionsTip">
{{ item.instructionsTip }}
</span>
</template>
</ms-instructions-icon>
</el-form-item>
</el-form>
</div>
@ -65,7 +74,7 @@ import {
getServiceIntegration,
saveServiceIntegration
} from "../../../api/workspace";
import {validateServiceIntegration} from "@/api/platform-plugin";
import {generatePlatformResourceUrl, validateServiceIntegration} from "@/api/platform-plugin";
import {getPlatformFormRules} from "metersphere-frontend/src/utils/platform";
export default {
@ -181,6 +190,9 @@ export default {
},
closeDialog() {
this.resVisible = false;
},
getPlatformImageUrl(config, item) {
return generatePlatformResourceUrl(config.id, item.instructionsIcon);
}
}
};

View File

@ -25,11 +25,11 @@
<el-form-item :label-width="labelWidth"
:label="$t('workspace.issue_template_manage')" prop="issueTemplateId">
<template-select :platform="form.platform" :data="form" scene="ISSUE" prop="issueTemplateId"
:disabled="form.platform === 'Jira' && form.thirdPartTemplate"
:disabled="thirdPartTemplateSupport && form.thirdPartTemplate"
:platformOptions="platformOptions" :project-id="form.id"
ref="issueTemplate"/>
<el-checkbox @change="thirdPartTemplateChange" v-if="form.platform === 'Jira' && thirdPartTemplateSupport"
<el-checkbox @change="thirdPartTemplateChange" v-if="thirdPartTemplateSupport"
v-model="form.thirdPartTemplate" style="margin-left: 10px">
{{ $t('test_track.issue.use_third_party') }}
</el-checkbox>
@ -61,20 +61,6 @@
ref="platformConfig"
/>
<el-form-item :label-width="labelWidth" :label="$t('project.zentao_id')" v-if="zentao">
<el-input v-model="form.zentaoId" autocomplete="off"></el-input>
<el-button @click="check" type="primary" class="checkButton">
{{ $t('test_track.issue.check_id_exist') }}
</el-button>
<ms-instructions-icon effect="light">
<template>
禅道流程产品-项目 | 产品-迭代 | 产品-冲刺 | 项目-迭代 | 项目-冲刺 <br/><br/>
根据 "后台 -> 自定义 -> 流程" 查看对应流程根据流程填写ID <br/><br/>
产品-项目 | 产品-迭代 | 产品-冲刺 需要填写产品ID <br/><br/>
项目-迭代 | 项目-冲刺 需要填写项目ID
</template>
</ms-instructions-icon>
</el-form-item>
<el-form-item :label-width="labelWidth" :label="$t('project.azureDevops_id')" v-if="azuredevops">
<el-input v-model="form.azureDevopsId" autocomplete="off"></el-input>
</el-form-item>
@ -194,9 +180,6 @@ export default {
tapd() {
return this.showPlatform(TAPD);
},
zentao() {
return this.showPlatform(ZEN_TAO);
},
azuredevops() {
return this.showPlatform(AZURE_DEVOPS);
},

View File

@ -1,84 +0,0 @@
<template>
<div>
<el-form-item :label-width="labelWidth" :label="$t('project.jira_key')">
<el-input v-model="form.jiraKey" autocomplete="off" @blur="getIssueTypeOption"/>
<slot name="checkBtn"></slot>
<ms-instructions-icon effect="light">
<template>
<img class="jira-image" src="assets/jira-key.png"/>
</template>
</ms-instructions-icon>
</el-form-item>
<el-form-item :label-width="labelWidth" :label="$t('organization.integration.jira_issuetype')" prop="issuetype">
<el-select filterable v-model="form.issueConfigObj.jiraIssueTypeId">
<el-option v-for="item in issueTypes" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label-width="labelWidth" :label="$t('organization.integration.jira_storytype')" prop="storytype">
<el-select filterable v-model="form.issueConfigObj.jiraStoryTypeId">
<el-option v-for="item in issueTypes" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item>
</div>
</template>
<script>
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
import {getJiraIssueType} from "../../../api/project";
import {getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
export default {
name: "ProjectJiraConfig",
components: {MsInstructionsIcon},
props: ['labelWidth', 'form', 'result'],
data() {
return {
issueTypes: []
}
},
mounted() {
this.getIssueTypeOption();
},
methods: {
getIssueTypeOption() {
this.issueTypes = [];
this.result.loading = true;
let param = {
projectId: this.form.id,
workspaceId: getCurrentWorkspaceId(),
jiraKey: this.form.jiraKey
}
getJiraIssueType(param)
.then((response) => {
this.issueTypes = response.data;
let hasJiraIssueType = false;
let hasJiraStoryType = false;
if (response.data) {
response.data.forEach(item => {
if (this.form.issueConfigObj.jiraIssueTypeId === item.id) {
hasJiraIssueType = true;
} else if (this.form.issueConfigObj.jiraStoryTypeId === item.id) {
hasJiraStoryType = true;
}
});
}
if (!hasJiraIssueType) {
this.form.issueConfigObj.jiraIssueTypeId = null;
}
if (!hasJiraStoryType) {
this.form.issueConfigObj.jiraStoryTypeId = null;
}
this.result.loading = false;
});
}
}
}
</script>
<style scoped>
.el-input, .el-textarea {
width: 80%;
}
</style>

View File

@ -19,10 +19,13 @@
class="checkButton">
{{ $t('test_track.issue.check_id_exist') }}
</el-button>
<ms-instructions-icon v-if="item.instructionsIcon" effect="light">
<ms-instructions-icon v-if="item.instructionsIcon || item.instructionsTip" effect="light">
<template>
<img class="jira-image"
<img v-if="item.instructionsIcon"
:src="getPlatformImageUrl(config, item)"/>
<span v-if="item.instructionsTip">
{{ item.instructionsTip }}
</span>
</template>
</ms-instructions-icon>
</el-form-item>