mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-02 18:15:22 +00:00
feat: Enhance associations for the Event widget (#120)
This commit is contained in:
parent
e144b43267
commit
42ead4a572
22
package-lock.json
generated
22
package-lock.json
generated
@ -22,8 +22,7 @@
|
|||||||
"vue-grid-layout": "^3.0.0-beta1",
|
"vue-grid-layout": "^3.0.0-beta1",
|
||||||
"vue-i18n": "^9.1.9",
|
"vue-i18n": "^9.1.9",
|
||||||
"vue-router": "^4.0.0-0",
|
"vue-router": "^4.0.0-0",
|
||||||
"vue-types": "^4.1.1",
|
"vue-types": "^4.1.1"
|
||||||
"vuex": "^4.0.0-0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/d3": "^7.1.0",
|
"@types/d3": "^7.1.0",
|
||||||
@ -27338,17 +27337,6 @@
|
|||||||
"vue": "^2.0.0 || ^3.0.0"
|
"vue": "^2.0.0 || ^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vuex": {
|
|
||||||
"version": "4.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
|
|
||||||
"integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
|
|
||||||
"dependencies": {
|
|
||||||
"@vue/devtools-api": "^6.0.0-beta.11"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"vue": "^3.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/w3c-hr-time": {
|
"node_modules/w3c-hr-time": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
||||||
@ -50552,14 +50540,6 @@
|
|||||||
"is-plain-object": "5.0.0"
|
"is-plain-object": "5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vuex": {
|
|
||||||
"version": "4.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
|
|
||||||
"integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
|
|
||||||
"requires": {
|
|
||||||
"@vue/devtools-api": "^6.0.0-beta.11"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"w3c-hr-time": {
|
"w3c-hr-time": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
"vue-grid-layout": "^3.0.0-beta1",
|
"vue-grid-layout": "^3.0.0-beta1",
|
||||||
"vue-i18n": "^9.1.9",
|
"vue-i18n": "^9.1.9",
|
||||||
"vue-router": "^4.0.0-0",
|
"vue-router": "^4.0.0-0",
|
||||||
"vue-types": "^4.1.1",
|
"vue-types": "^4.1.1"
|
||||||
"vuex": "^4.0.0-0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/d3": "^7.1.0",
|
"@types/d3": "^7.1.0",
|
||||||
|
@ -46,8 +46,12 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
type: Object as PropType<{
|
type: Object as PropType<{
|
||||||
value: number | string;
|
duration: {
|
||||||
dataIndex: number;
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
};
|
||||||
|
isRange: boolean;
|
||||||
|
dataIndex?: number;
|
||||||
sourceId: string;
|
sourceId: string;
|
||||||
}>,
|
}>,
|
||||||
},
|
},
|
||||||
@ -73,7 +77,7 @@ onMounted(async () => {
|
|||||||
});
|
});
|
||||||
document.addEventListener(
|
document.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
() => {
|
(event: Event) => {
|
||||||
if (instance.isDisposed()) {
|
if (instance.isDisposed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -84,6 +88,27 @@ onMounted(async () => {
|
|||||||
type: "updateAxisPointer",
|
type: "updateAxisPointer",
|
||||||
currTrigger: "leave",
|
currTrigger: "leave",
|
||||||
});
|
});
|
||||||
|
if (
|
||||||
|
["vis-item-overflow", "vis-item-content"].includes(
|
||||||
|
(event.target as HTMLDivElement).className
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const series = (window as any).structuredClone(props.option.series);
|
||||||
|
for (const temp of series) {
|
||||||
|
if (temp.markArea) {
|
||||||
|
delete temp.markArea;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
...props.option,
|
||||||
|
series,
|
||||||
|
};
|
||||||
|
if (JSON.stringify(options) === JSON.stringify(props.option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setOptions(options);
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@ -110,6 +135,39 @@ watch(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (props.filters) {
|
if (props.filters) {
|
||||||
|
if (props.filters.isRange) {
|
||||||
|
const markArea = {
|
||||||
|
silent: true,
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.3,
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
xAxis: props.filters.duration.startTime,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
xAxis: props.filters.duration.endTime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const series = (window as any).structuredClone(props.option.series);
|
||||||
|
for (const [key, temp] of series.entries()) {
|
||||||
|
if (key === 0) {
|
||||||
|
temp.markArea = markArea;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
...props.option,
|
||||||
|
series,
|
||||||
|
};
|
||||||
|
if (JSON.stringify(options) === JSON.stringify(props.option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setOptions(options);
|
||||||
|
return;
|
||||||
|
}
|
||||||
instance.dispatchAction({
|
instance.dispatchAction({
|
||||||
type: "showTip",
|
type: "showTip",
|
||||||
dataIndex: props.filters.dataIndex,
|
dataIndex: props.filters.dataIndex,
|
||||||
|
@ -18,7 +18,6 @@ import {
|
|||||||
BarSeriesOption,
|
BarSeriesOption,
|
||||||
LineSeriesOption,
|
LineSeriesOption,
|
||||||
HeatmapSeriesOption,
|
HeatmapSeriesOption,
|
||||||
PieSeriesOption,
|
|
||||||
SankeySeriesOption,
|
SankeySeriesOption,
|
||||||
} from "echarts/charts";
|
} from "echarts/charts";
|
||||||
import {
|
import {
|
||||||
@ -46,7 +45,6 @@ export type ECOption = echarts.ComposeOption<
|
|||||||
| DatasetComponentOption
|
| DatasetComponentOption
|
||||||
| LegendComponentOption
|
| LegendComponentOption
|
||||||
| HeatmapSeriesOption
|
| HeatmapSeriesOption
|
||||||
| PieSeriesOption
|
|
||||||
| SankeySeriesOption
|
| SankeySeriesOption
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
@ -147,6 +147,7 @@ const msg = {
|
|||||||
nameTip:
|
nameTip:
|
||||||
"The name only supports Chinese and English, horizontal lines and underscores. The length of the name is limited to 300 characters",
|
"The name only supports Chinese and English, horizontal lines and underscores. The length of the name is limited to 300 characters",
|
||||||
duplicateName: "Duplicate name",
|
duplicateName: "Duplicate name",
|
||||||
|
enableAssociate: "Enable association",
|
||||||
seconds: "Seconds",
|
seconds: "Seconds",
|
||||||
hourTip: "Select Hour",
|
hourTip: "Select Hour",
|
||||||
minuteTip: "Select Minute",
|
minuteTip: "Select Minute",
|
||||||
|
@ -147,6 +147,7 @@ const msg = {
|
|||||||
duplicateName: "Nombre duplicado",
|
duplicateName: "Nombre duplicado",
|
||||||
nameTip:
|
nameTip:
|
||||||
"El nombre sólo admite chino e inglés, líneas horizontales y subrayado, y la longitud del nombre no excederá de 300 caracteres",
|
"El nombre sólo admite chino e inglés, líneas horizontales y subrayado, y la longitud del nombre no excederá de 300 caracteres",
|
||||||
|
enableAssociate: "Activar asociación",
|
||||||
seconds: "Segundos",
|
seconds: "Segundos",
|
||||||
hourTip: "Seleccione Hora",
|
hourTip: "Seleccione Hora",
|
||||||
minuteTip: "Seleccione Minuto",
|
minuteTip: "Seleccione Minuto",
|
||||||
|
@ -142,6 +142,7 @@ const msg = {
|
|||||||
begin: "开始",
|
begin: "开始",
|
||||||
associateOptions: "关联选项",
|
associateOptions: "关联选项",
|
||||||
widget: "部件",
|
widget: "部件",
|
||||||
|
enableAssociate: "启用关联",
|
||||||
nameTip: "该名称仅支持中文和英文、横线和下划线, 并且限制长度为300个字符",
|
nameTip: "该名称仅支持中文和英文、横线和下划线, 并且限制长度为300个字符",
|
||||||
duplicateName: "重复的名称",
|
duplicateName: "重复的名称",
|
||||||
seconds: "秒",
|
seconds: "秒",
|
||||||
|
@ -104,6 +104,9 @@ export const eventStore = defineStore({
|
|||||||
scope = "Endpoint";
|
scope = "Endpoint";
|
||||||
}
|
}
|
||||||
item.scope = scope;
|
item.scope = scope;
|
||||||
|
if (!item.endTime || item.endTime === item.startTime) {
|
||||||
|
item.endTime = Number(item.startTime) + 60000;
|
||||||
|
}
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
11
src/types/dashboard.d.ts
vendored
11
src/types/dashboard.d.ts
vendored
@ -38,7 +38,16 @@ export interface LayoutConfig {
|
|||||||
metricConfig?: MetricConfigOpt[];
|
metricConfig?: MetricConfigOpt[];
|
||||||
id?: string;
|
id?: string;
|
||||||
associate?: { widgetId: string }[];
|
associate?: { widgetId: string }[];
|
||||||
filters?: { dataIndex: number; sourceId: string };
|
eventAssociate?: boolean;
|
||||||
|
filters?: {
|
||||||
|
dataIndex: number;
|
||||||
|
sourceId: string;
|
||||||
|
isRange?: boolean;
|
||||||
|
duration?: {
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MetricConfigOpt = {
|
export type MetricConfigOpt = {
|
||||||
|
@ -16,13 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
import * as echarts from "echarts/core";
|
import * as echarts from "echarts/core";
|
||||||
|
|
||||||
import {
|
import { BarChart, LineChart, HeatmapChart, SankeyChart } from "echarts/charts";
|
||||||
BarChart,
|
|
||||||
LineChart,
|
|
||||||
PieChart,
|
|
||||||
HeatmapChart,
|
|
||||||
SankeyChart,
|
|
||||||
} from "echarts/charts";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
TitleComponent,
|
TitleComponent,
|
||||||
@ -32,6 +26,7 @@ import {
|
|||||||
DataZoomComponent,
|
DataZoomComponent,
|
||||||
VisualMapComponent,
|
VisualMapComponent,
|
||||||
TimelineComponent,
|
TimelineComponent,
|
||||||
|
MarkAreaComponent,
|
||||||
} from "echarts/components";
|
} from "echarts/components";
|
||||||
|
|
||||||
import { SVGRenderer } from "echarts/renderers";
|
import { SVGRenderer } from "echarts/renderers";
|
||||||
@ -43,13 +38,13 @@ echarts.use([
|
|||||||
GridComponent,
|
GridComponent,
|
||||||
BarChart,
|
BarChart,
|
||||||
LineChart,
|
LineChart,
|
||||||
PieChart,
|
|
||||||
HeatmapChart,
|
HeatmapChart,
|
||||||
SankeyChart,
|
SankeyChart,
|
||||||
SVGRenderer,
|
SVGRenderer,
|
||||||
DataZoomComponent,
|
DataZoomComponent,
|
||||||
VisualMapComponent,
|
VisualMapComponent,
|
||||||
TimelineComponent,
|
TimelineComponent,
|
||||||
|
MarkAreaComponent,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export default echarts;
|
export default echarts;
|
||||||
|
82
src/views/dashboard/configuration/Event.vue
Normal file
82
src/views/dashboard/configuration/Event.vue
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<span class="label">{{ t("enableAssociate") }}</span>
|
||||||
|
<el-switch
|
||||||
|
v-model="eventAssociate"
|
||||||
|
active-text="Yes"
|
||||||
|
inactive-text="No"
|
||||||
|
@change="updateConfig"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<el-button size="small" @click="cancelConfig">
|
||||||
|
{{ t("cancel") }}
|
||||||
|
</el-button>
|
||||||
|
<el-button size="small" type="primary" @click="applyConfig">
|
||||||
|
{{ t("apply") }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const originConfig = dashboardStore.selectedGrid;
|
||||||
|
const eventAssociate = ref(dashboardStore.selectedGrid.eventAssociate || false);
|
||||||
|
|
||||||
|
function updateConfig() {
|
||||||
|
dashboardStore.selectedGrid = {
|
||||||
|
...dashboardStore.selectedGrid,
|
||||||
|
eventAssociate,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget(dashboardStore.selectedGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyConfig() {
|
||||||
|
dashboardStore.setConfigPanel(false);
|
||||||
|
dashboardStore.setConfigs(dashboardStore.selectedGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelConfig() {
|
||||||
|
dashboardStore.selectWidget(originConfig);
|
||||||
|
dashboardStore.setConfigPanel(false);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: right;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
@ -18,9 +18,11 @@
|
|||||||
import Text from "./Text.vue";
|
import Text from "./Text.vue";
|
||||||
import Widget from "./Widget.vue";
|
import Widget from "./Widget.vue";
|
||||||
import Topology from "./Topology.vue";
|
import Topology from "./Topology.vue";
|
||||||
|
import Event from "./Event.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Text,
|
Text,
|
||||||
Widget,
|
Widget,
|
||||||
Topology,
|
Topology,
|
||||||
|
Event,
|
||||||
};
|
};
|
||||||
|
@ -41,32 +41,16 @@ const widgetIds = ref<string[]>(
|
|||||||
associate.map((d: { widgetId: string }) => d.widgetId)
|
associate.map((d: { widgetId: string }) => d.widgetId)
|
||||||
);
|
);
|
||||||
const widgets = computed(() => {
|
const widgets = computed(() => {
|
||||||
const isLinear = ["Bar", "Line", "Area"].includes(
|
const all = getDashboard(dashboardStore.currentDashboard).widgets;
|
||||||
dashboardStore.selectedGrid.graph && dashboardStore.selectedGrid.graph.type
|
const items = all.filter(
|
||||||
);
|
|
||||||
// const isRank = ["TopList"].includes(
|
|
||||||
// dashboardStore.selectedGrid.graph && dashboardStore.selectedGrid.graph.type
|
|
||||||
// );
|
|
||||||
const { widgets } = getDashboard(dashboardStore.currentDashboard);
|
|
||||||
const items = widgets.filter(
|
|
||||||
(d: { value: string; label: string } & LayoutConfig) => {
|
(d: { value: string; label: string } & LayoutConfig) => {
|
||||||
if (dashboardStore.selectedGrid.id !== d.id) {
|
const isLinear = ["Bar", "Line", "Area"].includes(
|
||||||
if (
|
(d.graph && d.graph.type) || ""
|
||||||
isLinear &&
|
);
|
||||||
d.type === "Widget" &&
|
if (isLinear && d.id && dashboardStore.selectedGrid.id !== d.id) {
|
||||||
d.widget &&
|
d.value = d.id;
|
||||||
d.widget.name &&
|
d.label = (d.widget && d.widget.name) || d.id;
|
||||||
d.id
|
return d;
|
||||||
) {
|
|
||||||
d.value = d.id;
|
|
||||||
d.label = d.widget.name;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
// if (isRank && d.type !== "Widget" && d.widget && d.id) {
|
|
||||||
// d.value = d.id;
|
|
||||||
// d.label = d.widget.name || d.id;
|
|
||||||
// return d;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -84,6 +68,7 @@ function updateWidgetConfig(options: Option[]) {
|
|||||||
associate: opt,
|
associate: opt,
|
||||||
};
|
};
|
||||||
dashboardStore.selectWidget({ ...widget });
|
dashboardStore.selectWidget({ ...widget });
|
||||||
|
|
||||||
// remove unuse association widget option
|
// remove unuse association widget option
|
||||||
for (const id of widgetIds.value) {
|
for (const id of widgetIds.value) {
|
||||||
if (!newVal.includes(id)) {
|
if (!newVal.includes(id)) {
|
||||||
|
@ -25,6 +25,9 @@ limitations under the License. -->
|
|||||||
<Icon iconName="ellipsis_v" size="middle" class="operation" />
|
<Icon iconName="ellipsis_v" size="middle" class="operation" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
<div class="tools" @click="editConfig">
|
||||||
|
<span>{{ t("edit") }}</span>
|
||||||
|
</div>
|
||||||
<div class="tools" @click="removeWidget">
|
<div class="tools" @click="removeWidget">
|
||||||
<span>{{ t("delete") }}</span>
|
<span>{{ t("delete") }}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -58,6 +61,10 @@ const dashboardStore = useDashboardStore();
|
|||||||
function removeWidget() {
|
function removeWidget() {
|
||||||
dashboardStore.removeControls(props.data);
|
dashboardStore.removeControls(props.data);
|
||||||
}
|
}
|
||||||
|
function editConfig() {
|
||||||
|
dashboardStore.setConfigPanel(true);
|
||||||
|
dashboardStore.selectWidget(props.data);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.event-wrapper {
|
.event-wrapper {
|
||||||
|
@ -38,9 +38,13 @@ defineProps({
|
|||||||
type: Object as PropType<
|
type: Object as PropType<
|
||||||
AreaConfig & {
|
AreaConfig & {
|
||||||
filters: {
|
filters: {
|
||||||
value: number | string;
|
|
||||||
dataIndex: number;
|
|
||||||
sourceId: string;
|
sourceId: string;
|
||||||
|
duration: {
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
};
|
||||||
|
isRange: boolean;
|
||||||
|
dataIndex?: number;
|
||||||
};
|
};
|
||||||
} & { id: string }
|
} & { id: string }
|
||||||
>,
|
>,
|
||||||
|
@ -18,7 +18,6 @@ limitations under the License. -->
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { Event } from "@/types/events";
|
|
||||||
import { BarConfig, EventParams } from "@/types/dashboard";
|
import { BarConfig, EventParams } from "@/types/dashboard";
|
||||||
|
|
||||||
/*global defineProps, defineEmits */
|
/*global defineProps, defineEmits */
|
||||||
@ -30,14 +29,17 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
theme: { type: String, default: "light" },
|
theme: { type: String, default: "light" },
|
||||||
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
|
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<
|
type: Object as PropType<
|
||||||
BarConfig & {
|
BarConfig & {
|
||||||
filters: {
|
filters: {
|
||||||
value: number | string;
|
|
||||||
dataIndex: number;
|
|
||||||
sourceId: string;
|
sourceId: string;
|
||||||
|
duration: {
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
};
|
||||||
|
isRange: boolean;
|
||||||
|
dataIndex?: number;
|
||||||
};
|
};
|
||||||
} & { id: string }
|
} & { id: string }
|
||||||
>,
|
>,
|
||||||
@ -50,30 +52,7 @@ function getOption() {
|
|||||||
const keys = Object.keys(props.data || {}).filter(
|
const keys = Object.keys(props.data || {}).filter(
|
||||||
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
||||||
);
|
);
|
||||||
const startP = keys.length > 1 ? 50 : 15;
|
const temp = keys.map((i: string) => {
|
||||||
const diff = 15;
|
|
||||||
const markAreas = (props.itemEvents || []).map(
|
|
||||||
(event: Event, index: number) => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
name: `${event.name}:${event.type}`,
|
|
||||||
xAxis: event.startTime,
|
|
||||||
y: startP + diff * index,
|
|
||||||
itemStyle: {
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
|
||||||
color: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: event.message,
|
|
||||||
xAxis: event.endTime,
|
|
||||||
y: startP + diff * (index + 1),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const temp = keys.map((i: string, index: number) => {
|
|
||||||
if (!props.intervalTime) {
|
if (!props.intervalTime) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -94,23 +73,6 @@ function getOption() {
|
|||||||
backgroundStyle: {
|
backgroundStyle: {
|
||||||
color: "rgba(180, 180, 180, 0.1)",
|
color: "rgba(180, 180, 180, 0.1)",
|
||||||
},
|
},
|
||||||
markArea:
|
|
||||||
index === 0
|
|
||||||
? {
|
|
||||||
silent: false,
|
|
||||||
data: markAreas,
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
width: 60,
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
label: {
|
|
||||||
position: "bottom",
|
|
||||||
show: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
let color: string[] = [];
|
let color: string[] = [];
|
||||||
|
@ -18,7 +18,6 @@ limitations under the License. -->
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { Event } from "@/types/events";
|
|
||||||
import { LineConfig, EventParams } from "@/types/dashboard";
|
import { LineConfig, EventParams } from "@/types/dashboard";
|
||||||
|
|
||||||
/*global defineProps, defineEmits */
|
/*global defineProps, defineEmits */
|
||||||
@ -30,14 +29,17 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
theme: { type: String, default: "light" },
|
theme: { type: String, default: "light" },
|
||||||
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
|
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<
|
type: Object as PropType<
|
||||||
LineConfig & {
|
LineConfig & {
|
||||||
filters: {
|
filters: {
|
||||||
value: number | string;
|
|
||||||
dataIndex: number;
|
|
||||||
sourceId: string;
|
sourceId: string;
|
||||||
|
duration: {
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
};
|
||||||
|
isRange: boolean;
|
||||||
|
dataIndex?: number;
|
||||||
};
|
};
|
||||||
} & { id: string }
|
} & { id: string }
|
||||||
>,
|
>,
|
||||||
@ -58,30 +60,7 @@ function getOption() {
|
|||||||
const keys = Object.keys(props.data || {}).filter(
|
const keys = Object.keys(props.data || {}).filter(
|
||||||
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
||||||
);
|
);
|
||||||
const startP = keys.length > 1 ? 50 : 15;
|
const temp = keys.map((i: any) => {
|
||||||
const diff = 10;
|
|
||||||
const markAreas = (props.itemEvents || []).map(
|
|
||||||
(event: Event, index: number) => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
name: `${event.name}:${event.type}`,
|
|
||||||
xAxis: event.startTime,
|
|
||||||
y: startP + diff * index,
|
|
||||||
itemStyle: {
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
|
||||||
color: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: event.message,
|
|
||||||
xAxis: event.endTime,
|
|
||||||
y: startP + diff * (index + 1),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const temp = keys.map((i: any, index: number) => {
|
|
||||||
const serie: any = {
|
const serie: any = {
|
||||||
data: props.data[i].map((item: any, itemIndex: number) => [
|
data: props.data[i].map((item: any, itemIndex: number) => [
|
||||||
props.intervalTime[itemIndex],
|
props.intervalTime[itemIndex],
|
||||||
@ -98,23 +77,6 @@ function getOption() {
|
|||||||
width: 1.5,
|
width: 1.5,
|
||||||
type: "solid",
|
type: "solid",
|
||||||
},
|
},
|
||||||
markArea:
|
|
||||||
index === 0
|
|
||||||
? {
|
|
||||||
silent: false,
|
|
||||||
data: markAreas,
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
width: 60,
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
label: {
|
|
||||||
position: "bottom",
|
|
||||||
show: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
if (props.config.type === "Area") {
|
if (props.config.type === "Area") {
|
||||||
serie.areaStyle = {
|
serie.areaStyle = {
|
||||||
|
@ -19,15 +19,23 @@ limitations under the License. -->
|
|||||||
import { ref, watch, onMounted } from "vue";
|
import { ref, watch, onMounted } from "vue";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { useThrottleFn } from "@vueuse/core";
|
import { useThrottleFn } from "@vueuse/core";
|
||||||
|
import { Event } from "@/types/events";
|
||||||
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
import { useEventStore } from "@/store/modules/event";
|
import { useEventStore } from "@/store/modules/event";
|
||||||
import { DataSet, Timeline } from "vis-timeline/standalone";
|
import { DataSet, Timeline } from "vis-timeline/standalone";
|
||||||
import "vis-timeline/styles/vis-timeline-graph2d.css";
|
import "vis-timeline/styles/vis-timeline-graph2d.css";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
|
import { dateFormatTime } from "@/utils/dateFormat";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
|
||||||
const eventStore = useEventStore();
|
const eventStore = useEventStore();
|
||||||
/*global Nullable */
|
/*global Nullable */
|
||||||
const timeline = ref<Nullable<HTMLDivElement>>(null);
|
const timeline = ref<Nullable<HTMLDivElement>>(null);
|
||||||
const visGraph = ref<Nullable<any>>(null);
|
const visGraph = ref<Nullable<any>>(null);
|
||||||
const oldVal = ref<{ width: number; height: number }>({ width: 0, height: 0 });
|
const oldVal = ref<{ width: number; height: number }>({ width: 0, height: 0 });
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const appStore = useAppStoreWithOut();
|
||||||
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
||||||
new Date(dayjs(date).format(pattern));
|
new Date(dayjs(date).format(pattern));
|
||||||
const visDate = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
const visDate = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
||||||
@ -49,12 +57,12 @@ function visTimeline() {
|
|||||||
visGraph.value.destroy();
|
visGraph.value.destroy();
|
||||||
}
|
}
|
||||||
const h = timeline.value.getBoundingClientRect().height;
|
const h = timeline.value.getBoundingClientRect().height;
|
||||||
const events = eventStore.events.map((d, index) => {
|
const events = eventStore.events.map((d: Event, index: number) => {
|
||||||
return {
|
return {
|
||||||
id: index + 1,
|
id: index + 1,
|
||||||
content: d.name,
|
content: d.name,
|
||||||
start: dateFormat(d.startTime),
|
start: dateFormat(Number(d.startTime)),
|
||||||
end: dateFormat(d.endTime),
|
end: dateFormat(Number(d.endTime)),
|
||||||
data: d,
|
data: d,
|
||||||
className: d.type,
|
className: d.type,
|
||||||
};
|
};
|
||||||
@ -68,7 +76,7 @@ function visTimeline() {
|
|||||||
autoResize: false,
|
autoResize: false,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
overflowMethod: "cap",
|
overflowMethod: "cap",
|
||||||
template(item) {
|
template(item: Event | any) {
|
||||||
const data = item.data || {};
|
const data = item.data || {};
|
||||||
let tmp = `<div>ID: ${data.uuid || ""}</div>
|
let tmp = `<div>ID: ${data.uuid || ""}</div>
|
||||||
<div>Name: ${data.name || ""}</div>
|
<div>Name: ${data.name || ""}</div>
|
||||||
@ -88,6 +96,38 @@ function visTimeline() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
visGraph.value = new Timeline(timeline.value, items, options);
|
visGraph.value = new Timeline(timeline.value, items, options);
|
||||||
|
visGraph.value.on("select", (properties: { items: number[] }) => {
|
||||||
|
if (!dashboardStore.selectedGrid.eventAssociate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const all = getDashboard(dashboardStore.currentDashboard).widgets;
|
||||||
|
const widgets = all.filter(
|
||||||
|
(d: { value: string; label: string } & LayoutConfig) => {
|
||||||
|
const isLinear = ["Bar", "Line", "Area"].includes(
|
||||||
|
(d.graph && d.graph.type) || ""
|
||||||
|
);
|
||||||
|
if (isLinear) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const index = properties.items[0];
|
||||||
|
const i = events[index - 1 || 0];
|
||||||
|
|
||||||
|
for (const widget of widgets) {
|
||||||
|
const startTime = dateFormatTime(i.start, appStore.duration.step);
|
||||||
|
const endTime = dateFormatTime(i.end, appStore.duration.step);
|
||||||
|
widget.filters = {
|
||||||
|
sourceId: dashboardStore.selectedGrid.id || "",
|
||||||
|
isRange: true,
|
||||||
|
duration: {
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
dashboardStore.setWidget(widget);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function resize() {
|
function resize() {
|
||||||
const observer = new ResizeObserver((entries) => {
|
const observer = new ResizeObserver((entries) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user