修改data-visualization\custom-component

This commit is contained in:
limengnan 2025-07-01 15:55:42 +08:00
parent 540fb2e873
commit cdd714429d
47 changed files with 2168 additions and 558 deletions

View File

@ -0,0 +1,656 @@
import { DualAxes, Plot } from '@antv/g2plot'
/**
* 使 Map chart.container
*/
export const CAROUSEL_MANAGER_INSTANCES = new Map<string, ChartCarouselTooltip>()
/**
*
*/
const CHART_CATEGORY = {
COLUMN: ['bar', 'bar-stack', 'bar-group', 'bar-group-stack', 'percentage-bar-stack'],
LINE: ['line', 'area', 'area-stack'],
MIX: ['chart-mix', 'chart-mix-group', 'chart-mix-stack', 'chart-mix-dual-line'],
PIE: ['pie', 'pie-donut']
}
/**
*
* @param chartType
*/
export function isColumn(chartType: string) {
return CHART_CATEGORY.COLUMN.includes(chartType)
}
/**
* 线
* @param chartType
*/
export function isLine(chartType: string) {
return CHART_CATEGORY.LINE.includes(chartType)
}
/**
*
* @param chartType
*/
export function isPie(chartType: string) {
return CHART_CATEGORY.PIE.includes(chartType)
}
/**
*
* @param chartType
*/
export function isMix(chartType: string) {
return CHART_CATEGORY.MIX.includes(chartType)
}
export function isSupport(chartType: string) {
return Object.values(CHART_CATEGORY).some(category => category.includes(chartType))
}
// 轮播配置默认值
const DEFAULT_CAROUSEL_CONFIG: Required<CarouselConfig> = {
xField: '',
duration: 2000,
interval: 2000,
loop: true
}
type CarouselConfig = {
xField: string
duration?: number
interval?: number
loop?: boolean
}
/**
*
* */
class ChartCarouselTooltip {
private plot: Plot | DualAxes
private config: Required<CarouselConfig>
private currentIndex = 0
private values: string[] = []
// 合并定时器管理
private timers = { interval: null, carousel: null }
private states = { paused: false, destroyed: false }
// 图表可视性变化
private observers: Map<string, IntersectionObserver> = new Map()
// 图表元素大小变化
private resizeObservers: Map<string, ResizeObserver> = new Map()
// 图表是否在可视范围内
private chartIsVisible: boolean
private constructor(plot: Plot | DualAxes, private chart: Chart, config: CarouselConfig) {
this.plot = plot
this.config = { ...DEFAULT_CAROUSEL_CONFIG, ...config }
this.init()
}
/**
*
* */
static manage(plot: Plot | DualAxes, chart: Chart, config: CarouselConfig) {
if (!isSupport(chart.type)) return null
const container = chart.container
let instance = CAROUSEL_MANAGER_INSTANCES.get(container)
CAROUSEL_MANAGER_INSTANCES.forEach(instance => {
if (container.includes('viewDialog')) {
instance.paused()
}
})
if (instance) {
instance.update(plot, chart, config)
return instance
}
if (isSupport(chart.type)) {
instance = new this(plot, chart, config)
CAROUSEL_MANAGER_INSTANCES.set(container, instance)
}
return instance
}
/**
*
* @param container
*/
static destroyByContainer(container: string) {
const instance = CAROUSEL_MANAGER_INSTANCES.get(container)
if (instance) {
instance.destroy()
}
}
/**
* DOM获取对应实例
* */
static getInstanceByContainer(container: string) {
const instance = CAROUSEL_MANAGER_INSTANCES.get(container)
if (instance) {
return instance
}
return null
}
/**
* chart.id销毁对应实例
*
*
* */
static closeEnlargeDialogDestroy(id?: string) {
// 首先,暂停并删除包含 'viewDialog' 的实例
CAROUSEL_MANAGER_INSTANCES?.forEach((instance, key) => {
if (instance.chart.id === id && instance.chart.container.includes('viewDialog')) {
const dialogInstance = CAROUSEL_MANAGER_INSTANCES.get(key)
if (dialogInstance) {
dialogInstance.destroy()
}
}
})
setTimeout(() => {
// 然后,恢复
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
if (instance.chartIsVisible) {
instance.resume()
}
})
}, 400)
}
/**
*
* @param id
*/
static paused(id?: string) {
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
if (id && instance.chart.id === id) {
setTimeout(() => instance.paused(), 200)
}
if (!id) {
setTimeout(() => instance.paused(), 200)
}
})
}
/**
* @param id
*/
static resume(id?: string) {
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
if (instance.chart.id === id) {
instance.paused()
setTimeout(() => instance.resume(), 500)
}
if (!id) {
setTimeout(() => instance.resume(), 200)
}
})
}
/**
*
* */
private init() {
this.values = [].concat(this.getUniqueValues())
if (!this.values.length) return
this.chartIsVisible = true
this.states.paused = false
this.states.destroyed = false
this.bindEventListeners()
this.startCarousel()
}
/**
*
* */
private getUniqueValues() {
const data =
this.plot instanceof DualAxes
? [...this.plot.options.data[0], ...this.plot.options.data[1]]
: this.plot.options.data
return [...new Set(data.map(item => item[this.config.xField]))]
}
/**
*
* */
private startCarousel() {
if (!this.shouldStart()) {
this.stop()
return
}
// 定义启动嵌套定时器的函数
const startNestedTimers = () => {
// 重置当前索引
this.currentIndex = 0
// 定义递归处理数据数组的函数
const processArray = () => {
if (this.states.paused || this.states.destroyed || !this.isElementFullyVisible()) return
// 获取当前需要显示的值
const currentValue = this.values[this.currentIndex]
// 计算 Tooltip 显示的位置
const point = this.calculatePosition(currentValue)
// 高亮当前数据点
this.highlightElement(currentValue)
if (point) {
// 显示 Tooltip并设置其位置为顶部
this.plot.chart.showTooltip(point)
this.plot.chart.getController('tooltip').update()
}
// 更新索引,指向下一个数据点
this.currentIndex++
if (this.currentIndex > this.values.length) {
this.currentIndex = 0
this.hideTooltip()
this.plot.chart.showTooltip({ x: 0, y: 0 })
this.plot.chart.getController('tooltip').update()
this.unHighlightPoint(currentValue)
this.timers.interval = setTimeout(() => processArray(), this.config.interval)
} else {
// 如果未遍历完,继续处理下一个数据点
this.timers.carousel = setTimeout(() => processArray(), this.config.duration)
}
}
processArray()
}
this.stop()
startNestedTimers()
}
/**
* ' */
private shouldStart() {
return (
this.chart.customAttr?.tooltip?.show &&
this.chart.customAttr?.tooltip?.carousel?.enable &&
this.values.length > 0 &&
this.chartIsVisible
)
}
/**
*
* */
private isElementFullyVisible(): boolean {
// 全屏
const isFullscreen = document.fullscreenElement !== null
// 新页面或公共连接
const isNewPagePublicLink = document
.getElementById('enlarge-inner-content-' + this.chart.id)
?.getBoundingClientRect()
const isMobileEdit = document.getElementsByClassName('panel-mobile')?.length > 0
const isMobileList = document.getElementsByClassName('mobile-com-list')?.length > 0
if (isMobileList) {
return false
}
const rect = this.plot.chart.ele.getBoundingClientRect()
return (
rect.top >= (isFullscreen || isNewPagePublicLink || isMobileEdit ? 0 : 64) &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
)
}
/**
*
* */
private calculatePosition(value: string) {
const view = this.plot.chart.views?.[0] || this.plot.chart
// 饼图特殊处理
if (CHART_CATEGORY.PIE.includes(this.chart.type)) {
return this.getPieTooltipPosition(view, value)
}
if (this.plot instanceof DualAxes) {
return this.getDualAxesTooltipPosition(view, value)
}
const types = view
.scale()
.getGeometries()
.map(item => item.type)
let point = { x: 0, y: 0 }
if (!types.length) return point
types.forEach(type => {
if (type === 'interval' || type === 'point') {
point = view
.scale()
.getGeometries()
.find(item => item.type === type)
.elements.find(item => item.data.field === value && (item.model.x || item.model.y))?.model
}
})
// 处理柱状图和折线图,柱状图固定y轴位置
const y = CHART_CATEGORY.COLUMN.includes(this.chart.type) ? 0 : [].concat(point?.y)?.[0]
return { x: [].concat(point?.x)?.[0], y: y }
}
/**
*
* */
private getPieTooltipPosition(view, value: string) {
const piePoint = view
.scale()
.getGeometries()[0]
?.elements.find(item => item.data.field === value)
?.getModel()
if (!piePoint) {
return { x: 0, y: 0 }
}
const coordinates = [
{ x: [].concat(piePoint.x)[0], y: piePoint.y[0] },
{ x: piePoint.x[0], y: piePoint.y[1] },
{ x: piePoint.x[1], y: piePoint.y[0] },
{ x: piePoint.x[1], y: piePoint.y[1] }
]
const index = coordinates.findIndex(coord => {
const items = this.plot.chart.getTooltipItems(coord)
return items.some(item => item.data.field === value)
})
if (index !== -1) {
return coordinates[index]
} else {
return {
x: piePoint.x[0],
y: piePoint.y[0]
}
}
}
/**
* Tooltip
* @param view
* @param value
* @private
*/
private getDualAxesTooltipPosition(view, value: string) {
const xScale = view.getXScale()
if (!xScale) return { x: 0, y: 0 }
const values = xScale.values
if (values.length < 2) {
const point = view
.getGeometries()?.[0]
.elements[view.getGeometries()?.[0].elements?.length - 1].getModel()
return point || { x: 0, y: 0 }
}
const [rangeStart, rangeEnd] = xScale.range
const totalMonths = values.length
const bandWidth = (rangeEnd - rangeStart) / totalMonths
const index = values.indexOf(value)
const xPos = rangeStart + bandWidth * (index + 0.5)
return view.getCoordinate().convert({ x: xPos, y: 0 })
}
/**
*
* */
private highlightElement(value: string) {
if (CHART_CATEGORY.LINE.includes(this.chart.type)) return
this.unHighlightPoint(value)
this.plot.setState(
this.getHighlightType(),
(data: any) => data[this.config.xField] === value,
true
)
}
/**
*
* **/
private unHighlightPoint(value?: string) {
if (CHART_CATEGORY.LINE.includes(this.chart.type)) return
this.plot.setState(
this.getHighlightType(),
(data: any) => data[this.config.xField] !== value,
false
)
}
private getHighlightType() {
return 'active'
}
/**
*
* */
private hideTooltip() {
const container = this.getTooltipContainer()
if (container) {
container.style.display = 'none'
}
}
/**
*
* */
private getTooltipContainer() {
const tooltipCtl = this.plot.chart.getController('tooltip')
if (!tooltipCtl) {
return
}
return tooltipCtl.tooltip?.cfg?.container
}
/**
*
* */
private bindEventListeners() {
// 定义图表元素ID前缀数组
// 图表在不同的显示页面可能有不同的ID前缀
const chartElementIds = ['enlarge-inner-content-', 'enlarge-inner-shape-']
let chartElement = null
// 查找图表元素
for (const idPrefix of chartElementIds) {
chartElement = document.getElementById(idPrefix + this.chart.id)
if (chartElement) break
}
// 绑定鼠标进入和离开事件
chartElement?.addEventListener('mouseenter', () => this.paused())
chartElement?.addEventListener('mouseleave', ev => {
setTimeout(() => {
// 获取鼠标位置
const mouseX = ev.clientX
const mouseY = ev.clientY
// 获取div的边界信息
const rect = chartElement.getBoundingClientRect()
// 判断鼠标位置是否在div内
const isInside =
mouseX >= rect.left + 10 &&
mouseX <= rect.right - 10 &&
mouseY >= rect.top + 10 &&
mouseY <= rect.bottom - 10
console.log(isInside)
if (!isInside) {
this.paused()
this.resume()
}
}, 300)
})
// 定义鼠标滚轮事件处理函数
const handleMouseWheel = this.debounce(() => {
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
instance.paused()
instance.resume()
})
}, 50)
// 定义 touchmove 事件处理函数(移动端)
const handleTouchMove = (event: TouchEvent) => {
handleMouseWheel(event)
}
// 获取目标元素,优先全屏预览
const targetDiv =
document.getElementById('de-preview-content') ||
document.getElementById('preview-canvas-main') ||
document.getElementById('dv-main-center') ||
document.getElementById('edit-canvas-main') ||
document.getElementById('canvas-mark-line') ||
document.getElementById('de-canvas-canvas-main')
// 绑定目标元素的事件
if (targetDiv) {
targetDiv.removeEventListener('wheel', handleMouseWheel)
targetDiv.addEventListener('wheel', handleMouseWheel)
//移除和添加 touchmove 事件监听器(移动端)
targetDiv.removeEventListener('touchmove', handleTouchMove)
targetDiv.addEventListener('touchmove', handleTouchMove)
}
// 页面可见性控制
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
instance.paused()
})
} else if (this.chartIsVisible) {
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
instance.resume()
})
}
})
// 元素可视性观察(交叉观察器)
this.setupIntersectionObserver()
// 元素大小观察(大小观察器)
this.setupResizeObserver()
}
/**
*
* */
private setPaused(state: boolean) {
this.states.paused = state
state ? this.stop() : this.startCarousel()
}
/**
*
* */
private setupIntersectionObserver() {
setTimeout(() => {
// 监听元素可见性变化,全部可见时开始轮播
if (!this.observers.get(this.plot.chart.ele.id)) {
this.observers.set(
this.plot.chart.ele.id,
new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.intersectionRatio < 0.7) {
this.paused()
this.chartIsVisible = false
} else {
this.paused()
this.chartIsVisible = true
this.resume()
}
})
},
{ threshold: [0.7] }
)
)
this.observers.get(this.plot.chart.ele.id).observe(this.plot.chart.ele)
}
}, 100)
}
/**
*
*
*
* @private
*/
private setupResizeObserver() {
// 放大图表弹窗不需要监听
if (this.plot.chart.ele.id.includes('viewDialog')) return
// 创建防抖回调函数
const debouncedCallback = (entries: ResizeObserverEntry[]) => {
for (const entry of entries) {
if (entry.target) {
this.debounce(() => {
this.paused()
this.resume()
}, 200)
}
}
}
// 监听元素大小, 发生变化时重新轮播
if (!this.resizeObservers.get(this.plot.chart.ele.id)) {
this.resizeObservers.set(this.plot.chart.ele.id, new ResizeObserver(debouncedCallback))
this.resizeObservers.get(this.plot.chart.ele.id).observe(this.plot.chart.ele)
}
}
/**
*
* */
private update(plot: Plot | DualAxes, chart: Chart, config: CarouselConfig) {
this.stop()
this.plot = plot
this.chart = chart
this.config = { ...this.config, ...config }
this.currentIndex = 0
this.init()
}
/**
*
* @private
*/
private stop() {
clearTimeout(this.timers.interval)
clearTimeout(this.timers.carousel)
this.timers = { interval: null, carousel: null }
}
/**
*
* */
destroy() {
this.stop()
this.clearObserver()
this.states.destroyed = true
CAROUSEL_MANAGER_INSTANCES.delete(this.chart.container)
}
/**
*
* */
clearObserver() {
const observer = this.observers.get(this.plot.chart.ele.id)
if (observer) {
observer.disconnect()
this.observers.delete(this.plot.chart.ele.id)
}
const resizeObservers = this.resizeObservers.get(this.plot.chart.ele.id)
if (resizeObservers) {
resizeObservers.disconnect()
this.resizeObservers.delete(this.plot.chart.ele.id)
}
}
/** 暂停 */
paused() {
this.hideTooltip()
this.unHighlightPoint()
this.setPaused(true)
}
/** 恢复 */
resume() {
this.setPaused(false)
}
/**
*
*/
private debounce(func: (...args: any[]) => void, delay: number): (...args: any[]) => void {
let timeout: number | null = null
return (...args: any[]) => {
if (timeout) clearTimeout(timeout)
timeout = window.setTimeout(() => {
func(...args)
}, delay)
}
}
}
export default ChartCarouselTooltip

View File

@ -55,7 +55,7 @@ export const configHandler = config => {
if (wsCache.get('user.token')) { if (wsCache.get('user.token')) {
config.headers['X-DE-TOKEN'] = wsCache.get('user.token') config.headers['X-DE-TOKEN'] = wsCache.get('user.token')
const expired = isExpired() const expired = isExpired()
if (expired && config.url !== refreshUrl) { if (expired && !config.url.includes(refreshUrl)) {
if (!getRefreshStatus()) { if (!getRefreshStatus()) {
setRefreshStatus(true) setRefreshStatus(true)
// refreshApi() // refreshApi()

View File

@ -72,7 +72,6 @@ const handleInput = value => {
<span style="font-size: 12px">{{ t('visualization.carousel_time') }}</span> <span style="font-size: 12px">{{ t('visualization.carousel_time') }}</span>
<el-tooltip class="item" :effect="themes" placement="top"> <el-tooltip class="item" :effect="themes" placement="top">
<template #content> <template #content>
<div>{{ t('visualization.carousel_tips') }}</div>
<div v-if="element.innerType === 'picture-group'"> <div v-if="element.innerType === 'picture-group'">
{{ t('visualization.carousel_tips2') }} {{ t('visualization.carousel_tips2') }}
</div> </div>

View File

@ -58,7 +58,7 @@ const onBackgroundChange = val => {
emits('onAttrChange', { custom: 'commonBackground' }) emits('onAttrChange', { custom: 'commonBackground' })
} }
const onTitleBackgroundEnableChange = val => { const onTitleBackgroundEnableChange = () => {
snapshotStore.recordSnapshotCacheToMobile('titleBackground') snapshotStore.recordSnapshotCacheToMobile('titleBackground')
} }
@ -252,7 +252,7 @@ onMounted(() => {
} }
} }
:deep(.ed-collapse-item__content) { :deep(.ed-collapse-item__content) {
padding: 16px 8px 0; padding: 16px 8px 8px !important;
border: none; border: none;
} }
:deep(.ed-form-item) { :deep(.ed-form-item) {

View File

@ -83,7 +83,7 @@ watch(
<template> <template>
<el-row class="custom-row" style="padding-bottom: 8px"> <el-row class="custom-row" style="padding-bottom: 8px">
<el-form label-position="top"> <el-form size="small" label-position="top">
<template v-if="isSvgComponent"> <template v-if="isSvgComponent">
<el-row style="display: flex"> <el-row style="display: flex">
<el-form-item <el-form-item
@ -93,7 +93,7 @@ watch(
:class="'form-item-' + themes" :class="'form-item-' + themes"
> >
<el-color-picker <el-color-picker
:label="t('visualization.color')" :title="t('visualization.color')"
:disabled="!styleForm.borderActive" :disabled="!styleForm.borderActive"
v-model="styleForm.borderColor" v-model="styleForm.borderColor"
class="color-picker-style" class="color-picker-style"
@ -102,7 +102,7 @@ watch(
show-alpha show-alpha
:predefine="state.predefineColors" :predefine="state.predefineColors"
@change="changeStylePre('borderColor')" @change="changeStylePre('borderColor')"
>{{visualization.color}} >
</el-color-picker> </el-color-picker>
</el-form-item> </el-form-item>
<el-form-item <el-form-item

View File

@ -130,6 +130,11 @@ const typeMap = {
</template> </template>
<style scoped lang="less"> <style scoped lang="less">
.form-item-light {
.ed-radio {
margin-right: 3px !important;
}
}
.form-item-dark { .form-item-dark {
.ed-radio { .ed-radio {
margin-right: 3px !important; margin-right: 3px !important;

View File

@ -175,8 +175,8 @@
:class="{ dark: themes === 'dark', active: styleForm.textDecoration === 'underline' }" :class="{ dark: themes === 'dark', active: styleForm.textDecoration === 'underline' }"
@click="checkTextDecoration" @click="checkTextDecoration"
> >
<el-icon style="color: red;"> <el-icon>
<Icon name="style-underline"><styleUnderline class="svg-icon"/></Icon> <Icon name="style-underline"><styleUnderline class="svg-icon" /></Icon>
</el-icon> </el-icon>
</div> </div>
</el-tooltip> </el-tooltip>
@ -685,7 +685,7 @@ watch(
border-radius: 4px; border-radius: 4px;
padding-top: 1px; padding-top: 1px;
color: #a6a6a6; color: #1f2329;
cursor: pointer; cursor: pointer;
@ -777,4 +777,13 @@ watch(
background-color: rgba(31, 35, 41, 0.1); background-color: rgba(31, 35, 41, 0.1);
} }
} }
.form-item-dark {
:deep(.ed-color-picker__trigger) {
border-color: #5f5f5f;
}
:deep(.ed-color-picker__custom-icon::after) {
background-color: #5f5f5f;
}
}
</style> </style>

View File

@ -1,5 +1,7 @@
// 公共样式 // 公共样式
import { deepCopy } from '@/data-visualization/utils/utils' import { deepCopy } from '@/data-visualization/utils/utils'
import { guid } from '@/data-visualization/guid/util.js'
import { getViewConfig } from '@/data-visualization/chart/components/editor/util/chart'
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/data-visualization/hooks/web/useI18n'
const { t } = useI18n() const { t } = useI18n()
@ -294,6 +296,7 @@ const list = [
icon: 'icon_search', icon: 'icon_search',
innerType: 'VQuery', innerType: 'VQuery',
isHang: false, isHang: false,
freeze: false, // 是否冻结再顶部 主画布生效
x: 1, x: 1,
y: 1, y: 1,
sizeX: 72, sizeX: 72,
@ -605,6 +608,40 @@ for (let i = 0, len = list.length; i < len; i++) {
list[i] = { ...commonAttr, ...item } list[i] = { ...commonAttr, ...item }
} }
export function findNewComponentFromList(
componentName,
innerType,
curOriginThemes,
staticMap?: object
) {
const isPlugin = !!staticMap
let newComponent
list.forEach(comp => {
if (comp.component === componentName) {
newComponent = deepCopy(comp)
newComponent['commonBackground'] = deepCopy(
COMMON_COMPONENT_BACKGROUND_MAP[curOriginThemes.value]
)
newComponent.innerType = innerType
if (comp.component === 'DeTabs') {
newComponent.propValue[0].name = guid()
newComponent['titleBackground'] = deepCopy(COMMON_TAB_TITLE_BACKGROUND)
}
}
})
if (componentName === 'UserView') {
const viewConfig = getViewConfig(innerType)
newComponent.name = viewConfig?.title
newComponent.label = viewConfig?.title
newComponent.render = viewConfig?.render
newComponent.isPlugin = !!isPlugin
if (isPlugin) {
newComponent.staticMap = staticMap
}
}
return newComponent
}
export function findBaseDeFaultAttr(componentName) { export function findBaseDeFaultAttr(componentName) {
let result = {} let result = {}
@ -612,7 +649,14 @@ export function findBaseDeFaultAttr(componentName) {
if (comp.component === componentName) { if (comp.component === componentName) {
const stylePropertyInner = [] const stylePropertyInner = []
Object.keys(comp.style).forEach(styleKey => { Object.keys(comp.style).forEach(styleKey => {
if (
(!['width', 'height'].includes(styleKey) &&
componentName === 'VQuery' &&
!Object.keys(commonStyle).includes(styleKey)) ||
componentName !== 'VQuery'
) {
stylePropertyInner.push(styleKey) stylePropertyInner.push(styleKey)
}
}) })
result = { result = {
properties: ['common-style', 'background-overall-component'], properties: ['common-style', 'background-overall-component'],

View File

@ -22,7 +22,7 @@ import { useI18n } from '@/data-visualization/hooks/web/useI18n'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { curComponent, mobileInPc } = storeToRefs(dvMainStore) const { curComponent, mobileInPc } = storeToRefs(dvMainStore)
const { t } = useI18n() const { t } = useI18n()
const props = withDefaults( withDefaults(
defineProps<{ defineProps<{
themes?: EditorTheme themes?: EditorTheme
}>(), }>(),

View File

@ -30,11 +30,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, onMounted, reactive, toRefs } from 'vue' import { nextTick, onMounted, reactive, toRefs } from 'vue'
import { useEmitt } from '@/data-visualization/hooks/web/useEmitt'
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/data-visualization/hooks/web/useI18n'
import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
const dvMainStore = dvMainStoreWithOut()
const { canvasStyleData } = storeToRefs(dvMainStore)
const { t } = useI18n() const { t } = useI18n()
@ -62,7 +59,7 @@ const props = defineProps({
} }
}) })
const { propValue, element, isEdit, active, screenShot } = toRefs(props) const { element, isEdit, screenShot } = toRefs(props)
const state = reactive({ const state = reactive({
pOption: {}, pOption: {},
@ -77,6 +74,12 @@ const frameLinksChange = () => {
} }
onMounted(() => { onMounted(() => {
useEmitt({
name: 'frameLinksChange-' + element.value.id,
callback: function () {
frameLinksChange()
}
})
}) })
</script> </script>

View File

@ -27,17 +27,16 @@
<script setup lang="ts"> <script setup lang="ts">
import icon_info_outlined from '@/assets/svg/icon_info_outlined.svg' import icon_info_outlined from '@/assets/svg/icon_info_outlined.svg'
import { reactive, ref, toRefs, watch, computed } from 'vue' import { reactive, toRefs, watch, computed } from 'vue'
import { dvMainStoreWithOut } from '../../store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '../../store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia/dist/pinia' import { storeToRefs } from 'pinia/dist/pinia'
import { checkAddHttp, deepCopy } from '../../utils/utils' import { checkAddHttp, deepCopy } from '../../utils/utils'
import { snapshotStoreWithOut } from '../../store/modules/data-visualization/snapshot' import { snapshotStoreWithOut } from '../../store/modules/data-visualization/snapshot'
import { useI18n } from '../../hooks/web/useI18n' import { useI18n } from '../../hooks/web/useI18n'
import { useEmitt } from '@/data-visualization/hooks/web/useEmitt'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { curComponent, curActiveTabInner } = storeToRefs(dvMainStore) const { curComponent } = storeToRefs(dvMainStore)
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const emits = defineEmits(['close'])
const popover = ref(null)
const { t } = useI18n() const { t } = useI18n()
const props = defineProps({ const props = defineProps({
@ -59,7 +58,7 @@ const props = defineProps({
const { frameLinks } = toRefs(props) const { frameLinks } = toRefs(props)
const toolTip = computed(() => { const toolTip = computed(() => {
return props.themes === 'dark' ? 'ndark' : 'dark' return props.themes === 'dark' ? 'light' : 'dark'
}) })
const state = reactive({ const state = reactive({
@ -76,6 +75,7 @@ const onBlur = () => {
state.linkInfoTemp.src = checkAddHttp(state.linkInfoTemp.src) state.linkInfoTemp.src = checkAddHttp(state.linkInfoTemp.src)
curComponent.value.frameLinks.src = state.linkInfoTemp.src curComponent.value.frameLinks.src = state.linkInfoTemp.src
snapshotStore.recordSnapshotCache('frame-onBlur') snapshotStore.recordSnapshotCache('frame-onBlur')
useEmitt().emitter.emit('frameLinksChange-' + curComponent.value.id)
} }
init() init()
watch( watch(

View File

@ -17,11 +17,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import CommonAttr from '@/data-visualization/custom-component/common/CommonAttr.vue' import CommonAttr from '@/custom-component/common/CommonAttr.vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import StreamMediaLinks from '@/data-visualization/custom-component/de-stream-media/StreamMediaLinks.vue' import StreamMediaLinks from '@/custom-component/de-stream-media/StreamMediaLinks.vue'
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { curComponent, mobileInPc } = storeToRefs(dvMainStore) const { curComponent, mobileInPc } = storeToRefs(dvMainStore)
const { t } = useI18n() const { t } = useI18n()

View File

@ -22,7 +22,7 @@
import flvjs from 'flv.js' import flvjs from 'flv.js'
import '@/data-visualization/style/custom-theme.css' import '@/data-visualization/style/custom-theme.css'
import { onMounted, reactive, toRefs, getCurrentInstance, nextTick, onBeforeUnmount } from 'vue' import { onMounted, reactive, toRefs, getCurrentInstance, nextTick, onBeforeUnmount } from 'vue'
// import { useEmitt } from '@/hooks/web/useEmitt' import { useEmitt } from '@/data-visualization/hooks/web/useEmitt'
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/data-visualization/hooks/web/useI18n'
const { t } = useI18n() const { t } = useI18n()
@ -55,7 +55,7 @@ const props = defineProps({
} }
}) })
const { propValue, element, editMode } = toRefs(props) const { element } = toRefs(props)
let currentInstance let currentInstance
const state = reactive({ const state = reactive({
@ -66,12 +66,12 @@ const state = reactive({
onMounted(() => { onMounted(() => {
currentInstance = getCurrentInstance() currentInstance = getCurrentInstance()
// useEmitt({ useEmitt({
// name: 'streamMediaLinksChange-' + element.value.id, name: 'streamMediaLinksChange-' + element.value.id,
// callback: function () { callback: function () {
// initOption() initOption()
// } }
// }) })
initOption() initOption()
}) })

View File

@ -45,18 +45,16 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, toRefs, watch, computed } from 'vue' import { reactive, toRefs, watch } from 'vue'
import { dvMainStoreWithOut } from '../../store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '../../store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia/dist/pinia' import { storeToRefs } from 'pinia/dist/pinia'
import { checkAddHttp, deepCopy } from '../../utils/utils' import { checkAddHttp, deepCopy } from '../../utils/utils'
import { snapshotStoreWithOut } from '../../store/modules/data-visualization/snapshot' import { snapshotStoreWithOut } from '../../store/modules/data-visualization/snapshot'
import { useI18n } from '../../hooks/web/useI18n' import { useI18n } from '../../hooks/web/useI18n'
// import { useEmitt } from '@/hooks/web/useEmitt' import { useEmitt } from '@/data-visualization/hooks/web/useEmitt'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { curComponent, curActiveTabInner } = storeToRefs(dvMainStore) const { curComponent, curActiveTabInner } = storeToRefs(dvMainStore)
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const emits = defineEmits(['close'])
const popover = ref(null)
const { t } = useI18n() const { t } = useI18n()
const props = defineProps({ const props = defineProps({
@ -107,7 +105,7 @@ const onChange = () => {
curActiveTabInner.value.streamMediaLinks = state.streamMediaInfoTemp curActiveTabInner.value.streamMediaLinks = state.streamMediaInfoTemp
} }
snapshotStore.recordSnapshotCache('stream-onChange') snapshotStore.recordSnapshotCache('stream-onChange')
// useEmitt().emitter.emit('streamMediaLinksChange-' + curComponent.value.id) useEmitt().emitter.emit('streamMediaLinksChange-' + curComponent.value.id)
} }
init() init()

View File

@ -161,20 +161,17 @@ import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visu
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { guid } from '@/data-visualization/guid/util' import { guid } from '@/data-visualization/guid/util'
import eventBus from '@/data-visualization/utils/eventBus' import eventBus from '@/data-visualization/utils/eventBus'
import { import { canvasChangeAdaptor, findComponentIndexById, isDashboard } from '@/data-visualization/utils/canvasUtils'
canvasChangeAdaptor,
findComponentIndexById,
findComponentIndexByIdWithFilterHidden,
isDashboard
} from '@/data-visualization/utils/canvasUtils'
import DeCustomTab from '@/data-visualization/custom-component/de-tabs/DeCustomTab.vue' import DeCustomTab from '@/data-visualization/custom-component/de-tabs/DeCustomTab.vue'
import DePreview from '@/data-visualization/components/data-visualization/canvas/DePreview.vue' import DePreview from '@/data-visualization/components/data-visualization/canvas/DePreview.vue'
// import { getPanelAllLinkageInfo } from '@/api/visualization/linkage' import { getPanelAllLinkageInfo } from '@/api/data-visualization/visualization/linkage'
import { dataVTabComponentAdd, groupSizeStyleAdaptor } from '@/data-visualization/utils/style' import { dataVTabComponentAdd, groupSizeStyleAdaptor } from '@/data-visualization/utils/style'
import { deepCopyTabItemHelper } from '@/data-visualization/store/modules/data-visualization/copy'
import { snapshotStoreWithOut } from '@/data-visualization/store/modules/data-visualization/snapshot' import { snapshotStoreWithOut } from '@/data-visualization/store/modules/data-visualization/snapshot'
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/data-visualization/hooks/web/useI18n'
import { imgUrlTrans } from '@/data-visualization/utils/imgUtils' import { imgUrlTrans } from '@/data-visualization/utils/imgUtils'
import Board from '@/data-visualization/components/de-board/Board.vue' import Board from '@/data-visualization/components/de-board/Board.vue'
import ChartCarouselTooltip from '@/data-visualization/chart/components/js/g2plot_tooltip_carousel'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const { tabMoveInActiveId, bashMatrixInfo, editMode, mobileInPc } = storeToRefs(dvMainStore) const { tabMoveInActiveId, bashMatrixInfo, editMode, mobileInPc } = storeToRefs(dvMainStore)
@ -273,6 +270,23 @@ const svgInnerActiveEnable = itemName => {
) )
} }
// tooltips tab
const viewToolTipsChange = () => {
element.value.propValue?.forEach(tabItem => {
const tMethod =
editableTabsValue.value === tabItem.name
? ChartCarouselTooltip.resume
: ChartCarouselTooltip.paused
tabItem.componentData?.forEach(componentItem => {
tMethod(componentItem.id)
if (componentItem.component === 'Group')
componentItem.propValue.forEach(groupItem => {
tMethod(groupItem.id)
})
})
})
}
const handleMouseEnter = () => { const handleMouseEnter = () => {
state.hoverFlag = true state.hoverFlag = true
} }
@ -367,6 +381,12 @@ function deleteCur(param) {
} }
} }
function copyCur(param) { function copyCur(param) {
addTab()
const newTabItem = element.value.propValue[element.value.propValue.length - 1]
const idMap = {}
const newCanvasId = element.value.id + '--' + newTabItem.name
newTabItem.componentData = deepCopyTabItemHelper(newCanvasId, param.componentData, idMap)
dvMainStore.updateCopyCanvasView(idMap)
} }
function editCurTitle(param) { function editCurTitle(param) {
@ -395,9 +415,12 @@ function handleCommand(command) {
const reloadLinkage = () => { const reloadLinkage = () => {
// //
if (dvInfo.value.id) { if (dvInfo.value.id) {
// getPanelAllLinkageInfo(dvInfo.value.id).then(rsp => { const resourceTable = ['canvas', 'canvasDataV', 'edit'].includes(showPosition.value)
// dvMainStore.setNowPanelTrackInfo(rsp.data) ? 'snapshot'
// }) : 'core'
getPanelAllLinkageInfo(dvInfo.value.id, resourceTable).then(rsp => {
dvMainStore.setNowPanelTrackInfo(rsp.data)
})
} }
} }
@ -406,9 +429,7 @@ const componentMoveIn = component => {
if (editableTabsValue.value === tabItem.name) { if (editableTabsValue.value === tabItem.name) {
//index //index
if (isDashboard()) { if (isDashboard()) {
const curIndex = findComponentIndexByIdWithFilterHidden(component.id) eventBus.emit('removeMatrixItemById-canvas-main', component.id)
if (curIndex > -1) {
eventBus.emit('removeMatrixItem-canvas-main', curIndex)
dvMainStore.setCurComponent({ component: null, index: null }) dvMainStore.setCurComponent({ component: null, index: null })
component.canvasId = element.value.id + '--' + tabItem.name component.canvasId = element.value.id + '--' + tabItem.name
const refInstance = currentInstance.refs['tabCanvas_' + index][0] const refInstance = currentInstance.refs['tabCanvas_' + index][0]
@ -425,7 +446,6 @@ const componentMoveIn = component => {
refInstance.canvasInitImmediately() refInstance.canvasInitImmediately()
}) })
} }
}
} else { } else {
const curIndex = findComponentIndexById(component.id) const curIndex = findComponentIndexById(component.id)
// //
@ -622,6 +642,12 @@ watch(
} }
) )
watch(
() => editableTabsValue.value,
() => {
viewToolTipsChange()
}
)
const initCarousel = () => { const initCarousel = () => {
carouselTimer && clearInterval(carouselTimer) carouselTimer && clearInterval(carouselTimer)
carouselTimer = null carouselTimer = null
@ -654,12 +680,14 @@ onMounted(() => {
eventBus.on('onTabMoveOut-' + element.value.id, componentMoveOut) eventBus.on('onTabMoveOut-' + element.value.id, componentMoveOut)
eventBus.on('onTabSortChange-' + element.value.id, reShow) eventBus.on('onTabSortChange-' + element.value.id, reShow)
} }
currentInstance = getCurrentInstance() currentInstance = getCurrentInstance()
initCarousel() initCarousel()
nextTick(() => { nextTick(() => {
groupSizeStyleAdaptor(element.value) groupSizeStyleAdaptor(element.value)
}) })
setTimeout(() => {
viewToolTipsChange()
}, 1000)
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (['canvas', 'canvasDataV', 'edit'].includes(showPosition.value) && !mobileInPc.value) { if (['canvas', 'canvasDataV', 'edit'].includes(showPosition.value) && !mobileInPc.value) {

View File

@ -39,7 +39,6 @@ import { deepCopy } from '@/data-visualization/utils/utils'
import { ElButton } from 'element-plus-secondary' import { ElButton } from 'element-plus-secondary'
import { snapshotStoreWithOut } from '@/data-visualization/store/modules/data-visualization/snapshot' import { snapshotStoreWithOut } from '@/data-visualization/store/modules/data-visualization/snapshot'
import eventBus from '@/data-visualization/utils/eventBus' import eventBus from '@/data-visualization/utils/eventBus'
import { useI18n } from '@/data-visualization/hooks/web/useI18n'
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const config = ref(null) const config = ref(null)
@ -64,7 +63,7 @@ const save = () => {
eventBus.emit('onTabSortChange-' + config.value.id) eventBus.emit('onTabSortChange-' + config.value.id)
closeDialog() closeDialog()
} }
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n() const { t } = useI18n()
defineExpose({ defineExpose({

View File

@ -35,6 +35,14 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item>
<el-checkbox
:effect="themes"
v-model="formatInfo.showWeek"
:label="t('visualization.show_week')"
@change="onFormatChange"
/>
</el-form-item>
</el-form> </el-form>
</el-row> </el-row>
</template> </template>

View File

@ -46,8 +46,6 @@ import { useEmitt } from '@/data-visualization/hooks/web/useEmitt'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { curComponent, curActiveTabInner } = storeToRefs(dvMainStore) const { curComponent, curActiveTabInner } = storeToRefs(dvMainStore)
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const emits = defineEmits(['close'])
const popover = ref(null)
const { t } = useI18n() const { t } = useI18n()
const props = defineProps({ const props = defineProps({
@ -96,12 +94,7 @@ const onChange = () => {
snapshotStore.recordSnapshotCache('video-onChange') snapshotStore.recordSnapshotCache('video-onChange')
useEmitt().emitter.emit('videoLinksChange-' + curComponent.value.id) useEmitt().emitter.emit('videoLinksChange-' + curComponent.value.id)
} }
const onBlur = () => {
state.linkInfoTemp.src = checkAddHttp(state.linkInfoTemp.src)
curComponent.value.frameLinks.src = state.linkInfoTemp.src
snapshotStore.recordSnapshotCache('video-onBlur')
useEmitt().emitter.emit('frameLinksChange-' + curComponent.value.id)
}
init() init()
watch( watch(

View File

@ -13,8 +13,23 @@ import {
} from '@/data-visualization/chart/components/editor/util/chart' } from '@/data-visualization/chart/components/editor/util/chart'
import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' import { valueFormatter } from '@/data-visualization/chart/components/js/formatter'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { isDashboard, trackBarStyleCheck } from '@/data-visualization/utils/canvasUtils'
import ViewTrackBar from '@/data-visualization/components/visualization/ViewTrackBar.vue'
const props = defineProps({ const props = defineProps({
//
commonParams: {
type: Object,
required: false
},
element: {
type: Object,
default() {
return {
propValue: null
}
}
},
view: { view: {
type: Object as PropType<ChartObj>, type: Object as PropType<ChartObj>,
default() { default() {
@ -50,18 +65,26 @@ const props = defineProps({
} }
}) })
const { view, scale, terminal } = toRefs(props) const { view, scale, terminal, showPosition, commonParams } = toRefs(props)
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const dataVMobile = !isDashboard() && isMobile()
const { batchOptStatus } = storeToRefs(dvMainStore) const { embeddedCallBack, nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, inMobile } =
storeToRefs(dvMainStore)
const viewTrack = ref(null)
const indicatorRef = ref(null)
const errMsg = ref('') const errMsg = ref('')
const isError = ref(false) const isError = ref(false)
const state = reactive({ const state = reactive({
pointParam: null,
data: null, data: null,
loading: false, loading: false,
totalItems: 0 totalItems: 0,
trackBarStyle: {
position: 'absolute',
left: '50%',
top: '50%'
}
}) })
const chartData = shallowRef<Partial<Chart['data']>>({ const chartData = shallowRef<Partial<Chart['data']>>({
@ -101,7 +124,6 @@ const result = computed(() => {
}) })
const indicatorColor = ref(DEFAULT_INDICATOR_STYLE.color) const indicatorColor = ref(DEFAULT_INDICATOR_STYLE.color)
const thresholdColor = computed(() => { const thresholdColor = computed(() => {
let color: string = indicatorColor.value let color: string = indicatorColor.value
let backgroundColor: string = DEFAULT_INDICATOR_STYLE.backgroundColor let backgroundColor: string = DEFAULT_INDICATOR_STYLE.backgroundColor
@ -184,8 +206,13 @@ const formattedResult = computed(() => {
return _result return _result
}) })
const emit = defineEmits(['onChartClick', 'onDrillFilters', 'onJumpClick']) const emit = defineEmits([
'onPointClick',
'onChartClick',
'onDrillFilters',
'onJumpClick',
'onComponentEvent'
])
const contentStyle = ref<CSSProperties>({ const contentStyle = ref<CSSProperties>({
display: 'flex', display: 'flex',
'flex-direction': 'column', 'flex-direction': 'column',
@ -264,7 +291,7 @@ const renderChart = async view => {
recursionTransObj(customStyleTrans, chart.customStyle, scale.value, terminal.value) recursionTransObj(customStyleTrans, chart.customStyle, scale.value, terminal.value)
if (chart.customAttr) { if (chart.customAttr) {
const { indicator, indicatorName, basicStyle } = chart.customAttr const { indicator, indicatorName } = chart.customAttr
if (indicator) { if (indicator) {
switch (indicator.hPosition) { switch (indicator.hPosition) {
@ -375,6 +402,177 @@ const calcData = (view, callback) => {
} }
} }
const trackClick = trackAction => {
const param = state.pointParam
if (!param?.data?.dimensionList && !param?.data?.quotaList) {
return
}
const linkageParam = {
option: 'linkage',
innerType: 'indicator',
name: state.pointParam.data.name,
viewId: view.value.id,
dimensionList: state.pointParam.data.dimensionList,
quotaList: state.pointParam.data.quotaList,
customFilter: state.pointParam.data.customFilter
}
const jumpParam = {
option: 'jump',
innerType: 'indicator',
name: state.pointParam.data.name,
viewId: view.value.id,
dimensionList: state.pointParam.data.dimensionList,
quotaList: state.pointParam.data.quotaList,
sourceType: state.pointParam.data.sourceType
}
const clickParams = {
option: 'pointClick',
innerType: 'indicator',
name: state.pointParam.data.name,
viewId: view.value.id,
dimensionList: state.pointParam.data.dimensionList,
quotaList: state.pointParam.data.quotaList,
customFilter: state.pointParam.data.customFilter
}
switch (trackAction) {
case 'pointClick':
emit('onPointClick', clickParams)
break
case 'linkageAndDrill':
dvMainStore.addViewTrackFilter(linkageParam)
emit('onChartClick', param)
break
case 'drill':
emit('onChartClick', param)
break
case 'linkage':
dvMainStore.addViewTrackFilter(linkageParam)
break
case 'jump':
if (mobileInPc.value && !inMobile.value) return
emit('onJumpClick', jumpParam)
break
case 'event_jump':
case 'event_download':
case 'event_share':
case 'event_fullScreen':
case 'event_showHidden':
case 'event_refreshDataV':
case 'event_refreshView':
emit('onComponentEvent', jumpParam)
break
default:
break
}
}
const trackMenu = computed(() => {
let trackMenuInfo = []
if (showPosition.value === 'viewDialog') {
return trackMenuInfo
}
let linkageCount = 0
let jumpCount = 0
chartData.value?.fields?.forEach(item => {
const sourceInfo = view.value.id + '#' + item.id
if (nowPanelTrackInfo.value[sourceInfo]) {
linkageCount++
}
if (nowPanelJumpInfo.value[sourceInfo]) {
jumpCount++
}
})
jumpCount &&
view.value?.jumpActive &&
(!mobileInPc.value || inMobile.value) &&
trackMenuInfo.push('jump')
linkageCount && view.value?.linkageActive && trackMenuInfo.push('linkage')
view.value.drillFields.length && trackMenuInfo.push('drill')
// jump linkage drill '' ''
if (trackMenuInfo.length === 3 && props.element.actionSelection.linkageActive === 'auto') {
trackMenuInfo = ['jump', 'linkageAndDrill']
} else if (
trackMenuInfo.length === 2 &&
props.element.actionSelection.linkageActive === 'auto' &&
!trackMenuInfo.includes('jump')
) {
trackMenuInfo = ['linkageAndDrill']
}
if (commonParams.value?.eventEnable) {
trackMenuInfo.push('event_' + commonParams.value?.eventType)
}
return trackMenuInfo
})
const showCursor = computed(() => {
return trackMenu.value.length || embeddedCallBack.value === 'yes'
})
const pointClickTrans = () => {
if (embeddedCallBack.value === 'yes') {
trackClick('pointClick')
}
}
const action = param => {
state.pointParam = param
//
pointClickTrans()
//
if (trackMenu.value.length < 2) {
//
trackClick(trackMenu.value[0])
} else {
setTimeout(() => {
const barStyleTemp = {
left: param.x - 50,
top: param.y + 10
}
trackBarStyleCheck(props.element, barStyleTemp, props.scale, trackMenu.value.length)
if (dataVMobile) {
state.trackBarStyle.left = barStyleTemp.left + 40 + 'px'
state.trackBarStyle.top = barStyleTemp.top + 70 + 'px'
} else {
state.trackBarStyle.left = barStyleTemp.left + 'px'
state.trackBarStyle.top = barStyleTemp.top + 'px'
}
viewTrack.value.trackButtonClick()
}, 200)
}
}
const onPointClick = event => {
if (view.value?.yAxis?.length) {
const axis = view.value.yAxis[0]
//
const mouseX = event.clientX
const mouseY = event.clientY
// div
const rect = indicatorRef.value.getBoundingClientRect()
const offsetX = rect.left
const offsetY = rect.top
// div
const left = mouseX - offsetX
let top = mouseY - offsetY
//
const params = {
x: left,
y: top,
data: {
name: axis.name,
dimensionList: view.value.xAxis,
quotaList: view.value.yAxis,
customFilter: view.value.customFilter
}
}
action(params)
}
}
defineExpose({ defineExpose({
calcData, calcData,
renderChart renderChart
@ -382,7 +580,21 @@ defineExpose({
</script> </script>
<template> <template>
<div :style="contentStyle"> <div
ref="indicatorRef"
:class="{ 'menu-point': showCursor }"
:style="contentStyle"
@mousedown="onPointClick"
>
<view-track-bar
ref="viewTrack"
:track-menu="trackMenu"
:font-family="fontFamily"
class="track-bar"
:style="state.trackBarStyle"
@trackClick="trackClick"
:is-data-v-mobile="dataVMobile"
/>
<div> <div>
<span :style="indicatorClass">{{ formattedResult }}</span> <span :style="indicatorClass">{{ formattedResult }}</span>
<span :style="indicatorSuffixClass" v-if="showSuffix">{{ suffixContent }}</span> <span :style="indicatorSuffixClass" v-if="showSuffix">{{ suffixContent }}</span>
@ -393,4 +605,8 @@ defineExpose({
</div> </div>
</template> </template>
<style scoped lang="less"></style> <style scoped lang="less">
.menu-point {
cursor: pointer;
}
</style>

View File

@ -73,10 +73,6 @@ const { curComponent, canvasViewInfo, mobileInPc, batchOptStatus } = storeToRefs
margin: 0 6px 0 8px; margin: 0 6px 0 8px;
} }
} }
:deep(.ed-collapse-item__content) {
padding: 16px 8px 0;
}
:deep(.ed-form-item) { :deep(.ed-form-item) {
display: block; display: block;
margin-bottom: 8px; margin-bottom: 8px;

View File

@ -26,7 +26,6 @@ import {
onBeforeMount onBeforeMount
} from 'vue' } from 'vue'
import { imgUrlTrans } from '@/data-visualization/utils/imgUtils' import { imgUrlTrans } from '@/data-visualization/utils/imgUtils'
import eventBus from '@/data-visualization/utils/eventBus'
import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain'
import { getData } from '@/api/data-visualization/chart' import { getData } from '@/api/data-visualization/chart'
import { parseJson } from '@/data-visualization/chart/components/js/util' import { parseJson } from '@/data-visualization/chart/components/js/util'
@ -35,7 +34,7 @@ import { storeToRefs } from 'pinia'
import ChartEmptyInfo from '@/data-visualization/chart/components/views/components/ChartEmptyInfo.vue' import ChartEmptyInfo from '@/data-visualization/chart/components/views/components/ChartEmptyInfo.vue'
import ChartError from '@/data-visualization/chart/components/views/components/ChartError.vue' import ChartError from '@/data-visualization/chart/components/views/components/ChartError.vue'
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { canvasViewInfo, editMode, mobileInPc, canvasStyleData } = storeToRefs(dvMainStore) const { canvasViewInfo, mobileInPc, fullscreenFlag } = storeToRefs(dvMainStore)
const state = reactive({ const state = reactive({
emptyValue: '-', emptyValue: '-',
data: null, data: null,
@ -77,7 +76,9 @@ const dataRowFiledName = ref([])
let carouselTimer = null let carouselTimer = null
const { element, view, showPosition } = toRefs(props) const { element, view, showPosition } = toRefs(props)
const isEditMode = computed(() => showPosition.value.includes('canvas') && !mobileInPc.value) const isEditMode = computed(
() => showPosition.value.includes('canvas') && !mobileInPc.value && !fullscreenFlag.value
)
watch( watch(
() => isEditMode.value, () => isEditMode.value,
@ -121,12 +122,6 @@ const imageAdapter = computed(() => {
return style as CSSProperties return style as CSSProperties
}) })
const uploadImg = () => {
nextTick(() => {
eventBus.emit('uploadImg')
})
}
const initCurFields = chartDetails => { const initCurFields = chartDetails => {
dataRowFiledName.value = [] dataRowFiledName.value = []
dataRowSelect.value = {} dataRowSelect.value = {}
@ -146,7 +141,7 @@ const initCurFields = chartDetails => {
dataRowFiledName.value.push(`[记录数*]`) dataRowFiledName.value.push(`[记录数*]`)
} }
const sourceFieldNameIdMap = chartDetails.data.fields.reduce((pre, next) => { const sourceFieldNameIdMap = chartDetails.data.fields.reduce((pre, next) => {
pre[next['dataeaseName']] = next['name'] pre[next['gisbiName']] = next['name']
return pre return pre
}, {}) }, {})
const rowData = chartDetails.data.tableRow[0] const rowData = chartDetails.data.tableRow[0]
@ -251,7 +246,7 @@ const calcData = (viewCalc: Chart, callback) => {
} }
// //
const renderChart = viewInfo => { const renderChart = () => {
//do renderView //do renderView
} }

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { snapshotStoreWithOut } from '@/data-visualization/store/modules/data-visualization/snapshot' import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { ElIcon, ElMessage } from 'element-plus-secondary' import { ElIcon, ElMessage } from 'element-plus-secondary'
@ -42,14 +42,13 @@ const dialogImageUrl = ref('')
const dialogVisible = ref(false) const dialogVisible = ref(false)
const uploadDisabled = ref(false) const uploadDisabled = ref(false)
const files = ref(null) const files = ref(null)
const maxImageSize = 15000000
const handlePictureCardPreview = file => { const handlePictureCardPreview = file => {
dialogImageUrl.value = file.url dialogImageUrl.value = file.url
dialogVisible.value = true dialogVisible.value = true
} }
const handleRemove = (file, fileListArray) => { const handleRemove = file => {
uploadDisabled.value = false uploadDisabled.value = false
let file_static_part = file.url.split('static-resource/')[1] let file_static_part = file.url.split('static-resource/')[1]
let index = element.value.propValue['urlList'].findIndex( let index = element.value.propValue['urlList'].findIndex(
@ -62,13 +61,13 @@ const handleRemove = (file, fileListArray) => {
snapshotStore.recordSnapshotCache('picture-handleRemove') snapshotStore.recordSnapshotCache('picture-handleRemove')
} }
async function upload(file) { async function upload(file) {
// if (element.value.propValue.urlList.length < 10) { if (element.value.propValue.urlList.length < 10) {
// uploadFileResult(file.file, fileUrl => { uploadFileResult(file.file, fileUrl => {
// snapshotStore.recordSnapshotCache('pic-upload') snapshotStore.recordSnapshotCache('pic-upload')
// element.value.propValue.urlList.unshift({ name: file.file.name, url: fileUrl }) element.value.propValue.urlList.unshift({ name: file.file.name, url: fileUrl })
// useEmitt().emitter.emit('calcData-' + element.value.id) useEmitt().emitter.emit('calcData-' + element.value.id)
// }) })
// } }
} }
const onStyleChange = () => { const onStyleChange = () => {
@ -79,10 +78,6 @@ const goFile = () => {
files.value.click() files.value.click()
} }
const sizeMessage = () => {
ElMessage.success('图片大小不符合')
}
const fileListInit = () => { const fileListInit = () => {
fileList.value = [] fileList.value = []
if (element.value.propValue.urlList && element.value.propValue.urlList.length > 0) { if (element.value.propValue.urlList && element.value.propValue.urlList.length > 0) {
@ -95,10 +90,6 @@ const init = () => {
fileListInit() fileListInit()
} }
const toolTip = computed(() => {
return props.themes === 'dark' ? 'ndark' : 'dark'
})
watch( watch(
() => element.value.propValue['urlList'], () => element.value.propValue['urlList'],
() => { () => {

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import CommonAttr from '@/data-visualization/custom-component/common/CommonAttr.vue' import CommonAttr from '@/custom-component/common/CommonAttr.vue'
import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { snapshotStoreWithOut } from '@/data-visualization/store/modules/data-visualization/snapshot' import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { ElIcon, ElMessage } from 'element-plus-secondary' import { ElIcon, ElMessage } from 'element-plus-secondary'
@ -13,7 +13,7 @@ import ImgViewDialog from '@/data-visualization/custom-component/ImgViewDialog.v
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/data-visualization/hooks/web/useI18n'
const { t } = useI18n() const { t } = useI18n()
const props = defineProps({ defineProps({
themes: { themes: {
type: String as PropType<EditorTheme>, type: String as PropType<EditorTheme>,
default: 'dark' default: 'dark'
@ -31,7 +31,6 @@ const dialogVisible = ref(false)
const uploadDisabled = ref(false) const uploadDisabled = ref(false)
const files = ref(null) const files = ref(null)
const maxImageSize = 15000000 const maxImageSize = 15000000
const state = reactive({})
const handlePictureCardPreview = file => { const handlePictureCardPreview = file => {
dialogImageUrl.value = file.url dialogImageUrl.value = file.url
@ -45,10 +44,10 @@ const handleRemove = (_, fileList) => {
snapshotStore.recordSnapshotCache('handleRemove') snapshotStore.recordSnapshotCache('handleRemove')
} }
async function upload(file) { async function upload(file) {
// uploadFileResult(file.file, fileUrl => { uploadFileResult(file.file, fileUrl => {
// snapshotStore.recordSnapshotCache('pic-upload') snapshotStore.recordSnapshotCache('pic-upload')
// curComponent.value.propValue.url = fileUrl curComponent.value.propValue.url = fileUrl
// }) })
} }
const onStyleChange = () => { const onStyleChange = () => {
@ -60,20 +59,20 @@ const goFile = () => {
} }
const reUpload = e => { const reUpload = e => {
// const file = e.target.files[0] const file = e.target.files[0]
// if (file.size > maxImageSize) { if (file.size > maxImageSize) {
// sizeMessage() sizeMessage()
// return return
// } }
// uploadFileResult(file, fileUrl => { uploadFileResult(file, fileUrl => {
// snapshotStore.recordSnapshotCache('uploadFileResult') snapshotStore.recordSnapshotCache('uploadFileResult')
// curComponent.value.propValue.url = fileUrl curComponent.value.propValue.url = fileUrl
// fileList.value = [{ url: imgUrlTrans(curComponent.value.propValue.url) }] fileList.value = [{ url: imgUrlTrans(curComponent.value.propValue.url) }]
// }) })
} }
const sizeMessage = () => { const sizeMessage = () => {
ElMessage.success('图片大小不符合') ElMessage.success('图片大小不能超过15M')
} }
const init = () => { const init = () => {
if (curComponent.value.propValue.url) { if (curComponent.value.propValue.url) {
@ -83,10 +82,6 @@ const init = () => {
} }
} }
const toolTip = computed(() => {
return props.themes === 'dark' ? 'ndark' : 'dark'
})
watch( watch(
() => curComponent.value.propValue.url, () => curComponent.value.propValue.url,
() => { () => {
@ -132,7 +127,7 @@ onBeforeUnmount(() => {
> >
<el-row class="img-area" :class="`img-area_${themes}`"> <el-row class="img-area" :class="`img-area_${themes}`">
<el-col style="width: 130px !important"> <el-col style="width: 130px !important">
<!-- <el-upload <el-upload
:themes="themes" :themes="themes"
action="" action=""
accept=".jpeg,.jpg,.png,.gif,.svg" accept=".jpeg,.jpg,.png,.gif,.svg"
@ -146,7 +141,7 @@ onBeforeUnmount(() => {
:file-list="fileList" :file-list="fileList"
> >
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
</el-upload> --> </el-upload>
<img-view-dialog v-model="dialogVisible" :image-url="dialogImageUrl"></img-view-dialog> <img-view-dialog v-model="dialogVisible" :image-url="dialogImageUrl"></img-view-dialog>
</el-col> </el-col>
</el-row> </el-row>

View File

@ -42,6 +42,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, toRefs } from 'vue' import { computed, onBeforeUnmount, onMounted, ref, toRefs } from 'vue'
import { findDragComponent } from '@/data-visualization/utils/canvasUtils' import { findDragComponent } from '@/data-visualization/utils/canvasUtils'
import { guid } from '@/data-visualization/guid/util'
import { changeComponentSizeWithScale } from '@/data-visualization/utils/changeComponentsSizeWithScale' import { changeComponentSizeWithScale } from '@/data-visualization/utils/changeComponentsSizeWithScale'
import { adaptCurThemeCommonStyle } from '@/data-visualization/utils/canvasStyle' import { adaptCurThemeCommonStyle } from '@/data-visualization/utils/canvasStyle'
import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain'
@ -117,7 +118,7 @@ const handleDragOver = e => {
e.dataTransfer.dropEffect = 'copy' e.dataTransfer.dropEffect = 'copy'
} }
const handleDragLeave = e => { const handleDragLeave = () => {
areaActive.value = false areaActive.value = false
} }
@ -133,7 +134,7 @@ const handleDrop = e => {
if (component.component === 'VQuery') { if (component.component === 'VQuery') {
component.style.top = 0 component.style.top = 0
component.style.left = 0 component.style.left = 0
component.id = Math.random(); component.id = guid()
component.category = 'hidden' component.category = 'hidden'
component.commonBackground.backgroundColor = 'rgba(41, 41, 41, 1)' component.commonBackground.backgroundColor = 'rgba(41, 41, 41, 1)'
changeComponentSizeWithScale(component) changeComponentSizeWithScale(component)
@ -141,7 +142,7 @@ const handleDrop = e => {
adaptCurThemeCommonStyle(component) adaptCurThemeCommonStyle(component)
snapshotStore.recordSnapshotCache('renderChart', component.id) snapshotStore.recordSnapshotCache('renderChart', component.id)
} else { } else {
ElMessage.error('及支持添加查询组件') ElMessage.error(t('visualization.support_query'))
} }
} }
} }

View File

@ -219,7 +219,7 @@ const init = ref({
}) })
// mouseup // mouseup
doc.addEventListener('mouseup', event => { doc.addEventListener('mouseup', () => {
if (cloneHandle) { if (cloneHandle) {
// //
originalHandle.style.display = '' originalHandle.style.display = ''
@ -371,7 +371,7 @@ const jumpTargetAdaptor = () => {
const assignment = content => { const assignment = content => {
if (content) { if (content) {
const on = content?.match(/\[(.+?)\]/g) const on = content?.match(/\[(.+?)\]/g) || []
if (on) { if (on) {
const thresholdStyleInfo = conditionAdaptor(state.viewDataInfo) const thresholdStyleInfo = conditionAdaptor(state.viewDataInfo)
on.forEach(itm => { on.forEach(itm => {
@ -630,25 +630,25 @@ const initCurFields = chartDetails => {
} }
// Get the corresponding relationship between id and value // Get the corresponding relationship between id and value
const nameIdMap = chartDetails.data.fields.reduce((pre, next) => { const nameIdMap = chartDetails.data.fields.reduce((pre, next) => {
pre[next['dataeaseName']] = next['id'] pre[next['gisbiName']] = next['id']
return pre return pre
}, {}) }, {})
const sourceFieldNameIdMap = chartDetails.data.fields.reduce((pre, next) => { const sourceFieldNameIdMap = chartDetails.data.fields.reduce((pre, next) => {
pre[next['dataeaseName']] = next['name'] pre[next['gisbiName']] = next['name']
return pre return pre
}, {}) }, {})
const rowData = chartDetails.data.tableRow[0] const rowData = chartDetails.data.tableRow[0]
if (chartDetails.type === 'rich-text') { if (chartDetails.type === 'rich-text') {
let yAxis = JSON.parse(JSON.stringify(chartDetails.yAxis)) let yAxis = JSON.parse(JSON.stringify(chartDetails.yAxis))
const yDataeaseNames = [] const ygisbiNames = []
const yDataeaseNamesCfg = [] const ygisbiNamesCfg = []
yAxis.forEach(yItem => { yAxis.forEach(yItem => {
yDataeaseNames.push(yItem.dataeaseName) ygisbiNames.push(yItem.gisbiName)
yDataeaseNamesCfg[yItem.dataeaseName] = yItem.formatterCfg ygisbiNamesCfg[yItem.gisbiName] = yItem.formatterCfg
}) })
} }
const valueFieldMap: Record<string, Axis> = chartDetails.yAxis.reduce((p, n) => { const valueFieldMap: Record<string, Axis> = chartDetails.yAxis.reduce((p, n) => {
p[n.dataeaseName] = n p[n.gisbiName] = n
return p return p
}, {}) }, {})
for (const key in rowData) { for (const key in rowData) {

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import CommonAttr from '@/data-visualization/custom-component/common/CommonAttr.vue' import CommonAttr from '@/custom-component/common/CommonAttr.vue'
import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { toRefs } from 'vue' import { toRefs } from 'vue'
@ -37,9 +37,6 @@ const { themes } = toRefs(props)
font-size: 12px !important; font-size: 12px !important;
font-weight: 400 !important; font-weight: 400 !important;
} }
:deep(.ed-collapse-item__content) {
padding: 16px !important;
}
:deep(.ed-form-item) { :deep(.ed-form-item) {
display: block; display: block;
margin-bottom: 8px; margin-bottom: 8px;

View File

@ -42,7 +42,7 @@ const props = defineProps({
const { element, showPosition } = toRefs(props) const { element, showPosition } = toRefs(props)
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { editMode, curComponent, canvasStyleData } = storeToRefs(dvMainStore) const { editMode, curComponent } = storeToRefs(dvMainStore)
const onComponentClick = () => { const onComponentClick = () => {
if (curComponent.value.id !== element.value.id) { if (curComponent.value.id !== element.value.id) {

View File

@ -4,6 +4,11 @@ import Chart from '@/data-visualization/chart/components/views/index.vue'
import { isISOMobile } from '@/data-visualization/utils/utils' import { isISOMobile } from '@/data-visualization/utils/utils'
const props = defineProps({ const props = defineProps({
//
commonParams: {
type: Object,
required: false
},
active: { active: {
type: Boolean, type: Boolean,
default: false default: false
@ -70,6 +75,7 @@ const props = defineProps({
required: false required: false
} }
}) })
const { element, view, active, searchCount, scale } = toRefs(props) const { element, view, active, searchCount, scale } = toRefs(props)
const autoStyle = computed(() => { const autoStyle = computed(() => {
if (element.value.innerType === 'rich-text') { if (element.value.innerType === 'rich-text') {
@ -89,7 +95,7 @@ const autoStyle = computed(() => {
return {} return {}
} }
}) })
const emits = defineEmits(['onPointClick']) const emits = defineEmits(['onPointClick', 'onComponentEvent'])
const onPointClick = param => { const onPointClick = param => {
emits('onPointClick', param) emits('onPointClick', param)
@ -108,7 +114,9 @@ const onPointClick = param => {
:disabled="disabled" :disabled="disabled"
:suffixId="suffixId" :suffixId="suffixId"
:font-family="fontFamily" :font-family="fontFamily"
:common-params="commonParams"
@onPointClick="onPointClick" @onPointClick="onPointClick"
@onComponentEvent="() => emits('onComponentEvent')"
:opt-type="optType" :opt-type="optType"
></chart> ></chart>
</div> </div>

View File

@ -2,7 +2,10 @@
import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg' import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg'
import icon_deleteTrash_outlined from '@/assets/svg/icon_delete-trash_outlined.svg' import icon_deleteTrash_outlined from '@/assets/svg/icon_delete-trash_outlined.svg'
import eventBus from '@/data-visualization/utils/eventBus' import eventBus from '@/data-visualization/utils/eventBus'
import colorFunctions from 'less/lib/less/functions/color.js'
import colorTree from 'less/lib/less/tree/color.js'
import { isISOMobile, isMobile } from '@/data-visualization/utils/utils' import { isISOMobile, isMobile } from '@/data-visualization/utils/utils'
import { cloneDeep } from 'lodash-es'
import { ElMessage } from 'element-plus-secondary' import { ElMessage } from 'element-plus-secondary'
import { snapshotStoreWithOut } from '@/data-visualization/store/modules/data-visualization/snapshot' import { snapshotStoreWithOut } from '@/data-visualization/store/modules/data-visualization/snapshot'
import QueryConditionConfiguration from './QueryConditionConfiguration.vue' import QueryConditionConfiguration from './QueryConditionConfiguration.vue'
@ -23,10 +26,10 @@ import {
nextTick nextTick
} from 'vue' } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { comInfo } from './com-info' import { comInfo } from './com-info'
// import { useEmitt } from '@/data-visualization/hooks/web/useEmitt' import { useEmitt } from '@/data-visualization/hooks/web/useEmitt'
import StyleInject from './StyleInject.vue' import StyleInject from './StyleInject.vue'
const props = defineProps({ const props = defineProps({
view: { view: {
@ -61,7 +64,8 @@ const { element, view, scale } = toRefs(props)
const { t } = useI18n() const { t } = useI18n()
const vQueryRef = ref() const vQueryRef = ref()
const dvMainStore = dvMainStoreWithOut() const dvMainStore = dvMainStoreWithOut()
const { curComponent, canvasViewInfo, mobileInPc, firstLoadMap } = storeToRefs(dvMainStore) const { curComponent, canvasViewInfo, mobileInPc, firstLoadMap, editMode } =
storeToRefs(dvMainStore)
const canEdit = ref(false) const canEdit = ref(false)
const queryConfig = ref() const queryConfig = ref()
const defaultStyle = { const defaultStyle = {
@ -88,16 +92,18 @@ const defaultStyle = {
queryConditionWidth: 227, queryConditionWidth: 227,
nameboxSpacing: 8, nameboxSpacing: 8,
queryConditionSpacing: 16, queryConditionSpacing: 16,
queryConditionHeight: 32,
btnColor: '#3370ff', btnColor: '#3370ff',
labelColorBtn: '#ffffff' labelColorBtn: '#ffffff'
} }
const customStyle = reactive({ ...defaultStyle }) const customStyle = reactive({ ...defaultStyle })
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const userAgent = navigator.userAgent.toLowerCase()
//
const isFeiShu = /lark/i.test(userAgent)
const btnStyle = computed(() => { const btnStyle = computed(() => {
const style = { const style = {
backgroundColor: customStyle.btnColor,
borderColor: customStyle.btnColor,
color: customStyle.labelColorBtn color: customStyle.labelColorBtn
} as CSSProperties } as CSSProperties
if (customStyle.fontSizeBtn) { if (customStyle.fontSizeBtn) {
@ -115,6 +121,76 @@ const btnStyle = computed(() => {
return style return style
}) })
function rgbaTo16color(color) {
let val = color
.replace(/rgba?\(/, '')
.replace(/\)/, '')
.replace(/[\s+]/g, '')
.split(',')
let a = parseFloat(val[3] || 1),
r = Math.floor(a * parseInt(val[0]) + (1 - a) * 255),
g = Math.floor(a * parseInt(val[1]) + (1 - a) * 255),
b = Math.floor(a * parseInt(val[2]) + (1 - a) * 255)
return (
'#' +
('0' + r.toString(16)).slice(-2) +
('0' + g.toString(16)).slice(-2) +
('0' + b.toString(16)).slice(-2)
)
}
const btnHoverStyle = computed(() => {
let btnColor = customStyle.btnColor
if (customStyle.btnColor.startsWith('rgb')) {
btnColor = rgbaTo16color(customStyle.btnColor)
}
if (btnColor.startsWith('#')) {
btnColor = btnColor.substr(1)
}
return {
rawColor: customStyle.btnColor ?? '#3370ff',
hoverColor: customStyle.btnColor
? colorFunctions
.mix(new colorTree('ffffff'), new colorTree(btnColor), {
value: 15
})
.toRGB()
: '#5285FF',
activeColor: customStyle.btnColor
? colorFunctions
.mix(new colorTree('000000'), new colorTree(btnColor), {
value: 15
})
.toRGB()
: '#2B5FD9'
}
})
const btnPrimaryColor = computed(() => {
return btnHoverStyle.value.rawColor
})
const btnPrimaryHoverColor = computed(() => {
return btnHoverStyle.value.hoverColor
})
const btnPrimaryActiveColor = computed(() => {
return btnHoverStyle.value.activeColor
})
const tagColor = computed(() => {
if (customStyle.background && !customStyle.background.toLowerCase().includes('#ffffff')) {
return colorFunctions
.mix(new colorTree('ffffff'), new colorTree(customStyle.background.substr(1)), {
value: 15
})
.toRGB()
}
return '#f0f2f5'
})
const btnPlainStyle = computed(() => { const btnPlainStyle = computed(() => {
const style = { const style = {
backgroundColor: 'transparent', backgroundColor: 'transparent',
@ -162,6 +238,7 @@ const setCustomStyle = val => {
queryConditionWidth, queryConditionWidth,
nameboxSpacing, nameboxSpacing,
queryConditionSpacing, queryConditionSpacing,
queryConditionHeight,
labelColorBtn, labelColorBtn,
btnColor, btnColor,
placeholderSize, placeholderSize,
@ -195,6 +272,7 @@ const setCustomStyle = val => {
customStyle.queryConditionWidth = queryConditionWidth ?? 227 customStyle.queryConditionWidth = queryConditionWidth ?? 227
customStyle.nameboxSpacing = nameboxSpacing ?? 8 customStyle.nameboxSpacing = nameboxSpacing ?? 8
customStyle.queryConditionSpacing = queryConditionSpacing ?? 16 customStyle.queryConditionSpacing = queryConditionSpacing ?? 16
customStyle.queryConditionHeight = queryConditionHeight ?? 32
customStyle.labelColorBtn = labelColorBtn || '#ffffff' customStyle.labelColorBtn = labelColorBtn || '#ffffff'
customStyle.labelShow = labelShow ?? true customStyle.labelShow = labelShow ?? true
customStyle.btnColor = btnColor || '#3370ff' customStyle.btnColor = btnColor || '#3370ff'
@ -241,16 +319,81 @@ const onComponentClick = () => {
} }
} }
// const { emitter } = useEmitt() const { emitter } = useEmitt()
const unMountSelect = shallowRef([]) const unMountSelect = shallowRef([])
onBeforeMount(() => { onBeforeMount(() => {
unMountSelect.value = list.value.map(ele => ele.id) unMountSelect.value = list.value.map(ele => ele.id)
;(props.element.cascade || []).forEach(ele => {
ele.forEach(item => {
item.currentSelectValue = item.selectValue
})
})
}) })
const releaseSelect = id => { const releaseSelect = id => {
unMountSelect.value = unMountSelect.value.filter(ele => ele !== id) unMountSelect.value = unMountSelect.value.filter(ele => ele !== id)
} }
const getKeyList = next => {
let checkedFieldsMapArr = Object.entries(next.checkedFieldsMap).filter(ele =>
next.checkedFields.includes(ele[0])
)
if (next.displayType === '9') {
checkedFieldsMapArr = (
next.treeCheckedList?.length
? next.treeCheckedList.filter((_, index) => index < next.treeFieldList.length)
: next.treeFieldList.map(() => {
return {
checkedFields: [...next.checkedFields],
checkedFieldsMap: cloneDeep(next.checkedFieldsMap)
}
})
)
.map(item =>
Object.entries(item.checkedFieldsMap).filter(ele => item.checkedFields.includes(ele[0]))
)
.flat()
}
return checkedFieldsMapArr.filter(ele => !!ele[1]).map(ele => ele[0])
}
const fillRequireVal = arr => {
element.value.propValue.forEach(next => {
if (arr.some(itx => next.checkedFields.includes(itx)) && next.required) {
if (next.displayType === '8') {
const { conditionValueF, conditionValueS, conditionType } = next
if (conditionType === 0 && conditionValueF === '') {
next.conditionValueF = next.defaultConditionValueF
} else if (conditionValueF === '' || conditionValueS === '') {
next.conditionValueF = next.defaultConditionValueF
next.conditionValueS = next.defaultConditionValueS
}
} else if (next.displayType === '22') {
if (
(next.numValueStart !== 0 && !next.numValueStart) ||
(next.numValueEnd !== 0 && !next.numValueEnd)
) {
next.numValueStart = next.defaultNumValueStart
next.numValueEnd = next.defaultNumValueEnd
}
} else if (
(Array.isArray(next.selectValue) && !next.selectValue.length) ||
(next.selectValue !== 0 && !next.selectValue)
) {
if (
next.optionValueSource === 1 &&
(next.defaultMapValue?.length || next.displayId) &&
![1, 7].includes(+next.displayType)
) {
next.mapValue = next.defaultMapValue
next.selectValue = next.multiple ? next.defaultMapValue : next.defaultMapValue[0]
} else {
next.selectValue = next.defaultValue
}
}
}
})
}
const queryDataForId = id => { const queryDataForId = id => {
let requiredName = '' let requiredName = ''
let numName = '' let numName = ''
@ -302,10 +445,8 @@ const queryDataForId = id => {
requiredName = next.name requiredName = next.name
} }
} }
const keyList = Object.entries(next.checkedFieldsMap)
.filter(ele => next.checkedFields.includes(ele[0])) const keyList = getKeyList(next)
.filter(ele => !!ele[1])
.map(ele => ele[0])
pre = [...new Set([...keyList, ...pre])] pre = [...new Set([...keyList, ...pre])]
return pre return pre
}, []) }, [])
@ -318,6 +459,7 @@ const queryDataForId = id => {
return return
} }
if (!emitterList.length) return if (!emitterList.length) return
fillRequireVal(emitterList)
emitterList.forEach(ele => { emitterList.forEach(ele => {
emitter.emit(`query-data-${ele}`) emitter.emit(`query-data-${ele}`)
}) })
@ -486,15 +628,11 @@ const resetData = () => {
item.currentSelectValue = Array.isArray(next.selectValue) item.currentSelectValue = Array.isArray(next.selectValue)
? next.selectValue ? next.selectValue
: [next.selectValue].filter(itx => ![null, undefined].includes(itx)) : [next.selectValue].filter(itx => ![null, undefined].includes(itx))
// useEmitt().emitter.emit(`${item.datasetId.split('--')[1]}-select`) useEmitt().emitter.emit(`${item.datasetId.split('--')[1]}-select`)
} }
}) })
}) })
const keyList = getKeyList(next)
const keyList = Object.entries(next.checkedFieldsMap)
.filter(ele => next.checkedFields.includes(ele[0]))
.filter(ele => !!ele[1])
.map(ele => ele[0])
pre = [...new Set([...keyList, ...pre])] pre = [...new Set([...keyList, ...pre])]
return pre return pre
}, []) }, [])
@ -505,7 +643,7 @@ const clearData = () => {
;(props.element.cascade || []).forEach(ele => { ;(props.element.cascade || []).forEach(ele => {
ele.forEach(item => { ele.forEach(item => {
if (item.currentSelectValue?.length) { if (item.currentSelectValue?.length) {
// useEmitt().emitter.emit(`${item.datasetId.split('--')[1]}-select`) useEmitt().emitter.emit(`${item.datasetId.split('--')[1]}-select`)
item.currentSelectValue = [] item.currentSelectValue = []
} }
}) })
@ -525,10 +663,7 @@ const clearData = () => {
next.numValueEnd = undefined next.numValueEnd = undefined
next.numValueStart = undefined next.numValueStart = undefined
} }
const keyList = Object.entries(next.checkedFieldsMap) const keyList = getKeyList(next)
.filter(ele => next.checkedFields.includes(ele[0]))
.filter(ele => !!ele[1])
.map(ele => ele[0])
pre = [...new Set([...keyList, ...pre])] pre = [...new Set([...keyList, ...pre])]
return pre return pre
}, []) }, [])
@ -558,6 +693,10 @@ const boxWidth = computed(() => {
return `${customStyle.placeholderSize}px` return `${customStyle.placeholderSize}px`
}) })
const boxHeight = computed(() => {
return `${customStyle.queryConditionHeight || 32}px`
})
const queryData = () => { const queryData = () => {
let requiredName = '' let requiredName = ''
let numName = '' let numName = ''
@ -607,10 +746,7 @@ const queryData = () => {
requiredName = next.name requiredName = next.name
} }
} }
const keyList = Object.entries(next.checkedFieldsMap) const keyList = getKeyList(next)
.filter(ele => next.checkedFields.includes(ele[0]))
.filter(ele => !!ele[1])
.map(ele => ele[0])
pre = [...new Set([...keyList, ...pre])] pre = [...new Set([...keyList, ...pre])]
return pre return pre
}, []) }, [])
@ -657,20 +793,24 @@ const labelStyle = computed(() => {
return style return style
}) })
const comLayout = computed(() => {
return customStyle.labelShow ? customStyle.layout : 'horizontal'
})
const paddingTop = computed<CSSProperties>(() => { const paddingTop = computed<CSSProperties>(() => {
return { return {
paddingTop: customStyle.layout !== 'horizontal' ? customStyle.nameboxSpacing + 22 + 'px' : '0' paddingTop: comLayout.value !== 'horizontal' ? customStyle.nameboxSpacing + 22 + 'px' : '0'
} }
}) })
const marginRight = computed<CSSProperties>(() => { const marginRight = computed<CSSProperties>(() => {
return { return {
marginRight: customStyle.layout === 'horizontal' ? customStyle.nameboxSpacing + 'px' : '8px' marginRight: comLayout.value === 'horizontal' ? customStyle.nameboxSpacing + 'px' : '8px'
} }
}) })
const autoStyle = computed(() => { const autoStyle = computed(() => {
if (isISOMobile()) { if (isISOMobile() || isFeiShu) {
return { return {
position: 'absolute', position: 'absolute',
height: 100 / scale.value + '%!important', height: 100 / scale.value + '%!important',
@ -691,11 +831,7 @@ const autoStyle = computed(() => {
{{ customStyle.title }} {{ customStyle.title }}
</p> </p>
<div <div
:class="[ :class="['v-query', comLayout, customStyle.titleShow && !!customStyle.title && 'title-show']"
'v-query',
customStyle.layout,
customStyle.titleShow && !!customStyle.title && 'title-show'
]"
@dragover.prevent.stop="dragover" @dragover.prevent.stop="dragover"
@drop.prevent.stop="drop" @drop.prevent.stop="drop"
> >
@ -703,7 +839,7 @@ const autoStyle = computed(() => {
<div class="container flex-align-center"> <div class="container flex-align-center">
{{ t('v_query.here_or_click') }} {{ t('v_query.here_or_click') }}
<el-button <el-button
:disabled="showPosition === 'preview' || mobileInPc" :disabled="showPosition === 'preview' || mobileInPc || editMode === 'preview'"
@click="addCriteriaConfigOut" @click="addCriteriaConfigOut"
style="font-family: inherit" style="font-family: inherit"
text text
@ -737,7 +873,9 @@ const autoStyle = computed(() => {
</div> </div>
<div <div
class="label-wrapper-tooltip" class="label-wrapper-tooltip"
v-if="showPosition !== 'preview' && !dvMainStore.mobileInPc" v-if="
showPosition !== 'preview' && !dvMainStore.mobileInPc && editMode !== 'preview'
"
> >
<el-tooltip <el-tooltip
effect="dark" effect="dark"
@ -813,11 +951,46 @@ const autoStyle = computed(() => {
position: relative; position: relative;
--ed-font-size-base: v-bind(boxWidth); --ed-font-size-base: v-bind(boxWidth);
:deep(.ed-select-v2 .ed-select-v2__selection .ed-tag),
:deep(.select-trigger .ed-select__tags .ed-tag) {
background-color: v-bind(tagColor);
}
:deep(.ed-input),
:deep(.ed-date-editor) {
--ed-input-height: v-bind(boxHeight);
}
:deep(.ed-select__wrapper),
:deep(.text-search-select .ed-input__wrapper),
:deep(.text-search-select .ed-select__wrapper) {
height: v-bind(boxHeight);
}
.ed-button--primary {
--ed-button-bg-color: v-bind(btnHoverStyle.rawColor);
--ed-button-border-color: v-bind(btnHoverStyle.rawColor);
--ed-button-hover-border-color: v-bind(btnHoverStyle.hoverColor);
--ed-button-hover-bg-color: v-bind(btnHoverStyle.hoverColor);
background-color: v-bind(btnPrimaryColor);
}
.ed-button--primary.ed-button--primary.ed-button--primary:hover,
.ed-button--primary.ed-button--primary.ed-button--primary:focus {
background-color: v-bind(btnPrimaryHoverColor);
}
.ed-button--primary.ed-button--primary.ed-button--primary:active {
background-color: v-bind(btnPrimaryActiveColor);
border-color: v-bind(btnPrimaryHoverColor);
}
:deep(.ed-tag) { :deep(.ed-tag) {
--ed-tag-font-size: v-bind(boxWidth); --ed-tag-font-size: v-bind(boxWidth);
} }
:deep(.ed-select-v2) { :deep(.ed-select-v2),
:deep(.ed-select__wrapper) {
font-size: v-bind(boxWidth); font-size: v-bind(boxWidth);
} }
@ -1017,7 +1190,7 @@ const autoStyle = computed(() => {
.label-wrapper-tooltip { .label-wrapper-tooltip {
position: absolute; position: absolute;
right: 0; right: 0;
top: -26px; top: -21px;
z-index: 11; z-index: 11;
padding: 4px 8px; padding: 4px 8px;
height: 26px; height: 26px;

View File

@ -56,9 +56,19 @@ const props = defineProps({
}) })
const showFlag = computed(() => props.showPosition === 'main') const showFlag = computed(() => props.showPosition === 'main')
const { curComponent } = toRefs(props) const { curComponent } = toRefs(props)
const loadingDefault = ref(true)
watch(
() => curComponent.value.id,
val => {
if (!val) return
loadingDefault.value = false
nextTick(() => {
loadingDefault.value = true
})
},
{ immediate: true }
)
const relativeToCurrentTypeList = computed(() => { const relativeToCurrentTypeList = computed(() => {
if (!curComponent.value) return [] if (!curComponent.value) return []
let index = ['year', 'month', 'date', 'datetime'].indexOf(curComponent.value.timeGranularity) + 1 let index = ['year', 'month', 'date', 'datetime'].indexOf(curComponent.value.timeGranularity) + 1
@ -200,6 +210,10 @@ const relativeToCurrentListRange = computed(() => {
label: t('dynamic_month.last'), label: t('dynamic_month.last'),
value: 'lastMonth' value: 'lastMonth'
}, },
{
label: t('dynamic_time.tquarter'),
value: 'thisQuarter'
},
{ {
label: t('v_query.last_3_months'), label: t('v_query.last_3_months'),
value: 'LastThreeMonths' value: 'LastThreeMonths'
@ -225,6 +239,10 @@ const relativeToCurrentListRange = computed(() => {
label: t('dynamic_time.yesterday'), label: t('dynamic_time.yesterday'),
value: 'yesterday' value: 'yesterday'
}, },
{
label: t('dynamic_time.cweek'),
value: 'thisWeek'
},
{ {
label: t('v_query.last_3_days'), label: t('v_query.last_3_days'),
value: 'LastThreeDays' value: 'LastThreeDays'
@ -456,7 +474,8 @@ defineExpose({
</el-popover> </el-popover>
<span <span
v-if=" v-if="
curComponent.timeRange.intervalType !== 'none' || curComponent.timeRange.dynamicWindow curComponent.timeRange &&
(curComponent.timeRange.intervalType !== 'none' || curComponent.timeRange.dynamicWindow)
" "
class="config-flag range-filter-time-flag" class="config-flag range-filter-time-flag"
>{{ t('v_query.configured') }}</span >{{ t('v_query.configured') }}</span
@ -637,7 +656,11 @@ defineExpose({
</div> </div>
</template> </template>
</div> </div>
<div v-if="curComponent.defaultValueCheck" class="parameters" :class="dynamicTime && 'setting'"> <div
v-if="curComponent.defaultValueCheck && loadingDefault"
class="parameters"
:class="dynamicTime && 'setting'"
>
<div class="setting-label" v-if="dynamicTime">{{ t('template_manage.preview') }}</div> <div class="setting-label" v-if="dynamicTime">{{ t('template_manage.preview') }}</div>
<div :class="dynamicTime ? 'setting-value' : 'w100'"> <div :class="dynamicTime ? 'setting-value' : 'w100'">
<component :config="curComponent" isConfig ref="inputCom" :is="filterTypeCom"></component> <component :config="curComponent" isConfig ref="inputCom" :is="filterTypeCom"></component>
@ -874,6 +897,11 @@ defineExpose({
padding-left: 86px; padding-left: 86px;
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
width: 100%;
.ed-select {
--ed-select-width: 100px;
}
&.range { &.range {
padding-left: 0px; padding-left: 0px;
} }

View File

@ -1,4 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { ManipulateType } from 'dayjs'
import { toRefs, PropType, ref, onBeforeMount, watch, computed } from 'vue' import { toRefs, PropType, ref, onBeforeMount, watch, computed } from 'vue'
import { Calendar } from '@element-plus/icons-vue' import { Calendar } from '@element-plus/icons-vue'
import { type DatePickType } from 'element-plus-secondary' import { type DatePickType } from 'element-plus-secondary'
@ -22,7 +23,7 @@ interface SelectConfig {
defaultValueCheck: boolean defaultValueCheck: boolean
id: string id: string
timeNum: number timeNum: number
relativeToCurrentType: string relativeToCurrentType: ManipulateType
around: string around: string
arbitraryTime: Date arbitraryTime: Date
timeGranularity: DatePickType timeGranularity: DatePickType

View File

@ -3,7 +3,7 @@ import { toRefs, PropType, onBeforeMount, watch, computed } from 'vue'
import { Calendar } from '@element-plus/icons-vue' import { Calendar } from '@element-plus/icons-vue'
import { type DatePickType } from 'element-plus-secondary' import { type DatePickType } from 'element-plus-secondary'
import type { ManipulateType } from 'dayjs' import type { ManipulateType } from 'dayjs'
import { getThisStart, getLastStart, getAround } from './time-format-dayjs' import { getThisStart, getThisEnd, getLastStart, getAround } from './time-format-dayjs'
interface SelectConfig { interface SelectConfig {
intervalType: string intervalType: string
regularOrTrendsValue: Date regularOrTrendsValue: Date
@ -114,6 +114,9 @@ const init = () => {
case 'monthBeginning': case 'monthBeginning':
config.value.regularOrTrendsValue = getThisStart('month') config.value.regularOrTrendsValue = getThisStart('month')
break break
case 'monthEnd':
config.value.regularOrTrendsValue = getThisEnd('month')
break
case 'yearBeginning': case 'yearBeginning':
config.value.regularOrTrendsValue = getThisStart('year') config.value.regularOrTrendsValue = getThisStart('year')
break break

View File

@ -1,4 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { ManipulateType } from 'dayjs'
import { toRefs, PropType, ref, onBeforeMount, watch, computed } from 'vue' import { toRefs, PropType, ref, onBeforeMount, watch, computed } from 'vue'
import { type DatePickType } from 'element-plus-secondary' import { type DatePickType } from 'element-plus-secondary'
import { import {
@ -15,7 +16,7 @@ import {
interface SelectConfig { interface SelectConfig {
relativeToCurrent: string relativeToCurrent: string
timeNum: number timeNum: number
relativeToCurrentType: string relativeToCurrentType: ManipulateType
around: string around: string
arbitraryTime: Date arbitraryTime: Date
timeGranularity: DatePickType timeGranularity: DatePickType

View File

@ -1,4 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { ManipulateType } from 'dayjs'
import { toRefs, PropType, ref, onBeforeMount, watch, computed } from 'vue' import { toRefs, PropType, ref, onBeforeMount, watch, computed } from 'vue'
import { Calendar } from '@element-plus/icons-vue' import { Calendar } from '@element-plus/icons-vue'
import { type DatePickType } from 'element-plus-secondary' import { type DatePickType } from 'element-plus-secondary'
@ -13,12 +14,12 @@ interface SelectConfig {
id: string id: string
relativeToCurrentRange: string relativeToCurrentRange: string
timeNum: number timeNum: number
relativeToCurrentType: string relativeToCurrentType: ManipulateType
around: string around: string
arbitraryTime: Date arbitraryTime: Date
timeGranularity: DatePickType timeGranularity: DatePickType
timeNumRange: number timeNumRange: number
relativeToCurrentTypeRange: string relativeToCurrentTypeRange: ManipulateType
aroundRange: string aroundRange: string
arbitraryTimeRange: Date arbitraryTimeRange: Date
} }

View File

@ -1,10 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { DatePickType } from 'element-plus-secondary' import type { DatePickType } from 'element-plus-secondary'
import { toRefs, computed } from 'vue' import { toRefs, computed, watch } from 'vue'
import { type TimeRange } from './time-format' import { type TimeRange } from './time-format'
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/data-visualization/hooks/web/useI18n'
import DynamicTime from './DynamicTimeFiltering.vue' import DynamicTime from './DynamicTimeFiltering.vue'
import DynamicTimeRange from './DynamicTimeRangeFiltering.vue' import DynamicTimeRange from './DynamicTimeRangeFiltering.vue'
import { ManipulateType } from 'dayjs'
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
timeRange: TimeRange timeRange: TimeRange
@ -253,6 +254,35 @@ const relativeToCurrentListRange = computed(() => {
} }
] ]
}) })
watch(
() => relativeToCurrentListRange.value,
val => {
if (!val.some(ele => ele.value === timeRange.value.relativeToCurrentRange)) {
timeRange.value.relativeToCurrentRange = val[0].value
}
},
{ immediate: true }
)
watch(
() => relativeToCurrentList.value,
val => {
if (!val.some(ele => ele.value === timeRange.value.relativeToCurrent)) {
timeRange.value.relativeToCurrent = val[0].value
}
},
{ immediate: true }
)
watch(
() => relativeToCurrentTypeList.value,
val => {
if (!val.some(ele => ele.value === timeRange.value.relativeToCurrentType)) {
timeRange.value.relativeToCurrentType = val[0].value as ManipulateType
}
},
{ immediate: true }
)
</script> </script>
<template> <template>
@ -417,6 +447,9 @@ const relativeToCurrentListRange = computed(() => {
--ed-radio-input-height: 16px; --ed-radio-input-height: 16px;
--ed-radio-input-width: 16px; --ed-radio-input-width: 16px;
} }
.ed-select {
--ed-select-width: 100px;
}
.title { .title {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;

View File

@ -55,7 +55,7 @@ onBeforeMount(() => {
setParams() setParams()
}) })
const queryConditionWidth = inject('com-width', Function, true) const queryConditionWidth = inject('com-width', Function, true)
const customStyle = inject<{ background: string }>('$custom-style-filter') const customStyle = inject<{ background: string; border: string }>('$custom-style-filter')
const isConfirmSearch = inject('is-confirm-search', Function, true) const isConfirmSearch = inject('is-confirm-search', Function, true)
const getCustomWidth = () => { const getCustomWidth = () => {
@ -78,6 +78,10 @@ const handleValueChange = () => {
return return
} }
} }
const color = computed(() => {
return customStyle.border
})
</script> </script>
<template> <template>
@ -104,11 +108,18 @@ const handleValueChange = () => {
.num-search-select { .num-search-select {
display: flex; display: flex;
align-items: center; align-items: center;
border-radius: 4px;
.num-value_line { .num-value_line {
background: #1f2329; background: #1f2329;
width: 12px; width: 12px;
height: 1px; height: 1px;
margin: 0 8px; margin: 0 8px;
} }
:deep(.ed-input-number__increase),
:deep(.ed-input-number__decrease) {
background-color: transparent !important;
border-color: v-bind(color) !important;
}
} }
</style> </style>

View File

@ -24,10 +24,17 @@ import {
} from 'vue' } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { enumValueObj } from '@/api/data-visualization/dataset' import { enumValueObj } from '@/api/data-visualization/dataset'
import CustomSortFilter from './CustomSortFilter.vue'
import { addQueryCriteriaConfig } from './options' import { addQueryCriteriaConfig } from './options'
import { getCustomTime } from './time-format' import { getCustomTime } from './time-format'
import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain' import { dvMainStoreWithOut } from '@/data-visualization/store/modules/data-visualization/dvMain'
import { getThisStart, getLastStart, getAround, getCustomRange } from './time-format-dayjs' import {
getThisStart,
getThisEnd,
getLastStart,
getAround,
getCustomRange
} from './time-format-dayjs'
import { snapshotStoreWithOut } from '@/data-visualization/store/modules/data-visualization/snapshot' import { snapshotStoreWithOut } from '@/data-visualization/store/modules/data-visualization/snapshot'
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/data-visualization/hooks/web/useI18n'
import { fieldType } from '@/data-visualization/utils/attr' import { fieldType } from '@/data-visualization/utils/attr'
@ -38,7 +45,7 @@ import EmptyBackground from '@/data-visualization/components/empty-background/sr
import TreeFieldDialog from '@/data-visualization/custom-component/v-query/TreeFieldDialog.vue' import TreeFieldDialog from '@/data-visualization/custom-component/v-query/TreeFieldDialog.vue'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { getDatasetTree } from '@/api/data-visualization/dataset' import { getDatasetTree } from '@/api/data-visualization/dataset'
// import { Tree } from '@/views/visualized/data/dataset/form/CreatDsGroup.vue' // import { Tree } from '@/data-visualization/visualized/data/dataset/form/CreatDsGroup.vue'
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
import type { ManipulateType } from 'dayjs' import type { ManipulateType } from 'dayjs'
import dayjs from 'dayjs' import dayjs from 'dayjs'
@ -84,7 +91,6 @@ const activeConditionForRename = reactive({
}) })
const datasetMap = {} const datasetMap = {}
const snapshotStore = snapshotStoreWithOut() const snapshotStore = snapshotStoreWithOut()
const dfsComponentData = () => { const dfsComponentData = () => {
let arr = componentData.value.filter( let arr = componentData.value.filter(
com => !['VQuery', 'DeTabs'].includes(com.innerType) && com.component !== 'Group' com => !['VQuery', 'DeTabs'].includes(com.innerType) && com.component !== 'Group'
@ -98,6 +104,17 @@ const dfsComponentData = () => {
com => !['VQuery', 'DeTabs'].includes(com.innerType) && com.component !== 'Group' com => !['VQuery', 'DeTabs'].includes(com.innerType) && com.component !== 'Group'
) )
] ]
itx.componentData.forEach(j => {
if (j.component === 'Group') {
arr = [
...arr,
j.propValue.filter(
com => !['VQuery', 'DeTabs'].includes(com.innerType) && com.component !== 'Group'
)
]
}
})
}) })
} else if (ele.component === 'Group') { } else if (ele.component === 'Group') {
arr = [ arr = [
@ -261,22 +278,6 @@ const showTypeError = computed(() => {
}) })
}) })
const showDatasetError = computed(() => {
if (!curComponent.value || curComponent.value.displayType !== '9') return false
if (!curComponent.value.checkedFields?.length) return false
if (!fields.value?.length) return false
let displayField = null
return curComponent.value.checkedFields.some(id => {
const arr = fields.value.find(itx => itx.componentId === id)
const field = arr.id
if (!field) return false
if (displayField === null) {
displayField = field
return false
}
return displayField !== field
})
})
const typeList = [ const typeList = [
{ {
label: t('data_fill.rename'), label: t('data_fill.rename'),
@ -294,52 +295,6 @@ const handleCheckAllChange = (val: boolean) => {
val && setSameId() val && setSameId()
} }
const setTreeDefault = () => {
if (!!curComponent.value.checkedFields.length) {
let checkId = ''
let tableId = ''
let comId = ''
fields.value.forEach(ele => {
if (
curComponent.value.checkedFields.includes(ele.componentId) &&
curComponent.value.checkedFieldsMap[ele.componentId] &&
!checkId
) {
checkId = curComponent.value.checkedFieldsMap[ele.componentId]
comId = ele.componentId
tableId = datasetFieldList.value.find(itx => itx.id === ele.componentId)?.tableId
}
})
if (checkId && tableId) {
const componentObj = fields.value.find(ele => ele.componentId === comId)
const fieldArr =
curComponent.value.optionValueSource === 0
? componentObj?.fields?.dimensionList
: (fields.value.find(itx => itx.id === tableId) || {}).fields?.dimensionList
fields.value.forEach(ele => {
if (curComponent.value.checkedFields.includes(ele.componentId)) {
if (datasetFieldList.value.find(itx => itx.id === ele.componentId)?.tableId === tableId) {
curComponent.value.checkedFieldsMap[ele.componentId] = checkId
}
}
})
const fieldObj = fieldArr.find(element => element.id === checkId)
if (!!curComponent.value.treeFieldList.length) {
const [fir] = curComponent.value.treeFieldList
if (fir && fir.field !== checkId) {
const [top] = curComponent.value.treeFieldList || []
if (top?.id === fieldObj.id) return
curComponent.value.treeFieldList = [fieldObj]
}
} else if (fieldObj) {
const [top] = curComponent.value.treeFieldList || []
if (top?.id === fieldObj.id) return
curComponent.value.treeFieldList = [fieldObj]
}
}
}
}
const handleCheckedFieldsChange = (value: string[]) => { const handleCheckedFieldsChange = (value: string[]) => {
handleDialogClick() handleDialogClick()
const checkedCount = value.length const checkedCount = value.length
@ -386,10 +341,8 @@ const handleCheckedFieldsChangeTree = (value: string[]) => {
isIndeterminate.value = checkedCount > 0 && checkedCount < fields.value.length isIndeterminate.value = checkedCount > 0 && checkedCount < fields.value.length
setSameId() setSameId()
if (curComponent.value.displayType === '8') return if (curComponent.value.displayType === '8') return
if (curComponent.value.displayType === '9') {
setTreeDefault() setTreeDefault()
return setRelationBack()
}
setType() setType()
} }
@ -537,6 +490,44 @@ const timeTypeChange = () => {
timeDialogShow.value = false timeDialogShow.value = false
} }
const setTreeDefault = () => {
if (curComponent.value.displayType !== '9' || relationshipChartIndex.value !== 0) return
if (!!curComponent.value.checkedFields.length) {
let tableId = ''
fields.value.forEach(ele => {
if (
curComponent.value.checkedFields.includes(ele.componentId) &&
curComponent.value.checkedFieldsMap[ele.componentId] &&
!tableId
) {
tableId = datasetFieldList.value.find(itx => itx.id === ele.componentId)?.tableId
}
})
if (tableId && !curComponent.value.treeDatasetId) {
curComponent.value.treeDatasetId = tableId
getOptions(curComponent.value.treeDatasetId, curComponent.value)
}
}
}
const setTreeDefaultBatch = ele => {
if (!!ele.checkedFields.length) {
let tableId = ''
fields.value.forEach(ele => {
if (
ele.checkedFields.includes(ele.componentId) &&
ele.checkedFieldsMap[ele.componentId] &&
!tableId
) {
tableId = datasetFieldList.value.find(itx => itx.id === ele.componentId)?.tableId
}
})
if (tableId && !ele.treeDatasetId) {
ele.treeDatasetId = tableId
}
}
}
const numTypeChange = () => { const numTypeChange = () => {
if (!curComponent.value.checkedFieldsMapArrNum[currentComponentId]) { if (!curComponent.value.checkedFieldsMapArrNum[currentComponentId]) {
curComponent.value.checkedFieldsMapArrNum[currentComponentId] = [] curComponent.value.checkedFieldsMapArrNum[currentComponentId] = []
@ -742,9 +733,8 @@ const setParameters = field => {
if (notChangeType) return if (notChangeType) return
setType() setType()
if (curComponent.value.displayType === '9') {
setTreeDefault() setTreeDefault()
} setRelationBack()
} }
const setType = () => { const setType = () => {
@ -792,6 +782,27 @@ const setType = () => {
} }
} }
let oldDisplayType
const handleSetTypeChange = () => {
let displayType = curComponent.value.displayType
if (oldDisplayType === '9' && ['0', '8'].includes(displayType)) {
curComponent.value.displayType = '9'
ElMessageBox.confirm(t('common.changing_the_display'), {
confirmButtonType: 'primary',
type: 'warning',
cancelButtonText: t('common.cancel'),
autofocus: false,
showClose: false
}).then(() => {
curComponent.value.displayType = displayType
setTypeChange()
})
} else {
setTypeChange()
}
}
const setTypeChange = () => { const setTypeChange = () => {
handleDialogClick() handleDialogClick()
nextTick(() => { nextTick(() => {
@ -805,10 +816,13 @@ const setTypeChange = () => {
) { ) {
curComponent.value.timeGranularityMultiple = curComponent.value.timeGranularity curComponent.value.timeGranularityMultiple = curComponent.value.timeGranularity
} }
if (curComponent.value.displayType === '9') {
setTreeDefault() setTreeDefault()
setRelationBack()
if (curComponent.value.displayType === '0' && curComponent.value.treeFieldList?.length) {
curComponent.value.treeFieldList = []
curComponent.value.treeCheckedList = []
} }
oldDisplayType = curComponent.value.displayType
}) })
} }
@ -979,6 +993,14 @@ const handleDatasetChange = () => {
getOptions(curComponent.value.dataset.id, curComponent.value) getOptions(curComponent.value.dataset.id, curComponent.value)
} }
const handleDatasetTreeChange = () => {
curComponent.value.treeFieldList = []
curComponent.value.treeCheckedList = []
relationshipChartIndex.value = 0
curComponent.value.oldTreeLoad = true
getOptions(curComponent.value.treeDatasetId, curComponent.value)
}
const handleFieldChange = () => { const handleFieldChange = () => {
if (!curComponent.value.defaultValueCheck) return if (!curComponent.value.defaultValueCheck) return
curComponent.value.defaultValue = curComponent.value.multiple ? [] : undefined curComponent.value.defaultValue = curComponent.value.multiple ? [] : undefined
@ -1041,10 +1063,12 @@ const isInRange = (ele, startWindowTime, timeStamp) => {
dynamicWindow, dynamicWindow,
maximumSingleQuery, maximumSingleQuery,
timeNumRange, timeNumRange,
relativeToCurrentRange,
relativeToCurrentTypeRange, relativeToCurrentTypeRange,
aroundRange aroundRange
} = ele.timeRange || {} } = ele.timeRange || {}
let isDynamicWindowTime = false let isDynamicWindowTime = false
const noTime = ele.timeGranularityMultiple.split('time').join('').split('range')[0] const noTime = ele.timeGranularityMultiple.split('time').join('').split('range')[0]
const queryTimeType = noTime === 'date' ? 'day' : (noTime as ManipulateType) const queryTimeType = noTime === 'date' ? 'day' : (noTime as ManipulateType)
if (startWindowTime && dynamicWindow) { if (startWindowTime && dynamicWindow) {
@ -1078,6 +1102,14 @@ const isInRange = (ele, startWindowTime, timeStamp) => {
case 'lastMonth': case 'lastMonth':
startTime = getLastStart('month') startTime = getLastStart('month')
break break
case 'thisQuarter':
startTime = getThisStart('quarter')
break
case 'thisWeek':
startTime = new Date(
dayjs().startOf('week').add(1, 'day').startOf('day').format('YYYY/MM/DD HH:mm:ss')
)
break
case 'today': case 'today':
startTime = getThisStart('day') startTime = getThisStart('day')
break break
@ -1087,6 +1119,9 @@ const isInRange = (ele, startWindowTime, timeStamp) => {
case 'monthBeginning': case 'monthBeginning':
startTime = getThisStart('month') startTime = getThisStart('month')
break break
case 'monthEnd':
startTime = getThisEnd('month')
break
case 'yearBeginning': case 'yearBeginning':
startTime = getThisStart('year') startTime = getThisStart('year')
break break
@ -1105,13 +1140,15 @@ const isInRange = (ele, startWindowTime, timeStamp) => {
} }
if (intervalType === 'timeInterval') { if (intervalType === 'timeInterval') {
const startTime = let endTime
if (relativeToCurrentRange === 'custom') {
startTime =
regularOrTrends === 'fixed' regularOrTrends === 'fixed'
? new Date( ? new Date(
dayjs(new Date(regularOrTrendsValue[0])).startOf(noTime).format('YYYY/MM/DD HH:mm:ss') dayjs(new Date(regularOrTrendsValue[0])).startOf(noTime).format('YYYY/MM/DD HH:mm:ss')
) )
: getAround(relativeToCurrentType, around === 'f' ? 'subtract' : 'add', timeNum) : getAround(relativeToCurrentType, around === 'f' ? 'subtract' : 'add', timeNum)
const endTime = endTime =
regularOrTrends === 'fixed' regularOrTrends === 'fixed'
? new Date( ? new Date(
dayjs(new Date(regularOrTrendsValue[1])).endOf(noTime).format('YYYY/MM/DD HH:mm:ss') dayjs(new Date(regularOrTrendsValue[1])).endOf(noTime).format('YYYY/MM/DD HH:mm:ss')
@ -1121,6 +1158,9 @@ const isInRange = (ele, startWindowTime, timeStamp) => {
aroundRange === 'f' ? 'subtract' : 'add', aroundRange === 'f' ? 'subtract' : 'add',
timeNumRange timeNumRange
) )
} else {
;[startTime, endTime] = getCustomRange(relativeToCurrentRange)
}
return ( return (
startWindowTime < +new Date(startTime) - 1000 || startWindowTime < +new Date(startTime) - 1000 ||
@ -1209,6 +1249,49 @@ const validate = () => {
return true return true
} }
if (
ele.displayType === '0' &&
ele.defaultValueCheck &&
((Array.isArray(ele.defaultValue) && !ele.defaultValue.length) || !ele.defaultValue)
) {
ElMessage.error(t('report.filter.title'))
return true
}
if (ele.displayType === '9') {
if (
ele.defaultValueCheck &&
((Array.isArray(ele.defaultValue) && !ele.defaultValue.length) || !ele.defaultValue)
) {
ElMessage.error(t('report.filter.title'))
return true
}
if (!ele.treeDatasetId) {
setTreeDefaultBatch(ele)
if (!ele.treeDatasetId) {
ElMessage.error(t('data_set.dataset_cannot_be'))
}
return true
}
if (!ele.treeFieldList?.length) {
ElMessage.error(t('common.tree_structure'))
return true
}
if (
ele.treeCheckedList
?.slice(0, ele.treeFieldList.length)
.some(
item =>
!item.checkedFields?.length ||
item.checkedFields.some(itx => !item.checkedFieldsMap[itx])
)
) {
ElMessage.error(t('v_query.be_linked_first'))
return true
}
}
if (ele.displayType === '22' && ele.defaultValueCheck) { if (ele.displayType === '22' && ele.defaultValueCheck) {
ele.numValueEnd = ele.defaultNumValueEnd ele.numValueEnd = ele.defaultNumValueEnd
ele.numValueStart = ele.defaultNumValueStart ele.numValueStart = ele.defaultNumValueStart
@ -1431,10 +1514,6 @@ const validate = () => {
return false return false
} }
if ([1].includes(+ele.displayType)) {
return false
}
if ( if (
ele.displayType !== '9' && ele.displayType !== '9' &&
ele.optionValueSource === 2 && ele.optionValueSource === 2 &&
@ -1444,7 +1523,11 @@ const validate = () => {
return true return true
} }
if (!['9', '22'].includes(ele.displayType) && ele.optionValueSource === 1 && !ele.field.id) { if (
!['9', '22', '1', '7'].includes(ele.displayType) &&
ele.optionValueSource === 1 &&
!ele.field.id
) {
ElMessage.error( ElMessage.error(
!ele.dataset?.id ? t('v_query.option_value_field') : t('v_query.the_data_set') !ele.dataset?.id ? t('v_query.option_value_field') : t('v_query.the_data_set')
) )
@ -1457,6 +1540,8 @@ const handleBeforeClose = () => {
defaultConfigurationRef.value?.mult() defaultConfigurationRef.value?.mult()
defaultConfigurationRef.value?.single() defaultConfigurationRef.value?.single()
handleDialogClick() handleDialogClick()
curComponent.value.id = ''
relationshipChartIndex.value = 0
dialogVisible.value = false dialogVisible.value = false
} }
const emits = defineEmits(['queryData']) const emits = defineEmits(['queryData'])
@ -1491,6 +1576,8 @@ const confirmClick = () => {
cascadeArr = [] cascadeArr = []
queryElement.value.propValue = cloneDeep(conditions.value) queryElement.value.propValue = cloneDeep(conditions.value)
snapshotStore.recordSnapshotCache('confirmClick') snapshotStore.recordSnapshotCache('confirmClick')
curComponent.value.id = ''
relationshipChartIndex.value = 0
nextTick(() => { nextTick(() => {
emits('queryData') emits('queryData')
}) })
@ -1541,12 +1628,16 @@ const confirmValueSource = () => {
} }
const setCondition = (queryId: string) => { const setCondition = (queryId: string) => {
conditions.value = cloneDeep(props.queryElement.propValue) || [] conditions.value = (cloneDeep(props.queryElement.propValue) || []).map(ele =>
parameterCompletion(ele)
)
init(queryId) init(queryId)
} }
const setConditionOut = () => { const setConditionOut = () => {
conditions.value = cloneDeep(props.queryElement.propValue) || [] conditions.value = (cloneDeep(props.queryElement.propValue) || []).map(ele =>
parameterCompletion(ele)
)
addQueryCriteria() addQueryCriteria()
init(conditions.value[conditions.value.length - 1].id) init(conditions.value[conditions.value.length - 1].id)
} }
@ -1566,6 +1657,7 @@ const setActiveSelectTab = (arr, id) => {
const init = (queryId: string) => { const init = (queryId: string) => {
initDataset() initDataset()
relationshipChartIndex.value = 0
renameInput.value = [] renameInput.value = []
handleCondition({ id: queryId }) handleCondition({ id: queryId })
cascadeArr = cloneDeep(queryElement.value.cascade || []) cascadeArr = cloneDeep(queryElement.value.cascade || [])
@ -1616,6 +1708,11 @@ const init = (queryId: string) => {
.filter(ele => !!ele) .filter(ele => !!ele)
}) })
.finally(() => { .finally(() => {
if (!curComponent.value.treeDatasetId) {
nextTick(() => {
setTreeDefault()
})
}
handleCheckedFieldsChange(curComponent.value.checkedFields) handleCheckedFieldsChange(curComponent.value.checkedFields)
}) })
} }
@ -1624,7 +1721,7 @@ const weightlessness = () => {
valueSource.value = Array.from(new Set(valueSource.value)) valueSource.value = Array.from(new Set(valueSource.value))
} }
const parameterCompletion = () => { const parameterCompletion = ele => {
const attributes = { const attributes = {
timeType: 'fixed', timeType: 'fixed',
hideConditionSwitching: false, hideConditionSwitching: false,
@ -1652,6 +1749,7 @@ const parameterCompletion = () => {
timeNumRange: 0, timeNumRange: 0,
relativeToCurrentTypeRange: 'year', relativeToCurrentTypeRange: 'year',
aroundRange: 'f', aroundRange: 'f',
treeDatasetId: '',
displayId: '', displayId: '',
sortId: '', sortId: '',
sort: 'asc', sort: 'asc',
@ -1676,18 +1774,26 @@ const parameterCompletion = () => {
relativeToCurrentTypeRange: 'year', relativeToCurrentTypeRange: 'year',
aroundRange: 'f' aroundRange: 'f'
}, },
oldTreeLoad: false,
treeCheckedList: [],
treeFieldList: [] treeFieldList: []
} }
Object.entries(attributes).forEach(([key, val]) => { Object.entries(attributes).forEach(([key, val]) => {
curComponent.value[key] ?? (curComponent.value[key] = val) ele[key] ?? (ele[key] = val)
}) })
if (!curComponent.value.timeRange.relativeToCurrentRange) { if (!ele.treeDatasetId) {
curComponent.value.timeRange.relativeToCurrentRange = 'custom' ele.treeDatasetId = ele.dataset.id
} }
if (!ele.timeRange.relativeToCurrentRange) {
ele.timeRange.relativeToCurrentRange = 'custom'
}
return ele
} }
const handleCondition = item => { const handleCondition = (item, idx = 0) => {
handleDialogClick() handleDialogClick()
if (activeConditionForRename.id) return if (activeConditionForRename.id) return
activeCondition.value = item.id activeCondition.value = item.id
@ -1779,8 +1885,18 @@ const handleCondition = item => {
if (!valueSource.value.length) { if (!valueSource.value.length) {
valueSource.value.push('') valueSource.value.push('')
} }
parameterCompletion()
nextTick(() => { nextTick(() => {
if (curComponent.value.displayType === '9') {
oldDisplayType = '9'
handleRelationshipChart(idx, true)
if (!curComponent.value.treeDatasetId && fields.value?.length) {
nextTick(() => {
setTreeDefault()
})
} else if (curComponent.value.treeDatasetId) {
getOptions(curComponent.value.treeDatasetId, curComponent.value)
}
}
curComponent.value.showError = showError.value curComponent.value.showError = showError.value
curComponent.value.auto && (document.querySelector('.chart-field').scrollTop = 0) curComponent.value.auto && (document.querySelector('.chart-field').scrollTop = 0)
}) })
@ -1827,43 +1943,73 @@ const sortComputed = computed(() => {
const treeDialog = ref() const treeDialog = ref()
const startTreeDesign = () => { const startTreeDesign = () => {
const [comId] = curComponent.value.checkedFields
const componentObj = fields.value.find(ele => ele.componentId === comId)
treeDialog.value.init( treeDialog.value.init(
componentObj?.fields?.dimensionList.filter( curComponent.value.dataset.fields.filter(ele => ele.groupType === 'd' && ele.deType === 0),
ele => ele.deType === +curComponent.value.field.deType
),
curComponent.value.treeFieldList curComponent.value.treeFieldList
) )
} }
const saveTree = arr => { const saveTree = arr => {
curComponent.value.treeFieldList = arr curComponent.value.treeFieldList = arr
setSameField()
} }
const setSameField = () => {
curComponent.value.treeFieldList.forEach((ele, index) => {
if (!curComponent.value.treeCheckedList[index]) {
curComponent.value.treeCheckedList = [
...curComponent.value.treeCheckedList,
{
checkedFields: [...curComponent.value.checkedFields],
checkedFieldsMap: cloneDeep(curComponent.value.checkedFieldsMap)
}
]
}
fields.value.forEach(item => {
const ids = item.fields.dimensionList.map(itx => itx.id)
if (ids.includes(ele.id)) {
curComponent.value.treeCheckedList[index].checkedFieldsMap[item.componentId] = ele.id
}
})
})
curComponent.value.checkedFields =
curComponent.value.treeCheckedList[relationshipChartIndex.value].checkedFields
curComponent.value.checkedFieldsMap =
curComponent.value.treeCheckedList[relationshipChartIndex.value].checkedFieldsMap
}
const showError = computed(() => { const showError = computed(() => {
if (!curComponent.value) return false if (!curComponent.value) return false
const { optionValueSource, checkedFieldsMap, checkedFields, field, valueSource, displayType } = const {
curComponent.value optionValueSource,
checkedFieldsMap,
checkedFields,
field,
valueSource,
displayType,
treeCheckedList,
treeFieldList
} = curComponent.value
const arr = checkedFields.filter(ele => !!checkedFieldsMap[ele]) const arr = checkedFields.filter(ele => !!checkedFieldsMap[ele])
if (!checkedFields.length || !arr.length) { if (!checkedFields.length || !arr.length) {
return true return true
} }
if ([1, 7, 8, 22].includes(+displayType)) {
return false if (9 === +displayType) {
for (const key in treeCheckedList) {
if (key > treeFieldList.length) continue
const treeArr = treeCheckedList[key].checkedFields.filter(
ele => !!treeCheckedList[key].checkedFieldsMap[ele]
)
if (!treeCheckedList[key].checkedFields.length || !treeArr.length) {
return true
}
}
} }
if (displayType === '9') { if ([1, 7, 8, 22, 9].includes(+displayType)) {
let displayField = null
return checkedFields.some(id => {
const arr = (fields.value || []).find(itx => itx.componentId === id)
const field = arr?.id
if (!field) return false
if (displayField === null) {
displayField = field
return false return false
} }
return displayField !== field
})
}
return (optionValueSource === 1 && !field.id) || (optionValueSource === 2 && !valueSource.length) return (optionValueSource === 1 && !field.id) || (optionValueSource === 2 && !valueSource.length)
}) })
const handleDialogClick = () => { const handleDialogClick = () => {
@ -2090,6 +2236,55 @@ watch(
const setRenameInput = val => { const setRenameInput = val => {
renameInput.value.push(val) renameInput.value.push(val)
} }
const relationshipChartIndex = ref(0)
const notCurrentEle = (ele, index) => {
if (activeCondition.value !== ele.id) {
handleCondition(ele, index)
} else {
handleRelationshipChart(index)
}
}
const setRelationBack = () => {
curComponent.value.treeCheckedList[relationshipChartIndex.value] = {
checkedFields: [...curComponent.value.checkedFields],
checkedFieldsMap: cloneDeep(curComponent.value.checkedFieldsMap)
}
}
const handleRelationshipChart = (index, initShip = false) => {
if (curComponent.value.treeCheckedList?.length && !initShip) {
curComponent.value.treeCheckedList[relationshipChartIndex.value] = {
checkedFields: [...curComponent.value.checkedFields],
checkedFieldsMap: cloneDeep(curComponent.value.checkedFieldsMap)
}
}
relationshipChartIndex.value = index
if (!curComponent.value?.treeCheckedList?.length && !curComponent.value.oldTreeLoad) {
curComponent.value.treeCheckedList = curComponent.value.treeFieldList.map(ele => {
return {
checkedFields: [...curComponent.value.checkedFields],
checkedFieldsMap: curComponent.value.checkedFields.reduce((pre, next) => {
pre[next] = ele.id
return pre
}, {})
}
})
} else if (!curComponent.value?.treeCheckedList?.length && curComponent.value.oldTreeLoad) {
curComponent.value.treeCheckedList = curComponent.value.treeFieldList.map(() => {
return {
checkedFields: [...curComponent.value.checkedFields],
checkedFieldsMap: cloneDeep(curComponent.value.checkedFieldsMap)
}
})
}
if (!curComponent.value?.treeCheckedList[index]) return
const { checkedFields, checkedFieldsMap } = curComponent.value?.treeCheckedList[index]
curComponent.value.checkedFields = checkedFields
curComponent.value.checkedFieldsMap = checkedFieldsMap
const checkedCount = checkedFields?.length
checkAll.value = checkedCount === fields.value?.length
isIndeterminate.value = checkedCount > 0 && checkedCount < fields.value?.length
}
const addOperation = (cmd, condition, index) => { const addOperation = (cmd, condition, index) => {
switch (cmd) { switch (cmd) {
@ -2145,7 +2340,8 @@ const renameInputBlur = () => {
} }
const addQueryCriteria = () => { const addQueryCriteria = () => {
conditions.value.push(addQueryCriteriaConfig()) relationshipChartIndex.value = 0
conditions.value.push(parameterCompletion(addQueryCriteriaConfig()))
} }
const addQueryCriteriaAndSelect = () => { const addQueryCriteriaAndSelect = () => {
@ -2190,10 +2386,18 @@ defineExpose({
:key="element.id" :key="element.id"
@dblclick.stop="addOperation('rename', element, index)" @dblclick.stop="addOperation('rename', element, index)"
@click.stop="handleCondition(element)" @click.stop="handleCondition(element)"
class="list-item_primary" class="list-item_box"
:class="element.id === activeCondition && 'active'" :style="{
marginBottom: element.treeFieldList
? element.treeFieldList.slice(1).length * 40 + 'px'
: 0
}"
> >
<el-icon class="handle" style="color:#fff;"> <div
class="list-item_primary"
:class="element.id === activeCondition && relationshipChartIndex === 0 && 'active'"
>
<el-icon class="handle">
<Icon name="icon_drag_outlined"><icon_drag_outlined class="svg-icon" /></Icon> <Icon name="icon_drag_outlined"><icon_drag_outlined class="svg-icon" /></Icon>
</el-icon> </el-icon>
<div class="label flex-align-center icon" :title="element.name"> <div class="label flex-align-center icon" :title="element.name">
@ -2221,7 +2425,11 @@ defineExpose({
><icon_visible_outlined class="svg-icon" ><icon_visible_outlined class="svg-icon"
/></Icon> /></Icon>
</el-icon> </el-icon>
<el-icon class="hover-icon" @click.stop="element.visible = !element.visible" v-else> <el-icon
class="hover-icon"
@click.stop="element.visible = !element.visible"
v-else
>
<Icon name="de_pwd_invisible"><de_pwd_invisible class="svg-icon" /></Icon> <Icon name="de_pwd_invisible"><de_pwd_invisible class="svg-icon" /></Icon>
</el-icon> </el-icon>
</div> </div>
@ -2233,6 +2441,26 @@ defineExpose({
></el-input> ></el-input>
</div> </div>
</div> </div>
<template v-if="element.treeFieldList">
<div
:class="
element.id === activeCondition &&
relationshipChartIndex === index + 1 &&
'active'
"
class="list-item_primary list-tree_primary"
:style="{
top: 40 * (index + 1) + 'px',
paddingLeft: 32 + 16 * (index + 1) + 'px'
}"
v-for="(itx, index) in element.treeFieldList.slice(1)"
:key="itx.field"
@click.stop="notCurrentEle(element, index + 1)"
>
{{ itx.name }}
</div>
</template>
</div>
</template> </template>
</draggable> </draggable>
</div> </div>
@ -2245,7 +2473,7 @@ defineExpose({
<el-radio :disabled="!curComponent.auto" :label="true"> <el-radio :disabled="!curComponent.auto" :label="true">
<div class="flex-align-center"> <div class="flex-align-center">
{{ t('chart.margin_model_auto') }} {{ t('chart.margin_model_auto') }}
<el-tooltip placement="top"> <el-tooltip effect="dark" placement="top">
<template #content> <template #content>
<div> <div>
{{ t('v_query.be_switched_to') }} {{ t('v_query.be_switched_to') }}
@ -2621,13 +2849,19 @@ defineExpose({
<div class="title flex-align-center"> <div class="title flex-align-center">
{{ t('v_query.query_condition_configuration') }} {{ t('v_query.query_condition_configuration') }}
<el-checkbox <el-checkbox
:disabled="curComponent.auto" :disabled="
curComponent.auto ||
(curComponent.displayType === '9' && relationshipChartIndex !== 0)
"
v-model="curComponent.required" v-model="curComponent.required"
:label="t('v_query.required_items')" :label="t('v_query.required_items')"
/> />
</div> </div>
<div <div
v-show="showConfiguration && !showTypeError && !showDatasetError" v-show="
(curComponent.displayType !== '9' && showConfiguration && !showTypeError) ||
(curComponent.displayType === '9' && relationshipChartIndex == 0)
"
class="configuration-list" class="configuration-list"
> >
<div class="list-item"> <div class="list-item">
@ -2635,7 +2869,7 @@ defineExpose({
<div class="value"> <div class="value">
<el-select <el-select
@focus="handleDialogClick" @focus="handleDialogClick"
@change="setTypeChange" @change="handleSetTypeChange"
v-model="curComponent.displayType" v-model="curComponent.displayType"
> >
<el-option <el-option
@ -2705,6 +2939,42 @@ defineExpose({
</el-radio-group> </el-radio-group>
</div> </div>
</div> </div>
<div class="list-item" v-if="curComponent.displayType === '9'">
<div :title="t('copilot.pls_choose_dataset')" class="label ellipsis">
{{ t('copilot.pls_choose_dataset') }}
</div>
<div class="value">
<el-tree-select
:teleported="false"
v-model="curComponent.treeDatasetId"
:data="datasetTree"
:placeholder="t('copilot.pls_choose_dataset')"
@change="handleDatasetTreeChange"
:props="dsSelectProps"
placement="bottom"
:render-after-expand="false"
filterable
popper-class="dataset-tree"
>
<template #default="{ node, data }">
<div class="content">
<el-icon size="18px" v-if="!data.leaf">
<Icon><dvFolder class="svg-icon" /></Icon>
</el-icon>
<el-icon size="18px" v-if="data.leaf">
<Icon><icon_dataset class="svg-icon" /></Icon>
</el-icon>
<span
class="label-tree ellipsis"
style="margin-left: 8px"
:title="node.label"
>{{ node.label }}</span
>
</div>
</template>
</el-tree-select>
</div>
</div>
<div class="list-item" v-if="curComponent.displayType === '9'"> <div class="list-item" v-if="curComponent.displayType === '9'">
<div class="label" style="width: 135px; height: 26px; line-height: 26px"> <div class="label" style="width: 135px; height: 26px; line-height: 26px">
{{ t('v_query.tree_structure_design') }} {{ t('v_query.tree_structure_design') }}
@ -2714,7 +2984,7 @@ defineExpose({
@click="startTreeDesign" @click="startTreeDesign"
> >
<template #icon> <template #icon>
<icon name="icon_edit_outlined"><icon_edit_outlined class="svg-icon" /></icon> <icon><icon_edit_outlined class="svg-icon" /></icon>
</template> </template>
</el-button> </el-button>
</div> </div>
@ -2730,7 +3000,7 @@ defineExpose({
> >
<span class="field-type" <span class="field-type"
><el-icon> ><el-icon>
<Icon :className="`field-icon-${fieldType[ele.deType]}`" <Icon
><component ><component
:class="`field-icon-${fieldType[ele.deType]}`" :class="`field-icon-${fieldType[ele.deType]}`"
class="svg-icon" class="svg-icon"
@ -2738,10 +3008,18 @@ defineExpose({
></component ></component
></Icon> </el-icon ></Icon> </el-icon
></span> ></span>
<span class="field-tree_name">{{ ele.name }}</span> <span class="field-tree_name ellipsis" :title="ele.name">{{ ele.name }}</span>
<span class="field-relationship_chart" v-if="index === 0">{{
t('common.associated_chart_first')
}}</span>
<span class="field-relationship_chart" v-else>
<el-button text @click="handleRelationshipChart(index)">
{{ t('common.associated_chart') }}
</el-button>
</span>
</div> </div>
</template> </template>
<el-button @click="startTreeDesign" v-else text> <el-button class="start-tree_design" @click="startTreeDesign" v-else text>
<template #icon> <template #icon>
<Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon> <Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon>
</template> </template>
@ -3157,8 +3435,11 @@ defineExpose({
<div v-if="showTypeError && showConfiguration" class="empty"> <div v-if="showTypeError && showConfiguration" class="empty">
<empty-background :description="t('v_query.cannot_be_performed')" img-type="error" /> <empty-background :description="t('v_query.cannot_be_performed')" img-type="error" />
</div> </div>
<div v-else-if="showDatasetError && showConfiguration" class="empty"> <div
<empty-background :description="t('v_query.cannot_be_displayed')" img-type="error" /> v-else-if="curComponent.displayType === '9' && relationshipChartIndex !== 0"
class="empty"
>
<empty-background :description="t('common.other_levels')" img-type="error" />
</div> </div>
<div v-else-if="!showConfiguration" class="empty"> <div v-else-if="!showConfiguration" class="empty">
<empty-background :description="t('v_query.be_linked_first')" img-type="noneWhite" /> <empty-background :description="t('v_query.be_linked_first')" img-type="noneWhite" />
@ -3168,10 +3449,10 @@ defineExpose({
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button type="primary" class="query-cascade" @click="openCascadeDialog">{{ <el-button class="query-cascade" @click="openCascadeDialog">{{
t('v_query.component_cascade_configuration') t('v_query.component_cascade_configuration')
}}</el-button> }}</el-button>
<el-button @click="cancelClick">{{ t('chart.cancel') }}</el-button> <el-button @click="cancelClick">{{ t('chart.cancel') }} </el-button>
<el-button @click="confirmClick" type="primary">{{ t('chart.confirm') }} </el-button> <el-button @click="confirmClick" type="primary">{{ t('chart.confirm') }} </el-button>
</div> </div>
</template> </template>
@ -3234,7 +3515,7 @@ defineExpose({
min-width: 210px !important; min-width: 210px !important;
} }
.ed-select-dropdown__header { .ed-select-dropdown__header {
padding: 0 8px; padding: 0 8px !important;
.params-select--header { .params-select--header {
--ed-tabs-header-height: 32px; --ed-tabs-header-height: 32px;
.ed-tabs__item { .ed-tabs__item {
@ -3286,11 +3567,11 @@ defineExpose({
justify-content: center; justify-content: center;
} }
.ed-input .ed-select__prefix--light { .ed-select__prefix {
border-right: none;
padding: 0;
font-size: 16px; font-size: 16px;
margin-right: 4px; &::after {
display: none;
}
} }
.container { .container {
font-size: 14px; font-size: 14px;
@ -3330,6 +3611,17 @@ defineExpose({
color: var(--ed-color-primary); color: var(--ed-color-primary);
} }
} }
.list-item_box {
width: 100%;
position: relative;
.list-tree_primary {
position: absolute;
left: 0;
padding: 8px 32px;
width: 100%;
}
}
.list-item_primary { .list-item_primary {
border-radius: 0; border-radius: 0;
position: relative; position: relative;
@ -3532,13 +3824,13 @@ defineExpose({
flex-wrap: wrap; flex-wrap: wrap;
.search-tree { .search-tree {
width: 100%; width: 100%;
height: 200px; height: 216px;
margin-top: 8px; margin-top: 8px;
position: relative; position: relative;
padding: 16px; padding: 16px;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12); box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
.ed-button { .start-tree_design {
position: absolute; position: absolute;
left: 50%; left: 50%;
top: 50%; top: 50%;
@ -3562,6 +3854,11 @@ defineExpose({
.field-tree_name { .field-tree_name {
margin-left: 8px; margin-left: 8px;
width: 100px;
}
.field-relationship_chart {
margin-left: 8px;
} }
} }
} }

View File

@ -1,9 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { toRefs, computed, PropType } from 'vue' import { toRefs, computed, PropType, watch } from 'vue'
import { type TimeRange } from './time-format' import { type TimeRange } from './time-format'
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/data-visualization/hooks/web/useI18n'
import DynamicTime from './DynamicTimeFiltering.vue' import DynamicTime from './DynamicTimeFiltering.vue'
import DynamicTimeRange from './DynamicTimeRangeFiltering.vue' import DynamicTimeRange from './DynamicTimeRangeFiltering.vue'
import { ManipulateType } from 'dayjs'
const props = defineProps({ const props = defineProps({
timeRange: { timeRange: {
type: Object as PropType<TimeRange>, type: Object as PropType<TimeRange>,
@ -264,6 +265,40 @@ const relativeToCurrentListRange = computed(() => {
} }
] ]
}) })
watch(
() => relativeToCurrentListRange.value,
val => {
if (!val.some(ele => ele.value === timeRange.value.relativeToCurrentRange)) {
timeRange.value.relativeToCurrentRange = val[0].value
}
},
{ immediate: true }
)
watch(
() => relativeToCurrentList.value,
val => {
if (!val.some(ele => ele.value === timeRange.value.relativeToCurrent)) {
timeRange.value.relativeToCurrent = val[0].value
}
},
{ immediate: true }
)
watch(
() => relativeToCurrentTypeList.value,
val => {
if (!val.some(ele => ele.value === timeRange.value.relativeToCurrentType)) {
timeRange.value.relativeToCurrentType = val[0].value as ManipulateType
}
if (!val.some(ele => ele.value === timeRange.value.relativeToCurrentTypeRange)) {
timeRange.value.relativeToCurrentTypeRange = val[0].value as ManipulateType
}
},
{ immediate: true }
)
</script> </script>
<template> <template>
@ -448,6 +483,9 @@ const relativeToCurrentListRange = computed(() => {
--ed-radio-input-height: 16px; --ed-radio-input-height: 16px;
--ed-radio-input-width: 16px; --ed-radio-input-width: 16px;
} }
.ed-select {
--ed-select-width: 100px;
}
.title { .title {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;

View File

@ -4,6 +4,7 @@ import {
toRefs, toRefs,
PropType, PropType,
onBeforeMount, onBeforeMount,
onMounted,
shallowRef, shallowRef,
watch, watch,
nextTick, nextTick,
@ -171,6 +172,7 @@ const getCascadeFieldId = () => {
cascade.value.forEach(ele => { cascade.value.forEach(ele => {
let condition = null let condition = null
ele.forEach(item => { ele.forEach(item => {
// eslint-disable-next-line
const [_, queryId, fieldId] = item.datasetId.split('--') const [_, queryId, fieldId] = item.datasetId.split('--')
if (queryId === config.value.id && condition) { if (queryId === config.value.id && condition) {
if (item.fieldId) { if (item.fieldId) {
@ -617,6 +619,34 @@ onBeforeMount(() => {
}) })
}) })
const isDataV = ref(false)
const popperClass = computed(() => {
let str = 'filter-select-popper_class'
if (visible.value) {
str = 'load-select ' + str
}
if (isDataV.value) {
str = str + ' color-scrollbar__thumb'
}
return str
})
onMounted(() => {
isDataV.value =
Boolean(document.querySelector('#canvas-dv-outer')) ||
Boolean(document.querySelector('.datav-preview'))
})
const tagWidth = computed(() => {
return Math.min((getCustomWidth() - 60) / 2, 50) + 'px'
})
const tagTextWidth = computed(() => {
return Math.min((getCustomWidth() - 60) / 2 - 25, 40) + 'px'
})
defineExpose({ defineExpose({
displayTypeChange, displayTypeChange,
mult, mult,
@ -635,9 +665,7 @@ defineExpose({
filterable filterable
@click="selectHideClick" @click="selectHideClick"
@change="handleValueChange" @change="handleValueChange"
:popper-class=" :popper-class="popperClass"
visible ? 'load-select filter-select-popper_class' : 'filter-select-popper_class'
"
multiple multiple
show-checked show-checked
scrollbar-always-on scrollbar-always-on
@ -661,9 +689,7 @@ defineExpose({
:style="selectStyle" :style="selectStyle"
filterable filterable
radio radio
:popper-class=" :popper-class="popperClass"
visible ? 'load-select filter-select-popper_class' : 'filter-select-popper_class'
"
:options="options" :options="options"
> >
<template #default="{ item }"> <template #default="{ item }">
@ -705,4 +731,23 @@ defineExpose({
color: #1f2329; color: #1f2329;
} }
} }
.color-scrollbar__thumb {
.ed-scrollbar__thumb {
background: #bbbfc4 !important;
opacity: 1 !important;
}
}
</style>
<style lang="less" scoped>
:deep(.ed-select__selected-item) {
.ed-tag {
max-width: v-bind(tagWidth) !important;
}
.ed-select__tags-text {
max-width: v-bind(tagTextWidth) !important;
}
}
</style> </style>

View File

@ -181,7 +181,8 @@ const handleInnerMouseDown = e => {
.condition-type { .condition-type {
display: flex; display: flex;
position: relative; position: relative;
:deep(.ed-input__wrapper) { :deep(.ed-input__wrapper),
:deep(.ed-select__wrapper) {
border: none; border: none;
border-radius: 0; border-radius: 0;
box-shadow: none !important; box-shadow: none !important;

View File

@ -7,7 +7,13 @@ import { type TimeRange } from './time-format'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { useI18n } from '@/data-visualization/hooks/web/useI18n'
import { useShortcuts } from './shortcuts' import { useShortcuts } from './shortcuts'
import { getThisStart, getLastStart, getAround } from './time-format-dayjs' import {
getThisStart,
getThisEnd,
getLastStart,
getAround,
getCustomRange
} from './time-format-dayjs'
import VanPopup from 'vant/es/popup' import VanPopup from 'vant/es/popup'
import VanDatePicker from 'vant/es/date-picker' import VanDatePicker from 'vant/es/date-picker'
import VanTimePicker from 'vant/es/time-picker' import VanTimePicker from 'vant/es/time-picker'
@ -139,6 +145,9 @@ watch(
) )
const handleValueChange = () => { const handleValueChange = () => {
selectValue.value = Array.isArray(selectValue.value)
? selectValue.value.map(ele => ele && dayjs(ele).format('YYYY/MM/DD HH:mm:ss'))
: selectValue.value && dayjs(selectValue.value).format('YYYY/MM/DD HH:mm:ss')
const value = Array.isArray(selectValue.value) ? [...selectValue.value] : selectValue.value const value = Array.isArray(selectValue.value) ? [...selectValue.value] : selectValue.value
if (!props.isConfig) { if (!props.isConfig) {
config.value.selectValue = Array.isArray(selectValue.value) config.value.selectValue = Array.isArray(selectValue.value)
@ -251,6 +260,7 @@ const disabledDate = val => {
regularOrTrends, regularOrTrends,
regularOrTrendsValue, regularOrTrendsValue,
relativeToCurrent, relativeToCurrent,
relativeToCurrentRange,
timeNum, timeNum,
relativeToCurrentType, relativeToCurrentType,
around, around,
@ -261,6 +271,7 @@ const disabledDate = val => {
aroundRange aroundRange
} = config.value.timeRange || {} } = config.value.timeRange || {}
let isDynamicWindowTime = false let isDynamicWindowTime = false
if (startWindowTime.value && dynamicWindow) { if (startWindowTime.value && dynamicWindow) {
isDynamicWindowTime = isDynamicWindowTime =
dayjs(startWindowTime.value) dayjs(startWindowTime.value)
@ -297,6 +308,14 @@ const disabledDate = val => {
case 'lastMonth': case 'lastMonth':
startTime = getLastStart('month') startTime = getLastStart('month')
break break
case 'thisQuarter':
startTime = getThisStart('quarter')
break
case 'thisWeek':
startTime = new Date(
dayjs().startOf('week').add(1, 'day').startOf('day').format('YYYY/MM/DD HH:mm:ss')
)
break
case 'today': case 'today':
startTime = getThisStart('day') startTime = getThisStart('day')
break break
@ -306,6 +325,9 @@ const disabledDate = val => {
case 'monthBeginning': case 'monthBeginning':
startTime = getThisStart('month') startTime = getThisStart('month')
break break
case 'monthEnd':
startTime = getThisEnd('month')
break
case 'yearBeginning': case 'yearBeginning':
startTime = getThisStart('year') startTime = getThisStart('year')
break break
@ -325,7 +347,9 @@ const disabledDate = val => {
} }
if (intervalType === 'timeInterval') { if (intervalType === 'timeInterval') {
const startTime = let endTime
if (relativeToCurrentRange === 'custom') {
startTime =
regularOrTrends === 'fixed' regularOrTrends === 'fixed'
? new Date( ? new Date(
dayjs(new Date(regularOrTrendsValue[0])) dayjs(new Date(regularOrTrendsValue[0]))
@ -333,7 +357,7 @@ const disabledDate = val => {
.format('YYYY/MM/DD HH:mm:ss') .format('YYYY/MM/DD HH:mm:ss')
) )
: getAround(relativeToCurrentType, around === 'f' ? 'subtract' : 'add', timeNum) : getAround(relativeToCurrentType, around === 'f' ? 'subtract' : 'add', timeNum)
const endTime = endTime =
regularOrTrends === 'fixed' regularOrTrends === 'fixed'
? new Date( ? new Date(
dayjs(new Date(regularOrTrendsValue[1])) dayjs(new Date(regularOrTrendsValue[1]))
@ -345,6 +369,9 @@ const disabledDate = val => {
aroundRange === 'f' ? 'subtract' : 'add', aroundRange === 'f' ? 'subtract' : 'add',
timeNumRange timeNumRange
) )
} else {
;[startTime, endTime] = getCustomRange(relativeToCurrentRange)
}
return ( return (
timeStamp < +new Date(startTime) - 1000 || timeStamp < +new Date(startTime) - 1000 ||
timeStamp > +new Date(endTime) || timeStamp > +new Date(endTime) ||
@ -388,21 +415,24 @@ const selectSecond = ref(false)
const setArrValue = () => { const setArrValue = () => {
currentDate.value = currentDate.value.slice(0, getIndex() + 1) currentDate.value = currentDate.value.slice(0, getIndex() + 1)
const timeFormat = [1, 2].includes(currentDate.value.length)
? currentDate.value.concat(Array([0, 2, 1][currentDate.value.length]).fill('01'))
: currentDate.value
if (isRange.value) { if (isRange.value) {
const [start, end] = selectValue.value || [] const [start, end] = selectValue.value || []
if (selectSecond.value) { if (selectSecond.value) {
selectValue.value = [ selectValue.value = [
start ? start : new Date(`${currentDate.value.join('/')} ${currentTime.value.join(':')}`), start ? start : new Date(`${timeFormat.join('/')} ${currentTime.value.join(':')}`),
new Date(`${currentDate.value.join('/')} ${currentTime.value.join(':')}`) new Date(`${timeFormat.join('/')} ${currentTime.value.join(':')}`)
] ]
} else { } else {
selectValue.value = [ selectValue.value = [
new Date(`${currentDate.value.join('/')} ${currentTime.value.join(':')}`), new Date(`${timeFormat.join('/')} ${currentTime.value.join(':')}`),
end ? end : new Date(`${currentDate.value.join('/')} ${currentTime.value.join(':')}`) end ? end : new Date(`${timeFormat.join('/')} ${currentTime.value.join(':')}`)
] ]
} }
} else { } else {
selectValue.value = new Date(`${currentDate.value.join('/')} ${currentTime.value.join(':')}`) selectValue.value = new Date(`${timeFormat.join('/')} ${currentTime.value.join(':')}`)
} }
} }

View File

@ -66,50 +66,58 @@ const placeholderText = computed(() => {
return ' ' return ' '
}) })
const { config } = toRefs(props) const { config } = toRefs(props)
const fromTreeSelectConfirm = ref(false)
const multiple = ref(false) const multiple = ref(false)
const treeSelectConfirm = val => { const treeSelectConfirm = val => {
treeValue.value = val treeValue.value = val
handleValueChange() handleValueChange()
} }
const handleValueChange = () => { const handleValueChange = () => {
fromTreeSelectConfirm.value = true
const value = Array.isArray(treeValue.value) ? [...treeValue.value] : treeValue.value const value = Array.isArray(treeValue.value) ? [...treeValue.value] : treeValue.value
if (!props.isConfig) { if (!props.isConfig) {
config.value.selectValue = Array.isArray(treeValue.value) config.value.selectValue = Array.isArray(treeValue.value)
? [...treeValue.value] ? [...treeValue.value]
: treeValue.value : treeValue.value
nextTick(() => { nextTick(() => {
fromTreeSelectConfirm.value = false
isConfirmSearch(config.value.id) isConfirmSearch(config.value.id)
}) })
return return
} }
config.value.defaultValue = value config.value.defaultValue = value
fromTreeSelectConfirm.value = false
} }
const changeFromId = ref(false)
watch( watch(
() => config.value.defaultValue, () => config.value.id,
val => { () => {
if (config.value.multiple) { changeFromId.value = true
treeValue.value = Array.isArray(val) ? [...val] : val init()
}
nextTick(() => { nextTick(() => {
multiple.value = config.value.multiple changeFromId.value = false
}) })
} }
) )
let oldId
watch( watch(
() => config.value.treeFieldList, () => config.value.treeFieldList,
() => { val => {
let idStr = val.map(ele => ele.id).join('-')
if (changeFromId.value || idStr === oldId) return
oldId = idStr
treeValue.value = config.value.multiple ? [] : undefined treeValue.value = config.value.multiple ? [] : undefined
config.value.defaultValue = config.value.multiple ? [] : undefined
config.value.selectValue = config.value.multiple ? [] : undefined
showOrHide.value = false showOrHide.value = false
getTreeOption() getTreeOption()
} }
) )
const init = () => { const init = () => {
loading.value = true
const { defaultValueCheck, multiple: plus, defaultValue } = config.value const { defaultValueCheck, multiple: plus, defaultValue } = config.value
if (defaultValueCheck) { if (defaultValueCheck) {
config.value.selectValue = Array.isArray(defaultValue) config.value.selectValue = Array.isArray(defaultValue)
@ -121,17 +129,24 @@ const init = () => {
treeValue.value = plus ? [] : undefined treeValue.value = plus ? [] : undefined
} }
nextTick(() => { nextTick(() => {
oldId = config.value.treeFieldList?.map(ele => ele.id).join('-')
multiple.value = config.value.multiple multiple.value = config.value.multiple
}) })
getTreeOption() getTreeOption()
} }
watch( const tagWidth = computed(() => {
() => config.value.id, return Math.min(getCustomWidth() / 3, 50) + 'px'
() => { })
init()
} const tagsWidth = computed(() => {
) return getCustomWidth() - 40 + 'px'
})
const tagTextWidth = computed(() => {
return Math.min(getCustomWidth() / 3, 50) - 25 + 'px'
})
const showOrHide = ref(true) const showOrHide = ref(true)
const queryConditionWidth = inject('com-width', Function, true) const queryConditionWidth = inject('com-width', Function, true)
const isConfirmSearch = inject('is-confirm-search', Function, true) const isConfirmSearch = inject('is-confirm-search', Function, true)
@ -148,12 +163,27 @@ onMounted(() => {
}) })
watch( watch(
() => config.value.selectValue, () => config.value.defaultValue,
val => { val => {
if (props.isConfig) return if (props.isConfig) return
if (config.value.multiple) { if (config.value.multiple) {
treeValue.value = Array.isArray(val) ? [...val] : val treeValue.value = Array.isArray(val) ? [...val] : val
} }
nextTick(() => {
multiple.value = config.value.multiple
})
}
)
watch(
() => config.value.selectValue,
val => {
if (props.isConfig || fromTreeSelectConfirm.value) return
if (config.value.multiple) {
treeValue.value = Array.isArray(val) ? [...val] : val
}
nextTick(() => { nextTick(() => {
multiple.value = config.value.multiple multiple.value = config.value.multiple
if (!config.value.multiple) { if (!config.value.multiple) {
@ -164,11 +194,12 @@ watch(
}) })
} }
) )
const showWholePath = ref(false) const showWholePath = ref(false)
watch( watch(
() => config.value.multiple, () => config.value.multiple,
val => { val => {
if (!props.isConfig) return if (!props.isConfig || changeFromId.value) return
showWholePath.value = false showWholePath.value = false
if (val) { if (val) {
treeValue.value = [] treeValue.value = []
@ -227,15 +258,15 @@ watch(
} }
} }
) )
const fakeValue = '' const fakeValue = ref('')
const treeValue = ref() const treeValue = ref()
const getCustomWidth = () => { const getCustomWidth = () => {
if (placeholder?.value?.placeholderShow) { if (placeholder?.value?.placeholderShow) {
if (props.config.queryConditionWidth === undefined) { if (props.config.queryConditionWidth !== undefined) {
return queryConditionWidth()
}
return props.config.queryConditionWidth return props.config.queryConditionWidth
} }
return queryConditionWidth()
}
return 227 return 227
} }
const selectStyle = computed(() => { const selectStyle = computed(() => {
@ -253,12 +284,13 @@ const selectStyle = computed(() => {
:render-after-expand="false" :render-after-expand="false"
show-checkbox show-checkbox
showBtn showBtn
@change="handleValueChange"
:placeholder="placeholderText" :placeholder="placeholderText"
collapse-tags collapse-tags
:filter-node-method="filterMethod" :filter-node-method="filterMethod"
:showWholePath="showWholePath" :showWholePath="showWholePath"
collapse-tags-tooltip collapse-tags-tooltip
key="multipleTree" :key="'multipleTree' + getCustomWidth()"
filterable filterable
:style="selectStyle" :style="selectStyle"
multiple multiple
@ -273,7 +305,7 @@ const selectStyle = computed(() => {
:placeholder="placeholderText" :placeholder="placeholderText"
:render-after-expand="false" :render-after-expand="false"
v-else-if="!multiple && !loading" v-else-if="!multiple && !loading"
key="singleTree" :key="'singleTree' + getCustomWidth()"
:showWholePath="showWholePath" :showWholePath="showWholePath"
:style="selectStyle" :style="selectStyle"
filterable filterable
@ -294,4 +326,15 @@ const selectStyle = computed(() => {
:deep(.ed-select-tags-wrapper) { :deep(.ed-select-tags-wrapper) {
display: inline-flex !important; display: inline-flex !important;
} }
:deep(.ed-select__tags) {
max-width: v-bind(tagsWidth) !important;
.ed-tag {
max-width: v-bind(tagWidth);
}
.ed-select__tags-text {
max-width: v-bind(tagTextWidth) !important;
}
}
</style> </style>

View File

@ -39,7 +39,7 @@ const cancelClick = () => {
const setCascadeArrBack = () => { const setCascadeArrBack = () => {
let isError = false let isError = false
const arr = cloneDeep(treeList.value).map(item => { const arr = cloneDeep(treeList.value).map(item => {
if (!item.field) { if (!item.field?.id) {
isError = true isError = true
} }
return item.field return item.field
@ -80,7 +80,7 @@ defineExpose({
<el-dialog <el-dialog
v-model="dialogVisible" v-model="dialogVisible"
width="600" width="600"
custom-class="tree-field_dialog" modal-class="tree-field_dialog"
:before-close="handleBeforeClose" :before-close="handleBeforeClose"
@mousedown.stop @mousedown.stop
@mousedup.stop @mousedup.stop
@ -102,12 +102,7 @@ defineExpose({
<div class="cascade-item" v-for="(ele, idx) in treeList" :key="ele.id"> <div class="cascade-item" v-for="(ele, idx) in treeList" :key="ele.id">
<div class="label">{{ t('visualization.level') }}{{ indexNumCascade[idx] }}</div> <div class="label">{{ t('visualization.level') }}{{ indexNumCascade[idx] }}</div>
<div class="item-name"> <div class="item-name">
<el-select <el-select value-key="id" v-model="ele.field" style="width: 300px">
:disabled="idx === 0 && ele.field"
value-key="id"
v-model="ele.field"
style="width: 300px"
>
<el-option <el-option
:disabled="disableFieldArr.includes(item.id)" :disabled="disableFieldArr.includes(item.id)"
v-for="item in datasetMap" v-for="item in datasetMap"
@ -117,7 +112,7 @@ defineExpose({
/> />
</el-select> </el-select>
</div> </div>
<el-button v-show="idx !== 0" @click="deleteCascade(idx)" class="cascade-delete" text> <el-button @click="deleteCascade(idx)" class="cascade-delete" text>
<template #icon> <template #icon>
<Icon name="icon_delete-trash_outlined" <Icon name="icon_delete-trash_outlined"
><icon_deleteTrash_outlined class="svg-icon" ><icon_deleteTrash_outlined class="svg-icon"

View File

@ -25,6 +25,18 @@ export const comInfo = () => {
com => !['VQuery', 'DeTabs'].includes(com.innerType) && com.component !== 'Group' com => !['VQuery', 'DeTabs'].includes(com.innerType) && com.component !== 'Group'
) )
] ]
itx.componentData.forEach(element => {
if (element.component === 'Group') {
arr = [
...arr,
element.propValue.filter(
coms =>
!['VQuery', 'DeTabs'].includes(coms.innerType) && coms.component !== 'Group'
)
]
}
})
}) })
} else if (ele.component === 'Group') { } else if (ele.component === 'Group') {
arr = [ arr = [

View File

@ -1,10 +1,10 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
import type { ManipulateType } from 'dayjs' import type { ManipulateType } from 'dayjs'
function getThisStart(val = 'month' as ManipulateType) { function getThisStart(val = 'month' as ManipulateType | 'quarter') {
return new Date(dayjs().startOf(val).format('YYYY/MM/DD HH:mm:ss')) return new Date(dayjs().startOf(val).format('YYYY/MM/DD HH:mm:ss'))
} }
function getThisEnd(val = 'month' as ManipulateType) { function getThisEnd(val = 'month' as ManipulateType | 'quarter') {
return new Date(dayjs().endOf(val).format('YYYY/MM/DD HH:mm:ss')) return new Date(dayjs().endOf(val).format('YYYY/MM/DD HH:mm:ss'))
} }
@ -17,9 +17,19 @@ function getLastEnd(val = 'month' as ManipulateType) {
} }
function getAround(val = 'month' as ManipulateType, type = 'add', num = 0) { function getAround(val = 'month' as ManipulateType, type = 'add', num = 0) {
if (val === 'week') {
return new Date(dayjs().endOf('week').add(1, 'day').endOf('day').format('YYYY/MM/DD HH:mm:ss'))
}
return new Date(dayjs()[type](num, val).startOf('day').format('YYYY/MM/DD HH:mm:ss')) return new Date(dayjs()[type](num, val).startOf('day').format('YYYY/MM/DD HH:mm:ss'))
} }
function getThisWeek(): [Date, Date] {
return [
new Date(dayjs().startOf('week').add(1, 'day').startOf('day').format('YYYY/MM/DD HH:mm:ss')),
new Date(dayjs().endOf('week').add(1, 'day').endOf('day').format('YYYY/MM/DD HH:mm:ss'))
]
}
function getCustomRange(relativeToCurrentRange: string): [Date, Date] { function getCustomRange(relativeToCurrentRange: string): [Date, Date] {
switch (relativeToCurrentRange) { switch (relativeToCurrentRange) {
case 'thisYear': case 'thisYear':
@ -30,6 +40,10 @@ function getCustomRange(relativeToCurrentRange: string): [Date, Date] {
return [getThisStart('month'), getThisEnd('month')] return [getThisStart('month'), getThisEnd('month')]
case 'lastMonth': case 'lastMonth':
return [getLastStart('month'), getLastEnd('month')] return [getLastStart('month'), getLastEnd('month')]
case 'thisQuarter':
return [getThisStart('quarter'), getThisEnd('quarter')]
case 'thisWeek':
return getThisWeek()
case 'LastThreeMonths': case 'LastThreeMonths':
return [ return [
new Date(dayjs().subtract(3, 'month').startOf('month').format('YYYY/MM/DD HH:mm:ss')), new Date(dayjs().subtract(3, 'month').startOf('month').format('YYYY/MM/DD HH:mm:ss')),
@ -51,7 +65,7 @@ function getCustomRange(relativeToCurrentRange: string): [Date, Date] {
return [getLastStart('day'), getLastEnd('day')] return [getLastStart('day'), getLastEnd('day')]
case 'LastThreeDays': case 'LastThreeDays':
return [ return [
new Date(dayjs().subtract(3, 'day').startOf('day').format('YYYY/MM/DD HH:mm:ss')), new Date(dayjs().subtract(2, 'day').startOf('day').format('YYYY/MM/DD HH:mm:ss')),
getThisEnd('day') getThisEnd('day')
] ]
case 'monthBeginning': case 'monthBeginning':

View File

@ -1,20 +1,19 @@
import type { ManipulateType } from 'dayjs' import type { ManipulateType } from 'dayjs'
import dayjs from 'dayjs' import dayjs from 'dayjs'
function getThisYear() { function getThisYear() {
return new Date(`${new Date().getFullYear()}/1`) return new Date(dayjs().startOf('year').format('YYYY/MM/DD HH:mm:ss'))
} }
function getLastYear() { function getLastYear() {
return new Date(`${new Date().getFullYear() - 1}/1`) return new Date(dayjs().subtract(1, 'year').startOf('year').format('YYYY/MM/DD HH:mm:ss'))
} }
function getNextYear() { function getNextYear() {
return new Date(`${new Date().getFullYear() + 1}/1`) return new Date(dayjs().add(1, 'year').startOf('year').format('YYYY/MM/DD HH:mm:ss'))
} }
function getThisMonth() { function getThisMonth() {
const date = new Date() return new Date(dayjs().startOf('month').format('YYYY/MM/DD HH:mm:ss'))
return new Date(`${date.getFullYear()}/${date.getMonth() + 1}`)
} }
function getLastStart(val = 'month' as ManipulateType) { function getLastStart(val = 'month' as ManipulateType) {
@ -26,23 +25,19 @@ function getLastMonth() {
} }
function getNextMonth() { function getNextMonth() {
const date = getCustomTime(1, 'month', 'month', 'b') return new Date(dayjs().add(1, 'month').startOf('month').format('YYYY/MM/DD HH:mm:ss'))
return new Date(`${date.getFullYear()}/${date.getMonth() + 1}`)
} }
function getToday() { function getToday() {
const date = new Date() return new Date(dayjs().startOf('day').format('YYYY/MM/DD HH:mm:ss'))
return new Date(`${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`)
} }
function getYesterday() { function getYesterday() {
const date = new Date(new Date().getTime() - 24 * 60 * 60 * 1000) return new Date(dayjs().subtract(1, 'day').startOf('day').format('YYYY/MM/DD HH:mm:ss'))
return new Date(`${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`)
} }
function getMonthBeginning() { function getMonthBeginning() {
const date = new Date() return new Date(dayjs().startOf('month').format('YYYY/MM/DD HH:mm:ss'))
return new Date(`${date.getFullYear()}/${date.getMonth() + 1}/1`)
} }
function getMonthEnd() { function getMonthEnd() {
@ -50,99 +45,50 @@ function getMonthEnd() {
} }
function getYearBeginning() { function getYearBeginning() {
const date = new Date() return new Date(dayjs().startOf('year').format('YYYY/MM/DD HH:mm:ss'))
return new Date(`${date.getFullYear()}/1/1`)
} }
function getYearMonthRange(result, flag, sort) { function getYearMonthRange(result, sort, type) {
const [direction, scene] = (sort || '').split('-') const [direction, scene] = (sort || '').split('-')
const [dateTimeType] = (flag || '').split('range')
if (direction === 'start') { if (direction === 'start') {
return result return new Date(result.startOf(type).format('YYYY/MM/DD HH:mm:ss'))
} else if (direction === 'end') { } else if (direction === 'end') {
if (scene === 'config') { if (scene === 'config') {
return result return new Date(result.format('YYYY/MM/DD HH:mm:ss'))
} else if (scene === 'panel') { } else if (scene === 'panel') {
return new Date( return new Date(dayjs(result).endOf(type).format('YYYY/MM/DD HH:mm:ss'))
+getCustomTime(1, dateTimeType, dateTimeType, 'b', null, flag, 'start-config', result) -
1000
)
} }
} }
} }
function getCustomTime( function getCustomTime(
timeNum: number, timeNum: number,
timeType: string, timeType: ManipulateType | 'date',
timeGranularity: string, timeGranularity: string,
around: string, around: string,
arbitraryTime?: Date, arbitraryTime?: Date,
timeGranularityMultiple?: string, timeGranularityMultiple?: string,
sort?: string, sort?: string
withDate?: Date
) { ) {
const date = withDate ? new Date(withDate) : new Date() const type = around === 'f' ? 'subtract' : 'add'
const num = around === 'f' ? -timeNum : timeNum
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
let resultYear = timeType === 'year' ? year + num : year const result = dayjs()[type](timeNum, timeType === 'date' ? 'day' : timeType)
let resultMonth = timeType === 'month' ? month + num : month
if (resultMonth > 12) {
resultYear += parseInt(`${resultMonth / 12}`)
resultMonth = resultMonth % 12
} else if (resultMonth < 0) {
resultYear += parseInt(`${resultMonth / 12}`) - 1
resultMonth = (resultMonth % 12) + 12
} else if (resultMonth === 0) {
resultYear += parseInt(`${resultMonth / 12}`) - 1
resultMonth = 12
}
const resultDate =
timeType === 'date' ? new Date(date.getTime() + 24 * 60 * 60 * 1000 * num).getDate() : day
if (timeType === 'date') {
resultMonth = new Date(date.getTime() + 24 * 60 * 60 * 1000 * num).getMonth() + 1
resultYear = new Date(date.getTime() + 24 * 60 * 60 * 1000 * num).getFullYear()
}
switch (timeGranularityMultiple) { if (['monthrange', 'yearrange', 'daterange'].includes(timeGranularityMultiple)) {
case 'monthrange': return getYearMonthRange(result, sort, timeGranularityMultiple.split('range')[0])
return getYearMonthRange(new Date(`${resultYear}/${resultMonth}/1`), 'monthrange', sort)
case 'yearrange':
return getYearMonthRange(new Date(`${resultYear}/1`), 'yearrange', sort)
case 'daterange':
return getYearMonthRange(
new Date(`${resultYear}/${resultMonth}/${resultDate}`),
'daterange',
sort
)
default:
break
} }
if (!!arbitraryTime) { if (!!arbitraryTime) {
const time = new Date(arbitraryTime) const time = dayjs(arbitraryTime).format('YYYY/MM/DD HH:mm:ss')
time.setFullYear(resultYear) // eslint-disable-next-line
time.setMonth(resultMonth - 1) const [_, q] = time.split(' ')
time.setDate(resultDate) const [s] = result.format('YYYY/MM/DD HH:mm:ss').split(' ')
return time
return new Date(`${s} ${q}`)
} }
switch (timeGranularity) { const [k] = timeGranularity.split('range')
case 'year': return new Date(result.startOf(k as ManipulateType).format('YYYY/MM/DD HH:mm:ss'))
return new Date(`${resultYear}/1`)
case 'month':
return new Date(`${resultYear}/${resultMonth}/1`)
case 'date':
return new Date(`${resultYear}/${resultMonth}/${resultDate}`)
case 'monthrange':
return new Date(`${resultYear}/${resultMonth}/1`)
case 'yearrange':
return new Date(`${resultYear}/1`)
default:
break
}
} }
function getDynamicRange({ function getDynamicRange({

View File

@ -37,9 +37,6 @@ const { themes } = toRefs(props)
font-size: 12px !important; font-size: 12px !important;
font-weight: 400 !important; font-weight: 400 !important;
} }
:deep(.ed-collapse-item__content) {
padding: 16px !important;
}
:deep(.ed-form-item) { :deep(.ed-form-item) {
display: block; display: block;
margin-bottom: 8px; margin-bottom: 8px;