fix(测试跟踪): 测试计划和评审中的用例-其他信息-评论显示为空

--bug=1025872 --user=陈建星 【测试跟踪】测试跟踪评审中查看用例显示评论为空 https://www.tapd.cn/55049933/s/1367844
This commit is contained in:
chenjianxing 2023-04-28 14:04:01 +08:00 committed by fit2-zhao
parent 9c19b85e97
commit 3aea862c96
5 changed files with 17 additions and 1217 deletions

View File

@ -177,7 +177,6 @@ import MsTabButton from "metersphere-frontend/src/components/new-ui/MsTabButton"
import TestCaseMinder from "../common/minder/TestCaseMinder";
import IsChangeConfirm from "metersphere-frontend/src/components/IsChangeConfirm";
import {openMinderConfirm} from "../common/minder/minderUtils";
import TestCaseEditShow from "./components/TestCaseEditShow";
import {PROJECT_ID} from "metersphere-frontend/src/utils/constants";
import MxVersionSelect from "metersphere-frontend/src/components/version/MxVersionSelect";
import {useStore} from "@/store";
@ -195,7 +194,7 @@ export default {
name: "TestCase",
components: {
PublicTestCaseList, TestCaseTrashNodeTree, TestCasePublicNodeTree, IsChangeConfirm, TestCaseMinder, MsTabButton, TestCaseNodeTree,
MsMainContainer, MsAsideContainer, MsContainer, TestCaseList, SelectMenu, TestCaseEditShow, 'VersionSelect': MxVersionSelect,
MsMainContainer, MsAsideContainer, MsContainer, TestCaseList, SelectMenu, 'VersionSelect': MxVersionSelect,
MsMainButtonGroup, TestCaseCommonImportNew
},
comments: {},
@ -540,18 +539,6 @@ export default {
changeVersion(currentVersion) {
this.currentVersion = currentVersion || null;
},
checkoutPublic(testCase, item) {
Object.assign(item.testCaseInfo, testCase)
// copy
this.$refs.testCaseEditShow[0].initEdit(item.testCaseInfo, () => {
this.$nextTick(() => {
let vh = this.$refs.testCaseEditShow[0].$refs.versionHistory;
vh.getVersionOptionList(vh.handleVersionOptions);
vh.show = false;
vh.loading = false;
});
});
},
checkVersionEnable() {
if (!this.projectId) {
return;

View File

@ -359,14 +359,12 @@ import {
parseCustomField,
} from "metersphere-frontend/src/utils/custom_field";
import MsFormDivider from "metersphere-frontend/src/components/MsFormDivider";
import TestCaseEditOtherInfo from "@/business/case/components/TestCaseEditOtherInfo";
import FormRichTextItem from "@/business/case/components/richtext/FormRichTextItem";
import TestCaseStepItem from "@/business/case/components/TestCaseStepItem";
import StepChangeItem from "@/business/case/components/StepChangeItem";
import MsChangeHistory from "metersphere-frontend/src/components/history/ChangeHistory";
import { getTestTemplate } from "@/api/custom-field-template";
import CustomFiledFormItem from "metersphere-frontend/src/components/form/CustomFiledFormItem";
import TestCaseVersionDiff from "@/business/case/version/TestCaseVersionDiff";
import VersionCreateOtherInfoSelect from "@/business/case/components/VersionCreateOtherInfoSelect";
import TestCaseBaseInfo from "@/business/case/components/TestCaseBaseInfo";
import MsContainer from "metersphere-frontend/src/components/MsContainer";
@ -419,7 +417,6 @@ export default {
StepChangeItem,
TestCaseStepItem,
FormRichTextItem,
TestCaseEditOtherInfo,
MsFormDivider,
CustomFiledComponent,
MsTableButton,
@ -433,7 +430,6 @@ export default {
TestCaseAttachment,
MsTestCaseStepRichText,
MsChangeHistory,
TestCaseVersionDiff,
VersionCreateOtherInfoSelect,
TestCaseBaseInfo,
MsContainer,

View File

@ -122,6 +122,7 @@
<review-comment-item v-for="(comment,index) in comments"
:key="index"
:comment="comment"
:read-only="readOnly"
@refresh="getComments" api-url="/test/case"/>
<div v-if="!comments || comments.length === 0" style="text-align: center">
<i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;">
@ -180,7 +181,7 @@ export default {
FormRichTextItem, TestCaseIssueRelate, TestCaseAttachment, MsRichText, TestCaseRichText
},
props: ['form', 'labelWidth', 'caseId', 'readOnly', 'projectId', 'isTestPlan', 'planId', 'versionEnable', 'isCopy', 'copyCaseId',
'type', 'comments', 'isClickAttachmentTab',
'type', 'isClickAttachmentTab',
'defaultOpen'
],
data() {
@ -204,7 +205,8 @@ export default {
uploadFiles: [],
relateFiles: [],
unRelateFiles: [],
dumpFile: {}
dumpFile: {},
comments: []
};
},
computed: {
@ -224,6 +226,8 @@ export default {
this.$refs.relationship.open();
} else if (this.tabActiveName === 'attachment') {
this.getFileMetaData();
} else if (this.tabActiveName === 'comment') {
this.getComments();
} else if (this.tabActiveName === 'relateTest') {
this.$nextTick(() => {
this.getRelatedTest();
@ -253,16 +257,21 @@ export default {
},
getComments(testCase) {
let id = '';
if (testCase) {
id = testCase.id;
} else {
id = this.form.id;
if (!testCase) {
testCase = this.form
}
if (testCase.caseId) {
//
id = testCase.caseId;
} else {
id = testCase.id;
}
this.result.loading = true;
testCaseCommentList(id)
.then(res => {
this.result.loading = false;
this.$emit('update:comments', res.data);
this.comments = res.data;
});
},
setRelationshipCount(count) {

View File

@ -1,687 +0,0 @@
<template>
<el-card>
<div class="card-content">
<div class="ms-main-div" @click="showAll">
<!--操作按钮-->
<div class="ms-opt-btn">
<el-tooltip :content="$t('commons.follow')" placement="bottom" effect="dark" v-if="!showFollow">
<i class="el-icon-star-off"
style="color: var(--primary_color); font-size: 25px; margin-right: 15px;cursor: pointer;position: relative;top: 5px "
@click="saveFollow"/>
</el-tooltip>
<el-tooltip :content="$t('commons.cancel')" placement="bottom" effect="dark" v-if="showFollow">
<i class="el-icon-star-on"
style="color: var(--primary_color); font-size: 28px; margin-right: 15px;cursor: pointer;position: relative;top: 5px "
@click="saveFollow"/>
</el-tooltip>
<el-link type="primary" style="margin-right: 20px" @click="openHis" v-if="form.id">
{{ $t('operating_log.change_history') }}
</el-link>
<!-- 版本历史 -->
<mx-version-history v-xpack
ref="versionHistory"
:version-data="versionData"
:current-id="currentTestCaseInfo.id"
:current-project-id="currentProjectId"
:is-read="true"/>
<ms-table-button id="inputDelay"
type="primary"
:content="$t('commons.copy')"
size="small" @click="handleCopyPublic"
icon=""
/>
</div>
<el-form :model="form" :rules="rules" ref="caseFrom" v-loading="loading" class="case-form">
<ms-form-divider :title="$t('test_track.plan_view.base_info')"/>
<el-row>
<el-col :span="8">
<el-form-item
:placeholder="$t('test_track.case.input_name')"
:label="$t('test_track.case.name')"
:label-width="formLabelWidth"
prop="name">
<el-input :disabled="readOnly" v-model="form.name" size="small" class="ms-case-input"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('test_track.case.project')" :label-width="formLabelWidth" prop="projectId">
<el-select v-model="form.projectId" filterable clearable :disabled="readOnly">
<el-option v-for="item in projectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('commons.tag')" :label-width="formLabelWidth" prop="tag">
<ms-input-tag :read-only="readOnly" :currentScenario="form" v-if="showInputTag" ref="tag"
:disabled="true"
class="ms-case-input"/>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="isCustomNum">
<el-col :span="7">
<el-form-item label="ID" :label-width="formLabelWidth" prop="customNum">
<el-input :disabled="readOnly" v-model.trim="form.customNum" size="small"
class="ms-case-input"></el-input>
</el-form-item>
</el-col>
</el-row>
<ms-form-divider :title="$t('test_track.case.step_info')"/>
<form-rich-text-item :disabled="readOnly" :label-width="formLabelWidth"
:title="$t('test_track.case.prerequisite')" :data="form" prop="prerequisite"/>
<step-change-item :label-width="formLabelWidth" :form="form"/>
<form-rich-text-item :disabled="readOnly" :label-width="formLabelWidth" v-if="form.stepModel === 'TEXT'"
:title="$t('test_track.case.step_desc')" :data="form" prop="stepDescription"/>
<form-rich-text-item :disabled="readOnly" :label-width="formLabelWidth" v-if="form.stepModel === 'TEXT'"
:title="$t('test_track.case.expected_results')" :data="form" prop="expectedResult"/>
<test-case-step-item :label-width="formLabelWidth" v-if="form.stepModel === 'STEP' || !form.stepModel"
:form="form" :read-only="readOnly"/>
<ms-form-divider :title="$t('test_track.case.other_info')"/>
<test-case-edit-other-info :read-only="readOnly" :project-id="projectIds" :form="form"
:comments.sync="comments"
:label-width="formLabelWidth" :case-id="form.id" ref="otherInfo"/>
<test-case-comment :case-id="form.id"
@getComments="getComments" ref="testCaseComment"/>
</el-form>
</div>
<ms-change-history ref="changeHistory"/>
<el-dialog
:fullscreen="true"
:visible.sync="dialogVisible"
:destroy-on-close="true"
width="100%">
<test-case-version-diff v-if="dialogVisible" :old-data="oldData" :new-data="newData"
:tree-nodes="treeNodes" :is-public="publicEnable"></test-case-version-diff>
</el-dialog>
</div>
<batch-move ref="testBatchMove" :public-enable="publicEnable"
@copyPublic="copyPublic"/>
</el-card>
</template>
<script>
import MsDialogFooter from 'metersphere-frontend/src/components/MsDialogFooter';
import {getCurrentProjectID, getCurrentUser} from "metersphere-frontend/src/utils/token";
import {
getUUID,
handleCtrlSEvent,
listenGoBack,
removeGoBackListener
} from "metersphere-frontend/src/utils"
import {hasLicense} from "metersphere-frontend/src/utils/permission"
import TestCaseAttachment from "@/business/case/components/TestCaseAttachment";
import CaseComment from "@/business/case/components/CaseComment";
import MsInputTag from "metersphere-frontend/src/components/MsInputTag";
import MsPreviousNextButton from "metersphere-frontend/src/components/MsPreviousNextButton";
import TestCaseComment from "@/business/case/components/TestCaseComment";
import ReviewCommentItem from "@/business/review/commom/ReviewCommentItem";
import MsTableButton from "metersphere-frontend/src/components/MsTableButton";
import MsSelectTree from "metersphere-frontend/src/components/select-tree/SelectTree";
import MsTestCaseStepRichText from "./MsRichText";
import MsFormDivider from "metersphere-frontend/src/components/MsFormDivider";
import TestCaseEditOtherInfo from "@/business/case/components/TestCaseEditOtherInfo";
import FormRichTextItem from "metersphere-frontend/src/components/FormRichTextItem";
import TestCaseStepItem from "@/business/case/components/TestCaseStepItem";
import StepChangeItem from "@/business/case/components/StepChangeItem";
import MsChangeHistory from "metersphere-frontend/src/components/history/ChangeHistory";
import BatchMove from "@/business/case/components/BatchMove";
import TestCaseVersionDiff from "@/business/case/version/TestCaseVersionDiff";
import {useStore} from "@/store";
import {
getTestCase,
getTestCaseFollow,
getTestCaseVersions,
testCaseEditFollows,
testCasePublicBatchCopy
} from "@/api/testCase";
import {testCaseCommentList} from "@/api/test-case-comment";
import {getProjectListAll, getProjectMemberOption} from "@/business/utils/sdk-utils";
export default {
name: "TestCaseEditShow",
components: {
StepChangeItem,
TestCaseStepItem,
FormRichTextItem,
TestCaseEditOtherInfo,
MsFormDivider,
MsTableButton,
MsSelectTree,
ReviewCommentItem,
TestCaseComment, MsPreviousNextButton, MsInputTag, CaseComment, MsDialogFooter, TestCaseAttachment,
MsTestCaseStepRichText,
MsChangeHistory,
BatchMove,
TestCaseVersionDiff,
MxVersionHistory: () => import("metersphere-frontend/src/components/version/MxVersionHistory")
},
data() {
return {
selectIds: [],
projectList: [],
isPublic: false,
isXpack: false,
testCaseTemplate: {},
comments: [],
loading: false,
dialogFormVisible: false,
showFollow: false,
form: {
name: '',
module: 'default-module',
nodePath: '/未规划用例',
maintainer: getCurrentUser().id,
priority: 'P0',
type: '',
method: '',
prerequisite: '',
testId: '',
otherTestName: '',
steps: [{
num: 1,
desc: '',
result: ''
}],
stepDesc: '',
stepResult: '',
selected: [],
remark: '',
tags: [],
demandId: '',
demandName: '',
status: 'Prepare',
reviewStatus: 'Prepare',
stepDescription: '',
expectedResult: '',
stepModel: 'STEP',
customNum: '',
followPeople: '',
},
maintainerOptions: [],
// testOptions: [],
workspaceId: '',
rules: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 255, message: this.$t('test_track.length_less_than') + '255', trigger: 'blur'}
],
module: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
customNum: [
{required: true, message: "ID必填", trigger: 'blur'},
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
],
demandName: [{required: true, message: this.$t('test_track.case.input_demand_name'), trigger: 'change'}],
maintainer: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
priority: [{required: true, message: this.$t('test_track.case.input_priority'), trigger: 'change'}],
method: [{required: true, message: this.$t('test_track.case.input_method'), trigger: 'change'}],
},
formLabelWidth: "100px",
operationType: '',
isCreateContinue: false,
isStepTableAlive: true,
isFormAlive: true,
methodOptions: [
{value: 'auto', label: this.$t('test_track.case.auto')},
{value: 'manual', label: this.$t('test_track.case.manual')}
],
testCase: {},
showInputTag: true,
tableType: "",
moduleObj: {
id: 'id',
label: 'name',
},
tabId: getUUID(),
versionData: [],
currentProjectId: "",
dialogVisible: false,
oldData: null,
newData: null,
readOnly: true
};
},
props: {
treeNodes: {
type: Array
},
currentTestCaseInfo: {},
selectNode: {
type: Object
},
selectCondition: {
type: Object
},
type: String,
publicEnable: {
type: Boolean,
default: false
}
},
computed: {
projectIds() {
return getCurrentProjectID();
},
moduleOptions() {
return useStore().testCaseModuleOptions;
},
isCustomNum() {
return useStore().currentProjectIsCustomNum;
},
},
mounted() {
this.getSelectOptions();
this.open(this.currentTestCaseInfo)
this.getComments(this.currentTestCaseInfo)
// Cascader : input
setInterval(function () {
document.querySelectorAll('.el-cascader-node__label').forEach(el => {
el.onclick = function () {
if (this.previousElementSibling) this.previousElementSibling.click();
};
});
}, 1000);
if (this.selectNode && this.selectNode.data && !this.form.id) {
this.form.module = this.selectNode.data.id;
this.form.nodePath = this.selectNode.data.path;
}
if ((!this.form.module || this.form.module === "default-module" || this.form.module === "root") && this.treeNodes.length > 0) {
this.form.module = this.treeNodes[0].id;
this.form.nodePath = this.treeNodes[0].path;
}
if (!(useStore().testCaseMap instanceof Map)) {
useStore().testCaseMap = new Map();
}
useStore().testCaseMap.set(this.form.id, 0);
},
created() {
if (!this.projectList || this.projectList.length === 0) { //
getProjectListAll()
.then((response) => {
this.projectList = response.data; //,
});
}
this.projectId = this.projectIds;
this.initAddFuc();
getTestCaseFollow(this.currentTestCaseInfo.id)
.then(response => {
this.form.follows = response.data;
for (let i = 0; i < response.data.length; i++) {
if (response.data[i] === this.currentUser().id) {
this.showFollow = true;
break;
}
}
});
if (hasLicense()) {
this.isXpack = true;
} else {
this.isXpack = false;
}
if (hasLicense()) {
this.getVersionHistory();
}
},
methods: {
currentUser: () => {
return getCurrentUser();
},
openHis() {
this.$refs.changeHistory.open(this.form.id, ["测试用例", "測試用例", "Test case", "TRACK_TEST_CASE"]);
},
setModule(id, data) {
this.form.module = id;
this.form.nodePath = data.path;
},
initAddFuc() {
if (this.selectNode && this.selectNode.data && !this.form.id) {
this.form.module = this.selectNode.data.id;
this.form.nodePath = this.selectNode.data.path;
} else {
this.form.module = this.treeNodes && this.length > 0 ? this.treeNodes[0].id : "";
}
this.form.module = this.currentTestCaseInfo.nodeId;
this.form.nodePath = this.currentTestCaseInfo.nodePath;
if ((!this.form.module || this.form.module === "default-module" || this.form.module === "root") && this.treeNodes.length > 0) {
this.form.module = this.treeNodes[0].id;
this.form.nodePath = this.treeNodes[0].path;
}
},
setDefaultValue() {
if (!this.form.prerequisite) {
this.form.prerequisite = "";
}
if (!this.form.stepDescription) {
this.form.stepDescription = "";
}
if (!this.form.expectedResult) {
this.form.expectedResult = "";
}
if (!this.form.remark) {
this.form.remark = "";
}
useStore().testCaseMap.set(this.form.id, 0);
},
openComment() {
this.$refs.testCaseComment.open()
},
getComments(testCase) {
let id = '';
if (testCase) {
id = testCase.id;
} else {
id = this.form.id;
}
testCaseCommentList(id)
.then(res => {
this.comments = res.data;
});
},
showAll() {
if (!this.customizeVisible) {
this.selectedTreeNode = undefined;
}
},
reload() {
this.isStepTableAlive = false;
this.$nextTick(() => {
this.isStepTableAlive = true;
useStore().testCaseMap.set(this.form.id, 0);
});
},
reloadForm() {
this.isFormAlive = false;
this.$nextTick(() => (this.isFormAlive = true));
},
open(testCase) {
this.projectId = this.projectIds;
this.initEdit(testCase);
},
initEdit(testCase) {
if (window.history && window.history.pushState) {
history.pushState(null, null, document.URL);
window.addEventListener('popstate', this.close);
}
this.resetForm();
listenGoBack(this.close);
this.getTestCase(testCase.id);
},
getTestCase(id) {
this.showInputTag = false;
if (!id) {
id = this.currentTestCaseInfo.id;
}
this.loading = true;
getTestCase(id)
.then(response => {
this.loading = false;
let testCase = response.data;
this.setFormData(testCase);
this.setTestCaseExtInfo(testCase);
this.getSelectOptions();
this.reload();
this.$nextTick(() => {
this.showInputTag = true;
});
});
},
async setFormData(testCase) {
try {
testCase.selected = JSON.parse(testCase.testId);
} catch (error) {
testCase.selected = testCase.testId
}
let tmp = {};
Object.assign(tmp, testCase);
tmp.steps = JSON.parse(testCase.steps);
if (!tmp.steps || tmp.steps.length < 1) {
tmp.steps = [{
num: 1,
desc: '',
result: ''
}];
}
tmp.tags = JSON.parse(tmp.tags);
Object.assign(this.form, tmp);
if (!this.form.stepModel) {
this.form.stepModel = "STEP";
}
this.casePublic = tmp.casePublic;
this.form.module = testCase.nodeId;
this.setDefaultValue();
//
this.reloadForm();
},
setTestCaseExtInfo(testCase) {
this.testCase = {};
if (testCase) {
//
this.testCase = testCase.isCopy ? {} : testCase;
}
},
close() {
//
removeGoBackListener(this.close);
this.dialogFormVisible = false;
},
handleCopyPublic(testCase) {
this.selectIds.push(this.form.id);
this.$refs.testBatchMove.open(this.treeNodes, this.selectIds, this.moduleOptions);
},
copyPublic(param) {
param.condition = this.condition;
this.loading = true;
testCasePublicBatchCopy(param)
.then(() => {
this.loading = false;
this.$success(this.$t('commons.save_success'));
this.$refs.testBatchMove.close();
this.$emit("refresh", this.form);
});
},
validate(param) {
for (let i = 0; i < param.steps.length; i++) {
if ((param.steps[i].desc && param.steps[i].desc.length > 300) ||
(param.steps[i].result && param.steps[i].result.length > 300)) {
this.$warning(this.$t('test_track.case.step_desc') + ","
+ this.$t('test_track.case.expected_results') + this.$t('test_track.length_less_than') + '300');
return false;
}
}
if (param.name === '') {
this.$warning(this.$t('test_track.case.input_name'));
return false;
}
return true;
},
typeChange() {
this.form.testId = '';
},
getMaintainerOptions() {
getProjectMemberOption()
.then(response => {
this.maintainerOptions = response.data;
});
},
getSelectOptions() {
this.getMaintainerOptions();
},
resetForm() {
//
if (this.$refs['caseFrom']) {
this.$refs['caseFrom'].validate((valid) => {
this.$refs['caseFrom'].resetFields();
this._resetForm();
return true;
});
} else {
this._resetForm();
}
},
_resetForm() {
this.form.name = '';
this.form.module = '';
this.form.type = '';
this.form.method = '';
this.form.maintainer = '';
this.form.priority = '';
this.form.prerequisite = '';
this.form.remark = '';
this.form.testId = '';
this.form.testName = '';
this.form.steps = [{
num: 1,
desc: '',
result: ''
}];
this.form.customNum = '';
},
createCtrlSHandle(event) {
let curTabId = useStore().curTabId;
if (curTabId === this.tabId)
handleCtrlSEvent(event, this.saveCase);
},
saveFollow() {
if (this.showFollow) {
this.showFollow = false;
for (let i = 0; i < this.form.follows.length; i++) {
if (this.form.follows[i] === this.currentUser().id) {
this.form.follows.splice(i, 1)
break;
}
}
this.loading = true;
testCaseEditFollows(this.form.id, this.form.follows)
.then(() => {
this.loading = false
this.$success(this.$t('commons.cancel_follow_success'));
});
} else {
this.showFollow = true;
if (!this.form.follows) {
this.form.follows = [];
}
this.form.follows.push(this.currentUser().id)
this.loading = true;
testCaseEditFollows(this.form.id, this.form.follows)
.then(() => {
this.loading = false
this.$success(this.$t('commons.follow_success'));
});
}
},
getVersionHistory() {
getTestCaseVersions(this.currentTestCaseInfo.id)
.then(response => {
for (let i = 0; i < response.data.length; i++) {
this.currentProjectId = response.data[i].projectId
}
this.versionData = response.data;
this.$refs.versionHistory.loading = false;
});
},
setSpecialPropForCompare: function (that) {
that.newData.tags = JSON.parse(that.newData.tags || "");
that.newData.steps = JSON.parse(that.newData.steps || "");
that.oldData.tags = JSON.parse(that.oldData.tags || "");
that.oldData.steps = JSON.parse(that.oldData.steps || "");
that.newData.readOnly = true;
that.oldData.readOnly = true;
},
changeType(type) {
this.type = type;
}
}
}
</script>
<style scoped>
.el-switch {
margin-bottom: 10px;
}
.case-name {
width: 194px;
}
.container {
height: 100vh;
}
.case-form {
height: 95%;
overflow: auto;
}
.case-dialog :deep(.el-dialog__body) {
padding: 0 20px 10px 20px;
}
.container :deep(.el-card__body) {
height: calc(100vh - 120px);
}
.comment-card :deep(.el-card__header) {
padding: 27px 20px;
}
.comment-card :deep(.el-card__body) {
height: calc(100vh - 120px);
}
.head-right {
text-align: right;
}
.ms-main-div {
background-color: white;
}
.ms-opt-btn {
position: fixed;
right: 50px;
z-index: 9;
}
.ms-case-input {
width: 100%;
}
.ms-case {
width: 100%;
}
:deep(.el-button-group > .el-button:first-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
height: 32px;
width: 56px;
}
.other-info-tabs {
padding-left: 60px;
margin-left: 40px;
}
</style>

View File

@ -1,505 +0,0 @@
<template>
<div>
<el-row>
<el-col :span="12">
<el-tag>当前{{ oldData.versionName }}</el-tag>
<span style="margin-left: 10px">{{ oldData.userName }}</span><span
style="margin-left: 10px">{{ oldData.createTime | datetimeFormat }}</span>
</el-col>
<el-col :span="12">
<el-tag>{{ newData.versionName }}</el-tag>
<span style="margin-left: 10px">{{ newData.userName }}</span><span
style="margin-left: 10px">{{ newData.createTime | datetimeFormat }}</span>
</el-col>
</el-row>
<div class="compare-class" v-loading="isReloadData">
<el-card style="width: 50%;" ref="old">
<el-form :model="oldData" ref="old" class="case-form" v-loading="oldLoading">
<ms-form-divider :title="$t('test_track.plan_view.base_info')"/>
<el-row>
<el-col :span="8">
<el-form-item
:placeholder="$t('test_track.case.input_name')"
:label="$t('test_track.case.name')"
:label-width="oldData.formLabelWidth"
prop="name">
<el-input :disabled="oldData.readOnly" v-model="oldData.name" size="small"
class="ms-case-input"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('test_track.case.module')" :label-width="oldData.formLabelWidth" prop="module"
v-if="!isPublic">
<ms-select-tree :disabled="oldData.readOnly" :data="treeNodes" :defaultKey="oldData.module"
:obj="moduleObj"
clearable checkStrictly size="small"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('test_track.case.project')" :label-width="oldData.formLabelWidth"
prop="projectId"
v-if="isPublic">
<el-select v-model="oldData.projectId" filterable clearable :disabled="oldData.readOnly">
<el-option v-for="item in projectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('commons.tag')" :label-width="oldData.formLabelWidth" prop="tag">
<ms-input-tag :read-only="oldData.readOnly" :currentScenario="oldData" v-if="showInputTag" ref="tag"
class="ms-case-input"/>
</el-form-item>
</el-col>
</el-row>
<!-- 自定义字段 -->
<el-form v-if="oldData.isFormAlive" :model="oldData.customFieldForm" :rules="oldData.customFieldRules"
ref="oldCustomFieldForm"
class="case-form">
<custom-filed-form-item :form="oldData.customFieldForm"
:form-label-width="oldData.formLabelWidth"
:issue-template="oldData.testCaseTemplate"/>
</el-form>
<el-row v-if="oldData.isCustomNum">
<el-col :span="7">
<el-form-item label="ID" :label-width="oldData.formLabelWidth" prop="customNum">
<el-input :disabled="oldData.readOnly" v-model.trim="oldData.customNum" size="small"
class="ms-case-input"></el-input>
</el-form-item>
</el-col>
</el-row>
<ms-form-divider :title="$t('test_track.case.step_info')"/>
<form-rich-text-item :disabled="oldData.readOnly" :label-width="oldData.formLabelWidth"
:title="$t('test_track.case.prerequisite')" :data="oldData" prop="prerequisite"/>
<step-change-item :label-width="oldData.formLabelWidth" :form="oldData"/>
<form-rich-text-item :disabled="oldData.readOnly" :label-width="oldData.formLabelWidth"
v-if="oldData.stepModel === 'TEXT'"
:title="$t('test_track.case.step_desc')" :data="oldData" prop="stepDescription"/>
<form-rich-text-item :disabled="oldData.readOnly" :label-width="oldData.formLabelWidth"
v-if="oldData.stepModel === 'TEXT'"
:title="$t('test_track.case.expected_results')" :data="oldData" prop="expectedResult"/>
<test-case-step-item :label-width="oldData.formLabelWidth"
v-if="oldData.stepModel === 'STEP' || !oldData.stepModel"
:form="oldData" :read-only="oldData.readOnly"/>
<ms-form-divider :title="$t('test_track.case.other_info')"/>
<test-case-edit-other-info :read-only="oldData.readOnly" :project-id="projectIds" :form="oldData"
:label-width="oldData.formLabelWidth" :case-id="oldData.id" ref="oldOtherInfo"/>
<el-row style="margin-top: 10px">
<el-col :span="20" :offset="1">{{ $t('test_track.review.comment') }}:
</el-col>
</el-row>
<el-row>
<el-col :span="20" :offset="1">
<review-comment-item v-for="(comment,index) in oldData.comments"
:key="index"
:comment="comment"
@refresh="getComments" api-url="/test/case"/>
<div v-if="oldData.comments && oldData.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>
</el-col>
</el-row>
<test-case-comment :case-id="oldData.id"
@getComments="getComments" ref="testCaseComment"/>
</el-form>
</el-card>
<el-card style="width: 50%;" ref="new">
<el-form :model="newData" ref="new" class="case-form" v-loading="newLoading">
<ms-form-divider :title="$t('test_track.plan_view.base_info')"/>
<el-row>
<el-col :span="8">
<el-form-item
:placeholder="$t('test_track.case.input_name')"
:label="$t('test_track.case.name')"
:label-width="newData.formLabelWidth"
prop="name">
<el-input :disabled="newData.readOnly" v-model="newData.name" size="small"
class="ms-case-input"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('test_track.case.module')" :label-width="newData.formLabelWidth" prop="module"
v-if="!isPublic">
<ms-select-tree :disabled="newData.readOnly" :data="treeNodes" :defaultKey="newData.module"
:obj="moduleObj"
clearable checkStrictly size="small"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('test_track.case.project')" :label-width="newData.formLabelWidth"
prop="projectId"
v-if="isPublic">
<el-select v-model="newData.projectId" filterable clearable :disabled="newData.readOnly">
<el-option v-for="item in projectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('commons.tag')" :label-width="newData.formLabelWidth" prop="tag">
<ms-input-tag :read-only="newData.readOnly" :currentScenario="newData" v-if="showInputTag" ref="tag"
class="ms-case-input"/>
</el-form-item>
</el-col>
</el-row>
<!-- 自定义字段 -->
<el-form v-if="newData.isFormAlive" :model="newData.customFieldForm" :rules="newData.customFieldRules"
ref="newCustomFieldForm"
class="case-form">
<custom-filed-form-item :form="newData.customFieldForm" :form-label-width="newData.formLabelWidth"
:issue-template="newData.testCaseTemplate" :is-public="isPublic"/>
</el-form>
<el-row v-if="newData.isCustomNum">
<el-col :span="7">
<el-form-item label="ID" :label-width="newData.formLabelWidth" prop="customNum">
<el-input :disabled="newData.readOnly" v-model.trim="newData.customNum" size="small"
class="ms-case-input"></el-input>
</el-form-item>
</el-col>
</el-row>
<ms-form-divider :title="$t('test_track.case.step_info')"/>
<form-rich-text-item :disabled="newData.readOnly" :label-width="newData.formLabelWidth"
:title="$t('test_track.case.prerequisite')" :data="newData" prop="prerequisite"/>
<step-change-item :label-width="newData.formLabelWidth" :form="newData"/>
<form-rich-text-item :disabled="newData.readOnly" :label-width="newData.formLabelWidth"
v-if="newData.stepModel === 'TEXT'"
:title="$t('test_track.case.step_desc')" :data="newData" prop="stepDescription"/>
<form-rich-text-item :disabled="newData.readOnly" :label-width="newData.formLabelWidth"
v-if="newData.stepModel === 'TEXT'"
:title="$t('test_track.case.expected_results')" :data="newData" prop="expectedResult"/>
<test-case-step-item :label-width="newData.formLabelWidth"
v-if="newData.stepModel === 'STEP' || !newData.stepModel"
:form="newData" :read-only="newData.readOnly"/>
<ms-form-divider :title="$t('test_track.case.other_info')"/>
<test-case-edit-other-info :read-only="newData.readOnly" :project-id="projectIds" :form="newData"
:label-width="newData.formLabelWidth" :case-id="newData.id" ref="newOtherInfo"/>
<el-row style="margin-top: 10px">
<el-col :span="20" :offset="1">{{ $t('test_track.review.comment') }}:
</el-col>
</el-row>
<el-row>
<el-col :span="20" :offset="1">
<review-comment-item v-for="(comment,index) in newData.comments"
:key="index"
:comment="comment"
@refresh="getComments" api-url="/test/case"/>
<div v-if="newData.comments && newData.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>
</el-col>
</el-row>
<test-case-comment :case-id="newData.id"
@getComments="getComments" ref="testCaseComment"/>
</el-form>
</el-card>
</div>
</div>
</template>
<script>
import MsFormDivider from "metersphere-frontend/src/components/MsFormDivider";
import MsInputTag from "metersphere-frontend/src/components/MsInputTag";
import {getCurrentProjectID, getCurrentUser} from "metersphere-frontend/src/utils/token";
import {removeGoBackListener} from "metersphere-frontend/src/utils";
import {buildTestCaseOldFields, parseCustomField, sortCustomFields} from "metersphere-frontend/src/utils/custom_field";
import TestCaseEditOtherInfo from "@/business/case/components/TestCaseEditOtherInfo";
import TestCaseStepItem from "@/business/case/components/TestCaseStepItem";
import StepChangeItem from "@/business/case/components/StepChangeItem";
import TestCaseComment from "@/business/case/components/TestCaseComment";
import FormRichTextItem from "metersphere-frontend/src/components/FormRichTextItem";
import MsSelectTree from "metersphere-frontend/src/components/select-tree/SelectTree";
import CustomFiledFormItem from "metersphere-frontend/src/components/form/CustomFiledFormItem";
import ReviewCommentItem from "@/business/review/commom/ReviewCommentItem";
import {useStore} from "@/store";
import {getProjectListAll, getProjectMemberOption} from "@/business/utils/sdk-utils";
import {getTestTemplate} from "@/api/custom-field-template";
import {testCaseCommentList} from "@/api/test-case-comment";
const {diff} = require("@/business/v_node_diff");
export default {
name: "TestCaseVersionDiff",
components: {
MsFormDivider,
MsInputTag,
TestCaseEditOtherInfo,
TestCaseStepItem,
StepChangeItem,
TestCaseComment,
FormRichTextItem,
MsSelectTree,
CustomFiledFormItem,
ReviewCommentItem,
},
props: {
oldData: {
type: Object
},
newData: {
type: Object
},
treeNodes: [],
isPublic: {
type: Boolean,
default() {
return false;
}
}
},
computed: {
projectIds() {
return getCurrentProjectID();
},
moduleOptions() {
return useStore().testCaseModuleOptions;
},
isCustomNum() {
return useStore().currentProjectIsCustomNum;
}
},
data() {
return {
projectList: [],
dialogFormVisible: false,
workspaceId: '',
formLabelWidth: "100px",
operationType: '',
methodOptions: [
{value: 'auto', label: this.$t('test_track.case.auto')},
{value: 'manual', label: this.$t('test_track.case.manual')}
],
testCase: {},
testCases: [],
index: 0,
showInputTag: true,
tableType: "",
moduleObj: {
id: 'id',
label: 'name',
},
versionData: [],
dialogVisible: false,
maintainerOptions: [],
oldLoading: null,
newLoading: null,
isReloadData: true
};
},
mounted() {
this.oldLoading = true;
this.oldLoading = true;
this.getProjectList();
this.getComments("newData");
this.getComments("oldData");
this.open("oldData");
this.open("newData");
this.$nextTick(function () {
setTimeout(this.getDiff, (this.$refs.old.$children.length + 1) * 1500)
})
},
methods: {
getDiff() {
let oldVnode = this.$refs.old
let vnode = this.$refs.new
let oldColor = "";
let newColor = "";
if (this.oldData.createTime > this.newData.createTime) {
oldColor = "rgb(121, 225, 153,0.3)";
newColor = "rgb(241,200,196,0.45)"
} else {
oldColor = "rgb(241,200,196,0.45)"
newColor = "rgb(121, 225, 153,0.3)";
}
diff(oldVnode, vnode, oldColor, newColor);
this.isReloadData = false
},
alert: alert,
currentUser: () => {
return getCurrentUser();
},
setModule(id, data) {
this.form.module = id;
this.form.nodePath = data.path;
},
setDefaultValue(prop) {
if (!this[prop].prerequisite) {
this[prop].prerequisite = "";
}
if (!this[prop].stepDescription) {
this[prop].stepDescription = "";
}
if (!this[prop].expectedResult) {
this[prop].expectedResult = "";
}
if (!this[prop].remark) {
this[prop].remark = "";
}
useStore().testCaseMap.set(this[prop].id, 0);
},
openComment() {
this.$refs.testCaseComment.open()
},
getComments(prop, callback) {
let id = '';
if (this[prop]) {
id = this[prop].id;
} else {
id = this.form.id;
}
testCaseCommentList(id)
.then(res => {
this[prop].comments = res.data;
if (callback) {
callback();
}
});
},
reloadForm(prop) {
this[prop].isFormAlive = false;
this.$nextTick(() => {
this[prop].isFormAlive = true;
if (prop.indexOf("new") != -1) {
this.newLoading = false;
} else {
this.oldLoading = false;
}
});
},
open(prop) {
this[prop].projectId = this.projectIds;
let initFuc = this.initEdit;
this[prop].$get = this.$get;
let that = this;
getTestTemplate()
.then((testCaseTemplate) => {
this[prop].testCaseTemplate = testCaseTemplate;
initFuc(prop, () => {
that.reloadForm(prop);
});
});
},
initEdit(prop, callback) {
this.setFormData(prop);
this.getSelectOptions();
if (callback) {
callback();
}
},
setFormData(prop) {
try {
this[prop].selected = JSON.parse(this[prop].testId);
} catch (error) {
this[prop].selected = this[prop].testId
}
let tmp = {};
Object.assign(tmp, this[prop]);
if (!tmp.steps || tmp.steps.length < 1) {
tmp.steps = [{
num: 1,
desc: '',
result: ''
}];
}
Object.assign(this[prop], tmp);
if (!this[prop].stepModel) {
this[prop].stepModel = "STEP";
}
this[prop].module = this[prop].nodeId;
//
this[prop].customFieldForm = parseCustomField(this[prop], this[prop].testCaseTemplate, null, this[prop] ? buildTestCaseOldFields(this[prop]) : null);
sortCustomFields(this[prop].testCaseTemplate.customFields);
},
setTestCaseExtInfo(prop) {
this[prop] = {};
if (this[prop]) {
//
this[prop] = this[prop].isCopy ? {} : this[prop];
}
},
close() {
//
removeGoBackListener(this.close);
this.dialogFormVisible = false;
},
getMaintainerOptions() {
getProjectMemberOption()
.then(response => {
this.maintainerOptions = response.data;
});
},
getSelectOptions() {
this.getMaintainerOptions();
},
resetForm(prop) {
this[prop].name = '';
this[prop].module = '';
this[prop].type = '';
this[prop].method = '';
this[prop].maintainer = '';
this[prop].priority = '';
this[prop].prerequisite = '';
this[prop].remark = '';
this[prop].testId = '';
this[prop].testName = '';
this[prop].steps = [{
num: 1,
desc: '',
result: ''
}];
this[prop].customNum = '';
}
,
getProjectList() {
if (!this.projectList || this.projectList.length === 0) { //
getProjectListAll()
.then((response) => {
this.projectList = response.data; //,
});
}
}
}
}
</script>
<style scoped>
.compare-class {
display: flex;
justify-content: space-between;
}
</style>