fix(操作日志): 增加Diff插件展示变更对比内容。

This commit is contained in:
fit2-zhao 2021-05-26 18:30:29 +08:00 committed by fit2-zhao
parent 55d3661616
commit e074c50ba9
9 changed files with 46 additions and 85 deletions

View File

@ -2,16 +2,11 @@ package io.metersphere.log.utils;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import io.metersphere.log.utils.dff.Diff;
import io.metersphere.log.utils.dff.JsonDiff;
import io.metersphere.log.utils.dff.Operation;
import io.metersphere.log.vo.DetailColumn; import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails; import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.StatusReference; import io.metersphere.log.vo.StatusReference;
@ -60,7 +55,7 @@ public class ReflexObjectUtil {
column.setDepthDff(true); column.setDepthDff(true);
if (val != null) { if (val != null) {
try { try {
if (ReflexObjectUtil.isJsonArray(val.toString())) { if (f.getName().equals("loadConfiguration")) {
val = "{\"" + "压力配置" + "\":" + val.toString() + "}"; val = "{\"" + "压力配置" + "\":" + val.toString() + "}";
} }
Gson gson = new GsonBuilder().setPrettyPrinting().create(); Gson gson = new GsonBuilder().setPrettyPrinting().create();
@ -121,51 +116,10 @@ public class ReflexObjectUtil {
} }
} }
// 深度对比 // 深度对比
if (originalColumns.get(i).isDepthDff() && originalColumns.get(i).getOriginalValue() != null && newColumns.get(i).getOriginalValue() != null) { DetailColumn column = new DetailColumn();
ObjectMapper mapper = new ObjectMapper(); BeanUtils.copyBean(column, originalColumns.get(i));
JsonNode source = mapper.readTree(originalColumns.get(i).getOriginalValue().toString()); column.setNewValue(newColumns.get(i).getOriginalValue());
JsonNode target = mapper.readTree(newColumns.get(i).getOriginalValue().toString()); comparedColumns.add(column);
List<Diff> after = JsonDiff.jsonDiff(source, target);
StringBuilder addBuff = new StringBuilder();
StringBuilder removeBuff = new StringBuilder();
StringBuilder repBuff = new StringBuilder();
StringBuilder oldValue = new StringBuilder();
for (Diff item : after) {
if (item.getOperation().equals(Operation.ADD)) {
addBuff.append(item.getPath() + "" + item.getValue()).append("\n");
}
if (item.getOperation().equals(Operation.REMOVE)) {
removeBuff.append(item.getPath() + "" + item.getValue()).append("\n");
}
if (item.getOperation().equals(Operation.REPLACE)) {
repBuff.append(item.getPath() + "" + item.getValue()).append("\n");
oldValue.append(item.getPath() + "" + item.getSrcValue()).append("\n");
}
}
StringBuilder newValue = new StringBuilder();
if (addBuff != null && addBuff.toString().length() > 0) {
newValue.append("添加:\n").append(addBuff).append("\n");
}
if (removeBuff != null && removeBuff.toString().length() > 0) {
newValue.append("移除:\n").append(removeBuff).append("\n");
}
if (repBuff != null && repBuff.toString().length() > 0) {
newValue.append("修改:\n").append(repBuff).append("\n");
}
DetailColumn column = new DetailColumn();
BeanUtils.copyBean(column, originalColumns.get(i));
if (oldValue != null && oldValue.length() > 0) {
column.setOriginalValue(oldValue);
}
column.setNewValue(newValue);
comparedColumns.add(column);
} else {
DetailColumn column = new DetailColumn();
BeanUtils.copyBean(column, originalColumns.get(i));
column.setNewValue(newColumns.get(i).getOriginalValue());
comparedColumns.add(column);
}
} }
} }
} }

View File

@ -29,6 +29,7 @@
"json-bigint": "^1.0.0", "json-bigint": "^1.0.0",
"json-schema-faker": "^0.5.0-rcv.32", "json-schema-faker": "^0.5.0-rcv.32",
"json5": "^2.1.3", "json5": "^2.1.3",
"jsondiffpatch": "^0.4.1",
"jsoneditor": "^9.1.2", "jsoneditor": "^9.1.2",
"jsonpath": "^1.1.0", "jsonpath": "^1.1.0",
"jspdf": "^2.1.1", "jspdf": "^2.1.1",

View File

@ -63,7 +63,7 @@
infoVisible: false, infoVisible: false,
loading: false, loading: false,
details: [], details: [],
linkDatas: ["prerequisite", "steps", "remark", "request", "response", "scenarioDefinition", "loadConfiguration", "advancedConfiguration"], linkDatas: ["prerequisite", "steps", "remark", "request", "response", "scenarioDefinition","tags", "loadConfiguration", "advancedConfiguration"],
} }
}, },
methods: { methods: {

View File

@ -11,27 +11,9 @@
</div> </div>
<div style="overflow: auto"> <div style="overflow: auto">
<p class="tip">{{ this.$t('report.test_log_details') }} </p> <p class="tip">{{ this.$t('report.test_log_details') }} </p>
<el-row style="background:#F8F8F8">
<el-col :span="12">
{{$t('operating_log.before_change')}}
</el-col>
<el-col :span="12">
{{$t('operating_log.after_change')}}
</el-col>
</el-row>
<el-row> <el-row>
<el-col :span="12"> <pre v-html="getDiff(detail.originalValue,detail.newValue)"></pre>
<div style="width: 400px;overflow: auto"> <!--</el-col>-->
<pre v-if="formatData.indexOf(detail.columnName)!==-1">{{ detail.originalValue }}</pre>
<div v-else>{{ detail.originalValue }}</div>
</div>
</el-col>
<el-col :span="12">
<div style="width: 400px;overflow: auto">
<pre v-if="formatData.indexOf(detail.columnName)!==-1">{{ detail.newValue }}</pre>
<div v-else>{{ detail.newValue }}</div>
</div>
</el-col>
</el-row> </el-row>
</div> </div>
</div> </div>
@ -39,6 +21,8 @@
</template> </template>
<script> <script>
const jsondiffpatch = require('jsondiffpatch');
const formattersHtml = jsondiffpatch.formatters.html;
export default { export default {
name: "MsHistoryDetail", name: "MsHistoryDetail",
components: {}, components: {},
@ -49,10 +33,14 @@
return { return {
infoVisible: false, infoVisible: false,
detail: {}, detail: {},
formatData:["loadConfiguration","advancedConfiguration","config","variables","tags","customFields","steps","scenarioDefinition","request","response"], formatData: ["loadConfiguration", "advancedConfiguration", "config", "variables", "tags", "customFields", "steps", "scenarioDefinition", "request", "response"],
} }
}, },
methods: { methods: {
getDiff(v1, v2) {
let delta = jsondiffpatch.diff(v1, v2);
return formattersHtml.format(delta, v1);
},
handleClose() { handleClose() {
this.infoVisible = false; this.infoVisible = false;
}, },
@ -68,6 +56,8 @@
</script> </script>
<style scoped> <style scoped>
@import "~jsondiffpatch/dist/formatters-styles/html.css";
@import "~jsondiffpatch/dist/formatters-styles/annotated.css";
.tip { .tip {
padding: 3px 5px; padding: 3px 5px;

View File

@ -17,17 +17,16 @@
<div v-if="detail && detail.details && detail.details.columns" style="margin-left: 20px"> <div v-if="detail && detail.details && detail.details.columns" style="margin-left: 20px">
<el-table :data="detail.details.columns"> <el-table :data="detail.details.columns">
<el-table-column prop="columnTitle" :label="$t('operating_log.change_field')" width="150px" show-overflow-tooltip/> <el-table-column prop="columnTitle" :label="$t('operating_log.change_field')" width="150px" show-overflow-tooltip/>
<el-table-column prop="originalValue" :label="$t('operating_log.before_change')" width="400px" show-overflow-tooltip> <!--<el-table-column prop="originalValue" :label="$t('operating_log.before_change')" width="400px">-->
<template v-slot:default="scope"> <!--<template v-slot:default="scope">-->
<span v-if="timeDates.indexOf(scope.row.columnName)!==-1">{{ scope.row.originalValue | timestampFormatDate }}</span> <!--<span v-if="timeDates.indexOf(scope.row.columnName)!==-1">{{ scope.row.originalValue | timestampFormatDate }}</span>-->
<pre v-else>{{ scope.row.originalValue }}</pre> <!--<div v-else>{{ scope.row.originalValue }}</div>-->
<!--</template>-->
</template> <!--</el-table-column>-->
</el-table-column> <el-table-column prop="newValue" :label="$t('operating_log.change_content')">
<el-table-column prop="newValue" :label="$t('operating_log.after_change')" width="400px" show-overflow-tooltip>
<template v-slot:default="scope"> <template v-slot:default="scope">
<span v-if="timeDates.indexOf(scope.row.columnName)!==-1">{{ scope.row.newValue | timestampFormatDate }}</span> <span v-if="timeDates.indexOf(scope.row.columnName)!==-1">{{ scope.row.newValue | timestampFormatDate }}</span>
<pre v-else>{{ scope.row.newValue }}</pre> <pre v-html="getDiff(scope.row.originalValue,scope.row.newValue)" v-else></pre>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -48,7 +47,6 @@
{{n.columnTitle}}{{n.originalValue}} {{n.columnTitle}}{{n.originalValue}}
</pre> </pre>
</span> </span>
</div> </div>
</div> </div>
</div> </div>
@ -57,6 +55,9 @@
</template> </template>
<script> <script>
const jsondiffpatch = require('jsondiffpatch');
const formattersHtml = jsondiffpatch.formatters.html;
export default { export default {
name: "MsLogDetail", name: "MsLogDetail",
components: {}, components: {},
@ -66,6 +67,8 @@
data() { data() {
return { return {
infoVisible: false, infoVisible: false,
d1: "",
d2: "",
detail: {}, detail: {},
LOG_TYPE: [ LOG_TYPE: [
{id: 'CREATE', label: this.$t('api_test.definition.request.create_info')}, {id: 'CREATE', label: this.$t('api_test.definition.request.create_info')},
@ -122,10 +125,18 @@
handleClose() { handleClose() {
this.infoVisible = false; this.infoVisible = false;
}, },
getDiff(v1, v2) {
let delta = jsondiffpatch.diff(v1, v2);
return formattersHtml.format(delta, v1);
},
getDetails(id) { getDetails(id) {
this.result = this.$get("/operating/log/get/" + id, response => { this.result = this.$get("/operating/log/get/" + id, response => {
let data = response.data; let data = response.data;
this.detail = data; this.detail = data;
//let delta = jsondiffpatch.diff(this.d1, this.d2);/
//document.getElementById('visual').innerHTML = formattersHtml.format(delta, this.d1);
// self-explained json
//document.getElementById('annotated').innerHTML = jsondiffpatch.formatters.annotated.format(delta, this.d1);
}) })
}, },
open(id) { open(id) {
@ -140,6 +151,8 @@
</script> </script>
<style scoped> <style scoped>
@import "~jsondiffpatch/dist/formatters-styles/html.css";
@import "~jsondiffpatch/dist/formatters-styles/annotated.css";
.tip { .tip {
padding: 3px 5px; padding: 3px 5px;

@ -1 +1 @@
Subproject commit 0af67efb336b3f5f6718c7b2684de4d4985c0aee Subproject commit e6cc6ba0e8264f4f3780448b60dc149aef8a2cbc

View File

@ -817,7 +817,7 @@ export default {
wait_controller: "Wait controller", wait_controller: "Wait controller",
if_controller: "If controller", if_controller: "If controller",
loop_controller: "Loop Controller", loop_controller: "Loop Controller",
transcation_controller:"Transcation controller", transcation_controller: "Transcation controller",
scenario_import: "Scenario import", scenario_import: "Scenario import",
customize_script: "Customize script", customize_script: "Customize script",
customize_req: "Customize req", customize_req: "Customize req",
@ -1830,5 +1830,6 @@ export default {
after_change: "After change", after_change: "After change",
share: "Share", share: "Share",
change_history: "Change history", change_history: "Change history",
change_content: "Change content",
} }
}; };

View File

@ -1837,5 +1837,6 @@ export default {
after_change: "变更后", after_change: "变更后",
share: "分享", share: "分享",
change_history: "变更历史", change_history: "变更历史",
change_content: "变更内容",
} }
}; };

View File

@ -1837,5 +1837,6 @@ export default {
after_change: "變更後", after_change: "變更後",
share: "分享", share: "分享",
change_history: "變更歷史", change_history: "變更歷史",
change_content: "变更内容",
} }
}; };