forked from github/dataease
Merge branch 'dev-v2' of github.com:dataease/dataease into dev-v2
This commit is contained in:
commit
6401a2fe53
@ -913,7 +913,7 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.item-dimension:hover {
|
.item-dimension:hover {
|
||||||
border: 1px solid var(--blue-500, #3370ff);
|
border: 1px solid var(--ed-color-primary, #3370ff);
|
||||||
background: var(--ed-color-primary-1a, rgba(51, 112, 255, 0.1));
|
background: var(--ed-color-primary-1a, rgba(51, 112, 255, 0.1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,135 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { toRefs, PropType, ref, onBeforeMount, watch, computed } from 'vue'
|
||||||
|
import { type DatePickType } from 'element-plus-secondary'
|
||||||
|
import {
|
||||||
|
getThisYear,
|
||||||
|
getLastYear,
|
||||||
|
getThisMonth,
|
||||||
|
getLastMonth,
|
||||||
|
getToday,
|
||||||
|
getYesterday,
|
||||||
|
getMonthBeginning,
|
||||||
|
getYearBeginning,
|
||||||
|
getCustomTime
|
||||||
|
} from './time-format'
|
||||||
|
interface SelectConfig {
|
||||||
|
relativeToCurrent: string
|
||||||
|
timeNum: number
|
||||||
|
relativeToCurrentType: string
|
||||||
|
around: string
|
||||||
|
arbitraryTime: Date
|
||||||
|
timeGranularity: DatePickType
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
config: {
|
||||||
|
type: Object as PropType<SelectConfig>,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
relativeToCurrent: 'custom',
|
||||||
|
timeNum: 0,
|
||||||
|
relativeToCurrentType: 'year',
|
||||||
|
around: 'f',
|
||||||
|
arbitraryTime: new Date(),
|
||||||
|
timeGranularity: 'year'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const selectValue = ref()
|
||||||
|
|
||||||
|
const { config } = toRefs(props)
|
||||||
|
|
||||||
|
const timeConfig = computed(() => {
|
||||||
|
const {
|
||||||
|
relativeToCurrent,
|
||||||
|
timeNum,
|
||||||
|
relativeToCurrentType,
|
||||||
|
around,
|
||||||
|
arbitraryTime,
|
||||||
|
timeGranularity
|
||||||
|
} = config.value
|
||||||
|
return {
|
||||||
|
relativeToCurrent,
|
||||||
|
timeNum,
|
||||||
|
relativeToCurrentType,
|
||||||
|
around,
|
||||||
|
arbitraryTime,
|
||||||
|
timeGranularity
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => timeConfig.value,
|
||||||
|
() => {
|
||||||
|
init()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const {
|
||||||
|
relativeToCurrent,
|
||||||
|
timeNum,
|
||||||
|
relativeToCurrentType,
|
||||||
|
around,
|
||||||
|
arbitraryTime,
|
||||||
|
timeGranularity
|
||||||
|
} = timeConfig.value
|
||||||
|
if (relativeToCurrent === 'custom') {
|
||||||
|
selectValue.value = getCustomTime(
|
||||||
|
timeNum,
|
||||||
|
relativeToCurrentType,
|
||||||
|
timeGranularity,
|
||||||
|
around,
|
||||||
|
timeGranularity === 'datetime' ? arbitraryTime : null
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
switch (relativeToCurrent) {
|
||||||
|
case 'thisYear':
|
||||||
|
selectValue.value = getThisYear()
|
||||||
|
break
|
||||||
|
case 'lastYear':
|
||||||
|
selectValue.value = getLastYear()
|
||||||
|
break
|
||||||
|
case 'thisMonth':
|
||||||
|
selectValue.value = getThisMonth()
|
||||||
|
break
|
||||||
|
case 'lastMonth':
|
||||||
|
selectValue.value = getLastMonth()
|
||||||
|
break
|
||||||
|
case 'today':
|
||||||
|
selectValue.value = getToday()
|
||||||
|
break
|
||||||
|
case 'yesterday':
|
||||||
|
selectValue.value = getYesterday()
|
||||||
|
break
|
||||||
|
case 'monthBeginning':
|
||||||
|
selectValue.value = getMonthBeginning()
|
||||||
|
break
|
||||||
|
case 'yearBeginning':
|
||||||
|
selectValue.value = getYearBeginning()
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-date-picker
|
||||||
|
disabled
|
||||||
|
:key="config.timeGranularity"
|
||||||
|
v-model="selectValue"
|
||||||
|
:type="config.timeGranularity"
|
||||||
|
:placeholder="$t('commons.date.select_date_time')"
|
||||||
|
/>
|
||||||
|
</template>
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ElMessage } from 'element-plus-secondary'
|
import { ElMessage } from 'element-plus-secondary'
|
||||||
import { inject, computed, ref, nextTick, provide } from 'vue'
|
import { inject, computed, ref, nextTick, provide } from 'vue'
|
||||||
import RowAuth from '@/views/visualized/data/dataset/auth-tree/RowAuth.vue'
|
import RowAuth from '@/views/chart/components/editor/filter/auth-tree/RowAuth.vue'
|
||||||
|
|
||||||
const emits = defineEmits(['filter-data'])
|
const emits = defineEmits(['filter-data'])
|
||||||
const filedList = inject('filedList', () => [])
|
const filedList = inject('filedList', () => [])
|
||||||
|
@ -0,0 +1,308 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import DynamicTime from '@/custom-component/v-query/DynamicTimeForViewFilter.vue'
|
||||||
|
import { type DatePickType } from 'element-plus-secondary'
|
||||||
|
export interface SelectConfig {
|
||||||
|
relativeToCurrent: string
|
||||||
|
timeNum: number
|
||||||
|
relativeToCurrentType: string
|
||||||
|
around: string
|
||||||
|
arbitraryTime: Date
|
||||||
|
timeGranularity: DatePickType
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultValue: SelectConfig = {
|
||||||
|
relativeToCurrent: 'custom', //相对当前 thisYear | lastYear | thisMonth | lastMonth | today | yesterday | monthBeginning | yearBeginning
|
||||||
|
timeGranularity: 'year', //时间粒度 year | month | date | datetime
|
||||||
|
timeNum: 0, // 数值
|
||||||
|
relativeToCurrentType: 'year', // year | month | date
|
||||||
|
around: 'b', // 前 b | 后 f
|
||||||
|
arbitraryTime: new Date() //timeGranularity = datetime时 取时分秒
|
||||||
|
}
|
||||||
|
const curComponent = ref<SelectConfig>({ ...defaultValue })
|
||||||
|
|
||||||
|
const init = (val: SelectConfig) => {
|
||||||
|
curComponent.value = {
|
||||||
|
...defaultValue,
|
||||||
|
...val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const aroundList = [
|
||||||
|
{
|
||||||
|
label: '前',
|
||||||
|
value: 'f'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '后',
|
||||||
|
value: 'b'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const relativeToCurrentList = computed(() => {
|
||||||
|
let list = []
|
||||||
|
if (!curComponent.value) return list
|
||||||
|
switch (curComponent.value.timeGranularity) {
|
||||||
|
case 'year':
|
||||||
|
list = [
|
||||||
|
{
|
||||||
|
label: '今年',
|
||||||
|
value: 'thisYear'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '去年',
|
||||||
|
value: 'lastYear'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
break
|
||||||
|
case 'month':
|
||||||
|
list = [
|
||||||
|
{
|
||||||
|
label: '本月',
|
||||||
|
value: 'thisMonth'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '上月',
|
||||||
|
value: 'lastMonth'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
break
|
||||||
|
case 'date':
|
||||||
|
list = [
|
||||||
|
{
|
||||||
|
label: '今天',
|
||||||
|
value: 'today'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '昨天',
|
||||||
|
value: 'yesterday'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '月初',
|
||||||
|
value: 'monthBeginning'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '年初',
|
||||||
|
value: 'yearBeginning'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
break
|
||||||
|
case 'datetime':
|
||||||
|
list = [
|
||||||
|
{
|
||||||
|
label: '今天',
|
||||||
|
value: 'today'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '昨天',
|
||||||
|
value: 'yesterday'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '月初',
|
||||||
|
value: 'monthBeginning'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '年初',
|
||||||
|
value: 'yearBeginning'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
...list,
|
||||||
|
{
|
||||||
|
label: '自定义',
|
||||||
|
value: 'custom'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const relativeToCurrentTypeList = computed(() => {
|
||||||
|
if (!curComponent.value) return []
|
||||||
|
let index = ['year', 'month', 'date', 'datetime'].indexOf(curComponent.value.timeGranularity) + 1
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: '年',
|
||||||
|
value: 'year'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '月',
|
||||||
|
value: 'month'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '日',
|
||||||
|
value: 'date'
|
||||||
|
}
|
||||||
|
].slice(0, index)
|
||||||
|
})
|
||||||
|
|
||||||
|
const timeGranularityChange = (val: string) => {
|
||||||
|
if (
|
||||||
|
['year', 'month', 'date', 'datetime'].indexOf(val) <
|
||||||
|
['year', 'month', 'date'].indexOf(curComponent.value.relativeToCurrentType)
|
||||||
|
) {
|
||||||
|
curComponent.value.relativeToCurrentType = 'year'
|
||||||
|
}
|
||||||
|
if (curComponent.value.relativeToCurrent !== 'custom') {
|
||||||
|
curComponent.value.relativeToCurrent = relativeToCurrentList.value[0]?.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeList = [
|
||||||
|
{
|
||||||
|
label: '年',
|
||||||
|
value: 'year'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '年月',
|
||||||
|
value: 'month'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '年月日',
|
||||||
|
value: 'date'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '年月日时分秒',
|
||||||
|
value: 'datetime'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
init,
|
||||||
|
curComponent
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="time-dialog">
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">时间粒度</div>
|
||||||
|
<div class="setting-value select">
|
||||||
|
<el-select
|
||||||
|
@change="timeGranularityChange"
|
||||||
|
placeholder="请选择时间粒度"
|
||||||
|
v-model="curComponent.timeGranularity"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="ele in timeList"
|
||||||
|
:key="ele.value"
|
||||||
|
:label="ele.label"
|
||||||
|
:value="ele.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">相对当前</div>
|
||||||
|
<div class="setting-value select">
|
||||||
|
<el-select v-model="curComponent.relativeToCurrent">
|
||||||
|
<el-option
|
||||||
|
v-for="item in relativeToCurrentList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="setting" v-if="curComponent.relativeToCurrent === 'custom'">
|
||||||
|
<div
|
||||||
|
class="setting-input"
|
||||||
|
:class="curComponent.timeGranularity === 'datetime' && 'with-date'"
|
||||||
|
>
|
||||||
|
<el-input-number v-model="curComponent.timeNum" :min="0" controls-position="right" />
|
||||||
|
<el-select v-model="curComponent.relativeToCurrentType">
|
||||||
|
<el-option
|
||||||
|
v-for="item in relativeToCurrentTypeList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-select v-model="curComponent.around">
|
||||||
|
<el-option
|
||||||
|
v-for="item in aroundList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-time-picker
|
||||||
|
style="width: 146px; margin-left: 8px"
|
||||||
|
v-if="curComponent.timeGranularity === 'datetime'"
|
||||||
|
v-model="curComponent.arbitraryTime"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">预览</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
<component :config="curComponent" isConfig ref="inputCom" :is="DynamicTime"></component>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.time-dialog {
|
||||||
|
.setting {
|
||||||
|
&.setting {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
&.parameters {
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 24px;
|
||||||
|
.ed-date-editor {
|
||||||
|
width: 325px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
.setting-label {
|
||||||
|
width: 80px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-value {
|
||||||
|
margin: 8px 0;
|
||||||
|
&.select {
|
||||||
|
margin-top: 0;
|
||||||
|
.ed-select {
|
||||||
|
width: 325px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-input {
|
||||||
|
display: flex;
|
||||||
|
padding-left: 86px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
&.range {
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
& > div + div {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.with-date {
|
||||||
|
.ed-input-number {
|
||||||
|
width: 71px;
|
||||||
|
}
|
||||||
|
.ed-select {
|
||||||
|
width: 62px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ed-date-editor.ed-input {
|
||||||
|
width: 106px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,244 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'logic-relation'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { PropType, computed, toRefs } from 'vue'
|
||||||
|
import FilterFiled from './FilterFiled.vue'
|
||||||
|
import type { Item } from './FilterFiled.vue'
|
||||||
|
export type Logic = 'or' | 'and'
|
||||||
|
export type Relation = {
|
||||||
|
child?: Relation[]
|
||||||
|
logic: Logic
|
||||||
|
x: number
|
||||||
|
} & Item
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
relationList: {
|
||||||
|
type: Array as PropType<Relation[]>,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
x: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
logic: {
|
||||||
|
type: String as PropType<Logic>,
|
||||||
|
default: 'or'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const marginLeft = computed(() => {
|
||||||
|
return {
|
||||||
|
marginLeft: props.x ? '20px' : 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emits = defineEmits([
|
||||||
|
'addCondReal',
|
||||||
|
'changeAndOrDfs',
|
||||||
|
'update:logic',
|
||||||
|
'removeRelationList',
|
||||||
|
'del'
|
||||||
|
])
|
||||||
|
|
||||||
|
const { relationList } = toRefs(props)
|
||||||
|
|
||||||
|
const handleCommand = type => {
|
||||||
|
emits('update:logic', type)
|
||||||
|
emits('changeAndOrDfs', type)
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeRelationList = index => {
|
||||||
|
relationList.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
const addCondReal = type => {
|
||||||
|
emits('addCondReal', type, props.logic === 'or' ? 'and' : 'or')
|
||||||
|
}
|
||||||
|
const add = (type, child, logic) => {
|
||||||
|
child.push(
|
||||||
|
type === 'condition'
|
||||||
|
? {
|
||||||
|
fieldId: '',
|
||||||
|
value: '',
|
||||||
|
enumValue: '',
|
||||||
|
term: '',
|
||||||
|
filterType: 'logic',
|
||||||
|
name: '',
|
||||||
|
filterTypeTime: 'dateValue',
|
||||||
|
timeValue: '',
|
||||||
|
dynamicTimeSetting: {},
|
||||||
|
deType: ''
|
||||||
|
}
|
||||||
|
: { child: [], logic }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const del = (index, child) => {
|
||||||
|
child.splice(index, 1)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<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 fir">
|
||||||
|
{{ logic === 'or' ? 'OR' : 'AND' }}
|
||||||
|
<el-icon>
|
||||||
|
<Icon name="icon_down_outlined"></Icon>
|
||||||
|
</el-icon>
|
||||||
|
</span>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item command="and">AND</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="or">OR</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
<span class="operate-icon" v-if="x">
|
||||||
|
<el-icon @click="emits('removeRelationList')">
|
||||||
|
<Icon name="icon_delete-trash_outlined"></Icon>
|
||||||
|
</el-icon>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="logic-right">
|
||||||
|
<template :key="index" v-for="(item, index) in relationList">
|
||||||
|
<logic-relation
|
||||||
|
v-if="item.child"
|
||||||
|
:x="item.x"
|
||||||
|
@del="idx => del(idx, item.child)"
|
||||||
|
@addCondReal="(type, logic) => add(type, item.child, logic)"
|
||||||
|
:logic="item.logic"
|
||||||
|
@removeRelationList="removeRelationList(index)"
|
||||||
|
:relationList="item.child"
|
||||||
|
>
|
||||||
|
</logic-relation>
|
||||||
|
<filter-filed v-else :item="item" @del="emits('del', index)" :index="index"></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>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.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;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.operate-title {
|
||||||
|
font-family: '阿里巴巴普惠体 3.0 55 Regular L3', 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.operate-icon {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate-title {
|
||||||
|
.mrg-title:not(.fir) {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
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>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,375 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import AuthTree from './AuthTree.vue'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const errorMessage = ref('')
|
||||||
|
const logic = ref<'or' | 'and'>('or')
|
||||||
|
const relationList = ref([])
|
||||||
|
|
||||||
|
const svgRealinePath = computed(() => {
|
||||||
|
const lg = relationList.value.length
|
||||||
|
let a = { x: 0, y: 0, child: relationList.value }
|
||||||
|
a.y = Math.floor(dfsXY(a, 0) / 2)
|
||||||
|
if (!lg) return ''
|
||||||
|
let path = calculateDepth(a)
|
||||||
|
return path
|
||||||
|
})
|
||||||
|
|
||||||
|
const svgDashinePath = computed(() => {
|
||||||
|
const lg = relationList.value.length
|
||||||
|
let a = { x: 0, y: 0, child: relationList.value }
|
||||||
|
a.y = Math.floor(dfsXY(a, 0) / 2)
|
||||||
|
if (!lg) return `M48 20 L68 20`
|
||||||
|
let path = calculateDepthDash(a)
|
||||||
|
return path
|
||||||
|
})
|
||||||
|
|
||||||
|
const init = expressionTree => {
|
||||||
|
const { items } = expressionTree
|
||||||
|
logic.value = expressionTree.logic || 'or'
|
||||||
|
relationList.value = dfsInit(items || [])
|
||||||
|
}
|
||||||
|
const submit = () => {
|
||||||
|
errorMessage.value = ''
|
||||||
|
emits('save', {
|
||||||
|
logic: logic.value,
|
||||||
|
items: dfsSubmit(relationList.value),
|
||||||
|
errorMessage: errorMessage.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const errorDetected = ({ enumValue, deType, filterType, term, value, name, timeValue }) => {
|
||||||
|
if (!name) {
|
||||||
|
errorMessage.value = t('data_set.cannot_be_empty_')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (filterType === 'logic') {
|
||||||
|
if (!term) {
|
||||||
|
errorMessage.value = t('data_set.cannot_be_empty_de_ruler')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!term.includes('null') &&
|
||||||
|
!term.includes('empty') &&
|
||||||
|
['', null, undefined].includes(value) &&
|
||||||
|
deType !== 1
|
||||||
|
) {
|
||||||
|
errorMessage.value = t('chart.filter_value_can_null')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!term.includes('null') &&
|
||||||
|
!term.includes('empty') &&
|
||||||
|
['', null, undefined].includes(timeValue) &&
|
||||||
|
deType === 1
|
||||||
|
) {
|
||||||
|
errorMessage.value = t('chart.filter_value_can_null')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ([2, 3].includes(deType)) {
|
||||||
|
if (parseFloat(value).toString() === 'NaN') {
|
||||||
|
errorMessage.value = t('chart.filter_value_can_not_str')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filterType === 'enum') {
|
||||||
|
if (enumValue.length < 1) {
|
||||||
|
errorMessage.value = t('chart.enum_value_can_not_null')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const dfsInit = arr => {
|
||||||
|
const elementList = []
|
||||||
|
arr.forEach(ele => {
|
||||||
|
const { subTree } = ele
|
||||||
|
if (subTree) {
|
||||||
|
const { items = [], logic } = subTree
|
||||||
|
const child = dfsInit(items)
|
||||||
|
elementList.push({ logic, child })
|
||||||
|
} else {
|
||||||
|
const {
|
||||||
|
enumValue,
|
||||||
|
timeValue,
|
||||||
|
filterTypeTime,
|
||||||
|
dynamicTimeSetting,
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
field
|
||||||
|
} = ele
|
||||||
|
const { name, deType } = field || {}
|
||||||
|
elementList.push({
|
||||||
|
enumValue: enumValue.join(','),
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
term,
|
||||||
|
timeValue,
|
||||||
|
filterTypeTime,
|
||||||
|
dynamicTimeSetting,
|
||||||
|
value,
|
||||||
|
name,
|
||||||
|
deType
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return elementList
|
||||||
|
}
|
||||||
|
const dfsSubmit = arr => {
|
||||||
|
const items = []
|
||||||
|
arr.forEach(ele => {
|
||||||
|
const { child = [] } = ele
|
||||||
|
if (child.length) {
|
||||||
|
const { logic } = ele
|
||||||
|
const subTree = dfsSubmit(child)
|
||||||
|
items.push({
|
||||||
|
enumValue: [],
|
||||||
|
fieldId: '',
|
||||||
|
filterType: '',
|
||||||
|
term: '',
|
||||||
|
type: 'tree',
|
||||||
|
value: '',
|
||||||
|
filterTypeTime: 'dateValue',
|
||||||
|
timeValue: '',
|
||||||
|
dynamicTimeSetting: {},
|
||||||
|
subTree: { logic, items: subTree }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const {
|
||||||
|
enumValue,
|
||||||
|
filterTypeTime,
|
||||||
|
dynamicTimeSetting,
|
||||||
|
fieldId,
|
||||||
|
filterType,
|
||||||
|
deType,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
name,
|
||||||
|
timeValue
|
||||||
|
} = ele
|
||||||
|
errorDetected({ deType, enumValue, filterType, term, value, name, timeValue })
|
||||||
|
if (fieldId) {
|
||||||
|
items.push({
|
||||||
|
enumValue: enumValue ? enumValue.split(',') : [],
|
||||||
|
fieldId,
|
||||||
|
timeValue,
|
||||||
|
filterType,
|
||||||
|
filterTypeTime,
|
||||||
|
dynamicTimeSetting,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
type: 'item',
|
||||||
|
subTree: null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
const removeRelationList = () => {
|
||||||
|
relationList.value = []
|
||||||
|
}
|
||||||
|
const getY = arr => {
|
||||||
|
const [a] = arr
|
||||||
|
if (a.child?.length) {
|
||||||
|
return getY(a.child)
|
||||||
|
}
|
||||||
|
return a.y
|
||||||
|
}
|
||||||
|
const 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(dfsY(obj, 0), dfs(obj.child, 0) + getY(obj.child) - 1)
|
||||||
|
let parent = (dfs(obj.child, 0) * 41.4) / 2 + (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 += calculateDepthDash(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
const 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 = (dfs(obj.child, 0) * 41.4) / 2 + (getY(obj.child) || 0) * 41.4
|
||||||
|
let children = (dfs(item.child, 0) * 41.4) / 2 + 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 += calculateDepth(item)
|
||||||
|
}
|
||||||
|
if (!item.child?.length) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
const changeAndOrDfs = (arr, logic) => {
|
||||||
|
arr.forEach(ele => {
|
||||||
|
if (ele.child) {
|
||||||
|
ele.logic = logic === 'and' ? 'or' : 'and'
|
||||||
|
changeAndOrDfs(ele.child, ele.logic)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const dfs = (arr, count) => {
|
||||||
|
arr.forEach(ele => {
|
||||||
|
if (ele.child?.length) {
|
||||||
|
count = dfs(ele.child, count)
|
||||||
|
} else {
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
const dfsY = (obj, count) => {
|
||||||
|
obj.child.forEach(ele => {
|
||||||
|
if (ele.child?.length) {
|
||||||
|
count = dfsY(ele, count)
|
||||||
|
} else {
|
||||||
|
count = Math.max(count, ele.y, obj.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
const dfsXY = (obj, count) => {
|
||||||
|
obj.child.forEach(ele => {
|
||||||
|
ele.x = obj.x + 1
|
||||||
|
if (ele.child?.length) {
|
||||||
|
let l = dfs(ele.child, 0)
|
||||||
|
ele.y = Math.floor(l / 2) + count
|
||||||
|
count = dfsXY(ele, count)
|
||||||
|
} else {
|
||||||
|
count += 1
|
||||||
|
ele.y = count - 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
const addCondReal = (type, logic) => {
|
||||||
|
relationList.value.push(
|
||||||
|
type === 'condition'
|
||||||
|
? {
|
||||||
|
fieldId: '',
|
||||||
|
value: '',
|
||||||
|
enumValue: '',
|
||||||
|
term: '',
|
||||||
|
filterType: 'logic',
|
||||||
|
name: '',
|
||||||
|
timeValue: '',
|
||||||
|
filterTypeTime: 'dateValue',
|
||||||
|
dynamicTimeSetting: {},
|
||||||
|
deType: ''
|
||||||
|
}
|
||||||
|
: { child: [], logic }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const del = index => {
|
||||||
|
relationList.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
init,
|
||||||
|
submit
|
||||||
|
})
|
||||||
|
const emits = defineEmits(['save'])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="rowAuth">
|
||||||
|
<auth-tree
|
||||||
|
@del="idx => del(idx)"
|
||||||
|
@addCondReal="addCondReal"
|
||||||
|
@removeRelationList="removeRelationList"
|
||||||
|
@changeAndOrDfs="type => changeAndOrDfs(relationList, type)"
|
||||||
|
:relationList="relationList"
|
||||||
|
v-model:logic="logic"
|
||||||
|
/>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.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>
|
@ -205,8 +205,8 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
li.select {
|
li.select {
|
||||||
background: var(--deWhiteHover, #e0eaff) !important;
|
background: var(--ed-color-primary-1a, #e0eaff) !important;
|
||||||
color: var(--TextActive, #3370ff) !important;
|
color: var(--ed-color-primary, #3370ff) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.de-btn-fix {
|
.de-btn-fix {
|
||||||
|
2
de-xpack
2
de-xpack
@ -1 +1 @@
|
|||||||
Subproject commit ae2888958efe511c787b2ad8a9d21eafe9c4f6fb
|
Subproject commit 11240f0a32fc1916409c82580e79fb17bb7988eb
|
Loading…
Reference in New Issue
Block a user