forked from github/dataease
fix: 插件视图过滤器
This commit is contained in:
parent
868cfbe28e
commit
16f5249caf
@ -71,7 +71,6 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-row class="padding-lr" style="margin-top: 6px;">
|
<el-row class="padding-lr" style="margin-top: 6px;">
|
||||||
<span>test</span>
|
|
||||||
<span class="data-area-label">
|
<span class="data-area-label">
|
||||||
<span>{{ $t('chart.result_filter') }}</span>
|
<span>{{ $t('chart.result_filter') }}</span>
|
||||||
<span
|
<span
|
||||||
|
@ -1,12 +1,4 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": ["@babel/preset-env"],
|
||||||
["env", {
|
"plugins": ["@babel/plugin-transform-runtime", "@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-object-rest-spread"]
|
||||||
"modules": false,
|
|
||||||
"targets": {
|
|
||||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"stage-2"
|
|
||||||
],
|
|
||||||
"plugins": ["transform-vue-jsx", "transform-runtime"]
|
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@antv/g2plot": "^2.4.31",
|
"@antv/g2plot": "^2.4.31",
|
||||||
|
"@babel/polyfill": "^7.12.1",
|
||||||
|
"@babel/runtime": "^7.18.9",
|
||||||
"@riophae/vue-treeselect": "0.4.0",
|
"@riophae/vue-treeselect": "0.4.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
"vue": "2.6.10",
|
"vue": "2.6.10",
|
||||||
"vue-i18n": "7.3.2",
|
"vue-i18n": "7.3.2",
|
||||||
"vue-router": "^3.0.1",
|
"vue-router": "^3.0.1",
|
||||||
@ -22,15 +25,13 @@
|
|||||||
"vuex": "3.1.0"
|
"vuex": "3.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.6.4",
|
||||||
|
"@babel/plugin-proposal-object-rest-spread": "^7.18.9",
|
||||||
|
"@babel/plugin-proposal-optional-chaining": "^7.18.6",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.6.2",
|
||||||
|
"@babel/preset-env": "^7.6.3",
|
||||||
"autoprefixer": "^7.1.2",
|
"autoprefixer": "^7.1.2",
|
||||||
"babel-core": "^6.22.1",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
|
||||||
"babel-loader": "^7.1.1",
|
|
||||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
|
||||||
"babel-plugin-transform-runtime": "^6.22.0",
|
|
||||||
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
|
||||||
"babel-preset-env": "^1.3.2",
|
|
||||||
"babel-preset-stage-2": "^6.22.0",
|
|
||||||
"chalk": "^2.0.1",
|
"chalk": "^2.0.1",
|
||||||
"copy-webpack-plugin": "^4.6.0",
|
"copy-webpack-plugin": "^4.6.0",
|
||||||
"css-loader": "^0.28.0",
|
"css-loader": "^0.28.0",
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
width="896px"
|
||||||
|
append-to-body
|
||||||
|
title="添加过滤"
|
||||||
|
destroy-on-close
|
||||||
|
class="de-dialog-form filter-tree-cont"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
>
|
||||||
|
<div class="tree-cont">
|
||||||
|
<div class="content">
|
||||||
|
<rowAuth ref="rowAuth" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
slot="footer"
|
||||||
|
class="dialog-footer"
|
||||||
|
>
|
||||||
|
<de-btn
|
||||||
|
secondary
|
||||||
|
@click="closeFilter"
|
||||||
|
>{{ $t('chart.cancel') }}
|
||||||
|
</de-btn>
|
||||||
|
<de-btn
|
||||||
|
type="primary"
|
||||||
|
@click="changeFilter"
|
||||||
|
>{{ $t('chart.confirm') }}
|
||||||
|
</de-btn>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import rowAuth from './rowAuth.vue'
|
||||||
|
export default {
|
||||||
|
name: 'FilterTree',
|
||||||
|
inject: ['filedList'],
|
||||||
|
components: {
|
||||||
|
rowAuth
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
computedFiledList() {
|
||||||
|
return this.filedList().reduce((pre, next) => {
|
||||||
|
if (next.id !== 'count') {
|
||||||
|
pre[next.id] = next
|
||||||
|
}
|
||||||
|
return pre
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeFilter() {
|
||||||
|
this.dialogVisible = false
|
||||||
|
},
|
||||||
|
changeFilter() {
|
||||||
|
const { logic, items, errorMessage } = this.$refs.rowAuth.submit()
|
||||||
|
if (errorMessage) {
|
||||||
|
this.$message({
|
||||||
|
message: errorMessage,
|
||||||
|
type: 'error',
|
||||||
|
showClose: true
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.dfsTreeDelete(items)
|
||||||
|
this.$emit('filter-data', { logic, items })
|
||||||
|
this.dialogVisible = false
|
||||||
|
},
|
||||||
|
dfsTreeDelete(arr) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele?.subTree?.items?.length) {
|
||||||
|
this.dfsTreeDelete(ele.subTree.items)
|
||||||
|
} else {
|
||||||
|
if (ele.field) {
|
||||||
|
this.$delete(ele, 'field')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
dfsTree(arr) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele?.subTree?.items?.length) {
|
||||||
|
this.dfsTree(ele.subTree.items)
|
||||||
|
} else {
|
||||||
|
if (this.computedFiledList[ele.fieldId]) {
|
||||||
|
ele.field = this.computedFiledList[ele.fieldId]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
init(tree) {
|
||||||
|
this.dialogVisible = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.dfsTree(tree.items || [])
|
||||||
|
this.$refs.rowAuth.init(tree || {})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.filter-tree-cont {
|
||||||
|
.tree-cont {
|
||||||
|
min-height: 67px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--deBorderBase, #DCDFE6);
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 500px;
|
||||||
|
.content {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
|||||||
|
function formatEnum(ele) {
|
||||||
|
return {
|
||||||
|
value: ele,
|
||||||
|
label: `chart.filter_${ele.replace(' ', '_')}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const textEnum = ['eq', 'not_eq', 'like', 'not like', 'null', 'not_null', 'empty', 'not_empty']
|
||||||
|
const textOptions = textEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const dateEnum = ['eq', 'not_eq', 'lt', 'gt', 'le', 'ge']
|
||||||
|
const dateOptions = dateEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const valueEnum = [...dateEnum]
|
||||||
|
const valueOptions = valueEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const fieldEnum = ['text', 'time', 'value', 'value', '', 'location']
|
||||||
|
|
||||||
|
export {
|
||||||
|
textOptions,
|
||||||
|
dateOptions,
|
||||||
|
valueOptions,
|
||||||
|
fieldEnum
|
||||||
|
}
|
@ -0,0 +1,348 @@
|
|||||||
|
<template>
|
||||||
|
<div class="rowAuth">
|
||||||
|
<rowAuthTree
|
||||||
|
@del="(idx) => del(idx)"
|
||||||
|
@addCondReal="addCondReal"
|
||||||
|
@removeRelationList="removeRelationList"
|
||||||
|
@changeAndOrDfs="(type) => changeAndOrDfs(relationList, type)"
|
||||||
|
:relationList="relationList"
|
||||||
|
:logic.sync="logic"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
/>
|
||||||
|
<svg width="388" height="100%" class="real-line">
|
||||||
|
<path
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
:d="svgRealinePath"
|
||||||
|
fill="none"
|
||||||
|
stroke="#CCCCCC"
|
||||||
|
stroke-width="0.5"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<svg width="388" height="100%" class="dash-line">
|
||||||
|
<path
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
:d="svgDashinePath"
|
||||||
|
fill="none"
|
||||||
|
stroke="#CCCCCC"
|
||||||
|
stroke-width="0.5"
|
||||||
|
stroke-dasharray="4,4"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import rowAuthTree from "./rowTeeAuth.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "RowAuth",
|
||||||
|
components: {
|
||||||
|
rowAuthTree,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
svgRealinePath() {
|
||||||
|
const lg = this.relationList.length;
|
||||||
|
let a = { x: 0, y: 0, child: this.relationList };
|
||||||
|
a.y = Math.floor(this.dfsXY(a, 0) / 2);
|
||||||
|
if (!lg) return "";
|
||||||
|
let path = this.calculateDepth(a);
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
svgDashinePath() {
|
||||||
|
const lg = this.relationList.length;
|
||||||
|
let a = { x: 0, y: 0, child: this.relationList };
|
||||||
|
a.y = Math.floor(this.dfsXY(a, 0) / 2);
|
||||||
|
if (!lg) return `M48 20 L68 20`;
|
||||||
|
let path = this.calculateDepthDash(a);
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
executeAxios(url, type, data, callBack) {
|
||||||
|
this.$emit("execute-axios", url, type, data, callBack);
|
||||||
|
},
|
||||||
|
init(expressionTree) {
|
||||||
|
const { logic = "or", items = [] } = expressionTree;
|
||||||
|
this.logic = logic;
|
||||||
|
this.relationList = this.dfsInit(items);
|
||||||
|
},
|
||||||
|
submit() {
|
||||||
|
this.errorMessage = '';
|
||||||
|
return {
|
||||||
|
logic: this.logic,
|
||||||
|
items: this.dfsSubmit(this.relationList),
|
||||||
|
errorMessage: this.errorMessage
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorDetected({ enumValue, deType, filterType, term, value }) {
|
||||||
|
if (filterType === "logic") {
|
||||||
|
if (
|
||||||
|
!term.includes("null") &&
|
||||||
|
!term.includes("empty") &&
|
||||||
|
(value === "")
|
||||||
|
) {
|
||||||
|
this.errorMessage = this.$t("chart.filter_value_can_null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ([2, 3].includes(deType)) {
|
||||||
|
if (parseFloat(value).toString() === "NaN") {
|
||||||
|
this.errorMessage = this.$t("chart.filter_value_can_not_str");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filterType === "enum") {
|
||||||
|
if (enumValue.length < 1) {
|
||||||
|
this.errorMessage = this.$t("chart.enum_value_can_not_null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dfsInit(arr) {
|
||||||
|
const elementList = [];
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
const { subTree } = ele;
|
||||||
|
if (subTree) {
|
||||||
|
const { items, logic } = subTree;
|
||||||
|
const child = this.dfsInit(items);
|
||||||
|
elementList.push({ logic, child });
|
||||||
|
} else {
|
||||||
|
const {
|
||||||
|
enumValue,
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
field,
|
||||||
|
} = ele;
|
||||||
|
const { name, deType } = (field || {});
|
||||||
|
elementList.push({
|
||||||
|
enumValue: enumValue.join(','),
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
name,
|
||||||
|
deType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return elementList;
|
||||||
|
},
|
||||||
|
dfsSubmit(arr) {
|
||||||
|
const items = [];
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
const { child = [] } = ele;
|
||||||
|
if (child.length) {
|
||||||
|
const { logic } = ele;
|
||||||
|
const subTree = this.dfsSubmit(child);
|
||||||
|
items.push({
|
||||||
|
enumValue: [],
|
||||||
|
fieldId: '',
|
||||||
|
filterType: '',
|
||||||
|
term: '',
|
||||||
|
type: 'tree',
|
||||||
|
value: '', subTree: { logic, items: subTree} });
|
||||||
|
} else {
|
||||||
|
const { enumValue, fieldId, filterType,deType, term, value } = ele;
|
||||||
|
this.errorDetected({ deType, enumValue, filterType, term, value})
|
||||||
|
if (fieldId) {
|
||||||
|
items.push({
|
||||||
|
enumValue: enumValue ? enumValue.split(',') : [],
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
type: 'item',
|
||||||
|
subTree: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
},
|
||||||
|
removeRelationList() {
|
||||||
|
this.relationList = [];
|
||||||
|
},
|
||||||
|
getY(arr) {
|
||||||
|
const [a] = arr;
|
||||||
|
if (a.child?.length) {
|
||||||
|
return this.getY(a.child);
|
||||||
|
}
|
||||||
|
return a.y;
|
||||||
|
},
|
||||||
|
getLastY(arr) {
|
||||||
|
const a = arr[arr.length];
|
||||||
|
if (a.child?.length) {
|
||||||
|
return this.getLastY(a.child);
|
||||||
|
}
|
||||||
|
return a.y;
|
||||||
|
},
|
||||||
|
calculateDepthDash(obj) {
|
||||||
|
const lg = obj.child?.length;
|
||||||
|
let path = "";
|
||||||
|
if (!lg && Array.isArray(obj.child)) {
|
||||||
|
const { x, y } = obj;
|
||||||
|
path += `M${48 + x * 68} ${y * 41.4 + 20} L${88 + x * 68} ${
|
||||||
|
y * 41.4 + 20
|
||||||
|
}`;
|
||||||
|
} else if (obj.child?.length) {
|
||||||
|
let y = Math.max(
|
||||||
|
this.dfsY(obj, 0),
|
||||||
|
this.dfs(obj.child, 0) + this.getY(obj.child) - 1
|
||||||
|
);
|
||||||
|
let parent =
|
||||||
|
(this.dfs(obj.child, 0) * 41.4) / 2 +
|
||||||
|
(this.getY(obj.child) || 0) * 41.4;
|
||||||
|
const { x } = obj;
|
||||||
|
path += `M${24 + x * 68} ${parent} L${24 + x * 68} ${y * 41.4 + 20} L${
|
||||||
|
64 + x * 68
|
||||||
|
} ${y * 41.4 + 20}`;
|
||||||
|
obj.child.forEach((item) => {
|
||||||
|
path += this.calculateDepthDash(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
calculateDepth(obj) {
|
||||||
|
const lg = obj.child.length;
|
||||||
|
if (!lg) return "";
|
||||||
|
let path = "";
|
||||||
|
const { x: depth, y } = obj;
|
||||||
|
obj.child.forEach((item, index) => {
|
||||||
|
const { y: sibingLg, z } = item;
|
||||||
|
if (item.child?.length) {
|
||||||
|
let parent =
|
||||||
|
(this.dfs(obj.child, 0) * 41.4) / 2 +
|
||||||
|
(this.getY(obj.child) || 0) * 41.4;
|
||||||
|
let children =
|
||||||
|
(this.dfs(item.child, 0) * 41.4) / 2 + this.getY(item.child) * 41.4;
|
||||||
|
let path1 = 0;
|
||||||
|
let path2 = 0;
|
||||||
|
if (parent < children) {
|
||||||
|
path1 = parent;
|
||||||
|
path2 = children;
|
||||||
|
} else {
|
||||||
|
[path1, path2] = [children, parent];
|
||||||
|
}
|
||||||
|
if (y >= sibingLg) {
|
||||||
|
path1 = parent;
|
||||||
|
path2 = children;
|
||||||
|
}
|
||||||
|
path += `M${24 + depth * 68} ${path1} L${24 + depth * 68} ${path2} L${
|
||||||
|
68 + depth * 68
|
||||||
|
} ${path2}`;
|
||||||
|
// path += a;
|
||||||
|
path += this.calculateDepth(item);
|
||||||
|
}
|
||||||
|
if (!item.child?.length) {
|
||||||
|
// console.log(123, y, sibingLg, lg === 1 && index === 0 , item.z);
|
||||||
|
if (sibingLg >= y) {
|
||||||
|
path += `M${24 + depth * 68} ${y * 40} L${24 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 - 20.69921875
|
||||||
|
} L${68 + depth * 68} ${(sibingLg + 1) * 41.4 - 20.69921875}`;
|
||||||
|
} else {
|
||||||
|
path += `M${24 + depth * 68} ${
|
||||||
|
(sibingLg +
|
||||||
|
(lg === 1 && index === 0 ? 0 : 1) +
|
||||||
|
(obj.child[index + 1]?.child?.length ? y - sibingLg - 1 : 0)) *
|
||||||
|
41.4 +
|
||||||
|
20 +
|
||||||
|
(lg === 1 && index === 0 ? 26 : 0)
|
||||||
|
} L${24 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 -
|
||||||
|
20.69921875 -
|
||||||
|
(lg === 1 && index === 0 ? (z || 0) * 1.4 : 0)
|
||||||
|
} L${68 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 -
|
||||||
|
20.69921875 -
|
||||||
|
(lg === 1 && index === 0 ? (z || 0) * 1.4 : 0)
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
changeAndOrDfs(arr, logic) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele.child) {
|
||||||
|
ele.logic = logic === "and" ? "or" : "and";
|
||||||
|
this.changeAndOrDfs(ele.child, ele.logic);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
dfs(arr, count) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele.child?.length) {
|
||||||
|
count = this.dfs(ele.child, count);
|
||||||
|
} else {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
count += 1;
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
dfsY(obj, count) {
|
||||||
|
obj.child.forEach((ele) => {
|
||||||
|
if (ele.child?.length) {
|
||||||
|
count = this.dfsY(ele, count);
|
||||||
|
} else {
|
||||||
|
count = Math.max(count, ele.y, obj.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
dfsXY(obj, count) {
|
||||||
|
obj.child.forEach((ele) => {
|
||||||
|
ele.x = obj.x + 1;
|
||||||
|
if (ele.child?.length) {
|
||||||
|
let l = this.dfs(ele.child, 0);
|
||||||
|
ele.y = Math.floor(l / 2) + count;
|
||||||
|
count = this.dfsXY(ele, count);
|
||||||
|
} else {
|
||||||
|
count += 1;
|
||||||
|
ele.y = count - 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
count += 1;
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
addCondReal(type, logic) {
|
||||||
|
this.relationList.push(
|
||||||
|
type === "condition"
|
||||||
|
? { fieldId: '', value: "", enumValue: "", term: "", filterType: "logic", name: "", deType: "" }
|
||||||
|
: { child: [], logic }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
del(index) {
|
||||||
|
this.relationList.splice(index, 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
relationList: [],
|
||||||
|
logic: "or",
|
||||||
|
errorMessage: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.rowAuth {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
color: #2c3e50;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.real-line,
|
||||||
|
.dash-line {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,247 @@
|
|||||||
|
<template>
|
||||||
|
<div class="logic" :style="marginLeft">
|
||||||
|
<div class="logic-left">
|
||||||
|
<div class="operate-title">
|
||||||
|
<span
|
||||||
|
style="
|
||||||
|
{
|
||||||
|
color: '#bfbfbf';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
class="mrg-title"
|
||||||
|
v-if="x"
|
||||||
|
>
|
||||||
|
{{ logic === 'or' ? "OR" : "AND" }}
|
||||||
|
</span>
|
||||||
|
<el-dropdown @command="handleCommand" trigger="click" v-else>
|
||||||
|
<span
|
||||||
|
style="
|
||||||
|
{
|
||||||
|
color: 'rgba(0,0,0,.65)';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
class="mrg-title"
|
||||||
|
>
|
||||||
|
{{ logic === 'or' ? "OR" : "AND" }}<i class="el-icon-arrow-down"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item command="and">AND</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="or">OR</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
<span class="operate-icon" v-if="x">
|
||||||
|
<!-- <el-tooltip
|
||||||
|
class="item"
|
||||||
|
effect="light"
|
||||||
|
content="切换最外侧关系节点类型时,所有关系都会切换,内外层关系必然相反"
|
||||||
|
placement="top-end"
|
||||||
|
>
|
||||||
|
<i v-if="!x" class="el-icon-warning-outline"></i>
|
||||||
|
</el-tooltip> -->
|
||||||
|
<i class="el-icon-delete" @click="$emit('removeRelationList')"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="logic-right">
|
||||||
|
<template v-for="(item, index) in relationList">
|
||||||
|
<logic-relation
|
||||||
|
:x="item.x"
|
||||||
|
@del="(idx) => del(idx, item.child)"
|
||||||
|
@addCondReal="(type, logic) => add(type, item.child, logic)"
|
||||||
|
v-if="item.child"
|
||||||
|
:key="index"
|
||||||
|
:logic="item.logic"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
@removeRelationList="removeRelationList(index)"
|
||||||
|
:relationList="item.child"
|
||||||
|
>
|
||||||
|
</logic-relation>
|
||||||
|
<filter-filed
|
||||||
|
v-else
|
||||||
|
:item="item"
|
||||||
|
@del="$emit('del', index)"
|
||||||
|
:index="index"
|
||||||
|
:key="index"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
></filter-filed>
|
||||||
|
</template>
|
||||||
|
<div class="logic-right-add">
|
||||||
|
<button @click="addCondReal('condition')" class="operand-btn">
|
||||||
|
+ {{ $t('auth.add_condition')}}
|
||||||
|
</button>
|
||||||
|
<button v-if="x < 2" @click="addCondReal('relation')" class="operand-btn">
|
||||||
|
+ {{ $t('auth.add_relationship')}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import filterFiled from "./filterFiled";
|
||||||
|
export default {
|
||||||
|
name: "LogicRelation",
|
||||||
|
props: {
|
||||||
|
relationList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
x: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
logic: {
|
||||||
|
type: String,
|
||||||
|
default: 'or',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
filterFiled,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
marginLeft() {
|
||||||
|
return {
|
||||||
|
marginLeft: this.x ? "20px" : 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
executeAxios(url, type, data, callBack) {
|
||||||
|
this.$emit("execute-axios", url, type, data, callBack);
|
||||||
|
},
|
||||||
|
handleCommand(type) {
|
||||||
|
this.$emit('update:logic', type);
|
||||||
|
this.$emit("changeAndOrDfs", type)
|
||||||
|
},
|
||||||
|
removeRelationList(index) {
|
||||||
|
this.relationList.splice(index, 1);
|
||||||
|
},
|
||||||
|
addCondReal(type) {
|
||||||
|
this.$emit("addCondReal", type, this.logic === 'or' ? 'and' : 'or');
|
||||||
|
},
|
||||||
|
add(type, child, logic) {
|
||||||
|
child.push(type === "condition" ?{ fieldId: '', value: '', enumValue: '', term: '', filterType: 'logic', name: '', deType: "" } : { child: [], logic });
|
||||||
|
},
|
||||||
|
del(index, child) {
|
||||||
|
child.splice(index, 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scope>
|
||||||
|
.logic {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.logic-left {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 48px;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
flex-direction: row;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.operate-title {
|
||||||
|
font-family: PingFang SC, Hiragino Sans GB, Microsoft YaHei, sans-serif;
|
||||||
|
word-wrap: break-word;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
font-size: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 65px;
|
||||||
|
background-color: #f8f8fa;
|
||||||
|
line-height: 28px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
height: 28px;
|
||||||
|
|
||||||
|
.mrg-title {
|
||||||
|
text-align: left;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
margin-left: 11px;
|
||||||
|
margin-right: 11px;
|
||||||
|
line-height: 28px;
|
||||||
|
height: 28px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
// width: 65px;
|
||||||
|
|
||||||
|
.operate-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate-title {
|
||||||
|
.mrg-title {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
|
background-color: #f8f8fa;
|
||||||
|
z-index: 1;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
display: unset;
|
||||||
|
padding: 5px 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logic-right-add {
|
||||||
|
display: flex;
|
||||||
|
height: 41.4px;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 26px;
|
||||||
|
|
||||||
|
.operand-btn {
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
|
||||||
|
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
outline: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1;
|
||||||
|
-webkit-appearance: button;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #246dff;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #246dff;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -111,37 +111,33 @@
|
|||||||
|
|
||||||
<!-- 结果过滤器 -->
|
<!-- 结果过滤器 -->
|
||||||
<el-row class="padding-lr" style="margin-top: 6px;">
|
<el-row class="padding-lr" style="margin-top: 6px;">
|
||||||
<span>{{ $t('chart.result_filter') }}</span>
|
<span class="data-area-label">
|
||||||
|
<span>{{ $t('chart.result_filter') }}</span>
|
||||||
<draggable
|
<span
|
||||||
v-model="view.customFilter"
|
v-if="!!view.customFilter.logic"
|
||||||
:move="onMove"
|
class="setting"
|
||||||
animation="300"
|
>已设置</span>
|
||||||
class="theme-item-class"
|
<i
|
||||||
group="drag"
|
class="el-icon-arrow-down el-icon-delete data-area-clear"
|
||||||
style="padding:2px 0 0 0;width:100%;min-height: 32px;border-radius: 4px;border: 1px solid #DCDFE6;overflow-x: auto;display: flex;align-items: center;background-color: white;"
|
@click="deleteTreeFilter"
|
||||||
@add="addCustomFilter"
|
|
||||||
@update="calcData(true)"
|
|
||||||
>
|
|
||||||
<transition-group class="draggable-group">
|
|
||||||
<filter-item
|
|
||||||
v-for="(item,index) in view.customFilter"
|
|
||||||
:key="item.id"
|
|
||||||
:bus="bus"
|
|
||||||
:dimension-data="dimension"
|
|
||||||
:index="index"
|
|
||||||
:item="item"
|
|
||||||
:param="param"
|
|
||||||
:quota-data="quota"
|
|
||||||
@editItemFilter="showEditFilter"
|
|
||||||
@onFilterItemRemove="filterItemRemove"
|
|
||||||
/>
|
/>
|
||||||
</transition-group>
|
</span>
|
||||||
</draggable>
|
<div
|
||||||
<div v-if="!view.customFilter || view.customFilter.length === 0" class="drag-placeholder-style">
|
class="tree-btn"
|
||||||
<span class="drag-placeholder-style-span">{{ $t('chart.placeholder_field') }}</span>
|
:class="!!view.customFilter.logic && 'active'"
|
||||||
</div>
|
@click="openTreeFilter"
|
||||||
|
>
|
||||||
|
<svg-icon
|
||||||
|
class="svg-background"
|
||||||
|
icon-class="icon-filter_outlined"
|
||||||
|
/>
|
||||||
|
<span>过滤</span>
|
||||||
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<FilterTree
|
||||||
|
ref="filterTree"
|
||||||
|
@filter-data="changeFilterData"
|
||||||
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -153,8 +149,14 @@ import QuotaExtItem from '../../../components/views/QuotaExtItem'
|
|||||||
import FilterItem from '../../../components/views/FilterItem'
|
import FilterItem from '../../../components/views/FilterItem'
|
||||||
import messages from '@/de-base/lang/messages'
|
import messages from '@/de-base/lang/messages'
|
||||||
import {defaultTo} from "lodash-es"
|
import {defaultTo} from "lodash-es"
|
||||||
|
import FilterTree from '@/components/views/filter/FilterTree.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
filedList: () => this.filedList
|
||||||
|
}
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
obj: {
|
obj: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -171,7 +173,8 @@ export default {
|
|||||||
DimensionItem,
|
DimensionItem,
|
||||||
QuotaItem,
|
QuotaItem,
|
||||||
QuotaExtItem,
|
QuotaExtItem,
|
||||||
FilterItem
|
FilterItem,
|
||||||
|
FilterTree
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -194,6 +197,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
filedList() {
|
||||||
|
return [...this.dimension, ...this.quota].filter(ele => ele.id !== 'count')
|
||||||
|
},
|
||||||
param() {
|
param() {
|
||||||
return this.obj.param
|
return this.obj.param
|
||||||
},
|
},
|
||||||
@ -260,6 +266,16 @@ export default {
|
|||||||
}*/
|
}*/
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
changeFilterData(customFilter) {
|
||||||
|
this.view.customFilter =JSON.parse(JSON.stringify(customFilter))
|
||||||
|
this.calcData(true)
|
||||||
|
},
|
||||||
|
openTreeFilter() {
|
||||||
|
this.$refs.filterTree.init(JSON.parse(JSON.stringify(this.view.customFilter)))
|
||||||
|
},
|
||||||
|
deleteTreeFilter() {
|
||||||
|
this.changeFilterData({})
|
||||||
|
},
|
||||||
executeAxios(url, type, data, callBack) {
|
executeAxios(url, type, data, callBack) {
|
||||||
const param = {
|
const param = {
|
||||||
url: url,
|
url: url,
|
||||||
@ -463,6 +479,49 @@ export default {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.padding-lr {
|
.padding-lr {
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
|
.data-area-label {
|
||||||
|
text-align: left;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
.setting {
|
||||||
|
padding: 0px 4px 0px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: #1F23291A;
|
||||||
|
color: #646A73;
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
right: 23px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-btn {
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #DCDFE6;
|
||||||
|
display: flex;
|
||||||
|
color: #CCCCCC;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: #3370FF;
|
||||||
|
border-color: #3370FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.data-area-clear {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 6px;
|
||||||
|
color: rgb(135, 141, 159);
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.itxst {
|
.itxst {
|
||||||
|
@ -1,12 +1,4 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": ["@babel/preset-env"],
|
||||||
["env", {
|
"plugins": ["@babel/plugin-transform-runtime", "@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-object-rest-spread"]
|
||||||
"modules": false,
|
|
||||||
"targets": {
|
|
||||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"stage-2"
|
|
||||||
],
|
|
||||||
"plugins": ["transform-vue-jsx", "transform-runtime"]
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
"buildPlugin": "node build/build-async-plugins.js"
|
"buildPlugin": "node build/build-async-plugins.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@babel/polyfill": "^7.12.1",
|
||||||
|
"@babel/runtime": "^7.18.9",
|
||||||
"@riophae/vue-treeselect": "0.4.0",
|
"@riophae/vue-treeselect": "0.4.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"vue": "2.6.10",
|
"vue": "2.6.10",
|
||||||
@ -22,14 +24,12 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^7.1.2",
|
"autoprefixer": "^7.1.2",
|
||||||
"babel-core": "^6.22.1",
|
"@babel/core": "^7.6.4",
|
||||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
"@babel/plugin-proposal-object-rest-spread": "^7.18.9",
|
||||||
"babel-loader": "^7.1.1",
|
"@babel/plugin-proposal-optional-chaining": "^7.18.6",
|
||||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
"@babel/plugin-transform-runtime": "^7.6.2",
|
||||||
"babel-plugin-transform-runtime": "^6.22.0",
|
"@babel/preset-env": "^7.6.3",
|
||||||
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-preset-env": "^1.3.2",
|
|
||||||
"babel-preset-stage-2": "^6.22.0",
|
|
||||||
"chalk": "^2.0.1",
|
"chalk": "^2.0.1",
|
||||||
"copy-webpack-plugin": "^4.6.0",
|
"copy-webpack-plugin": "^4.6.0",
|
||||||
"css-loader": "^0.28.0",
|
"css-loader": "^0.28.0",
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
width="896px"
|
||||||
|
append-to-body
|
||||||
|
title="添加过滤"
|
||||||
|
destroy-on-close
|
||||||
|
class="de-dialog-form filter-tree-cont"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
>
|
||||||
|
<div class="tree-cont">
|
||||||
|
<div class="content">
|
||||||
|
<rowAuth ref="rowAuth" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
slot="footer"
|
||||||
|
class="dialog-footer"
|
||||||
|
>
|
||||||
|
<de-btn
|
||||||
|
secondary
|
||||||
|
@click="closeFilter"
|
||||||
|
>{{ $t('chart.cancel') }}
|
||||||
|
</de-btn>
|
||||||
|
<de-btn
|
||||||
|
type="primary"
|
||||||
|
@click="changeFilter"
|
||||||
|
>{{ $t('chart.confirm') }}
|
||||||
|
</de-btn>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import rowAuth from './rowAuth.vue'
|
||||||
|
export default {
|
||||||
|
name: 'FilterTree',
|
||||||
|
inject: ['filedList'],
|
||||||
|
components: {
|
||||||
|
rowAuth
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
computedFiledList() {
|
||||||
|
return this.filedList().reduce((pre, next) => {
|
||||||
|
if (next.id !== 'count') {
|
||||||
|
pre[next.id] = next
|
||||||
|
}
|
||||||
|
return pre
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeFilter() {
|
||||||
|
this.dialogVisible = false
|
||||||
|
},
|
||||||
|
changeFilter() {
|
||||||
|
const { logic, items, errorMessage } = this.$refs.rowAuth.submit()
|
||||||
|
if (errorMessage) {
|
||||||
|
this.$message({
|
||||||
|
message: errorMessage,
|
||||||
|
type: 'error',
|
||||||
|
showClose: true
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.dfsTreeDelete(items)
|
||||||
|
this.$emit('filter-data', { logic, items })
|
||||||
|
this.dialogVisible = false
|
||||||
|
},
|
||||||
|
dfsTreeDelete(arr) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele?.subTree?.items?.length) {
|
||||||
|
this.dfsTreeDelete(ele.subTree.items)
|
||||||
|
} else {
|
||||||
|
if (ele.field) {
|
||||||
|
this.$delete(ele, 'field')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
dfsTree(arr) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele?.subTree?.items?.length) {
|
||||||
|
this.dfsTree(ele.subTree.items)
|
||||||
|
} else {
|
||||||
|
if (this.computedFiledList[ele.fieldId]) {
|
||||||
|
ele.field = this.computedFiledList[ele.fieldId]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
init(tree) {
|
||||||
|
this.dialogVisible = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.dfsTree(tree.items || [])
|
||||||
|
this.$refs.rowAuth.init(tree || {})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.filter-tree-cont {
|
||||||
|
.tree-cont {
|
||||||
|
min-height: 67px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--deBorderBase, #DCDFE6);
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 500px;
|
||||||
|
.content {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
|||||||
|
function formatEnum(ele) {
|
||||||
|
return {
|
||||||
|
value: ele,
|
||||||
|
label: `chart.filter_${ele.replace(' ', '_')}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const textEnum = ['eq', 'not_eq', 'like', 'not like', 'null', 'not_null', 'empty', 'not_empty']
|
||||||
|
const textOptions = textEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const dateEnum = ['eq', 'not_eq', 'lt', 'gt', 'le', 'ge']
|
||||||
|
const dateOptions = dateEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const valueEnum = [...dateEnum]
|
||||||
|
const valueOptions = valueEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const fieldEnum = ['text', 'time', 'value', 'value', '', 'location']
|
||||||
|
|
||||||
|
export {
|
||||||
|
textOptions,
|
||||||
|
dateOptions,
|
||||||
|
valueOptions,
|
||||||
|
fieldEnum
|
||||||
|
}
|
@ -0,0 +1,348 @@
|
|||||||
|
<template>
|
||||||
|
<div class="rowAuth">
|
||||||
|
<rowAuthTree
|
||||||
|
@del="(idx) => del(idx)"
|
||||||
|
@addCondReal="addCondReal"
|
||||||
|
@removeRelationList="removeRelationList"
|
||||||
|
@changeAndOrDfs="(type) => changeAndOrDfs(relationList, type)"
|
||||||
|
:relationList="relationList"
|
||||||
|
:logic.sync="logic"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
/>
|
||||||
|
<svg width="388" height="100%" class="real-line">
|
||||||
|
<path
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
:d="svgRealinePath"
|
||||||
|
fill="none"
|
||||||
|
stroke="#CCCCCC"
|
||||||
|
stroke-width="0.5"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<svg width="388" height="100%" class="dash-line">
|
||||||
|
<path
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
:d="svgDashinePath"
|
||||||
|
fill="none"
|
||||||
|
stroke="#CCCCCC"
|
||||||
|
stroke-width="0.5"
|
||||||
|
stroke-dasharray="4,4"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import rowAuthTree from "./rowTeeAuth.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "RowAuth",
|
||||||
|
components: {
|
||||||
|
rowAuthTree,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
svgRealinePath() {
|
||||||
|
const lg = this.relationList.length;
|
||||||
|
let a = { x: 0, y: 0, child: this.relationList };
|
||||||
|
a.y = Math.floor(this.dfsXY(a, 0) / 2);
|
||||||
|
if (!lg) return "";
|
||||||
|
let path = this.calculateDepth(a);
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
svgDashinePath() {
|
||||||
|
const lg = this.relationList.length;
|
||||||
|
let a = { x: 0, y: 0, child: this.relationList };
|
||||||
|
a.y = Math.floor(this.dfsXY(a, 0) / 2);
|
||||||
|
if (!lg) return `M48 20 L68 20`;
|
||||||
|
let path = this.calculateDepthDash(a);
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
executeAxios(url, type, data, callBack) {
|
||||||
|
this.$emit("execute-axios", url, type, data, callBack);
|
||||||
|
},
|
||||||
|
init(expressionTree) {
|
||||||
|
const { logic = "or", items = [] } = expressionTree;
|
||||||
|
this.logic = logic;
|
||||||
|
this.relationList = this.dfsInit(items);
|
||||||
|
},
|
||||||
|
submit() {
|
||||||
|
this.errorMessage = '';
|
||||||
|
return {
|
||||||
|
logic: this.logic,
|
||||||
|
items: this.dfsSubmit(this.relationList),
|
||||||
|
errorMessage: this.errorMessage
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorDetected({ enumValue, deType, filterType, term, value }) {
|
||||||
|
if (filterType === "logic") {
|
||||||
|
if (
|
||||||
|
!term.includes("null") &&
|
||||||
|
!term.includes("empty") &&
|
||||||
|
(value === "")
|
||||||
|
) {
|
||||||
|
this.errorMessage = this.$t("chart.filter_value_can_null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ([2, 3].includes(deType)) {
|
||||||
|
if (parseFloat(value).toString() === "NaN") {
|
||||||
|
this.errorMessage = this.$t("chart.filter_value_can_not_str");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filterType === "enum") {
|
||||||
|
if (enumValue.length < 1) {
|
||||||
|
this.errorMessage = this.$t("chart.enum_value_can_not_null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dfsInit(arr) {
|
||||||
|
const elementList = [];
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
const { subTree } = ele;
|
||||||
|
if (subTree) {
|
||||||
|
const { items, logic } = subTree;
|
||||||
|
const child = this.dfsInit(items);
|
||||||
|
elementList.push({ logic, child });
|
||||||
|
} else {
|
||||||
|
const {
|
||||||
|
enumValue,
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
field,
|
||||||
|
} = ele;
|
||||||
|
const { name, deType } = (field || {});
|
||||||
|
elementList.push({
|
||||||
|
enumValue: enumValue.join(','),
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
name,
|
||||||
|
deType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return elementList;
|
||||||
|
},
|
||||||
|
dfsSubmit(arr) {
|
||||||
|
const items = [];
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
const { child = [] } = ele;
|
||||||
|
if (child.length) {
|
||||||
|
const { logic } = ele;
|
||||||
|
const subTree = this.dfsSubmit(child);
|
||||||
|
items.push({
|
||||||
|
enumValue: [],
|
||||||
|
fieldId: '',
|
||||||
|
filterType: '',
|
||||||
|
term: '',
|
||||||
|
type: 'tree',
|
||||||
|
value: '', subTree: { logic, items: subTree} });
|
||||||
|
} else {
|
||||||
|
const { enumValue, fieldId, filterType,deType, term, value } = ele;
|
||||||
|
this.errorDetected({ deType, enumValue, filterType, term, value})
|
||||||
|
if (fieldId) {
|
||||||
|
items.push({
|
||||||
|
enumValue: enumValue ? enumValue.split(',') : [],
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
type: 'item',
|
||||||
|
subTree: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
},
|
||||||
|
removeRelationList() {
|
||||||
|
this.relationList = [];
|
||||||
|
},
|
||||||
|
getY(arr) {
|
||||||
|
const [a] = arr;
|
||||||
|
if (a.child?.length) {
|
||||||
|
return this.getY(a.child);
|
||||||
|
}
|
||||||
|
return a.y;
|
||||||
|
},
|
||||||
|
getLastY(arr) {
|
||||||
|
const a = arr[arr.length];
|
||||||
|
if (a.child?.length) {
|
||||||
|
return this.getLastY(a.child);
|
||||||
|
}
|
||||||
|
return a.y;
|
||||||
|
},
|
||||||
|
calculateDepthDash(obj) {
|
||||||
|
const lg = obj.child?.length;
|
||||||
|
let path = "";
|
||||||
|
if (!lg && Array.isArray(obj.child)) {
|
||||||
|
const { x, y } = obj;
|
||||||
|
path += `M${48 + x * 68} ${y * 41.4 + 20} L${88 + x * 68} ${
|
||||||
|
y * 41.4 + 20
|
||||||
|
}`;
|
||||||
|
} else if (obj.child?.length) {
|
||||||
|
let y = Math.max(
|
||||||
|
this.dfsY(obj, 0),
|
||||||
|
this.dfs(obj.child, 0) + this.getY(obj.child) - 1
|
||||||
|
);
|
||||||
|
let parent =
|
||||||
|
(this.dfs(obj.child, 0) * 41.4) / 2 +
|
||||||
|
(this.getY(obj.child) || 0) * 41.4;
|
||||||
|
const { x } = obj;
|
||||||
|
path += `M${24 + x * 68} ${parent} L${24 + x * 68} ${y * 41.4 + 20} L${
|
||||||
|
64 + x * 68
|
||||||
|
} ${y * 41.4 + 20}`;
|
||||||
|
obj.child.forEach((item) => {
|
||||||
|
path += this.calculateDepthDash(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
calculateDepth(obj) {
|
||||||
|
const lg = obj.child.length;
|
||||||
|
if (!lg) return "";
|
||||||
|
let path = "";
|
||||||
|
const { x: depth, y } = obj;
|
||||||
|
obj.child.forEach((item, index) => {
|
||||||
|
const { y: sibingLg, z } = item;
|
||||||
|
if (item.child?.length) {
|
||||||
|
let parent =
|
||||||
|
(this.dfs(obj.child, 0) * 41.4) / 2 +
|
||||||
|
(this.getY(obj.child) || 0) * 41.4;
|
||||||
|
let children =
|
||||||
|
(this.dfs(item.child, 0) * 41.4) / 2 + this.getY(item.child) * 41.4;
|
||||||
|
let path1 = 0;
|
||||||
|
let path2 = 0;
|
||||||
|
if (parent < children) {
|
||||||
|
path1 = parent;
|
||||||
|
path2 = children;
|
||||||
|
} else {
|
||||||
|
[path1, path2] = [children, parent];
|
||||||
|
}
|
||||||
|
if (y >= sibingLg) {
|
||||||
|
path1 = parent;
|
||||||
|
path2 = children;
|
||||||
|
}
|
||||||
|
path += `M${24 + depth * 68} ${path1} L${24 + depth * 68} ${path2} L${
|
||||||
|
68 + depth * 68
|
||||||
|
} ${path2}`;
|
||||||
|
// path += a;
|
||||||
|
path += this.calculateDepth(item);
|
||||||
|
}
|
||||||
|
if (!item.child?.length) {
|
||||||
|
// console.log(123, y, sibingLg, lg === 1 && index === 0 , item.z);
|
||||||
|
if (sibingLg >= y) {
|
||||||
|
path += `M${24 + depth * 68} ${y * 40} L${24 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 - 20.69921875
|
||||||
|
} L${68 + depth * 68} ${(sibingLg + 1) * 41.4 - 20.69921875}`;
|
||||||
|
} else {
|
||||||
|
path += `M${24 + depth * 68} ${
|
||||||
|
(sibingLg +
|
||||||
|
(lg === 1 && index === 0 ? 0 : 1) +
|
||||||
|
(obj.child[index + 1]?.child?.length ? y - sibingLg - 1 : 0)) *
|
||||||
|
41.4 +
|
||||||
|
20 +
|
||||||
|
(lg === 1 && index === 0 ? 26 : 0)
|
||||||
|
} L${24 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 -
|
||||||
|
20.69921875 -
|
||||||
|
(lg === 1 && index === 0 ? (z || 0) * 1.4 : 0)
|
||||||
|
} L${68 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 -
|
||||||
|
20.69921875 -
|
||||||
|
(lg === 1 && index === 0 ? (z || 0) * 1.4 : 0)
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
changeAndOrDfs(arr, logic) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele.child) {
|
||||||
|
ele.logic = logic === "and" ? "or" : "and";
|
||||||
|
this.changeAndOrDfs(ele.child, ele.logic);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
dfs(arr, count) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele.child?.length) {
|
||||||
|
count = this.dfs(ele.child, count);
|
||||||
|
} else {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
count += 1;
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
dfsY(obj, count) {
|
||||||
|
obj.child.forEach((ele) => {
|
||||||
|
if (ele.child?.length) {
|
||||||
|
count = this.dfsY(ele, count);
|
||||||
|
} else {
|
||||||
|
count = Math.max(count, ele.y, obj.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
dfsXY(obj, count) {
|
||||||
|
obj.child.forEach((ele) => {
|
||||||
|
ele.x = obj.x + 1;
|
||||||
|
if (ele.child?.length) {
|
||||||
|
let l = this.dfs(ele.child, 0);
|
||||||
|
ele.y = Math.floor(l / 2) + count;
|
||||||
|
count = this.dfsXY(ele, count);
|
||||||
|
} else {
|
||||||
|
count += 1;
|
||||||
|
ele.y = count - 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
count += 1;
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
addCondReal(type, logic) {
|
||||||
|
this.relationList.push(
|
||||||
|
type === "condition"
|
||||||
|
? { fieldId: '', value: "", enumValue: "", term: "", filterType: "logic", name: "", deType: "" }
|
||||||
|
: { child: [], logic }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
del(index) {
|
||||||
|
this.relationList.splice(index, 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
relationList: [],
|
||||||
|
logic: "or",
|
||||||
|
errorMessage: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.rowAuth {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
color: #2c3e50;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.real-line,
|
||||||
|
.dash-line {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,247 @@
|
|||||||
|
<template>
|
||||||
|
<div class="logic" :style="marginLeft">
|
||||||
|
<div class="logic-left">
|
||||||
|
<div class="operate-title">
|
||||||
|
<span
|
||||||
|
style="
|
||||||
|
{
|
||||||
|
color: '#bfbfbf';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
class="mrg-title"
|
||||||
|
v-if="x"
|
||||||
|
>
|
||||||
|
{{ logic === 'or' ? "OR" : "AND" }}
|
||||||
|
</span>
|
||||||
|
<el-dropdown @command="handleCommand" trigger="click" v-else>
|
||||||
|
<span
|
||||||
|
style="
|
||||||
|
{
|
||||||
|
color: 'rgba(0,0,0,.65)';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
class="mrg-title"
|
||||||
|
>
|
||||||
|
{{ logic === 'or' ? "OR" : "AND" }}<i class="el-icon-arrow-down"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item command="and">AND</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="or">OR</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
<span class="operate-icon" v-if="x">
|
||||||
|
<!-- <el-tooltip
|
||||||
|
class="item"
|
||||||
|
effect="light"
|
||||||
|
content="切换最外侧关系节点类型时,所有关系都会切换,内外层关系必然相反"
|
||||||
|
placement="top-end"
|
||||||
|
>
|
||||||
|
<i v-if="!x" class="el-icon-warning-outline"></i>
|
||||||
|
</el-tooltip> -->
|
||||||
|
<i class="el-icon-delete" @click="$emit('removeRelationList')"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="logic-right">
|
||||||
|
<template v-for="(item, index) in relationList">
|
||||||
|
<logic-relation
|
||||||
|
:x="item.x"
|
||||||
|
@del="(idx) => del(idx, item.child)"
|
||||||
|
@addCondReal="(type, logic) => add(type, item.child, logic)"
|
||||||
|
v-if="item.child"
|
||||||
|
:key="index"
|
||||||
|
:logic="item.logic"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
@removeRelationList="removeRelationList(index)"
|
||||||
|
:relationList="item.child"
|
||||||
|
>
|
||||||
|
</logic-relation>
|
||||||
|
<filter-filed
|
||||||
|
v-else
|
||||||
|
:item="item"
|
||||||
|
@del="$emit('del', index)"
|
||||||
|
:index="index"
|
||||||
|
:key="index"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
></filter-filed>
|
||||||
|
</template>
|
||||||
|
<div class="logic-right-add">
|
||||||
|
<button @click="addCondReal('condition')" class="operand-btn">
|
||||||
|
+ {{ $t('auth.add_condition')}}
|
||||||
|
</button>
|
||||||
|
<button v-if="x < 2" @click="addCondReal('relation')" class="operand-btn">
|
||||||
|
+ {{ $t('auth.add_relationship')}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import filterFiled from "./filterFiled";
|
||||||
|
export default {
|
||||||
|
name: "LogicRelation",
|
||||||
|
props: {
|
||||||
|
relationList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
x: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
logic: {
|
||||||
|
type: String,
|
||||||
|
default: 'or',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
filterFiled,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
marginLeft() {
|
||||||
|
return {
|
||||||
|
marginLeft: this.x ? "20px" : 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
executeAxios(url, type, data, callBack) {
|
||||||
|
this.$emit("execute-axios", url, type, data, callBack);
|
||||||
|
},
|
||||||
|
handleCommand(type) {
|
||||||
|
this.$emit('update:logic', type);
|
||||||
|
this.$emit("changeAndOrDfs", type)
|
||||||
|
},
|
||||||
|
removeRelationList(index) {
|
||||||
|
this.relationList.splice(index, 1);
|
||||||
|
},
|
||||||
|
addCondReal(type) {
|
||||||
|
this.$emit("addCondReal", type, this.logic === 'or' ? 'and' : 'or');
|
||||||
|
},
|
||||||
|
add(type, child, logic) {
|
||||||
|
child.push(type === "condition" ?{ fieldId: '', value: '', enumValue: '', term: '', filterType: 'logic', name: '', deType: "" } : { child: [], logic });
|
||||||
|
},
|
||||||
|
del(index, child) {
|
||||||
|
child.splice(index, 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scope>
|
||||||
|
.logic {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.logic-left {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 48px;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
flex-direction: row;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.operate-title {
|
||||||
|
font-family: PingFang SC, Hiragino Sans GB, Microsoft YaHei, sans-serif;
|
||||||
|
word-wrap: break-word;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
font-size: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 65px;
|
||||||
|
background-color: #f8f8fa;
|
||||||
|
line-height: 28px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
height: 28px;
|
||||||
|
|
||||||
|
.mrg-title {
|
||||||
|
text-align: left;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
margin-left: 11px;
|
||||||
|
margin-right: 11px;
|
||||||
|
line-height: 28px;
|
||||||
|
height: 28px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
// width: 65px;
|
||||||
|
|
||||||
|
.operate-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate-title {
|
||||||
|
.mrg-title {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
|
background-color: #f8f8fa;
|
||||||
|
z-index: 1;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
display: unset;
|
||||||
|
padding: 5px 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logic-right-add {
|
||||||
|
display: flex;
|
||||||
|
height: 41.4px;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 26px;
|
||||||
|
|
||||||
|
.operand-btn {
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
|
||||||
|
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
outline: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1;
|
||||||
|
-webkit-appearance: button;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #246dff;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #246dff;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -114,37 +114,33 @@
|
|||||||
|
|
||||||
<!-- 结果过滤器 -->
|
<!-- 结果过滤器 -->
|
||||||
<el-row class="padding-lr" style="margin-top: 6px;">
|
<el-row class="padding-lr" style="margin-top: 6px;">
|
||||||
<span>{{ $t('chart.result_filter') }}</span>
|
<span class="data-area-label">
|
||||||
|
<span>{{ $t('chart.result_filter') }}</span>
|
||||||
<draggable
|
<span
|
||||||
v-model="view.customFilter"
|
v-if="!!view.customFilter.logic"
|
||||||
:move="onMove"
|
class="setting"
|
||||||
animation="300"
|
>已设置</span>
|
||||||
class="theme-item-class"
|
<i
|
||||||
group="drag"
|
class="el-icon-arrow-down el-icon-delete data-area-clear"
|
||||||
style="padding:2px 0 0 0;width:100%;min-height: 32px;border-radius: 4px;border: 1px solid #DCDFE6;overflow-x: auto;display: flex;align-items: center;background-color: white;"
|
@click="deleteTreeFilter"
|
||||||
@add="addCustomFilter"
|
|
||||||
@update="calcData(true)"
|
|
||||||
>
|
|
||||||
<transition-group class="draggable-group">
|
|
||||||
<filter-item
|
|
||||||
v-for="(item,index) in view.customFilter"
|
|
||||||
:key="item.id"
|
|
||||||
:bus="bus"
|
|
||||||
:dimension-data="dimension"
|
|
||||||
:index="index"
|
|
||||||
:item="item"
|
|
||||||
:param="param"
|
|
||||||
:quota-data="quota"
|
|
||||||
@editItemFilter="showEditFilter"
|
|
||||||
@onFilterItemRemove="filterItemRemove"
|
|
||||||
/>
|
/>
|
||||||
</transition-group>
|
</span>
|
||||||
</draggable>
|
<div
|
||||||
<div v-if="!view.customFilter || view.customFilter.length === 0" class="drag-placeholder-style">
|
class="tree-btn"
|
||||||
<span class="drag-placeholder-style-span">{{ $t('chart.placeholder_field') }}</span>
|
:class="!!view.customFilter.logic && 'active'"
|
||||||
</div>
|
@click="openTreeFilter"
|
||||||
|
>
|
||||||
|
<svg-icon
|
||||||
|
class="svg-background"
|
||||||
|
icon-class="icon-filter_outlined"
|
||||||
|
/>
|
||||||
|
<span>过滤</span>
|
||||||
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<FilterTree
|
||||||
|
ref="filterTree"
|
||||||
|
@filter-data="changeFilterData"
|
||||||
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -155,8 +151,14 @@ import DimensionExtItem from '../../../components/views/DimensionExtItem'
|
|||||||
import QuotaItem from '../../../components/views/QuotaItem'
|
import QuotaItem from '../../../components/views/QuotaItem'
|
||||||
import FilterItem from '../../../components/views/FilterItem'
|
import FilterItem from '../../../components/views/FilterItem'
|
||||||
import messages from '@/de-base/lang/messages'
|
import messages from '@/de-base/lang/messages'
|
||||||
|
import FilterTree from '@/components/views/filter/FilterTree.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
filedList: () => this.filedList
|
||||||
|
}
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
obj: {
|
obj: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -173,7 +175,8 @@ export default {
|
|||||||
DimensionItem,
|
DimensionItem,
|
||||||
DimensionExtItem,
|
DimensionExtItem,
|
||||||
QuotaItem,
|
QuotaItem,
|
||||||
FilterItem
|
FilterItem,
|
||||||
|
FilterTree
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -194,6 +197,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
filedList() {
|
||||||
|
return [...this.dimension, ...this.quota].filter(ele => ele.id !== 'count')
|
||||||
|
},
|
||||||
param() {
|
param() {
|
||||||
return this.obj.param
|
return this.obj.param
|
||||||
},
|
},
|
||||||
@ -257,6 +263,16 @@ export default {
|
|||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
changeFilterData(customFilter) {
|
||||||
|
this.view.customFilter =JSON.parse(JSON.stringify(customFilter))
|
||||||
|
this.calcData(true)
|
||||||
|
},
|
||||||
|
openTreeFilter() {
|
||||||
|
this.$refs.filterTree.init(JSON.parse(JSON.stringify(this.view.customFilter)))
|
||||||
|
},
|
||||||
|
deleteTreeFilter() {
|
||||||
|
this.changeFilterData({})
|
||||||
|
},
|
||||||
executeAxios(url, type, data, callBack) {
|
executeAxios(url, type, data, callBack) {
|
||||||
const param = {
|
const param = {
|
||||||
url: url,
|
url: url,
|
||||||
@ -455,6 +471,49 @@ export default {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.padding-lr {
|
.padding-lr {
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
|
.data-area-label {
|
||||||
|
text-align: left;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
.setting {
|
||||||
|
padding: 0px 4px 0px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: #1F23291A;
|
||||||
|
color: #646A73;
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
right: 23px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-btn {
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #DCDFE6;
|
||||||
|
display: flex;
|
||||||
|
color: #CCCCCC;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: #3370FF;
|
||||||
|
border-color: #3370FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.data-area-clear {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 6px;
|
||||||
|
color: rgb(135, 141, 159);
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.itxst {
|
.itxst {
|
||||||
|
@ -1,12 +1,4 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": ["@babel/preset-env"],
|
||||||
["env", {
|
"plugins": ["@babel/plugin-transform-runtime", "@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-object-rest-spread"]
|
||||||
"modules": false,
|
|
||||||
"targets": {
|
|
||||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"stage-2"
|
|
||||||
],
|
|
||||||
"plugins": ["transform-vue-jsx", "transform-runtime"]
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
"buildPlugin": "node build/build-async-plugins.js"
|
"buildPlugin": "node build/build-async-plugins.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@babel/polyfill": "^7.12.1",
|
||||||
|
"@babel/runtime": "^7.18.9",
|
||||||
"@antv/g2plot": "^2.4.31",
|
"@antv/g2plot": "^2.4.31",
|
||||||
"@riophae/vue-treeselect": "0.4.0",
|
"@riophae/vue-treeselect": "0.4.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
@ -23,14 +25,12 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^7.1.2",
|
"autoprefixer": "^7.1.2",
|
||||||
"babel-core": "^6.22.1",
|
"@babel/core": "^7.6.4",
|
||||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
"@babel/plugin-proposal-object-rest-spread": "^7.18.9",
|
||||||
"babel-loader": "^7.1.1",
|
"@babel/plugin-proposal-optional-chaining": "^7.18.6",
|
||||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
"@babel/plugin-transform-runtime": "^7.6.2",
|
||||||
"babel-plugin-transform-runtime": "^6.22.0",
|
"@babel/preset-env": "^7.6.3",
|
||||||
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-preset-env": "^1.3.2",
|
|
||||||
"babel-preset-stage-2": "^6.22.0",
|
|
||||||
"chalk": "^2.0.1",
|
"chalk": "^2.0.1",
|
||||||
"copy-webpack-plugin": "^4.6.0",
|
"copy-webpack-plugin": "^4.6.0",
|
||||||
"css-loader": "^0.28.0",
|
"css-loader": "^0.28.0",
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
width="896px"
|
||||||
|
append-to-body
|
||||||
|
title="添加过滤"
|
||||||
|
destroy-on-close
|
||||||
|
class="de-dialog-form filter-tree-cont"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
>
|
||||||
|
<div class="tree-cont">
|
||||||
|
<div class="content">
|
||||||
|
<rowAuth ref="rowAuth" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
slot="footer"
|
||||||
|
class="dialog-footer"
|
||||||
|
>
|
||||||
|
<de-btn
|
||||||
|
secondary
|
||||||
|
@click="closeFilter"
|
||||||
|
>{{ $t('chart.cancel') }}
|
||||||
|
</de-btn>
|
||||||
|
<de-btn
|
||||||
|
type="primary"
|
||||||
|
@click="changeFilter"
|
||||||
|
>{{ $t('chart.confirm') }}
|
||||||
|
</de-btn>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import rowAuth from './rowAuth.vue'
|
||||||
|
export default {
|
||||||
|
name: 'FilterTree',
|
||||||
|
inject: ['filedList'],
|
||||||
|
components: {
|
||||||
|
rowAuth
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
computedFiledList() {
|
||||||
|
return this.filedList().reduce((pre, next) => {
|
||||||
|
if (next.id !== 'count') {
|
||||||
|
pre[next.id] = next
|
||||||
|
}
|
||||||
|
return pre
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeFilter() {
|
||||||
|
this.dialogVisible = false
|
||||||
|
},
|
||||||
|
changeFilter() {
|
||||||
|
const { logic, items, errorMessage } = this.$refs.rowAuth.submit()
|
||||||
|
if (errorMessage) {
|
||||||
|
this.$message({
|
||||||
|
message: errorMessage,
|
||||||
|
type: 'error',
|
||||||
|
showClose: true
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.dfsTreeDelete(items)
|
||||||
|
this.$emit('filter-data', { logic, items })
|
||||||
|
this.dialogVisible = false
|
||||||
|
},
|
||||||
|
dfsTreeDelete(arr) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele?.subTree?.items?.length) {
|
||||||
|
this.dfsTreeDelete(ele.subTree.items)
|
||||||
|
} else {
|
||||||
|
if (ele.field) {
|
||||||
|
this.$delete(ele, 'field')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
dfsTree(arr) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele?.subTree?.items?.length) {
|
||||||
|
this.dfsTree(ele.subTree.items)
|
||||||
|
} else {
|
||||||
|
if (this.computedFiledList[ele.fieldId]) {
|
||||||
|
ele.field = this.computedFiledList[ele.fieldId]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
init(tree) {
|
||||||
|
this.dialogVisible = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.dfsTree(tree.items || [])
|
||||||
|
this.$refs.rowAuth.init(tree || {})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.filter-tree-cont {
|
||||||
|
.tree-cont {
|
||||||
|
min-height: 67px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--deBorderBase, #DCDFE6);
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 500px;
|
||||||
|
.content {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
|||||||
|
function formatEnum(ele) {
|
||||||
|
return {
|
||||||
|
value: ele,
|
||||||
|
label: `chart.filter_${ele.replace(' ', '_')}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const textEnum = ['eq', 'not_eq', 'like', 'not like', 'null', 'not_null', 'empty', 'not_empty']
|
||||||
|
const textOptions = textEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const dateEnum = ['eq', 'not_eq', 'lt', 'gt', 'le', 'ge']
|
||||||
|
const dateOptions = dateEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const valueEnum = [...dateEnum]
|
||||||
|
const valueOptions = valueEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const fieldEnum = ['text', 'time', 'value', 'value', '', 'location']
|
||||||
|
|
||||||
|
export {
|
||||||
|
textOptions,
|
||||||
|
dateOptions,
|
||||||
|
valueOptions,
|
||||||
|
fieldEnum
|
||||||
|
}
|
@ -0,0 +1,348 @@
|
|||||||
|
<template>
|
||||||
|
<div class="rowAuth">
|
||||||
|
<rowAuthTree
|
||||||
|
@del="(idx) => del(idx)"
|
||||||
|
@addCondReal="addCondReal"
|
||||||
|
@removeRelationList="removeRelationList"
|
||||||
|
@changeAndOrDfs="(type) => changeAndOrDfs(relationList, type)"
|
||||||
|
:relationList="relationList"
|
||||||
|
:logic.sync="logic"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
/>
|
||||||
|
<svg width="388" height="100%" class="real-line">
|
||||||
|
<path
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
:d="svgRealinePath"
|
||||||
|
fill="none"
|
||||||
|
stroke="#CCCCCC"
|
||||||
|
stroke-width="0.5"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<svg width="388" height="100%" class="dash-line">
|
||||||
|
<path
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
:d="svgDashinePath"
|
||||||
|
fill="none"
|
||||||
|
stroke="#CCCCCC"
|
||||||
|
stroke-width="0.5"
|
||||||
|
stroke-dasharray="4,4"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import rowAuthTree from "./rowTeeAuth.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "RowAuth",
|
||||||
|
components: {
|
||||||
|
rowAuthTree,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
svgRealinePath() {
|
||||||
|
const lg = this.relationList.length;
|
||||||
|
let a = { x: 0, y: 0, child: this.relationList };
|
||||||
|
a.y = Math.floor(this.dfsXY(a, 0) / 2);
|
||||||
|
if (!lg) return "";
|
||||||
|
let path = this.calculateDepth(a);
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
svgDashinePath() {
|
||||||
|
const lg = this.relationList.length;
|
||||||
|
let a = { x: 0, y: 0, child: this.relationList };
|
||||||
|
a.y = Math.floor(this.dfsXY(a, 0) / 2);
|
||||||
|
if (!lg) return `M48 20 L68 20`;
|
||||||
|
let path = this.calculateDepthDash(a);
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
executeAxios(url, type, data, callBack) {
|
||||||
|
this.$emit("execute-axios", url, type, data, callBack);
|
||||||
|
},
|
||||||
|
init(expressionTree) {
|
||||||
|
const { logic = "or", items = [] } = expressionTree;
|
||||||
|
this.logic = logic;
|
||||||
|
this.relationList = this.dfsInit(items);
|
||||||
|
},
|
||||||
|
submit() {
|
||||||
|
this.errorMessage = '';
|
||||||
|
return {
|
||||||
|
logic: this.logic,
|
||||||
|
items: this.dfsSubmit(this.relationList),
|
||||||
|
errorMessage: this.errorMessage
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorDetected({ enumValue, deType, filterType, term, value }) {
|
||||||
|
if (filterType === "logic") {
|
||||||
|
if (
|
||||||
|
!term.includes("null") &&
|
||||||
|
!term.includes("empty") &&
|
||||||
|
(value === "")
|
||||||
|
) {
|
||||||
|
this.errorMessage = this.$t("chart.filter_value_can_null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ([2, 3].includes(deType)) {
|
||||||
|
if (parseFloat(value).toString() === "NaN") {
|
||||||
|
this.errorMessage = this.$t("chart.filter_value_can_not_str");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filterType === "enum") {
|
||||||
|
if (enumValue.length < 1) {
|
||||||
|
this.errorMessage = this.$t("chart.enum_value_can_not_null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dfsInit(arr) {
|
||||||
|
const elementList = [];
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
const { subTree } = ele;
|
||||||
|
if (subTree) {
|
||||||
|
const { items, logic } = subTree;
|
||||||
|
const child = this.dfsInit(items);
|
||||||
|
elementList.push({ logic, child });
|
||||||
|
} else {
|
||||||
|
const {
|
||||||
|
enumValue,
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
field,
|
||||||
|
} = ele;
|
||||||
|
const { name, deType } = (field || {});
|
||||||
|
elementList.push({
|
||||||
|
enumValue: enumValue.join(','),
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
name,
|
||||||
|
deType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return elementList;
|
||||||
|
},
|
||||||
|
dfsSubmit(arr) {
|
||||||
|
const items = [];
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
const { child = [] } = ele;
|
||||||
|
if (child.length) {
|
||||||
|
const { logic } = ele;
|
||||||
|
const subTree = this.dfsSubmit(child);
|
||||||
|
items.push({
|
||||||
|
enumValue: [],
|
||||||
|
fieldId: '',
|
||||||
|
filterType: '',
|
||||||
|
term: '',
|
||||||
|
type: 'tree',
|
||||||
|
value: '', subTree: { logic, items: subTree} });
|
||||||
|
} else {
|
||||||
|
const { enumValue, fieldId, filterType,deType, term, value } = ele;
|
||||||
|
this.errorDetected({ deType, enumValue, filterType, term, value})
|
||||||
|
if (fieldId) {
|
||||||
|
items.push({
|
||||||
|
enumValue: enumValue ? enumValue.split(',') : [],
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
type: 'item',
|
||||||
|
subTree: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
},
|
||||||
|
removeRelationList() {
|
||||||
|
this.relationList = [];
|
||||||
|
},
|
||||||
|
getY(arr) {
|
||||||
|
const [a] = arr;
|
||||||
|
if (a.child?.length) {
|
||||||
|
return this.getY(a.child);
|
||||||
|
}
|
||||||
|
return a.y;
|
||||||
|
},
|
||||||
|
getLastY(arr) {
|
||||||
|
const a = arr[arr.length];
|
||||||
|
if (a.child?.length) {
|
||||||
|
return this.getLastY(a.child);
|
||||||
|
}
|
||||||
|
return a.y;
|
||||||
|
},
|
||||||
|
calculateDepthDash(obj) {
|
||||||
|
const lg = obj.child?.length;
|
||||||
|
let path = "";
|
||||||
|
if (!lg && Array.isArray(obj.child)) {
|
||||||
|
const { x, y } = obj;
|
||||||
|
path += `M${48 + x * 68} ${y * 41.4 + 20} L${88 + x * 68} ${
|
||||||
|
y * 41.4 + 20
|
||||||
|
}`;
|
||||||
|
} else if (obj.child?.length) {
|
||||||
|
let y = Math.max(
|
||||||
|
this.dfsY(obj, 0),
|
||||||
|
this.dfs(obj.child, 0) + this.getY(obj.child) - 1
|
||||||
|
);
|
||||||
|
let parent =
|
||||||
|
(this.dfs(obj.child, 0) * 41.4) / 2 +
|
||||||
|
(this.getY(obj.child) || 0) * 41.4;
|
||||||
|
const { x } = obj;
|
||||||
|
path += `M${24 + x * 68} ${parent} L${24 + x * 68} ${y * 41.4 + 20} L${
|
||||||
|
64 + x * 68
|
||||||
|
} ${y * 41.4 + 20}`;
|
||||||
|
obj.child.forEach((item) => {
|
||||||
|
path += this.calculateDepthDash(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
calculateDepth(obj) {
|
||||||
|
const lg = obj.child.length;
|
||||||
|
if (!lg) return "";
|
||||||
|
let path = "";
|
||||||
|
const { x: depth, y } = obj;
|
||||||
|
obj.child.forEach((item, index) => {
|
||||||
|
const { y: sibingLg, z } = item;
|
||||||
|
if (item.child?.length) {
|
||||||
|
let parent =
|
||||||
|
(this.dfs(obj.child, 0) * 41.4) / 2 +
|
||||||
|
(this.getY(obj.child) || 0) * 41.4;
|
||||||
|
let children =
|
||||||
|
(this.dfs(item.child, 0) * 41.4) / 2 + this.getY(item.child) * 41.4;
|
||||||
|
let path1 = 0;
|
||||||
|
let path2 = 0;
|
||||||
|
if (parent < children) {
|
||||||
|
path1 = parent;
|
||||||
|
path2 = children;
|
||||||
|
} else {
|
||||||
|
[path1, path2] = [children, parent];
|
||||||
|
}
|
||||||
|
if (y >= sibingLg) {
|
||||||
|
path1 = parent;
|
||||||
|
path2 = children;
|
||||||
|
}
|
||||||
|
path += `M${24 + depth * 68} ${path1} L${24 + depth * 68} ${path2} L${
|
||||||
|
68 + depth * 68
|
||||||
|
} ${path2}`;
|
||||||
|
// path += a;
|
||||||
|
path += this.calculateDepth(item);
|
||||||
|
}
|
||||||
|
if (!item.child?.length) {
|
||||||
|
// console.log(123, y, sibingLg, lg === 1 && index === 0 , item.z);
|
||||||
|
if (sibingLg >= y) {
|
||||||
|
path += `M${24 + depth * 68} ${y * 40} L${24 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 - 20.69921875
|
||||||
|
} L${68 + depth * 68} ${(sibingLg + 1) * 41.4 - 20.69921875}`;
|
||||||
|
} else {
|
||||||
|
path += `M${24 + depth * 68} ${
|
||||||
|
(sibingLg +
|
||||||
|
(lg === 1 && index === 0 ? 0 : 1) +
|
||||||
|
(obj.child[index + 1]?.child?.length ? y - sibingLg - 1 : 0)) *
|
||||||
|
41.4 +
|
||||||
|
20 +
|
||||||
|
(lg === 1 && index === 0 ? 26 : 0)
|
||||||
|
} L${24 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 -
|
||||||
|
20.69921875 -
|
||||||
|
(lg === 1 && index === 0 ? (z || 0) * 1.4 : 0)
|
||||||
|
} L${68 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 -
|
||||||
|
20.69921875 -
|
||||||
|
(lg === 1 && index === 0 ? (z || 0) * 1.4 : 0)
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
changeAndOrDfs(arr, logic) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele.child) {
|
||||||
|
ele.logic = logic === "and" ? "or" : "and";
|
||||||
|
this.changeAndOrDfs(ele.child, ele.logic);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
dfs(arr, count) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele.child?.length) {
|
||||||
|
count = this.dfs(ele.child, count);
|
||||||
|
} else {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
count += 1;
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
dfsY(obj, count) {
|
||||||
|
obj.child.forEach((ele) => {
|
||||||
|
if (ele.child?.length) {
|
||||||
|
count = this.dfsY(ele, count);
|
||||||
|
} else {
|
||||||
|
count = Math.max(count, ele.y, obj.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
dfsXY(obj, count) {
|
||||||
|
obj.child.forEach((ele) => {
|
||||||
|
ele.x = obj.x + 1;
|
||||||
|
if (ele.child?.length) {
|
||||||
|
let l = this.dfs(ele.child, 0);
|
||||||
|
ele.y = Math.floor(l / 2) + count;
|
||||||
|
count = this.dfsXY(ele, count);
|
||||||
|
} else {
|
||||||
|
count += 1;
|
||||||
|
ele.y = count - 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
count += 1;
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
addCondReal(type, logic) {
|
||||||
|
this.relationList.push(
|
||||||
|
type === "condition"
|
||||||
|
? { fieldId: '', value: "", enumValue: "", term: "", filterType: "logic", name: "", deType: "" }
|
||||||
|
: { child: [], logic }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
del(index) {
|
||||||
|
this.relationList.splice(index, 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
relationList: [],
|
||||||
|
logic: "or",
|
||||||
|
errorMessage: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.rowAuth {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
color: #2c3e50;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.real-line,
|
||||||
|
.dash-line {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,247 @@
|
|||||||
|
<template>
|
||||||
|
<div class="logic" :style="marginLeft">
|
||||||
|
<div class="logic-left">
|
||||||
|
<div class="operate-title">
|
||||||
|
<span
|
||||||
|
style="
|
||||||
|
{
|
||||||
|
color: '#bfbfbf';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
class="mrg-title"
|
||||||
|
v-if="x"
|
||||||
|
>
|
||||||
|
{{ logic === 'or' ? "OR" : "AND" }}
|
||||||
|
</span>
|
||||||
|
<el-dropdown @command="handleCommand" trigger="click" v-else>
|
||||||
|
<span
|
||||||
|
style="
|
||||||
|
{
|
||||||
|
color: 'rgba(0,0,0,.65)';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
class="mrg-title"
|
||||||
|
>
|
||||||
|
{{ logic === 'or' ? "OR" : "AND" }}<i class="el-icon-arrow-down"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item command="and">AND</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="or">OR</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
<span class="operate-icon" v-if="x">
|
||||||
|
<!-- <el-tooltip
|
||||||
|
class="item"
|
||||||
|
effect="light"
|
||||||
|
content="切换最外侧关系节点类型时,所有关系都会切换,内外层关系必然相反"
|
||||||
|
placement="top-end"
|
||||||
|
>
|
||||||
|
<i v-if="!x" class="el-icon-warning-outline"></i>
|
||||||
|
</el-tooltip> -->
|
||||||
|
<i class="el-icon-delete" @click="$emit('removeRelationList')"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="logic-right">
|
||||||
|
<template v-for="(item, index) in relationList">
|
||||||
|
<logic-relation
|
||||||
|
:x="item.x"
|
||||||
|
@del="(idx) => del(idx, item.child)"
|
||||||
|
@addCondReal="(type, logic) => add(type, item.child, logic)"
|
||||||
|
v-if="item.child"
|
||||||
|
:key="index"
|
||||||
|
:logic="item.logic"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
@removeRelationList="removeRelationList(index)"
|
||||||
|
:relationList="item.child"
|
||||||
|
>
|
||||||
|
</logic-relation>
|
||||||
|
<filter-filed
|
||||||
|
v-else
|
||||||
|
:item="item"
|
||||||
|
@del="$emit('del', index)"
|
||||||
|
:index="index"
|
||||||
|
:key="index"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
></filter-filed>
|
||||||
|
</template>
|
||||||
|
<div class="logic-right-add">
|
||||||
|
<button @click="addCondReal('condition')" class="operand-btn">
|
||||||
|
+ {{ $t('auth.add_condition')}}
|
||||||
|
</button>
|
||||||
|
<button v-if="x < 2" @click="addCondReal('relation')" class="operand-btn">
|
||||||
|
+ {{ $t('auth.add_relationship')}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import filterFiled from "./filterFiled";
|
||||||
|
export default {
|
||||||
|
name: "LogicRelation",
|
||||||
|
props: {
|
||||||
|
relationList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
x: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
logic: {
|
||||||
|
type: String,
|
||||||
|
default: 'or',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
filterFiled,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
marginLeft() {
|
||||||
|
return {
|
||||||
|
marginLeft: this.x ? "20px" : 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
executeAxios(url, type, data, callBack) {
|
||||||
|
this.$emit("execute-axios", url, type, data, callBack);
|
||||||
|
},
|
||||||
|
handleCommand(type) {
|
||||||
|
this.$emit('update:logic', type);
|
||||||
|
this.$emit("changeAndOrDfs", type)
|
||||||
|
},
|
||||||
|
removeRelationList(index) {
|
||||||
|
this.relationList.splice(index, 1);
|
||||||
|
},
|
||||||
|
addCondReal(type) {
|
||||||
|
this.$emit("addCondReal", type, this.logic === 'or' ? 'and' : 'or');
|
||||||
|
},
|
||||||
|
add(type, child, logic) {
|
||||||
|
child.push(type === "condition" ?{ fieldId: '', value: '', enumValue: '', term: '', filterType: 'logic', name: '', deType: "" } : { child: [], logic });
|
||||||
|
},
|
||||||
|
del(index, child) {
|
||||||
|
child.splice(index, 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scope>
|
||||||
|
.logic {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.logic-left {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 48px;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
flex-direction: row;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.operate-title {
|
||||||
|
font-family: PingFang SC, Hiragino Sans GB, Microsoft YaHei, sans-serif;
|
||||||
|
word-wrap: break-word;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
font-size: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 65px;
|
||||||
|
background-color: #f8f8fa;
|
||||||
|
line-height: 28px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
height: 28px;
|
||||||
|
|
||||||
|
.mrg-title {
|
||||||
|
text-align: left;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
margin-left: 11px;
|
||||||
|
margin-right: 11px;
|
||||||
|
line-height: 28px;
|
||||||
|
height: 28px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
// width: 65px;
|
||||||
|
|
||||||
|
.operate-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate-title {
|
||||||
|
.mrg-title {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
|
background-color: #f8f8fa;
|
||||||
|
z-index: 1;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
display: unset;
|
||||||
|
padding: 5px 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logic-right-add {
|
||||||
|
display: flex;
|
||||||
|
height: 41.4px;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 26px;
|
||||||
|
|
||||||
|
.operand-btn {
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
|
||||||
|
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
outline: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1;
|
||||||
|
-webkit-appearance: button;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #246dff;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #246dff;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -112,36 +112,33 @@
|
|||||||
|
|
||||||
<!-- 结果过滤器 -->
|
<!-- 结果过滤器 -->
|
||||||
<el-row class="padding-lr" style="margin-top: 6px;">
|
<el-row class="padding-lr" style="margin-top: 6px;">
|
||||||
<span>{{ $t('chart.result_filter') }}</span>
|
<span class="data-area-label">
|
||||||
|
<span>{{ $t('chart.result_filter') }}</span>
|
||||||
<draggable
|
<span
|
||||||
v-model="view.customFilter"
|
v-if="!!view.customFilter.logic"
|
||||||
:move="onMove"
|
class="setting"
|
||||||
animation="300"
|
>已设置</span>
|
||||||
class="theme-item-class"
|
<i
|
||||||
group="drag"
|
class="el-icon-arrow-down el-icon-delete data-area-clear"
|
||||||
style="padding:2px 0 0 0;width:100%;min-height: 32px;border-radius: 4px;border: 1px solid #DCDFE6;overflow-x: auto;display: flex;align-items: center;background-color: white;"
|
@click="deleteTreeFilter"
|
||||||
@add="addCustomFilter"
|
|
||||||
@update="calcData(true)"
|
|
||||||
>
|
|
||||||
<transition-group class="draggable-group">
|
|
||||||
<filter-item
|
|
||||||
v-for="(item,index) in view.customFilter"
|
|
||||||
:key="item.id"
|
|
||||||
:dimension-data="dimension"
|
|
||||||
:index="index"
|
|
||||||
:item="item"
|
|
||||||
:param="param"
|
|
||||||
:quota-data="quota"
|
|
||||||
@editItemFilter="showEditFilter"
|
|
||||||
@onFilterItemRemove="filterItemRemove"
|
|
||||||
/>
|
/>
|
||||||
</transition-group>
|
</span>
|
||||||
</draggable>
|
<div
|
||||||
<div v-if="!view.customFilter || view.customFilter.length === 0" class="drag-placeholder-style">
|
class="tree-btn"
|
||||||
<span class="drag-placeholder-style-span">{{ $t('chart.placeholder_field') }}</span>
|
:class="!!view.customFilter.logic && 'active'"
|
||||||
</div>
|
@click="openTreeFilter"
|
||||||
|
>
|
||||||
|
<svg-icon
|
||||||
|
class="svg-background"
|
||||||
|
icon-class="icon-filter_outlined"
|
||||||
|
/>
|
||||||
|
<span>过滤</span>
|
||||||
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<FilterTree
|
||||||
|
ref="filterTree"
|
||||||
|
@filter-data="changeFilterData"
|
||||||
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -151,8 +148,14 @@ import SankeyDimensionItem from '../../../components/views/SankeyDimensionItem'
|
|||||||
import SankeyQuotaItem from '../../../components/views/SankeyQuotaItem'
|
import SankeyQuotaItem from '../../../components/views/SankeyQuotaItem'
|
||||||
import FilterItem from '../../../components/views/FilterItem'
|
import FilterItem from '../../../components/views/FilterItem'
|
||||||
import messages from '@/de-base/lang/messages'
|
import messages from '@/de-base/lang/messages'
|
||||||
|
import FilterTree from '@/components/views/filter/FilterTree.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
filedList: () => this.filedList
|
||||||
|
}
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
obj: {
|
obj: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -168,7 +171,8 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
SankeyDimensionItem,
|
SankeyDimensionItem,
|
||||||
SankeyQuotaItem,
|
SankeyQuotaItem,
|
||||||
FilterItem
|
FilterItem,
|
||||||
|
FilterTree
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -190,6 +194,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
filedList() {
|
||||||
|
return [...this.dimension, ...this.quota].filter(ele => ele.id !== 'count')
|
||||||
|
},
|
||||||
param() {
|
param() {
|
||||||
return this.obj.param
|
return this.obj.param
|
||||||
},
|
},
|
||||||
@ -242,6 +249,16 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
changeFilterData(customFilter) {
|
||||||
|
this.view.customFilter =JSON.parse(JSON.stringify(customFilter))
|
||||||
|
this.calcData(true)
|
||||||
|
},
|
||||||
|
openTreeFilter() {
|
||||||
|
this.$refs.filterTree.init(JSON.parse(JSON.stringify(this.view.customFilter)))
|
||||||
|
},
|
||||||
|
deleteTreeFilter() {
|
||||||
|
this.changeFilterData({})
|
||||||
|
},
|
||||||
executeAxios(url, type, data, callBack) {
|
executeAxios(url, type, data, callBack) {
|
||||||
const param = {
|
const param = {
|
||||||
url: url,
|
url: url,
|
||||||
@ -430,6 +447,49 @@ export default {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.padding-lr {
|
.padding-lr {
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
|
.data-area-label {
|
||||||
|
text-align: left;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
.setting {
|
||||||
|
padding: 0px 4px 0px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: #1F23291A;
|
||||||
|
color: #646A73;
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
right: 23px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-btn {
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #DCDFE6;
|
||||||
|
display: flex;
|
||||||
|
color: #CCCCCC;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: #3370FF;
|
||||||
|
border-color: #3370FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.data-area-clear {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 6px;
|
||||||
|
color: rgb(135, 141, 159);
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.itxst {
|
.itxst {
|
||||||
|
@ -1,12 +1,4 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": ["@babel/preset-env"],
|
||||||
["env", {
|
"plugins": ["@babel/plugin-transform-runtime", "@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-object-rest-spread"]
|
||||||
"modules": false,
|
|
||||||
"targets": {
|
|
||||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"stage-2"
|
|
||||||
],
|
|
||||||
"plugins": ["transform-vue-jsx", "transform-runtime"]
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
"buildPlugin": "node build/build-async-plugins.js"
|
"buildPlugin": "node build/build-async-plugins.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@babel/polyfill": "^7.12.1",
|
||||||
|
"@babel/runtime": "^7.18.9",
|
||||||
"@antv/l7": "2.15.0",
|
"@antv/l7": "2.15.0",
|
||||||
"@antv/l7-component": "2.15.0",
|
"@antv/l7-component": "2.15.0",
|
||||||
"@antv/l7-core": "2.15.0",
|
"@antv/l7-core": "2.15.0",
|
||||||
@ -30,14 +32,12 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^7.1.2",
|
"autoprefixer": "^7.1.2",
|
||||||
"babel-core": "^6.22.1",
|
"@babel/core": "^7.6.4",
|
||||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
"@babel/plugin-proposal-object-rest-spread": "^7.18.9",
|
||||||
"babel-loader": "^7.1.1",
|
"@babel/plugin-proposal-optional-chaining": "^7.18.6",
|
||||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
"@babel/plugin-transform-runtime": "^7.6.2",
|
||||||
"babel-plugin-transform-runtime": "^6.22.0",
|
"@babel/preset-env": "^7.6.3",
|
||||||
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-preset-env": "^1.3.2",
|
|
||||||
"babel-preset-stage-2": "^6.22.0",
|
|
||||||
"chalk": "^2.0.1",
|
"chalk": "^2.0.1",
|
||||||
"copy-webpack-plugin": "^4.6.0",
|
"copy-webpack-plugin": "^4.6.0",
|
||||||
"css-loader": "^0.28.0",
|
"css-loader": "^0.28.0",
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
width="896px"
|
||||||
|
append-to-body
|
||||||
|
title="添加过滤"
|
||||||
|
destroy-on-close
|
||||||
|
class="de-dialog-form filter-tree-cont"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
>
|
||||||
|
<div class="tree-cont">
|
||||||
|
<div class="content">
|
||||||
|
<rowAuth ref="rowAuth" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
slot="footer"
|
||||||
|
class="dialog-footer"
|
||||||
|
>
|
||||||
|
<de-btn
|
||||||
|
secondary
|
||||||
|
@click="closeFilter"
|
||||||
|
>{{ $t('chart.cancel') }}
|
||||||
|
</de-btn>
|
||||||
|
<de-btn
|
||||||
|
type="primary"
|
||||||
|
@click="changeFilter"
|
||||||
|
>{{ $t('chart.confirm') }}
|
||||||
|
</de-btn>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import rowAuth from './rowAuth.vue'
|
||||||
|
export default {
|
||||||
|
name: 'FilterTree',
|
||||||
|
inject: ['filedList'],
|
||||||
|
components: {
|
||||||
|
rowAuth
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
computedFiledList() {
|
||||||
|
return this.filedList().reduce((pre, next) => {
|
||||||
|
if (next.id !== 'count') {
|
||||||
|
pre[next.id] = next
|
||||||
|
}
|
||||||
|
return pre
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeFilter() {
|
||||||
|
this.dialogVisible = false
|
||||||
|
},
|
||||||
|
changeFilter() {
|
||||||
|
const { logic, items, errorMessage } = this.$refs.rowAuth.submit()
|
||||||
|
if (errorMessage) {
|
||||||
|
this.$message({
|
||||||
|
message: errorMessage,
|
||||||
|
type: 'error',
|
||||||
|
showClose: true
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.dfsTreeDelete(items)
|
||||||
|
this.$emit('filter-data', { logic, items })
|
||||||
|
this.dialogVisible = false
|
||||||
|
},
|
||||||
|
dfsTreeDelete(arr) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele?.subTree?.items?.length) {
|
||||||
|
this.dfsTreeDelete(ele.subTree.items)
|
||||||
|
} else {
|
||||||
|
if (ele.field) {
|
||||||
|
this.$delete(ele, 'field')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
dfsTree(arr) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele?.subTree?.items?.length) {
|
||||||
|
this.dfsTree(ele.subTree.items)
|
||||||
|
} else {
|
||||||
|
if (this.computedFiledList[ele.fieldId]) {
|
||||||
|
ele.field = this.computedFiledList[ele.fieldId]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
init(tree) {
|
||||||
|
this.dialogVisible = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.dfsTree(tree.items || [])
|
||||||
|
this.$refs.rowAuth.init(tree || {})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.filter-tree-cont {
|
||||||
|
.tree-cont {
|
||||||
|
min-height: 67px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--deBorderBase, #DCDFE6);
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 500px;
|
||||||
|
.content {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
|||||||
|
function formatEnum(ele) {
|
||||||
|
return {
|
||||||
|
value: ele,
|
||||||
|
label: `chart.filter_${ele.replace(' ', '_')}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const textEnum = ['eq', 'not_eq', 'like', 'not like', 'null', 'not_null', 'empty', 'not_empty']
|
||||||
|
const textOptions = textEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const dateEnum = ['eq', 'not_eq', 'lt', 'gt', 'le', 'ge']
|
||||||
|
const dateOptions = dateEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const valueEnum = [...dateEnum]
|
||||||
|
const valueOptions = valueEnum.map(formatEnum)
|
||||||
|
|
||||||
|
const fieldEnum = ['text', 'time', 'value', 'value', '', 'location']
|
||||||
|
|
||||||
|
export {
|
||||||
|
textOptions,
|
||||||
|
dateOptions,
|
||||||
|
valueOptions,
|
||||||
|
fieldEnum
|
||||||
|
}
|
@ -0,0 +1,348 @@
|
|||||||
|
<template>
|
||||||
|
<div class="rowAuth">
|
||||||
|
<rowAuthTree
|
||||||
|
@del="(idx) => del(idx)"
|
||||||
|
@addCondReal="addCondReal"
|
||||||
|
@removeRelationList="removeRelationList"
|
||||||
|
@changeAndOrDfs="(type) => changeAndOrDfs(relationList, type)"
|
||||||
|
:relationList="relationList"
|
||||||
|
:logic.sync="logic"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
/>
|
||||||
|
<svg width="388" height="100%" class="real-line">
|
||||||
|
<path
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
:d="svgRealinePath"
|
||||||
|
fill="none"
|
||||||
|
stroke="#CCCCCC"
|
||||||
|
stroke-width="0.5"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<svg width="388" height="100%" class="dash-line">
|
||||||
|
<path
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
:d="svgDashinePath"
|
||||||
|
fill="none"
|
||||||
|
stroke="#CCCCCC"
|
||||||
|
stroke-width="0.5"
|
||||||
|
stroke-dasharray="4,4"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import rowAuthTree from "./rowTeeAuth.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "RowAuth",
|
||||||
|
components: {
|
||||||
|
rowAuthTree,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
svgRealinePath() {
|
||||||
|
const lg = this.relationList.length;
|
||||||
|
let a = { x: 0, y: 0, child: this.relationList };
|
||||||
|
a.y = Math.floor(this.dfsXY(a, 0) / 2);
|
||||||
|
if (!lg) return "";
|
||||||
|
let path = this.calculateDepth(a);
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
svgDashinePath() {
|
||||||
|
const lg = this.relationList.length;
|
||||||
|
let a = { x: 0, y: 0, child: this.relationList };
|
||||||
|
a.y = Math.floor(this.dfsXY(a, 0) / 2);
|
||||||
|
if (!lg) return `M48 20 L68 20`;
|
||||||
|
let path = this.calculateDepthDash(a);
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
executeAxios(url, type, data, callBack) {
|
||||||
|
this.$emit("execute-axios", url, type, data, callBack);
|
||||||
|
},
|
||||||
|
init(expressionTree) {
|
||||||
|
const { logic = "or", items = [] } = expressionTree;
|
||||||
|
this.logic = logic;
|
||||||
|
this.relationList = this.dfsInit(items);
|
||||||
|
},
|
||||||
|
submit() {
|
||||||
|
this.errorMessage = '';
|
||||||
|
return {
|
||||||
|
logic: this.logic,
|
||||||
|
items: this.dfsSubmit(this.relationList),
|
||||||
|
errorMessage: this.errorMessage
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorDetected({ enumValue, deType, filterType, term, value }) {
|
||||||
|
if (filterType === "logic") {
|
||||||
|
if (
|
||||||
|
!term.includes("null") &&
|
||||||
|
!term.includes("empty") &&
|
||||||
|
(value === "")
|
||||||
|
) {
|
||||||
|
this.errorMessage = this.$t("chart.filter_value_can_null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ([2, 3].includes(deType)) {
|
||||||
|
if (parseFloat(value).toString() === "NaN") {
|
||||||
|
this.errorMessage = this.$t("chart.filter_value_can_not_str");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filterType === "enum") {
|
||||||
|
if (enumValue.length < 1) {
|
||||||
|
this.errorMessage = this.$t("chart.enum_value_can_not_null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dfsInit(arr) {
|
||||||
|
const elementList = [];
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
const { subTree } = ele;
|
||||||
|
if (subTree) {
|
||||||
|
const { items, logic } = subTree;
|
||||||
|
const child = this.dfsInit(items);
|
||||||
|
elementList.push({ logic, child });
|
||||||
|
} else {
|
||||||
|
const {
|
||||||
|
enumValue,
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
field,
|
||||||
|
} = ele;
|
||||||
|
const { name, deType } = (field || {});
|
||||||
|
elementList.push({
|
||||||
|
enumValue: enumValue.join(','),
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
name,
|
||||||
|
deType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return elementList;
|
||||||
|
},
|
||||||
|
dfsSubmit(arr) {
|
||||||
|
const items = [];
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
const { child = [] } = ele;
|
||||||
|
if (child.length) {
|
||||||
|
const { logic } = ele;
|
||||||
|
const subTree = this.dfsSubmit(child);
|
||||||
|
items.push({
|
||||||
|
enumValue: [],
|
||||||
|
fieldId: '',
|
||||||
|
filterType: '',
|
||||||
|
term: '',
|
||||||
|
type: 'tree',
|
||||||
|
value: '', subTree: { logic, items: subTree} });
|
||||||
|
} else {
|
||||||
|
const { enumValue, fieldId, filterType,deType, term, value } = ele;
|
||||||
|
this.errorDetected({ deType, enumValue, filterType, term, value})
|
||||||
|
if (fieldId) {
|
||||||
|
items.push({
|
||||||
|
enumValue: enumValue ? enumValue.split(',') : [],
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
type: 'item',
|
||||||
|
subTree: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
},
|
||||||
|
removeRelationList() {
|
||||||
|
this.relationList = [];
|
||||||
|
},
|
||||||
|
getY(arr) {
|
||||||
|
const [a] = arr;
|
||||||
|
if (a.child?.length) {
|
||||||
|
return this.getY(a.child);
|
||||||
|
}
|
||||||
|
return a.y;
|
||||||
|
},
|
||||||
|
getLastY(arr) {
|
||||||
|
const a = arr[arr.length];
|
||||||
|
if (a.child?.length) {
|
||||||
|
return this.getLastY(a.child);
|
||||||
|
}
|
||||||
|
return a.y;
|
||||||
|
},
|
||||||
|
calculateDepthDash(obj) {
|
||||||
|
const lg = obj.child?.length;
|
||||||
|
let path = "";
|
||||||
|
if (!lg && Array.isArray(obj.child)) {
|
||||||
|
const { x, y } = obj;
|
||||||
|
path += `M${48 + x * 68} ${y * 41.4 + 20} L${88 + x * 68} ${
|
||||||
|
y * 41.4 + 20
|
||||||
|
}`;
|
||||||
|
} else if (obj.child?.length) {
|
||||||
|
let y = Math.max(
|
||||||
|
this.dfsY(obj, 0),
|
||||||
|
this.dfs(obj.child, 0) + this.getY(obj.child) - 1
|
||||||
|
);
|
||||||
|
let parent =
|
||||||
|
(this.dfs(obj.child, 0) * 41.4) / 2 +
|
||||||
|
(this.getY(obj.child) || 0) * 41.4;
|
||||||
|
const { x } = obj;
|
||||||
|
path += `M${24 + x * 68} ${parent} L${24 + x * 68} ${y * 41.4 + 20} L${
|
||||||
|
64 + x * 68
|
||||||
|
} ${y * 41.4 + 20}`;
|
||||||
|
obj.child.forEach((item) => {
|
||||||
|
path += this.calculateDepthDash(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
calculateDepth(obj) {
|
||||||
|
const lg = obj.child.length;
|
||||||
|
if (!lg) return "";
|
||||||
|
let path = "";
|
||||||
|
const { x: depth, y } = obj;
|
||||||
|
obj.child.forEach((item, index) => {
|
||||||
|
const { y: sibingLg, z } = item;
|
||||||
|
if (item.child?.length) {
|
||||||
|
let parent =
|
||||||
|
(this.dfs(obj.child, 0) * 41.4) / 2 +
|
||||||
|
(this.getY(obj.child) || 0) * 41.4;
|
||||||
|
let children =
|
||||||
|
(this.dfs(item.child, 0) * 41.4) / 2 + this.getY(item.child) * 41.4;
|
||||||
|
let path1 = 0;
|
||||||
|
let path2 = 0;
|
||||||
|
if (parent < children) {
|
||||||
|
path1 = parent;
|
||||||
|
path2 = children;
|
||||||
|
} else {
|
||||||
|
[path1, path2] = [children, parent];
|
||||||
|
}
|
||||||
|
if (y >= sibingLg) {
|
||||||
|
path1 = parent;
|
||||||
|
path2 = children;
|
||||||
|
}
|
||||||
|
path += `M${24 + depth * 68} ${path1} L${24 + depth * 68} ${path2} L${
|
||||||
|
68 + depth * 68
|
||||||
|
} ${path2}`;
|
||||||
|
// path += a;
|
||||||
|
path += this.calculateDepth(item);
|
||||||
|
}
|
||||||
|
if (!item.child?.length) {
|
||||||
|
// console.log(123, y, sibingLg, lg === 1 && index === 0 , item.z);
|
||||||
|
if (sibingLg >= y) {
|
||||||
|
path += `M${24 + depth * 68} ${y * 40} L${24 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 - 20.69921875
|
||||||
|
} L${68 + depth * 68} ${(sibingLg + 1) * 41.4 - 20.69921875}`;
|
||||||
|
} else {
|
||||||
|
path += `M${24 + depth * 68} ${
|
||||||
|
(sibingLg +
|
||||||
|
(lg === 1 && index === 0 ? 0 : 1) +
|
||||||
|
(obj.child[index + 1]?.child?.length ? y - sibingLg - 1 : 0)) *
|
||||||
|
41.4 +
|
||||||
|
20 +
|
||||||
|
(lg === 1 && index === 0 ? 26 : 0)
|
||||||
|
} L${24 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 -
|
||||||
|
20.69921875 -
|
||||||
|
(lg === 1 && index === 0 ? (z || 0) * 1.4 : 0)
|
||||||
|
} L${68 + depth * 68} ${
|
||||||
|
(sibingLg + 1) * 41.4 -
|
||||||
|
20.69921875 -
|
||||||
|
(lg === 1 && index === 0 ? (z || 0) * 1.4 : 0)
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
changeAndOrDfs(arr, logic) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele.child) {
|
||||||
|
ele.logic = logic === "and" ? "or" : "and";
|
||||||
|
this.changeAndOrDfs(ele.child, ele.logic);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
dfs(arr, count) {
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (ele.child?.length) {
|
||||||
|
count = this.dfs(ele.child, count);
|
||||||
|
} else {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
count += 1;
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
dfsY(obj, count) {
|
||||||
|
obj.child.forEach((ele) => {
|
||||||
|
if (ele.child?.length) {
|
||||||
|
count = this.dfsY(ele, count);
|
||||||
|
} else {
|
||||||
|
count = Math.max(count, ele.y, obj.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
dfsXY(obj, count) {
|
||||||
|
obj.child.forEach((ele) => {
|
||||||
|
ele.x = obj.x + 1;
|
||||||
|
if (ele.child?.length) {
|
||||||
|
let l = this.dfs(ele.child, 0);
|
||||||
|
ele.y = Math.floor(l / 2) + count;
|
||||||
|
count = this.dfsXY(ele, count);
|
||||||
|
} else {
|
||||||
|
count += 1;
|
||||||
|
ele.y = count - 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
count += 1;
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
addCondReal(type, logic) {
|
||||||
|
this.relationList.push(
|
||||||
|
type === "condition"
|
||||||
|
? { fieldId: '', value: "", enumValue: "", term: "", filterType: "logic", name: "", deType: "" }
|
||||||
|
: { child: [], logic }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
del(index) {
|
||||||
|
this.relationList.splice(index, 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
relationList: [],
|
||||||
|
logic: "or",
|
||||||
|
errorMessage: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.rowAuth {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
color: #2c3e50;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.real-line,
|
||||||
|
.dash-line {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,247 @@
|
|||||||
|
<template>
|
||||||
|
<div class="logic" :style="marginLeft">
|
||||||
|
<div class="logic-left">
|
||||||
|
<div class="operate-title">
|
||||||
|
<span
|
||||||
|
style="
|
||||||
|
{
|
||||||
|
color: '#bfbfbf';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
class="mrg-title"
|
||||||
|
v-if="x"
|
||||||
|
>
|
||||||
|
{{ logic === 'or' ? "OR" : "AND" }}
|
||||||
|
</span>
|
||||||
|
<el-dropdown @command="handleCommand" trigger="click" v-else>
|
||||||
|
<span
|
||||||
|
style="
|
||||||
|
{
|
||||||
|
color: 'rgba(0,0,0,.65)';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
class="mrg-title"
|
||||||
|
>
|
||||||
|
{{ logic === 'or' ? "OR" : "AND" }}<i class="el-icon-arrow-down"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item command="and">AND</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="or">OR</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
<span class="operate-icon" v-if="x">
|
||||||
|
<!-- <el-tooltip
|
||||||
|
class="item"
|
||||||
|
effect="light"
|
||||||
|
content="切换最外侧关系节点类型时,所有关系都会切换,内外层关系必然相反"
|
||||||
|
placement="top-end"
|
||||||
|
>
|
||||||
|
<i v-if="!x" class="el-icon-warning-outline"></i>
|
||||||
|
</el-tooltip> -->
|
||||||
|
<i class="el-icon-delete" @click="$emit('removeRelationList')"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="logic-right">
|
||||||
|
<template v-for="(item, index) in relationList">
|
||||||
|
<logic-relation
|
||||||
|
:x="item.x"
|
||||||
|
@del="(idx) => del(idx, item.child)"
|
||||||
|
@addCondReal="(type, logic) => add(type, item.child, logic)"
|
||||||
|
v-if="item.child"
|
||||||
|
:key="index"
|
||||||
|
:logic="item.logic"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
@removeRelationList="removeRelationList(index)"
|
||||||
|
:relationList="item.child"
|
||||||
|
>
|
||||||
|
</logic-relation>
|
||||||
|
<filter-filed
|
||||||
|
v-else
|
||||||
|
:item="item"
|
||||||
|
@del="$emit('del', index)"
|
||||||
|
:index="index"
|
||||||
|
:key="index"
|
||||||
|
@execute-axios="executeAxios"
|
||||||
|
></filter-filed>
|
||||||
|
</template>
|
||||||
|
<div class="logic-right-add">
|
||||||
|
<button @click="addCondReal('condition')" class="operand-btn">
|
||||||
|
+ {{ $t('auth.add_condition')}}
|
||||||
|
</button>
|
||||||
|
<button v-if="x < 2" @click="addCondReal('relation')" class="operand-btn">
|
||||||
|
+ {{ $t('auth.add_relationship')}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import filterFiled from "./filterFiled";
|
||||||
|
export default {
|
||||||
|
name: "LogicRelation",
|
||||||
|
props: {
|
||||||
|
relationList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
x: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
logic: {
|
||||||
|
type: String,
|
||||||
|
default: 'or',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
filterFiled,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
marginLeft() {
|
||||||
|
return {
|
||||||
|
marginLeft: this.x ? "20px" : 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
executeAxios(url, type, data, callBack) {
|
||||||
|
this.$emit("execute-axios", url, type, data, callBack);
|
||||||
|
},
|
||||||
|
handleCommand(type) {
|
||||||
|
this.$emit('update:logic', type);
|
||||||
|
this.$emit("changeAndOrDfs", type)
|
||||||
|
},
|
||||||
|
removeRelationList(index) {
|
||||||
|
this.relationList.splice(index, 1);
|
||||||
|
},
|
||||||
|
addCondReal(type) {
|
||||||
|
this.$emit("addCondReal", type, this.logic === 'or' ? 'and' : 'or');
|
||||||
|
},
|
||||||
|
add(type, child, logic) {
|
||||||
|
child.push(type === "condition" ?{ fieldId: '', value: '', enumValue: '', term: '', filterType: 'logic', name: '', deType: "" } : { child: [], logic });
|
||||||
|
},
|
||||||
|
del(index, child) {
|
||||||
|
child.splice(index, 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scope>
|
||||||
|
.logic {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.logic-left {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 48px;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
flex-direction: row;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.operate-title {
|
||||||
|
font-family: PingFang SC, Hiragino Sans GB, Microsoft YaHei, sans-serif;
|
||||||
|
word-wrap: break-word;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
font-size: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 65px;
|
||||||
|
background-color: #f8f8fa;
|
||||||
|
line-height: 28px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
height: 28px;
|
||||||
|
|
||||||
|
.mrg-title {
|
||||||
|
text-align: left;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
margin-left: 11px;
|
||||||
|
margin-right: 11px;
|
||||||
|
line-height: 28px;
|
||||||
|
height: 28px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
// width: 65px;
|
||||||
|
|
||||||
|
.operate-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate-title {
|
||||||
|
.mrg-title {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
|
background-color: #f8f8fa;
|
||||||
|
z-index: 1;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
display: unset;
|
||||||
|
padding: 5px 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logic-right-add {
|
||||||
|
display: flex;
|
||||||
|
height: 41.4px;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 26px;
|
||||||
|
|
||||||
|
.operand-btn {
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
|
||||||
|
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
outline: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1;
|
||||||
|
-webkit-appearance: button;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #246dff;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #246dff;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -112,36 +112,33 @@
|
|||||||
|
|
||||||
<!-- 结果过滤器 -->
|
<!-- 结果过滤器 -->
|
||||||
<el-row class="padding-lr" style="margin-top: 6px;">
|
<el-row class="padding-lr" style="margin-top: 6px;">
|
||||||
<span>{{ $t('chart.result_filter') }}</span>
|
<span class="data-area-label">
|
||||||
|
<span>{{ $t('chart.result_filter') }}</span>
|
||||||
<draggable
|
<span
|
||||||
v-model="view.customFilter"
|
v-if="!!view.customFilter.logic"
|
||||||
:move="onMove"
|
class="setting"
|
||||||
animation="300"
|
>已设置</span>
|
||||||
class="theme-item-class"
|
<i
|
||||||
group="drag"
|
class="el-icon-arrow-down el-icon-delete data-area-clear"
|
||||||
style="padding:2px 0 0 0;width:100%;min-height: 32px;border-radius: 4px;border: 1px solid #DCDFE6;overflow-x: auto;display: flex;align-items: center;background-color: white;"
|
@click="deleteTreeFilter"
|
||||||
@add="addCustomFilter"
|
|
||||||
@update="calcData(true)"
|
|
||||||
>
|
|
||||||
<transition-group class="draggable-group">
|
|
||||||
<filter-item
|
|
||||||
v-for="(item,index) in view.customFilter"
|
|
||||||
:key="item.id"
|
|
||||||
:dimension-data="dimensionData"
|
|
||||||
:index="index"
|
|
||||||
:item="item"
|
|
||||||
:param="param"
|
|
||||||
:quota-data="quotaData"
|
|
||||||
@editItemFilter="showEditFilter"
|
|
||||||
@onFilterItemRemove="filterItemRemove"
|
|
||||||
/>
|
/>
|
||||||
</transition-group>
|
</span>
|
||||||
</draggable>
|
<div
|
||||||
<div v-if="!view.customFilter || view.customFilter.length === 0" class="drag-placeholder-style">
|
class="tree-btn"
|
||||||
<span class="drag-placeholder-style-span">{{ $t('chart.placeholder_field') }}</span>
|
:class="!!view.customFilter.logic && 'active'"
|
||||||
</div>
|
@click="openTreeFilter"
|
||||||
|
>
|
||||||
|
<svg-icon
|
||||||
|
class="svg-background"
|
||||||
|
icon-class="icon-filter_outlined"
|
||||||
|
/>
|
||||||
|
<span>过滤</span>
|
||||||
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<FilterTree
|
||||||
|
ref="filterTree"
|
||||||
|
@filter-data="changeFilterData"
|
||||||
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -152,8 +149,14 @@ import LocationYItem from '@/components/views/LocationYItem'
|
|||||||
import QuotaItem from '@/components/views/QuotaItem'
|
import QuotaItem from '@/components/views/QuotaItem'
|
||||||
import FilterItem from '@/components/views/FilterItem'
|
import FilterItem from '@/components/views/FilterItem'
|
||||||
import messages from '@/de-base/lang/messages'
|
import messages from '@/de-base/lang/messages'
|
||||||
|
import FilterTree from '@/components/views/filter/FilterTree.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
filedList: () => this.filedList
|
||||||
|
}
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|
||||||
obj: {
|
obj: {
|
||||||
@ -166,7 +169,8 @@ export default {
|
|||||||
LocationXItem,
|
LocationXItem,
|
||||||
LocationYItem,
|
LocationYItem,
|
||||||
QuotaItem,
|
QuotaItem,
|
||||||
FilterItem
|
FilterItem,
|
||||||
|
FilterTree
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -188,6 +192,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
filedList() {
|
||||||
|
return [...this.dimensionData, ...this.quotaData].filter(ele => ele.id !== 'count')
|
||||||
|
},
|
||||||
param() {
|
param() {
|
||||||
return this.obj.param
|
return this.obj.param
|
||||||
},
|
},
|
||||||
@ -224,6 +231,16 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
changeFilterData(customFilter) {
|
||||||
|
this.view.customFilter =JSON.parse(JSON.stringify(customFilter))
|
||||||
|
this.calcData(true)
|
||||||
|
},
|
||||||
|
openTreeFilter() {
|
||||||
|
this.$refs.filterTree.init(JSON.parse(JSON.stringify(this.view.customFilter)))
|
||||||
|
},
|
||||||
|
deleteTreeFilter() {
|
||||||
|
this.changeFilterData({})
|
||||||
|
},
|
||||||
executeAxios(url, type, data, callBack) {
|
executeAxios(url, type, data, callBack) {
|
||||||
const param = {
|
const param = {
|
||||||
url: url,
|
url: url,
|
||||||
@ -401,6 +418,49 @@ export default {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.padding-lr {
|
.padding-lr {
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
|
.data-area-label {
|
||||||
|
text-align: left;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
.setting {
|
||||||
|
padding: 0px 4px 0px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: #1F23291A;
|
||||||
|
color: #646A73;
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
right: 23px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-btn {
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #DCDFE6;
|
||||||
|
display: flex;
|
||||||
|
color: #CCCCCC;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: #3370FF;
|
||||||
|
border-color: #3370FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.data-area-clear {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 6px;
|
||||||
|
color: rgb(135, 141, 159);
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.itxst {
|
.itxst {
|
||||||
|
Loading…
Reference in New Issue
Block a user