Merge branch 'dev-v2' into pr@dev-v2_dzz

This commit is contained in:
dataeaseShu 2023-10-31 17:40:33 +08:00
commit d1799baaf3
21 changed files with 579 additions and 239 deletions

2
.gitignore vendored
View File

@ -48,3 +48,5 @@ core/core-frontend/src/assets/fsSvg.html
/sdk/dataease-plugin-filter/
/sdk/dataease-plugin-interface/
/sdk/dataease-plugin-view/
/extensions/
.vite/

View File

@ -53,3 +53,4 @@ i18n_schema_is_empty=schema \u4E3A\u7A7A\uFF01
i18n_table_name_repeat=\u540D\u79F0\u91CD\u590D:
i18n_sql_not_empty=sql \u4E0D\u80FD\u4E3A\u7A7A
i18n_menu.parameter=\u7CFB\u7EDF\u53C2\u6570
i18n_user_old_pwd_error=\u539F\u59CB\u5BC6\u7801\u9519\u8BEF

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 2.5C4 1.94772 4.44772 1.5 5 1.5H14.8608C14.9949 1.5 15.1234 1.55387 15.2174 1.64951L19.8566 6.36941C19.9485 6.46292 20 6.58879 20 6.7199V21.5C20 22.0523 19.5523 22.5 19 22.5H5C4.44772 22.5 4 22.0523 4 21.5V2.5Z" fill="#3370FF"/>
<path d="M15 1.51978C15.0817 1.54345 15.1567 1.58778 15.2174 1.64952L19.8566 6.36942C19.8946 6.40806 19.9256 6.45223 19.949 6.50001H16.1351C15.5082 6.50001 15 5.99179 15 5.36488V1.51978Z" fill="#245BDB"/>
<path d="M8.07282 10.1819H15.6546C15.745 10.1819 15.8183 10.2551 15.8183 10.3455V11.1092C15.8183 11.1995 15.745 11.2728 15.6546 11.2728H8.07282C7.98244 11.2728 7.90918 11.1995 7.90918 11.1092V10.3455C7.90918 10.2551 7.98244 10.1819 8.07282 10.1819ZM8.07282 13.4546H15.6546C15.745 13.4546 15.8183 13.5279 15.8183 13.6182V14.3819C15.8183 14.4723 15.745 14.5455 15.6546 14.5455H8.07282C7.98244 14.5455 7.90918 14.4723 7.90918 14.3819V13.6182C7.90918 13.5279 7.98244 13.4546 8.07282 13.4546ZM8.07282 16.7273H12.1092C12.1996 16.7273 12.2728 16.8006 12.2728 16.891V17.6546C12.2728 17.745 12.1996 17.8182 12.1092 17.8182H8.07282C7.98244 17.8182 7.90918 17.745 7.90918 17.6546V16.891C7.90918 16.8006 7.98244 16.7273 8.07282 16.7273Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 2.63514C4 2.00822 4.49403 1.5 5.10345 1.5L15.0674 1.5C15.2129 1.5 15.3526 1.55913 15.4559 1.66452L19.8367 6.13257C19.9412 6.23915 20 6.38425 20 6.53562V21.3649C20 21.9918 19.506 22.5 18.8966 22.5H5.10345C4.49403 22.5 4 21.9918 4 21.3649L4 2.63514Z" fill="#14C0FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.2947 1.55029C15.3541 1.5779 15.4088 1.61637 15.456 1.66447L19.8368 6.13253C19.8908 6.18764 19.9327 6.25304 19.9604 6.32428H16.3981C15.7887 6.32428 15.2947 5.81607 15.2947 5.18915V1.55029Z" fill="#72D9FF"/>
<path d="M12 10C11.7239 10 11.5 10.2239 11.5 10.5V13.5H8.5C8.22386 13.5 8 13.7239 8 14C8 14.2761 8.22386 14.5 8.5 14.5H11.5V17.5C11.5 17.7761 11.7239 18 12 18C12.2761 18 12.5 17.7761 12.5 17.5V14.5H15.5C15.7761 14.5 16 14.2761 16 14C16 13.7239 15.7761 13.5 15.5 13.5H12.5V10.5C12.5 10.2239 12.2761 10 12 10Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 964 B

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 2.5C4 1.94772 4.44772 1.5 5 1.5H14.8608C14.9949 1.5 15.1234 1.55387 15.2174 1.64951L19.8566 6.36941C19.9485 6.46292 20 6.58879 20 6.7199V21.5C20 22.0523 19.5523 22.5 19 22.5H5C4.44772 22.5 4 22.0523 4 21.5V2.5Z" fill="#3370FF"/>
<path d="M15 1.51978C15.0817 1.54345 15.1567 1.58778 15.2174 1.64952L19.8566 6.36942C19.8946 6.40806 19.9256 6.45223 19.949 6.50001H16.1351C15.5082 6.50001 15 5.99179 15 5.36488V1.51978Z" fill="#85A9FF"/>
<path d="M8.07282 10.1819H15.6546C15.745 10.1819 15.8183 10.2551 15.8183 10.3455V11.1092C15.8183 11.1995 15.745 11.2728 15.6546 11.2728H8.07282C7.98244 11.2728 7.90918 11.1995 7.90918 11.1092V10.3455C7.90918 10.2551 7.98244 10.1819 8.07282 10.1819ZM8.07282 13.4546H15.6546C15.745 13.4546 15.8183 13.5279 15.8183 13.6182V14.3819C15.8183 14.4723 15.745 14.5455 15.6546 14.5455H8.07282C7.98244 14.5455 7.90918 14.4723 7.90918 14.3819V13.6182C7.90918 13.5279 7.98244 13.4546 8.07282 13.4546ZM8.07282 16.7273H12.1092C12.1996 16.7273 12.2728 16.8006 12.2728 16.891V17.6546C12.2728 17.745 12.1996 17.8182 12.1092 17.8182H8.07282C7.98244 17.8182 7.90918 17.745 7.90918 17.6546V16.891C7.90918 16.8006 7.98244 16.7273 8.07282 16.7273Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M17 11C17 10.4477 17.4477 10 18 10H22C22.5523 10 23 10.4477 23 11V19C23 19.5523 22.5523 20 22 20H19.9142L18.7071 21.2071C18.3166 21.5976 17.6834 21.5976 17.2929 21.2071L16.0858 20H11C10.4477 20 10 19.5523 10 19V15C10 14.4477 10.4477 14 11 14H17V11ZM19 12V15C19 15.5523 18.5523 16 18 16H12V18H16.5C16.7652 18 17.0196 18.1054 17.2071 18.2929L18 19.0858L18.7929 18.2929C18.9804 18.1054 19.2348 18 19.5 18H21V12H19Z" fill="#FFB866"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 2C1.44772 2 1 2.44772 1 3V15C1 15.5523 1.44772 16 2 16H4.08579L5.79289 17.7071C6.18342 18.0976 6.81658 18.0976 7.20711 17.7071L8.91421 16H18C18.5523 16 19 15.5523 19 15V3C19 2.44772 18.5523 2 18 2H2ZM7 9C7 9.55228 6.55228 10 6 10C5.44772 10 5 9.55228 5 9C5 8.44772 5.44772 8 6 8C6.55228 8 7 8.44772 7 9ZM11 9C11 9.55228 10.5523 10 10 10C9.44772 10 9 9.55228 9 9C9 8.44772 9.44772 8 10 8C10.5523 8 11 8.44772 11 9ZM15 9C15 9.55228 14.5523 10 14 10C13.4477 10 13 9.55228 13 9C13 8.44772 13.4477 8 14 8C14.5523 8 15 8.44772 15 9Z" fill="#FF8800"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 1C18.075 1 23 5.925 23 12C23 18.075 18.075 23 12 23C5.925 23 1 18.075 1 12C1 5.925 5.925 1 12 1ZM9.869 7C9.63898 7.00035 9.41817 7.0904 9.2535 7.251C9.0905 7.411 8.999 7.6275 9 7.853V16.148C9 16.3075 9.046 16.4635 9.132 16.5995C9.2552 16.7922 9.44972 16.9283 9.673 16.978C9.898 17.029 10.134 16.9905 10.3295 16.8705L17.092 12.7235C17.346 12.5665 17.5 12.2935 17.5 12C17.5 11.7065 17.346 11.434 17.092 11.2765L10.33 7.13C10.1912 7.0451 10.0317 6.99978 9.869 7Z" fill="#FFC60A"/>
</svg>

After

Width:  |  Height:  |  Size: 594 B

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.04762 2.04768H7V6.00024C7 6.55253 7.44772 7.00024 8 7.00024H16C16.5523 7.00024 17 6.55253 17 6.00025V2.04768L19.9524 2.04761C20.671 2.04761 21 2.45202 21 3.09526V21.9523C21 22.5949 20.671 23 19.9524 23L4.04762 23C3.32895 23 3 22.5956 3 21.9524V3.09529C3 2.45275 3.32895 2.04768 4.04762 2.04768ZM7.52376 11.0002C7.23447 11.0002 6.99995 11.2347 6.99995 11.524V12.5716C6.99995 12.8609 7.23447 13.0954 7.52376 13.0954H16.4761C16.7654 13.0954 16.9999 12.8609 16.9999 12.5716V11.524C16.9999 11.2347 16.7654 11.0002 16.4761 11.0002H7.52376ZM7.52376 15.9999C7.23447 15.9999 6.99995 16.2344 6.99995 16.5237V17.5713C6.99995 17.8606 7.23447 18.0951 7.52376 18.0951H16.7618C17.0511 18.0951 17.2856 17.8606 17.2856 17.5713V16.5237C17.2856 16.2344 17.0511 15.9999 16.7618 15.9999H7.52376Z" fill="#00D6B9"/>
<path d="M9.5 1C9.22386 1 9 1.22386 9 1.5V4.5C9 4.77614 9.22386 5 9.5 5H14.5C14.7761 5 15 4.77614 15 4.5V1.5C15 1.22386 14.7761 1 14.5 1H9.5Z" fill="#66E6D5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -158,7 +158,6 @@ const { t } = useI18n()
const dvMainStore = dvMainStoreWithOut()
const snapshotStore = snapshotStoreWithOut()
const filterStyle = computed<any>(() => {
console.log('filterStyle==' + JSON.stringify(dvMainStore.canvasStyleData.component.filterStyle))
return dvMainStore.canvasStyleData.component.filterStyle
})

View File

@ -1,20 +1,48 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { Icon } from '@/components/icon-custom'
import TopDocCard from '@/layout/components/TopDocCard.vue'
const helpLink = ref('https://dataease.io/docs/')
const openBlank = () => {
window.open(helpLink.value)
}
const cardInfoList = [
{ name: '帮助文档', url: 'https://dataease.io/docs/index.html', icon: 'top-help-doc' },
{ name: '产品论坛', url: 'https://bbs.fit2cloud.com/c/de/6', icon: 'top-product-bbs' },
{
name: '技术博客',
url: 'https://blog.fit2cloud.com/categories/dataease',
icon: 'top-technology'
},
{ name: '企业版试用', url: 'https://jinshuju.net/f/TK5TTd', icon: 'top-enterprise-trial' }
]
</script>
<template>
<el-tooltip class="box-item" effect="dark" content="帮助文档" placement="top">
<div class="sys-setting">
<el-icon @click="openBlank">
<Icon name="docs" />
</el-icon>
</div>
</el-tooltip>
<el-popover
:show-arrow="false"
popper-class="top-popover"
placement="bottom-end"
width="208"
trigger="click"
>
<el-row>
<top-doc-card
:span="12"
v-for="(item, index) in cardInfoList"
:key="index"
:card-info="item"
></top-doc-card>
</el-row>
<template #reference>
<div class="sys-setting">
<el-icon>
<Icon name="docs" />
</el-icon>
</div>
</template>
</el-popover>
</template>
<style lang="less" scoped>
@ -31,3 +59,9 @@ const openBlank = () => {
}
}
</style>
<style lang="less">
.top-popover {
padding: 0 0 16px 0 !important;
}
</style>

View File

@ -0,0 +1,63 @@
<script lang="ts" setup>
import { toRefs } from 'vue'
const props = defineProps({
cardInfo: {
type: Object,
default() {
return {
name: '',
url: '',
icon: ''
}
}
}
})
const { cardInfo } = toRefs(props)
const openBlank = () => {
window.open(cardInfo.value.url)
}
</script>
<template>
<div class="doc-card" @click="openBlank">
<el-row class="base-show">
<Icon class-name="item-top-icon" :name="cardInfo.icon" />
</el-row>
<el-row class="base-show show-content"> {{ cardInfo.name }}</el-row>
</div>
</template>
<style lang="less" scoped>
.doc-card {
padding-top: 2px;
margin-top: 16px;
margin-left: 16px;
width: 80px;
height: 50px;
cursor: pointer;
&:hover {
background-color: rgba(30, 39, 56, 0.05);
}
&:active {
background-color: rgba(30, 39, 56, 0.1);
}
}
.base-show {
justify-content: center;
}
.show-content {
font-size: 14px;
color: #1f2329;
line-height: 22px;
font-weight: 400;
margin-top: 4px;
}
.item-top-icon {
width: 24px;
height: 24px;
}
</style>

View File

@ -230,6 +230,7 @@ export default {
manage: '管理',
auth: '授权',
resource_name: '资源名称',
menu_name: '菜单名称',
from_role: '继承自以下角色:',
auth_alone: '单独授权',
org_role_empty: '组织管理员已拥有所有资源的权限,无需再授权',

View File

@ -86,4 +86,25 @@ declare interface ChartEditorForm<T> {
*
*/
render: boolean
/**
*
*/
prop?: string
}
/**
*
*/
declare interface AxisEditForm {
/**
*
*/
axisType: AxisType
/**
*
*/
axis: Axis[]
/**
*
*/
editType: 'add' | 'remove' | 'update'
}

View File

@ -95,6 +95,9 @@ export const pathValid = path => {
* @returns
*/
const hasCurrentRouter = (locations, routers, index) => {
if (!routers?.length) {
return false
}
const location = locations[index]
let kids = []
const isvalid = routers.some(router => {

View File

@ -7,10 +7,11 @@ import cloneDeep from 'lodash-es/cloneDeep'
import defaultsDeep from 'lodash-es/defaultsDeep'
import { formatterType, unitType } from '../../../js/formatter'
import { fieldType } from '@/utils/attr'
import { differenceBy, partition } from 'lodash-es'
import { partition } from 'lodash-es'
import chartViewManager from '../../../js/panel'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
import { useEmitt } from '@/hooks/web/useEmitt'
const { t } = useI18n()
@ -34,11 +35,10 @@ const toolTip = computed(() => {
return props.themes === 'dark' ? 'ndark' : 'dark'
})
const emit = defineEmits(['onTooltipChange', 'onExtTooltipChange'])
const curSeriesFormatter = ref<DeepPartial<SeriesFormatter>>({})
const quotaData = ref<Axis[]>(inject('quotaData'))
const showSeriesTooltipFormatter = computed(() => {
return showProperty('seriesTooltipFormatter') && !batchOptStatus.value
return showProperty('seriesTooltipFormatter') && !batchOptStatus.value && props.chart.id
})
//
const initSeriesTooltip = () => {
@ -90,84 +90,15 @@ const initSeriesTooltip = () => {
}
curSeriesFormatter.value = axisMap[curSeriesFormatter.value.seriesId]
}
//
const updateSeriesTooltip = (newAxis?: SeriesFormatter[], oldAxis?: SeriesFormatter[]) => {
if (
!showSeriesTooltipFormatter.value ||
!state.tooltipForm.seriesTooltipFormatter.length ||
!quotaData.value?.length
) {
return
}
const axisMap: Record<string, Axis> = newAxis?.reduce((pre, next) => {
pre[next.seriesId] = next
return pre
}, {})
//
const addedAxisMap = differenceBy(newAxis, oldAxis, 'seriesId').reduce((pre, next) => {
pre[next.id] = next
return pre
}, {}) as Record<string, SeriesFormatter>
//
const removedAxisMap = differenceBy(oldAxis, newAxis, 'seriesId').reduce((pre, next) => {
pre[next.seriesId] = next
return pre
}, {}) as Record<string, SeriesFormatter>
const quotaIds = quotaData.value?.map(i => i.id)
state.tooltipForm.seriesTooltipFormatter = state.tooltipForm.seriesTooltipFormatter?.filter(i =>
quotaIds?.includes(i.id)
)
const dupAxis: SeriesFormatter[] = []
state.tooltipForm.seriesTooltipFormatter?.forEach(ele => {
if (addedAxisMap[ele.id]) {
//
ele.show = true
if (ele.seriesId === ele.id) {
ele.seriesId = addedAxisMap[ele.id].seriesId
ele.axisType = addedAxisMap[ele.id].axisType
} else {
//
const tmp = cloneDeep(addedAxisMap[ele.id])
tmp.show = true
dupAxis.push(tmp)
}
}
if (removedAxisMap[ele.seriesId]) {
ele.show = false
ele.seriesId = ele.id
}
ele.chartShowName = axisMap[ele.seriesId]?.chartShowName
ele.summary = axisMap[ele.seriesId]?.summary ?? ele.summary
})
//
state.tooltipForm.seriesTooltipFormatter =
state.tooltipForm.seriesTooltipFormatter.concat(dupAxis)
state.tooltipForm.seriesTooltipFormatter = partition(
state.tooltipForm.seriesTooltipFormatter,
ele => axisMap[ele.seriesId]
).flat()
if (removedAxisMap[curSeriesFormatter.value?.seriesId]) {
curSeriesFormatter.value = state.tooltipForm.seriesTooltipFormatter?.[0]
}
if (!newAxis.length) {
curSeriesFormatter.value = {}
}
emit('onTooltipChange', { data: state.tooltipForm, render: false })
emit('onExtTooltipChange', extTooltip.value)
}
const AXIS_PROP: AxisType[] = ['yAxis', 'yAxisExt', 'extBubble']
const quotaAxis = computed(() => {
let result = []
const axisProp: AxisType[] = ['yAxis', 'yAxisExt', 'extBubble']
axisProp.forEach(prop => {
AXIS_PROP.forEach(prop => {
if (!chartViewInstance.value?.axis?.includes(prop)) {
return
}
const axis = props.chart[prop]
axis?.forEach(item => {
item.axisType = prop
item.seriesId = `${item.id}-${prop}`
result.push(item)
})
axis?.forEach(item => result.push(item))
})
return result
})
@ -205,13 +136,6 @@ const AGGREGATION_TYPE = [
{ name: t('chart.count'), value: 'count' },
{ name: t('chart.count_distinct'), value: 'count_distinct' }
]
watch(
() => cloneDeep(quotaAxis.value),
(newVal, oldVal) => {
updateSeriesTooltip(newVal, oldVal)
},
{ deep: true }
)
watch(
[() => props.chart.customAttr.tooltip, () => props.chart.customAttr.tooltip.show],
() => {
@ -262,7 +186,15 @@ const init = () => {
if (customAttr.tooltip) {
state.tooltipForm = defaultsDeep(customAttr.tooltip, cloneDeep(DEFAULT_TOOLTIP))
formatterSelector.value?.blur()
//
const formatter = state.tooltipForm.seriesTooltipFormatter
if (!quotaAxis.value?.length) {
if (!formatter.length) {
quotaData.value?.forEach(i => formatter.push({ ...i, seriesId: i.id, show: false }))
}
curSeriesFormatter.value = {}
return
}
const seriesAxisMap = formatter.reduce((pre, next) => {
next.seriesId = next.seriesId ?? next.id
pre[next.seriesId] = next
@ -278,9 +210,131 @@ const init = () => {
}
const showProperty = prop => props.propertyInner?.includes(prop)
const updateSeriesTooltipFormatter = (form: AxisEditForm) => {
const { axisType, editType } = form
if (
!showSeriesTooltipFormatter.value ||
!state.tooltipForm.seriesTooltipFormatter.length ||
!quotaData.value?.length ||
!AXIS_PROP.includes(axisType)
) {
return
}
switch (editType) {
case 'add':
addAxis(form)
break
case 'remove':
removeAxis(form)
break
case 'update':
updateAxis(form)
break
default:
break
}
emit('onTooltipChange', { data: state.tooltipForm, render: false }, 'seriesTooltipFormatter')
emit('onExtTooltipChange', extTooltip.value)
}
const addAxis = (form: AxisEditForm) => {
const { axis, axisType } = form
const axisMap = axis.reduce((pre, next) => {
next.axisType = axisType
next.seriesId = `${next.id}-${axisType}`
pre[next.id] = next
return pre
}, {})
const dupAxis = []
state.tooltipForm.seriesTooltipFormatter.forEach(ele => {
if (axisMap[ele.id]) {
//
ele.show = true
if (ele.seriesId === ele.id) {
ele.seriesId = axisMap[ele.id].seriesId
ele.axisType = axisMap[ele.id].axisType
ele.summary = axisMap[ele.id].summary
ele.chartShowName = axisMap[ele.id].chartShowName
} else {
//
const tmp = cloneDeep(axisMap[ele.id])
tmp.show = true
dupAxis.push(tmp)
}
}
})
state.tooltipForm.seriesTooltipFormatter =
state.tooltipForm.seriesTooltipFormatter.concat(dupAxis)
state.tooltipForm.seriesTooltipFormatter = partition(
state.tooltipForm.seriesTooltipFormatter,
ele => quotaAxis.value.findIndex(item => item.id === ele.id) !== -1
).flat()
}
const removeAxis = (form: AxisEditForm) => {
const { axis, axisType } = form
const axisMap = axis.reduce((pre, next) => {
if (!next) {
return pre
}
next.axisType = axisType
next.seriesId = `${next.id}-${axisType}`
pre[next.seriesId] = next
return pre
}, {})
const quotaIds = quotaData.value?.map(i => i.id)
const formatterDupMap = state.tooltipForm.seriesTooltipFormatter.reduce((pre, next) => {
if (pre[next.id] !== undefined) {
pre[`${next.id}-${axisType}`] = true
} else {
pre[next.id] = false
}
return pre
}, {})
state.tooltipForm.seriesTooltipFormatter = state.tooltipForm.seriesTooltipFormatter?.filter(
i => quotaIds?.includes(i.id) && !formatterDupMap[i.seriesId]
)
state.tooltipForm.seriesTooltipFormatter.forEach(ele => {
if (axisMap[ele.seriesId]) {
//
ele.show = false
ele.seriesId = ele.id
ele.summary = 'sum'
}
})
state.tooltipForm.seriesTooltipFormatter = partition(
state.tooltipForm.seriesTooltipFormatter,
ele => quotaAxis.value.findIndex(item => item.id === ele.id) !== -1
).flat()
if (!quotaAxis.value?.length) {
curSeriesFormatter.value = {}
return
}
if (axisMap[curSeriesFormatter.value?.seriesId]) {
curSeriesFormatter.value = state.tooltipForm.seriesTooltipFormatter?.[0]
}
}
const updateAxis = (form: AxisEditForm) => {
const { axis, axisType } = form
const axisMap = axis.reduce((pre, next) => {
if (!next) {
return pre
}
next.axisType = axisType
next.seriesId = `${next.id}-${axisType}`
pre[next.seriesId] = next
return pre
}, {})
state.tooltipForm.seriesTooltipFormatter.forEach(ele => {
if (axisMap[ele.seriesId]) {
ele.chartShowName = axisMap[ele.seriesId]?.chartShowName
ele.summary = axisMap[ele.seriesId]?.summary ?? ele.summary
}
})
}
onMounted(() => {
init()
useEmitt({ name: 'addAxis', callback: updateSeriesTooltipFormatter })
useEmitt({ name: 'removeAxis', callback: updateSeriesTooltipFormatter })
useEmitt({ name: 'updateAxis', callback: updateSeriesTooltipFormatter })
})
</script>
@ -482,10 +536,11 @@ onMounted(() => {
<template v-if="curSeriesFormatter?.seriesId">
<el-form-item class="form-item form-item-checkbox" :class="'form-item-' + themes">
<el-checkbox
size="small"
@change="changeTooltipAttr('seriesTooltipFormatter', true)"
:disabled="!formatterEditable"
v-model="curSeriesFormatter.show"
size="small"
label="quota"
@change="changeTooltipAttr('seriesTooltipFormatter', true)"
>
{{ t('chart.show') }}
</el-checkbox>

View File

@ -15,7 +15,6 @@ import {
import Icon from '@/components/icon-custom/src/Icon.vue'
import type { FormInstance, FormRules } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n'
import { Field, getFieldByDQ } from '@/api/chart'
import { Tree } from '../../../visualized/data/dataset/form/CreatDsGroup.vue'
import { useEmitt } from '@/hooks/web/useEmitt'
import { ElMessage, ElTreeSelect } from 'element-plus-secondary'
@ -43,13 +42,13 @@ import CustomSortEdit from '@/views/chart/components/editor/drag-item/components
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import CalcFieldEdit from '@/views/visualized/data/dataset/form/CalcFieldEdit.vue'
import { getFieldName, guid } from '@/views/visualized/data/dataset/form/util'
import { cloneDeep } from 'lodash-es'
import { cloneDeep, get } from 'lodash-es'
import { deleteField, saveField } from '@/api/dataset'
import { getWorldTree } from '@/api/map'
import chartViewManager from '@/views/chart/components/js/panel'
import DatasetSelect from '@/views/chart/components/editor/dataset-select/DatasetSelect.vue'
import { useDraggable } from '@vueuse/core'
import _ from 'lodash'
import { set, concat, keys } from 'lodash-es'
const snapshotStore = snapshotStoreWithOut()
const dvMainStore = dvMainStoreWithOut()
@ -63,7 +62,7 @@ const tabActiveVQuery = ref('style')
const datasetSelector = ref(null)
const curDatasetWeight = ref(0)
const renameForm = ref<FormInstance>()
const { emitter } = useEmitt()
const props = defineProps({
view: {
type: Object as PropType<ChartObj>,
@ -144,14 +143,6 @@ const state = reactive({
useless: null
})
watch(
[() => props.view.tableId],
() => {
getFields(props.view.tableId, props.view.id)
},
{ deep: true }
)
watch(
[() => view.value['tableId']],
() => {
@ -222,31 +213,8 @@ const filterNode = (value, data) => {
return data.name?.includes(value)
}
const getFields = (id, chartId) => {
if (id && chartId) {
getFieldByDQ(id, chartId)
.then(res => {
state.dimension = (res.dimensionList as unknown as Field[]) || []
state.quota = (res.quotaList as unknown as Field[]) || []
state.dimensionData = JSON.parse(JSON.stringify(state.dimension))
state.quotaData = JSON.parse(JSON.stringify(state.quota))
})
.catch(() => {
state.dimension = []
state.quota = []
state.dimensionData = []
state.quotaData = []
})
} else {
state.dimension = []
state.quota = []
state.dimensionData = []
state.quotaData = []
}
}
const allFields = computed(() => {
return _.concat(state.quotaData, state.dimensionData)
return concat(state.quotaData, state.dimensionData)
})
const queryList = computed(() => {
@ -266,9 +234,9 @@ const queryList = computed(() => {
const quotaData = computed(() => {
if (view.value?.type === 'table-info') {
return state.quotaData?.filter(item => item.id !== '-1')
return state.quota?.filter(item => item.id !== '-1')
}
return state.quotaData
return state.quota
})
provide('quotaData', quotaData)
@ -313,23 +281,29 @@ const dimensionItemRemove = item => {
}
}
const quotaItemChange = () => {
const quotaItemChange = (axis: Axis, axisType: AxisType) => {
recordSnapshotInfo('calcData')
// do quotaItemChange
emitter.emit('updateAxis', { axisType, axis: [axis], editType: 'update' })
}
const quotaItemRemove = item => {
recordSnapshotInfo('calcData')
let axisType: AxisType = item.removeType
let axis
if (item.removeType === 'quota') {
view.value.yAxis.splice(item.index, 1)
axisType = 'yAxis'
axis = view.value.yAxis.splice(item.index, 1)
} else if (item.removeType === 'quotaExt') {
view.value.yAxisExt.splice(item.index, 1)
axisType = 'yAxisExt'
axis = view.value.yAxisExt.splice(item.index, 1)
} else if (item.removeType === 'extLabel') {
view.value.extLabel.splice(item.index, 1)
axis = view.value.extLabel.splice(item.index, 1)
} else if (item.removeType === 'extTooltip') {
view.value.extTooltip.splice(item.index, 1)
axis = view.value.extTooltip.splice(item.index, 1)
} else if (item.removeType === 'extBubble') {
view.value.extBubble.splice(item.index, 1)
axis = view.value.extBubble.splice(item.index, 1)
}
useEmitt().emitter.emit('removeAxis', { axisType, axis, editType: 'remove' })
}
const arrowIcon = () => {
return h(Icon, { name: 'icon_down_outlined-1' })
@ -394,7 +368,7 @@ const onMove = e => {
// drag
const dragCheckType = (list, type) => {
if (list && list.length > 0) {
var valid = true
let valid = true
for (let i = 0; i < list.length; i++) {
if (list[i].groupType !== type) {
list.splice(i, 1)
@ -407,6 +381,7 @@ const dragCheckType = (list, type) => {
type: 'warning'
})
}
return valid
}
}
const dragMoveDuplicate = (list, e, mode) => {
@ -418,6 +393,7 @@ const dragMoveDuplicate = (list, e, mode) => {
})
if (dup && dup.length > 1) {
list.splice(e.newDraggableIndex, 1)
return dup
}
}
}
@ -439,14 +415,37 @@ const addAxis = (e, axis: AxisType) => {
return
}
const { type, limit, duplicate } = axisSpec
let typeValid, dup
if (type) {
dragCheckType(view.value[axis], type)
typeValid = dragCheckType(view.value[axis], type)
}
if (!duplicate) {
dragMoveDuplicate(view.value[axis], e, 'chart')
dup = dragMoveDuplicate(view.value[axis], e, 'chart')
}
if (limit) {
view.value[axis] = view.value[axis].splice(0, limit)
if (view.value[axis].length > limit) {
const removedAxis = view.value[axis].splice(limit)
if (e.newDraggableIndex + 1 <= limit) {
emitter.emit('removeAxis', { axisType: axis, axis: removedAxis, editType: 'remove' })
emitter.emit('addAxis', {
axisType: axis,
axis: [view.value[axis][e.newDraggableIndex]],
editType: 'add'
})
}
} else {
if (!dup && typeValid) {
emitter.emit('addAxis', {
axisType: axis,
axis: [view.value[axis][e.newDraggableIndex]],
editType: 'add'
})
}
}
if (view.value.type === 'line') {
if (view.value?.xAxisExt?.length && view.value?.yAxis?.length > 1) {
const axis = view.value.yAxis.splice(1)
emitter.emit('removeAxis', { axisType: 'yAxis', axis, editType: 'remove' })
}
}
}
@ -505,6 +504,13 @@ const moveToQuota = e => {
dragMoveDuplicate(state.quotaData, e, 'ds')
}
const onAxisChange = (e, axis: AxisType) => {
if (e.removed) {
const { element } = e.removed
emitter.emit('removeAxis', { axisType: axis, axis: [element], editType: 'remove' })
}
}
const calcData = (view, resetDrill = false, updateQuery = '') => {
if (
view.refreshTime === '' ||
@ -551,26 +557,36 @@ const onTypeChange = (render, type) => {
view.value = chartViewInstance.setupDefaultOptions(view.value) as unknown as ChartObj
//
const axisConfig = chartViewInstance.axisConfig
_.keys(axisConfig).forEach((axis: AxisType) => {
keys(axisConfig).forEach((axis: AxisType) => {
const axisArr = view.value[axis] as Axis[]
if (!axisArr?.length) {
return
}
const axisSpec = axisConfig[axis]
const { type, limit } = axisSpec
const removedAxis = []
// check type
if (type) {
for (let i = axisArr.length - 1; i >= 0; i--) {
if (axisArr[i].groupType !== type) {
axisArr.splice(i, 1)
const [axis] = axisArr.splice(i, 1)
removedAxis.push(axis)
}
}
}
// check limit
if (limit && axisArr.length) {
axisArr.splice(0, axisArr.length - limit)
if (limit && limit < axisArr.length) {
axisArr.splice(limit).forEach(i => removedAxis.push(i))
}
removedAxis.length &&
emitter.emit('removeAxis', { axisType: axis, axis: removedAxis, editType: 'remove' })
})
if (view.value.type === 'line') {
if (view.value?.xAxisExt?.length && view.value?.yAxis?.length > 1) {
const axis = view.value.yAxis.splice(1)
emitter.emit('removeAxis', { axisType: 'yAxis', axis, editType: 'remove' })
}
}
}
curComponent.value.innerType = type
calcData(view.value, true)
@ -617,23 +633,22 @@ const onLabelChange = val => {
view.value.customAttr.label = val
renderChart(view.value)
}
watch([() => view.value.xAxisExt?.length, () => view.value.yAxis?.length], () => {
if (view.value.type === 'line') {
if (view.value?.xAxisExt?.length && view.value?.yAxis?.length > 1) {
view.value.yAxis.splice(1)
}
}
})
const onTooltipChange = (chartForm: ChartEditorForm<ChartTooltipAttr>) => {
const onTooltipChange = (chartForm: ChartEditorForm<ChartTooltipAttr>, prop: string) => {
const { data, requestData, render } = chartForm
let tooltipObj = data
if (!data) {
view.value.customAttr.tooltip = chartForm as unknown as ChartTooltipAttr
tooltipObj = chartForm as unknown as ChartTooltipAttr
}
if (prop) {
const val = get(tooltipObj, prop)
set(view.value.customAttr.tooltip, prop, val)
} else {
view.value.customAttr.tooltip = data
view.value.customAttr.tooltip = tooltipObj
}
if (requestData) {
calcData(view.value)
return
}
// for compatibility
if (render !== false) {
@ -716,29 +731,31 @@ const removeItems = (
_type: 'xAxis' | 'xAxisExt' | 'extStack' | 'yAxis' | 'extBubble' | 'customFilter' | 'drillFields'
) => {
recordSnapshotInfo('calcData')
let axis = []
switch (_type) {
case 'xAxis':
view.value.xAxis = []
axis = view.value.xAxis?.splice(0)
break
case 'xAxisExt':
view.value.xAxisExt = []
axis = view.value.xAxisExt?.splice(0)
break
case 'extStack':
view.value.extStack = []
axis = view.value.extStack?.splice(0)
break
case 'yAxis':
view.value.yAxis = []
axis = view.value.yAxis?.splice(0)
break
case 'extBubble':
view.value.extBubble = []
axis = view.value.extBubble?.splice(0)
break
case 'customFilter':
view.value.customFilter = []
axis = view.value.customFilter?.splice(0)
break
case 'drillFields':
view.value.drillFields = []
axis = view.value.drillFields?.splice(0)
break
}
axis?.length && emitter.emit('removeAxis', { axisType: _type, axis, editType: 'remove' })
}
const saveRename = ref => {
@ -746,14 +763,19 @@ const saveRename = ref => {
ref.validate(valid => {
if (valid) {
const { renameType, index, chartShowName } = state.itemForm
let axisType, axis
switch (renameType) {
case 'quota':
axisType = 'yAxis'
axis = view.value.yAxis[index]
view.value.yAxis[index].chartShowName = chartShowName
break
case 'dimension':
view.value.xAxis[index].chartShowName = chartShowName
break
case 'quotaExt':
axisType = 'yAxisExt'
axis = view.value.yAxisExt[index]
view.value.yAxisExt[index].chartShowName = chartShowName
break
case 'dimensionExt':
@ -763,6 +785,8 @@ const saveRename = ref => {
view.value.extStack[index].chartShowName = chartShowName
break
case 'extBubble':
axisType = 'extBubble'
axis = view.value.extBubble[index]
view.value.extBubble[index].chartShowName = chartShowName
break
case 'extLabel':
@ -774,6 +798,7 @@ const saveRename = ref => {
default:
break
}
axisType && emitter.emit('updateAxis', { axisType, axis: [axis], editType: 'update' })
closeRename()
} else {
return false
@ -1356,6 +1381,7 @@ const onRefreshChange = val => {
class="drag-block-style"
:class="{ dark: themes === 'dark' }"
@add="addYaxis"
@change="e => onAxisChange(e, 'yAxis')"
>
<template #item="{ element, index }">
<quota-item
@ -1366,7 +1392,7 @@ const onRefreshChange = val => {
:index="index"
type="quota"
:themes="props.themes"
@onQuotaItemChange="quotaItemChange"
@onQuotaItemChange="item => quotaItemChange(item, 'yAxis')"
@onQuotaItemRemove="quotaItemRemove"
@onNameEdit="showRename"
@editItemFilter="showQuotaEditFilter"
@ -1403,6 +1429,7 @@ const onRefreshChange = val => {
class="drag-block-style"
:class="{ dark: themes === 'dark' }"
@add="addExtBubble"
@change="e => onAxisChange(e, 'extBubble')"
>
<template #item="{ element, index }">
<quota-item
@ -1413,7 +1440,7 @@ const onRefreshChange = val => {
:index="index"
type="extBubble"
:themes="props.themes"
@onQuotaItemChange="quotaItemChange"
@onQuotaItemChange="item => quotaItemChange(item, 'extBubble')"
@onQuotaItemRemove="quotaItemRemove"
@onNameEdit="showRename"
@editItemFilter="showQuotaEditFilter"

View File

@ -253,9 +253,8 @@ export function handleEmptyDataStrategy<O extends PickOptions>(chart: Chart, opt
handleIgnoreData(data)
return options
}
const yAxis = JSON.parse(JSON.stringify(chart.yAxis))
const extAxis = JSON.parse(JSON.stringify(chart.xAxisExt))
const multiDimension = yAxis?.length >= 2 || extAxis?.length > 0
const { yAxis, xAxisExt, extStack } = chart
const multiDimension = yAxis?.length >= 2 || xAxisExt?.length > 0 || extStack?.length > 0
switch (strategy) {
case 'breakLine': {
if (multiDimension) {

View File

@ -434,7 +434,7 @@ onMounted(() => {
}
})
useEmitt({
name: 'calc-data-' + view.value.id,
name: 'calcData-' + view.value.id,
callback: function (val) {
if (!state.initReady) {
return

View File

@ -40,7 +40,7 @@ const handleClick = (tab, event: Event) => {
.sys-setting-p {
width: 100%;
background: var(--ContentBG, #ffffff);
height: calc(100% - 95px);
height: calc(100vh - 176px);
box-sizing: border-box;
margin-top: 12px;
}

View File

@ -1,6 +1,6 @@
<template>
<el-container class="geometry-container">
<el-aside width="200px" class="geonetry-aside">
<el-aside class="geonetry-aside">
<div class="geo-title">
<span>{{ t('online_map.geometry') }}</span>
<span class="add-icon-span">
@ -10,7 +10,13 @@
</span>
</div>
<div class="geo-search">
<el-input class="m16 w100" v-model="keyword" clearable :placeholder="t('commons.search')">
<el-input
class="m16 w100"
v-model="keyword"
clearable
:placeholder="t('commons.search')"
@change="filterResource"
>
<template #prefix>
<el-icon>
<Icon name="icon_search-outline_outlined"></Icon>
@ -19,90 +25,118 @@
</el-input>
</div>
<div class="map-tree-container">
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick" />
<el-scrollbar class="menu-tree">
<el-tree
menu
ref="areaTreeRef"
node-key="id"
:data="treeData"
@node-click="handleNodeClick"
:highlight-current="true"
:expand-on-click-node="false"
:default-expand-all="false"
:filter-node-method="filterResourceNode"
>
<template #default="{ node, data }">
<span class="custom-tree-node" :class="{ 'is-disabled': node.disabled || data.root }">
<span
:title="data.name"
v-html="data.colorName && keyword ? data.colorName : data.name"
/>
</span>
</template>
</el-tree>
</el-scrollbar>
</div>
</el-aside>
<el-main>地理信息内容区域</el-main>
<el-main class="geometry-main">
<div class="geo-content-container" v-if="!selectedData">
<EmptyBackground img-type="noneWhite" description="请在左侧选择区域" />
</div>
<div v-else class="geo-content-container">
<div class="geo-content-top">
<span>{{ selectedData.name }}</span>
</div>
<div class="geo-content-middle">
<div class="geo-area">
<div class="area-label"><span>区域代码</span></div>
<div class="area-content">
<span>{{ selectedData.id }}</span>
</div>
</div>
<div class="geo-area">
<div class="area-label"><span>上级区域</span></div>
<div class="area-content">
<span>{{ selectedData.parentName }}</span>
<span v-if="selectedData.pid" class="area-secondary">{{
'(' + selectedData.pid + ')'
}}</span>
</div>
</div>
</div>
<div class="geo-content-bottom">
<div class="area-label"><span>坐标文件</span></div>
<el-scrollbar class="area-content-geo">
<span>{{ selectedData.geoJson }}</span>
</el-scrollbar>
</div>
</div>
</el-main>
</el-container>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { getWorldTree } from '@/api/map'
import EmptyBackground from '@/components/empty-background/src/EmptyBackground.vue'
import { getGeoJsonFile } from '@/views/chart/components/js/util'
import { cloneDeep } from 'lodash-es'
import { setColorName } from '@/utils/utils'
const { t } = useI18n()
const keyword = ref('')
const treeData = ref([])
interface Tree {
label: string
children?: Tree[]
}
const areaTreeRef = ref(null)
const handleNodeClick = (data: Tree) => {
console.log(data)
}
const selectedData = ref(null)
const data: Tree[] = [
{
label: 'Level one 1',
children: [
{
label: 'Level two 1-1',
children: [
{
label: 'Level three 1-1-1'
}
]
}
]
},
{
label: 'Level one 2',
children: [
{
label: 'Level two 2-1',
children: [
{
label: 'Level three 2-1-1'
}
]
},
{
label: 'Level two 2-2',
children: [
{
label: 'Level three 2-2-1'
}
]
}
]
},
{
label: 'Level one 3',
children: [
{
label: 'Level two 3-1',
children: [
{
label: 'Level three 3-1-1'
}
]
},
{
label: 'Level two 3-2',
children: [
{
label: 'Level three 3-2-1'
}
]
}
]
const handleNodeClick = async (data: Tree) => {
selectedData.value = data
const geoJson = cloneDeep(await getGeoJsonFile(data['id']))
selectedData.value['geoJson'] = geoJson
const pid = data['pid']
if (pid) {
const parent = areaTreeRef.value.getNode(pid)
if (parent) {
selectedData.value.parentName = parent.data.name
}
}
]
const defaultProps = {
children: 'children',
label: 'label'
}
const filterResource = val => {
areaTreeRef.value?.filter(val)
}
const filterResourceNode = (value: string, data) => {
setColorName(data, value)
if (!value) return true
return data.name.toLocaleLowerCase().includes(value.toLocaleLowerCase())
}
const loadTreeData = () => {
getWorldTree()
.then(res => {
const root = res.data
treeData.value = [root]
})
.catch(e => {
console.error(e)
})
}
loadTreeData()
</script>
<style lang="less" scoped>
@ -112,6 +146,7 @@ const defaultProps = {
width: 280px !important;
border-right: 1px solid #1f232926;
padding: 16px;
height: 100%;
.geo-title {
display: flex;
justify-content: space-between;
@ -123,6 +158,7 @@ const defaultProps = {
line-height: 24px;
}
.add-icon-span {
display: none;
color: #3370ff;
height: 20px;
width: 20px;
@ -140,6 +176,79 @@ const defaultProps = {
.geo-search {
margin-bottom: 16px;
}
.map-tree-container {
height: calc(100% - 96px);
overflow-y: auto;
}
}
.geometry-main {
padding: 16px !important;
}
}
.geo-content-container {
width: 100%;
height: 100%;
.geo-content-top {
height: 24px;
line-height: 24px;
margin-bottom: 16px;
span {
font-weight: 500;
font-size: 16px;
color: #1f2329;
}
}
.geo-content-middle {
display: flex;
.geo-area {
height: 48px;
width: 50%;
}
margin-bottom: 16px;
}
:deep(.area-label) {
height: 22px;
line-height: 22px;
span {
font-size: 14px;
color: #646a73;
font-weight: 400;
}
}
:deep(.area-content) {
line-height: 22px;
height: 22px;
span {
font-size: 14px;
color: #1f2329;
font-weight: 400;
}
.area-secondary {
color: #646a73;
}
}
.geo-content-bottom {
width: 100%;
height: calc(100% - 110px);
.area-content-geo {
line-height: 22px;
overflow-x: hidden;
overflow-y: auto;
height: calc(100% - 30px);
span {
font-size: 14px;
color: #1f2329;
font-weight: 400;
}
}
}
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
box-sizing: content-box;
padding-right: 4px;
overflow: hidden;
}
</style>

@ -1 +1 @@
Subproject commit 1ca8187376d058b65d163dbad52ff6159ca024f3
Subproject commit c2c4436bac4d300e5297ff1854fd6d45e01435ad