feat: set config

This commit is contained in:
Qiuxia Fan 2022-01-06 22:30:22 +08:00
parent f19b69d050
commit e72368b6fc
10 changed files with 134 additions and 38 deletions

View File

@ -51,6 +51,9 @@ function drawEcharts(): void {
if (!chart.value) { if (!chart.value) {
return; return;
} }
if (state.instanceChart) {
return;
}
state.instanceChart = echarts.init(chart.value, ""); state.instanceChart = echarts.init(chart.value, "");
unWarp(state.instanceChart).setOption(props.option); unWarp(state.instanceChart).setOption(props.option);
state.instanceChart.on("click", (params: any) => { state.instanceChart.on("click", (params: any) => {

View File

@ -32,7 +32,7 @@ limitations under the License. -->
</el-select> </el-select>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineProps, ref, defineEmits } from "vue"; import { ref, defineEmits } from "vue";
import type { PropType } from "vue"; import type { PropType } from "vue";
import { ElSelect, ElOption } from "element-plus"; import { ElSelect, ElOption } from "element-plus";
@ -42,21 +42,30 @@ interface Option {
} }
const emit = defineEmits(["change"]); const emit = defineEmits(["change"]);
/*global defineProps*/
const props = defineProps({ const props = defineProps({
options: { options: {
type: Array as PropType<Option[]>, type: Array as PropType<Option[]>,
default: () => [], default: () => [],
}, },
value: { type: String, default: "" }, value: {
type: [Array, String] as PropType<string[] | string>,
default: () => [],
},
size: { type: String, default: "small" }, size: { type: String, default: "small" },
placeholder: { type: String, default: "Select a option" }, placeholder: { type: String, default: "Select a option" },
borderRadius: { type: Number, default: 3 }, borderRadius: { type: Number, default: 3 },
multiple: { type: Boolean, default: false }, multiple: { type: Boolean, default: false },
}); });
const selected = ref<string>(props.value); const selected = ref<string[] | string>(props.value);
function changeSelected() { function changeSelected() {
if (!props.multiple) {
return;
}
const options = props.options.filter((d: Option) => const options = props.options.filter((d: Option) =>
selected.value.includes(d.value) props.multiple
? selected.value.includes(d.value)
: selected.value === d.value
); );
emit("change", options); emit("change", options);
} }

View File

@ -23,7 +23,7 @@ export const ConfigData: LayoutConfig = {
i: "0", i: "0",
metrics: ["service_resp_time"], metrics: ["service_resp_time"],
queryMetricType: "readMetricsValues", queryMetricType: "readMetricsValues",
visualization: "Bar", chart: "Line",
widget: { widget: {
title: "Title", title: "Title",
tips: "Tooltip", tips: "Tooltip",

View File

@ -24,7 +24,7 @@ export interface LayoutConfig {
graph?: GraphConfig; graph?: GraphConfig;
standard?: StandardConfig; standard?: StandardConfig;
metrics?: string[]; metrics?: string[];
visualization?: string; chart?: string;
queryMetricType?: string; queryMetricType?: string;
} }

View File

@ -15,25 +15,25 @@ limitations under the License. -->
<template> <template>
<div class="widget-config flex-v"> <div class="widget-config flex-v">
<div class="graph"> <div class="graph">
<div class="header">Title</div> <div class="header">{{ title }}</div>
<div class="render-chart"> <div class="render-chart">
<component <component
:is="states.chartType" :is="chartType"
:intervalTime="appStoreWithOut.intervalTime" :intervalTime="appStoreWithOut.intervalTime"
:data="states.source" :data="source"
/> />
</div> </div>
<span v-show="!states.source">{{ t("noData") }}</span> <span v-show="!source">{{ t("noData") }}</span>
</div> </div>
<div class="collapse" :style="{ height: configHeight + 'px' }"> <div class="collapse" :style="{ height: configHeight + 'px' }">
<el-collapse <el-collapse
v-model="states.activeNames" v-model="activeNames"
:style="{ '--el-collapse-header-font-size': '15px' }" :style="{ '--el-collapse-header-font-size': '15px' }"
> >
<el-collapse-item :title="t('metricName')" name="1"> <el-collapse-item :title="t('metricName')" name="1">
<div> <div>
<Selector <Selector
:value="states.metrics" :value="metrics"
:options="metricOpts" :options="metricOpts"
:multiple="true" :multiple="true"
size="mini" size="mini"
@ -42,9 +42,9 @@ limitations under the License. -->
class="selectors" class="selectors"
/> />
<Selector <Selector
v-show="states.valueType" v-if="valueType"
:value="states.valueType" :value="valueType"
:options="states.valueTypes" :options="valueTypes"
size="mini" size="mini"
placeholder="Select a metric" placeholder="Select a metric"
@change="changeValueType" @change="changeValueType"
@ -58,17 +58,20 @@ limitations under the License. -->
v-for="(type, index) in ChartTypes" v-for="(type, index) in ChartTypes"
:key="index" :key="index"
@click="changeChartType(type)" @click="changeChartType(type)"
:class="{ active: type.value === states.chartType }" :class="{ active: type.value === chartType }"
> >
{{ type.label }} {{ type.label }}
</span> </span>
</div> </div>
</el-collapse-item> </el-collapse-item>
<el-collapse-item :title="t('graphStyles')" name="3"> <el-collapse-item :title="t('graphStyles')" name="3">
<component :is="`${states.chartType}Config`" /> <component
:is="`${chartType}Config`"
:config="dashboardStore.selectedWidget.graph"
/>
</el-collapse-item> </el-collapse-item>
<el-collapse-item :title="t('widgetOptions')" name="4"> <el-collapse-item :title="t('widgetOptions')" name="4">
<WidgetOptions /> <WidgetOptions @update="updateWidgetOptions" />
</el-collapse-item> </el-collapse-item>
<el-collapse-item :title="t('standardOptions')" name="5"> <el-collapse-item :title="t('standardOptions')" name="5">
<StandardOptions /> <StandardOptions />
@ -86,7 +89,7 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { reactive, defineComponent } from "vue"; import { reactive, defineComponent, toRefs } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
@ -118,30 +121,41 @@ export default defineComponent({
const appStoreWithOut = useAppStoreWithOut(); const appStoreWithOut = useAppStoreWithOut();
const { loading } = Loading(); const { loading } = Loading();
const states = reactive<{ const states = reactive<{
metrics?: string[] | string; metrics: string[];
valueTypes: Option[]; valueTypes: Option[];
valueType: string; valueType: string;
metricQueryType: string; metricQueryType: string;
chartType: string; chartType: string;
activeNames: string; activeNames: string;
tips: string;
source: any; source: any;
title: string;
}>({ }>({
metrics: "", metrics: dashboardStore.selectedWidget.metrics || [],
valueTypes: [], valueTypes: [],
valueType: "", valueType: "",
metricQueryType: "", metricQueryType: "",
chartType: "Line", chartType: dashboardStore.selectedWidget.chart,
activeNames: "1", activeNames: "1",
source: {}, source: {},
tips: "",
title: "",
}); });
async function changeMetrics(val: Option[]) { queryMetricType(states.metrics[0]);
if (!val.length) {
async function changeMetrics(arr: Option[]) {
if (!arr.length) {
states.valueTypes = []; states.valueTypes = [];
states.valueType = ""; states.valueType = "";
return; return;
} }
states.metrics = arr.map((d: Option) => String(d.value));
queryMetricType(String(arr[0].value));
}
async function queryMetricType(metric: string) {
const loadingInstance = loading({ text: t("loading"), fullscreen: true }); const loadingInstance = loading({ text: t("loading"), fullscreen: true });
const resp = await dashboardStore.fetchMetricType(val[0].value); const resp = await dashboardStore.fetchMetricType(metric);
loadingInstance.close(); loadingInstance.close();
if (resp.error) { if (resp.error) {
ElMessage.error(resp.data.error); ElMessage.error(resp.data.error);
@ -150,14 +164,18 @@ export default defineComponent({
const { typeOfMetrics } = resp.data; const { typeOfMetrics } = resp.data;
states.valueTypes = ValuesTypes[typeOfMetrics]; states.valueTypes = ValuesTypes[typeOfMetrics];
states.valueType = ValuesTypes[typeOfMetrics][0].value; states.valueType = ValuesTypes[typeOfMetrics][0].value;
console.log(states.valueType);
} }
function changeValueType(val: Option[]) { function changeValueType(val: Option[]) {
states.valueType = String(val[0].value); states.valueType = String(val[0].value);
states.metricQueryType = (MetricQueryTypes as any)[states.valueType]; states.metricQueryType = (MetricQueryTypes as any)[states.valueType];
} }
function changeChartType(item: Option) { function changeChartType(item: Option) {
states.chartType = String(item.value); states.chartType = String(item.value);
} }
const metricOpts = [ const metricOpts = [
{ value: "service_apdex", label: "service_apdex" }, { value: "service_apdex", label: "service_apdex" },
{ value: "service_sla", label: "service_sla" }, { value: "service_sla", label: "service_sla" },
@ -171,6 +189,16 @@ export default defineComponent({
{ value: "service_mq_consume_count", label: "service_mq_consume_count" }, { value: "service_mq_consume_count", label: "service_mq_consume_count" },
]; ];
const configHeight = document.documentElement.clientHeight - 520; const configHeight = document.documentElement.clientHeight - 520;
function updateWidgetOptions(param: any) {
if (param.title !== undefined) {
states.title = param.title;
}
if (param.tips !== undefined) {
states.tips = param.tips;
}
}
async function queryMetrics() { async function queryMetrics() {
const json = await dashboardStore.fetchMetricValue( const json = await dashboardStore.fetchMetricValue(
dashboardStore.selectedWidget dashboardStore.selectedWidget
@ -192,9 +220,11 @@ export default defineComponent({
[m]: metricVal, [m]: metricVal,
}; };
} }
queryMetrics(); queryMetrics();
return { return {
states, ...toRefs(states),
changeChartType, changeChartType,
changeValueType, changeValueType,
changeMetrics, changeMetrics,
@ -202,7 +232,9 @@ export default defineComponent({
appStoreWithOut, appStoreWithOut,
ChartTypes, ChartTypes,
metricOpts, metricOpts,
updateWidgetOptions,
configHeight, configHeight,
dashboardStore,
}; };
}, },
}); });
@ -223,10 +255,11 @@ export default defineComponent({
} }
.header { .header {
padding: 3px 0; height: 25px;
line-height: 25px;
text-align: center; text-align: center;
// border-bottom: 1px solid #eee;
background-color: aliceblue; background-color: aliceblue;
font-size: 12px;
} }
.render-chart { .render-chart {

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<div class="item"> <div class="item">
<span class="label">{{ t("title") }}</span> <span class="label">{{ t("unit") }}</span>
<el-input <el-input
class="input" class="input"
v-model="state.unit" v-model="state.unit"

View File

@ -20,6 +20,7 @@ limitations under the License. -->
v-model="title" v-model="title"
size="mini" size="mini"
placeholder="Please input title" placeholder="Please input title"
@change="updateTitle"
/> />
</div> </div>
<div class="item"> <div class="item">
@ -29,17 +30,26 @@ limitations under the License. -->
v-model="tooltip" v-model="tooltip"
size="mini" size="mini"
placeholder="Please input tips" placeholder="Please input tips"
@change="updateTips"
/> />
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ElInput } from "element-plus"; import { ElInput } from "element-plus";
import { ref } from "vue"; import { ref, defineEmits } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const emits = defineEmits(["update"]);
const { t } = useI18n(); const { t } = useI18n();
const title = ref<string>(""); const title = ref<string>("");
const tooltip = ref<string>(""); const tooltip = ref<string>("");
function updateTitle(value: string) {
emits("update", { title: value });
}
function updateTips(value: string) {
emits("update", { tips: value });
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.label { .label {

View File

@ -12,7 +12,50 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template>bar config</template> <template>
<div>
<span class="label">Bar Width</span>
<el-slider
class="bar-width"
v-model="barWidth"
show-input
input-size="small"
/>
</div>
<div>
<span class="label">Show Background</span>
<el-switch
v-model="showBackground"
active-text="Yes"
inactive-text="No"
></el-switch>
</div>
</template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { defineProps, ref } from "vue";
import type { PropType } from "vue";
import { BarConfig } from "./types";
import { ElSlider, ElSwitch } from "element-plus";
const props = defineProps({
config: {
type: Object as PropType<BarConfig>,
default: () => ({ showBackground: true, barWidth: 30 }),
},
});
const barWidth = ref(props.config.barWidth);
const showBackground = ref(props.config.showBackground);
</script> </script>
<style lang="scss" scoped>
.bar-width {
width: 500px;
margin-top: -13px;
}
.label {
font-size: 13px;
font-weight: 500;
display: block;
margin-bottom: 5px;
}
</style>

View File

@ -16,7 +16,7 @@ limitations under the License. -->
<Graph :option="option" /> <Graph :option="option" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineProps, ref, computed } from "vue"; import { defineProps, computed } from "vue";
import type { PropType } from "vue"; import type { PropType } from "vue";
const props = defineProps({ const props = defineProps({
@ -26,8 +26,6 @@ const props = defineProps({
}, },
theme: { type: String, default: "dark" }, theme: { type: String, default: "dark" },
}); });
/*global Nullable */
const chart = ref<Nullable<HTMLElement>>(null);
const option = computed(() => getOption()); const option = computed(() => getOption());
function getOption() { function getOption() {
return { return {

View File

@ -28,7 +28,7 @@ limitations under the License. -->
</div> </div>
<div class="body" :style="{ height: '200px', width: '400px' }"> <div class="body" :style="{ height: '200px', width: '400px' }">
<component <component
:is="item.visualization" :is="item.chart"
:intervalTime="appStoreWithOut.intervalTime" :intervalTime="appStoreWithOut.intervalTime"
:data="state.source" :data="state.source"
/> />
@ -76,11 +76,11 @@ export default defineComponent({
} }
function removeWidget() { function removeWidget() {
dashboardStore.removeWidget(props.item); dashboardStore.removeWidget(item);
} }
function setConfig() { function setConfig() {
dashboardStore.setConfigPanel(true); dashboardStore.setConfigPanel(true);
dashboardStore.selectWidget(props.item); dashboardStore.selectWidget(item);
} }
return { return {
state, state,