尝试优化添加图表功能 图表适配黑暗模式
This commit is contained in:
parent
4277e5cc92
commit
055c011167
|
@ -1,12 +1,15 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { darkTheme } from 'naive-ui'
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<NuxtPwaManifest />
|
<NuxtPwaManifest />
|
||||||
<n-loading-bar-provider>
|
<n-loading-bar-provider>
|
||||||
|
<n-config-provider :theme="$colorMode.value === 'dark' ? darkTheme : null">
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
|
</n-config-provider>
|
||||||
</n-loading-bar-provider>
|
</n-loading-bar-provider>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
transition: color .2s, background-color .2s, border-color .2s, box-shadow .2s, stork .2s, fill .2s, opacity .2s;
|
transition: background-color .08s, border-color .2s, box-shadow .2s, stork .2s, fill .2s, opacity .2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@ -20,3 +20,26 @@ body {
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection CssInvalidPseudoSelector
|
||||||
|
::view-transition-old(root),
|
||||||
|
::view-transition-new(root) {
|
||||||
|
animation: none;
|
||||||
|
mix-blend-mode: normal;
|
||||||
|
}
|
||||||
|
//noinspection CssInvalidPseudoSelector
|
||||||
|
::view-transition-old(root) {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
//noinspection CssInvalidPseudoSelector
|
||||||
|
::view-transition-new(root) {
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
//noinspection CssInvalidPseudoSelector
|
||||||
|
.dark-mode::view-transition-old(root) {
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
//noinspection CssInvalidPseudoSelector
|
||||||
|
.dark-mode::view-transition-new(root) {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
|
@ -3,10 +3,16 @@ import {charts} from "~/config/charts";
|
||||||
import type {PropType} from "vue";
|
import type {PropType} from "vue";
|
||||||
import type {serverValueItem} from "~/components/SettingCard.vue";
|
import type {serverValueItem} from "~/components/SettingCard.vue";
|
||||||
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
|
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
|
||||||
|
import {THEME_KEY} from "vue-echarts";
|
||||||
|
|
||||||
|
|
||||||
const mainLayoutStore = useMainLayoutStore()
|
const mainLayoutStore = useMainLayoutStore()
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
|
const cardRef = ref(null)
|
||||||
|
const {width} = useElementBounding(cardRef)
|
||||||
|
const rangeNum = ref(6)
|
||||||
|
const targetIsVisible = useElementVisibility(cardRef)
|
||||||
|
const isSwitched = ref(false)
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -29,12 +35,8 @@ const props = defineProps({
|
||||||
required: false
|
required: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const cardRef = ref(null)
|
|
||||||
const {width} = useElementBounding(cardRef)
|
watch(() => mainLayoutStore.SelectServer.value, () => {
|
||||||
const rangeNum = ref(6)
|
|
||||||
const targetIsVisible = useElementVisibility(cardRef)
|
|
||||||
const isSwitched = ref(false)
|
|
||||||
watch(() => mainLayoutStore.SelectServer.id, () => {
|
|
||||||
isSwitched.value = true
|
isSwitched.value = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
isSwitched.value = false
|
isSwitched.value = false
|
||||||
|
@ -50,6 +52,17 @@ watchDebounced(
|
||||||
},
|
},
|
||||||
{debounce: 500, maxWait: 1000},
|
{debounce: 500, maxWait: 1000},
|
||||||
)
|
)
|
||||||
|
// watchDebounced(
|
||||||
|
// ()=>useColorMode().value,
|
||||||
|
//
|
||||||
|
// {debounce: 500, maxWait: 1000}
|
||||||
|
// )
|
||||||
|
watch(()=>useColorMode().value,()=>{
|
||||||
|
isSwitched.value = true
|
||||||
|
setTimeout(() => {
|
||||||
|
isSwitched.value = false
|
||||||
|
})
|
||||||
|
})
|
||||||
const valueIds = computed(() => props.values.map(x => x.dataType))
|
const valueIds = computed(() => props.values.map(x => x.dataType))
|
||||||
const valueNames = computed(() => props.values.map(x => x.dataName))
|
const valueNames = computed(() => props.values.map(x => x.dataName))
|
||||||
const items = [
|
const items = [
|
||||||
|
|
|
@ -32,6 +32,7 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
const option = computed(() => {
|
const option = computed(() => {
|
||||||
return {
|
return {
|
||||||
|
backgroundColor:'',
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
|
@ -87,9 +88,6 @@ const option = computed(() => {
|
||||||
],
|
],
|
||||||
legend: {
|
legend: {
|
||||||
data: props.valueNames,
|
data: props.valueNames,
|
||||||
textStyle: {
|
|
||||||
fontSize: 16,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
series: props.valueNames?.map((id) => {
|
series: props.valueNames?.map((id) => {
|
||||||
return {
|
return {
|
||||||
|
@ -169,7 +167,7 @@ const zoom = _.throttle((e: any) => {
|
||||||
'Authorization': 'Bearer ' + useCookie('token').value
|
'Authorization': 'Bearer ' + useCookie('token').value
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
ServerId: mainLayoutStore.SelectServer.id,
|
ServerId: mainLayoutStore.SelectServer.value,
|
||||||
DataTypes: props.valueIds,
|
DataTypes: props.valueIds,
|
||||||
StartIndex: endIndex,
|
StartIndex: endIndex,
|
||||||
},
|
},
|
||||||
|
@ -203,6 +201,7 @@ const zoom = _.throttle((e: any) => {
|
||||||
<template>
|
<template>
|
||||||
<v-chart ref="chartRet" :loading="isLoading" :manual-update="true" :option="option"
|
<v-chart ref="chartRet" :loading="isLoading" :manual-update="true" :option="option"
|
||||||
autoresize
|
autoresize
|
||||||
|
:theme="$colorMode.value"
|
||||||
class="chart"
|
class="chart"
|
||||||
@datazoom="zoom"/>
|
@datazoom="zoom"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -10,7 +10,7 @@ const mainLayoutStore = useMainLayoutStore()
|
||||||
const dataStore = useDataStore()
|
const dataStore = useDataStore()
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const chartRef = ref<any>(null);
|
const chartRef = ref<any>(null);
|
||||||
|
const isSwitch= ref(false)
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
valueIds: {
|
valueIds: {
|
||||||
type: Array as PropType<string[]>,
|
type: Array as PropType<string[]>,
|
||||||
|
@ -67,6 +67,7 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
const option = computed(() => {
|
const option = computed(() => {
|
||||||
return {
|
return {
|
||||||
|
backgroundColor:'',
|
||||||
grid: {
|
grid: {
|
||||||
left: '0',
|
left: '0',
|
||||||
right: '0',
|
right: '0',
|
||||||
|
@ -197,7 +198,7 @@ const zoom = _.throttle((e: any) => {
|
||||||
'Authorization': 'Bearer ' + useCookie('token').value
|
'Authorization': 'Bearer ' + useCookie('token').value
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
ServerId: mainLayoutStore.SelectServer.id,
|
ServerId: mainLayoutStore.SelectServer.value,
|
||||||
DataTypes: props.valueIds,
|
DataTypes: props.valueIds,
|
||||||
StartIndex: endIndex,
|
StartIndex: endIndex,
|
||||||
},
|
},
|
||||||
|
@ -225,13 +226,20 @@ const zoom = _.throttle((e: any) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
watch(()=>useColorMode().value,()=>{
|
||||||
|
isSwitch.value=true
|
||||||
|
nextTick(()=>{
|
||||||
|
isSwitch.value=false
|
||||||
|
})
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-chart ref="chartRef" :loading="isLoading" :manual-update="true"
|
<v-chart ref="chartRef" :loading="isLoading" :manual-update="true"
|
||||||
:option="option"
|
:option="option"
|
||||||
autoresize
|
autoresize
|
||||||
|
v-if="!isSwitch"
|
||||||
|
:theme="$colorMode.value"
|
||||||
class="chart"
|
class="chart"
|
||||||
@datazoom="zoom"
|
@datazoom="zoom"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -19,6 +19,7 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
const option = computed(() => {
|
const option = computed(() => {
|
||||||
return {
|
return {
|
||||||
|
backgroundColor:'',
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
|
@ -44,6 +45,18 @@ const option = computed(() => {
|
||||||
data: props.valueNames
|
data: props.valueNames
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
legend: {
|
||||||
|
data: props.valueNames,
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
feature: {
|
||||||
|
dataZoom: {
|
||||||
|
yAxisIndex: 'none'
|
||||||
|
},
|
||||||
|
|
||||||
|
saveAsImage: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
yAxis: [
|
yAxis: [
|
||||||
{
|
{
|
||||||
type: 'value'
|
type: 'value'
|
||||||
|
@ -62,5 +75,5 @@ const option = computed(() => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-chart :option="option" autoresize class="chart"/>
|
<v-chart :option="option" autoresize class="chart" :theme="$colorMode.value"/>
|
||||||
</template>
|
</template>
|
|
@ -32,6 +32,7 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
const option = computed(() => {
|
const option = computed(() => {
|
||||||
return {
|
return {
|
||||||
|
backgroundColor:'',
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
|
@ -168,7 +169,7 @@ const zoom = _.throttle((e: any) => {
|
||||||
'Authorization': 'Bearer ' + useCookie('token').value
|
'Authorization': 'Bearer ' + useCookie('token').value
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
ServerId: mainLayoutStore.SelectServer.id,
|
ServerId: mainLayoutStore.SelectServer.value,
|
||||||
DataTypes: props.valueIds,
|
DataTypes: props.valueIds,
|
||||||
StartIndex: endIndex,
|
StartIndex: endIndex,
|
||||||
},
|
},
|
||||||
|
@ -201,6 +202,7 @@ const zoom = _.throttle((e: any) => {
|
||||||
<template>
|
<template>
|
||||||
<v-chart ref="chartRet" :loading="isLoading" :manual-update="true" :option="option"
|
<v-chart ref="chartRet" :loading="isLoading" :manual-update="true" :option="option"
|
||||||
autoresize
|
autoresize
|
||||||
|
:theme="$colorMode.value"
|
||||||
class="chart"
|
class="chart"
|
||||||
@datazoom="zoom"/>
|
@datazoom="zoom"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -18,6 +18,7 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
const option = computed(() => {
|
const option = computed(() => {
|
||||||
return {
|
return {
|
||||||
|
backgroundColor:'',
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item'
|
trigger: 'item'
|
||||||
},
|
},
|
||||||
|
@ -46,5 +47,5 @@ const option = computed(() => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-chart :option="option" autoresize class="chart"/>
|
<v-chart :option="option" autoresize class="chart" :theme="$colorMode.value"/>
|
||||||
</template>
|
</template>
|
|
@ -88,7 +88,6 @@ watchDebounced(
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="main-grid-layout">
|
<div class="main-grid-layout">
|
||||||
|
|
||||||
<n-float-button :right="42" :bottom="90" position="fixed" style="z-index: 200" type="primary" menu-trigger="hover">
|
<n-float-button :right="42" :bottom="90" position="fixed" style="z-index: 200" type="primary" menu-trigger="hover">
|
||||||
<n-icon>
|
<n-icon>
|
||||||
<Atom/>
|
<Atom/>
|
||||||
|
@ -108,8 +107,7 @@ watchDebounced(
|
||||||
</n-float-button >
|
</n-float-button >
|
||||||
<n-modal
|
<n-modal
|
||||||
v-model:show="visible"
|
v-model:show="visible"
|
||||||
preset="card"
|
style="width: auto;"
|
||||||
style="width: 500px"
|
|
||||||
>
|
>
|
||||||
<SettingCard />
|
<SettingCard />
|
||||||
</n-modal>
|
</n-modal>
|
||||||
|
|
|
@ -1,116 +1,28 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {Check, ChevronRight, Settings} from "lucide-vue-next"
|
|
||||||
import {charts} from "~/config/charts";
|
import {charts} from "~/config/charts";
|
||||||
import {type cardConfigType, type IGridItem, useMainLayoutStore} from "~/strores/UseMainLayoutStore";
|
import { ArrowRight,ArrowLeft } from 'lucide-vue-next';
|
||||||
import {v4 as uuidv4} from 'uuid';
|
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
|
||||||
|
import type { CascaderOption } from 'naive-ui'
|
||||||
|
|
||||||
|
const current = ref<number | undefined>(1)
|
||||||
|
const selectChart = ref<number>(0)
|
||||||
const mainLayoutStore=useMainLayoutStore()
|
const mainLayoutStore=useMainLayoutStore()
|
||||||
const select = ref(0)
|
const options=ref<CascaderOption[]>([])
|
||||||
export type serverValueItem = {
|
const value=ref<number|string|null>(null)
|
||||||
dataName: string,
|
const prev=()=>{
|
||||||
dataType: string,
|
if (current.value === 0)
|
||||||
serverId:string
|
current.value = undefined
|
||||||
|
else if (!current.value)
|
||||||
|
current.value = 4
|
||||||
|
else current.value--
|
||||||
}
|
}
|
||||||
const props = defineProps({
|
const next=()=>{
|
||||||
closeCallback: {
|
if (current.value === 4)
|
||||||
type: Function,
|
current.value=4
|
||||||
required: true
|
else if (!current.value)
|
||||||
},
|
current.value = 1
|
||||||
isSetting: {
|
else current.value++
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
cardId: {
|
|
||||||
type: String,
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
const steps = ref([
|
|
||||||
{
|
|
||||||
label: '图表',
|
|
||||||
}, {
|
|
||||||
label: '数据',
|
|
||||||
}, {
|
|
||||||
label: '设置',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '预览',
|
|
||||||
end: true,
|
|
||||||
}
|
|
||||||
])
|
|
||||||
const ServerValues = ref<serverValueItem[]>([])
|
|
||||||
const ServerSelect = ref<serverValueItem[]>([])
|
|
||||||
const CardSettings = ref<cardConfigType>({
|
|
||||||
name: {
|
|
||||||
label: '卡片名称',
|
|
||||||
value: '默认卡片名称',
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
label: '卡片描述',
|
|
||||||
value: '这是一张默认的卡片',
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
foreground: {
|
|
||||||
label: '卡片前景色',
|
|
||||||
value: 'ffffff',
|
|
||||||
type: 'color',
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
label: '图表主色',
|
|
||||||
value: '002EA6',
|
|
||||||
type: 'color',
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const ValueIds = ref<string[]>([])
|
|
||||||
const stepNext = () => {
|
|
||||||
if (select.value === 2) {
|
|
||||||
ValueIds.value = ServerSelect.value.map(item => item.dataType)
|
|
||||||
}
|
|
||||||
select.value++
|
|
||||||
}
|
|
||||||
|
|
||||||
const stepPrev = () => {
|
|
||||||
select.value--
|
|
||||||
}
|
|
||||||
|
|
||||||
const stepFinish = () => {
|
|
||||||
if (props.isSetting) {
|
|
||||||
for (const configKey in mainLayoutStore.LayoutsConfig) {
|
|
||||||
let config = mainLayoutStore.LayoutsConfig[configKey].find(x => x.i === props.cardId)
|
|
||||||
if (!config) return;
|
|
||||||
config = config as IGridItem
|
|
||||||
config.serverValues = ServerSelect.value
|
|
||||||
config.cardConfig = CardSettings.value
|
|
||||||
config.selectChart = charts[selectChart.value].id
|
|
||||||
}
|
|
||||||
props.closeCallback()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const newItem: IGridItem = {
|
|
||||||
type: "chart",
|
|
||||||
chartRage: 6,
|
|
||||||
serverValues: ServerSelect.value.filter(i => i.dataName && i.dataName !== ''),
|
|
||||||
i: uuidv4(),
|
|
||||||
x: 1,
|
|
||||||
y: 1,
|
|
||||||
h: 5,
|
|
||||||
w: 5,
|
|
||||||
selectChart: charts[selectChart.value].id,
|
|
||||||
cardConfig: CardSettings.value
|
|
||||||
};
|
|
||||||
console.log(newItem)
|
|
||||||
mainLayoutStore.addLayout(newItem)
|
|
||||||
props.closeCallback()
|
|
||||||
}
|
|
||||||
|
|
||||||
const addServerValue = () => {
|
|
||||||
console.log(ServerSelect.value)
|
|
||||||
ServerSelect.value.push(<serverValueItem>{});
|
|
||||||
}
|
|
||||||
const removeServerValue = (index: number) => {
|
|
||||||
// 从索引 index 开始删除 1 个元素
|
|
||||||
ServerSelect.value.splice(index, 1);
|
|
||||||
};
|
|
||||||
const selectChart = ref<number>(0);
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
$fetch('/Api/Job/GetJobList', {
|
$fetch('/Api/Job/GetJobList', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
@ -124,85 +36,74 @@ onMounted(() => {
|
||||||
baseURL: useRuntimeConfig().public.baseUrl
|
baseURL: useRuntimeConfig().public.baseUrl
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
console.log(res)
|
console.log(res)
|
||||||
ServerValues.value = res as serverValueItem[];
|
const data=res as any[]
|
||||||
//排序
|
data.forEach(d=>{
|
||||||
ServerValues.value.sort((a, b) => {
|
options.value.push({label:d.groupName,value:d.groupName, children:d.items.map(r=>{return {label:r.dataName,value:r.dataType}})})
|
||||||
return a.dataName.localeCompare(b.dataName);
|
console.log(options.value)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
onMounted(() => {
|
|
||||||
if (!props.isSetting) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
select.value = 2
|
|
||||||
let config = mainLayoutStore.LayoutsConfig.lg.find(x => x.i === props.cardId)
|
|
||||||
// 断言config类型
|
|
||||||
if (!config) return;
|
|
||||||
config = config as IGridItem
|
|
||||||
if (!config.serverValues) return;
|
|
||||||
ServerSelect.value = config.serverValues.map(x => {
|
|
||||||
return x
|
|
||||||
})
|
|
||||||
if (!config.cardConfig) return;
|
|
||||||
CardSettings.value = config.cardConfig
|
|
||||||
if (!config.selectChart) return;
|
|
||||||
selectChart.value = charts.findIndex(x => x.id == config.selectChart)
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="setting-card-layout">
|
<div class="setting-card-layout">
|
||||||
<div class="card-top">
|
<n-steps v-model:current="current" class="setting-card-header">
|
||||||
<template v-for="(step, index) in steps">
|
<n-step
|
||||||
<div
|
title="选择图表"
|
||||||
:class="{'card-step-item':true,'card-step-item-active':select===index,'card-step-item-activated':select>index}">
|
/>
|
||||||
<div><p v-if="select<=index">{{ index + 1 }}</p>
|
<n-step
|
||||||
<Check v-else :size="18"/>
|
title="选择数据"
|
||||||
|
/>
|
||||||
|
<n-step
|
||||||
|
title="设置卡片"
|
||||||
|
/>
|
||||||
|
<n-step
|
||||||
|
title="预览"
|
||||||
|
/>
|
||||||
|
</n-steps>
|
||||||
|
<div class="setting-card-content">
|
||||||
|
<n-scrollbar>
|
||||||
|
<div v-if="current===1" class="step1-box">
|
||||||
|
<div v-for="(chart,index) in charts" :class="{'chart-box':true,'chart-box-active':selectChart===index}" @click="selectChart=index" :key="index">
|
||||||
|
<n-image
|
||||||
|
width="100"
|
||||||
|
:src="chart.image"
|
||||||
|
/>
|
||||||
|
<p>{{chart.description}}</p>
|
||||||
</div>
|
</div>
|
||||||
<h3>{{ step.label }}</h3>
|
|
||||||
</div>
|
</div>
|
||||||
<ChevronRight v-if="!step.end"/>
|
<div v-if="current===2" class="step2-box">
|
||||||
|
<n-cascader
|
||||||
|
v-model:value="value"
|
||||||
|
placeholder="没啥用的值"
|
||||||
|
expand-trigger="click"
|
||||||
|
:options="options"
|
||||||
|
|
||||||
|
check-strategy="child"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- 空布局-->
|
||||||
|
<n-empty description="你什么也找不到" v-if="current&¤t>= 5||current&¤t<=0">
|
||||||
|
</n-empty>
|
||||||
|
</n-scrollbar>
|
||||||
|
</div>
|
||||||
|
<div class="setting-card-folder">
|
||||||
|
<n-button @click="prev" quaternary type="info" v-if="current!==1">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<ArrowLeft />
|
||||||
|
</n-icon>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
上一步
|
||||||
<div class="card-split"></div>
|
</n-button>
|
||||||
<div class="card-container">
|
<n-button @click="next" type="info">
|
||||||
<div v-if="select===0" class="step1-box">
|
<template #icon>
|
||||||
<div v-for="(chart,index) in charts" :class="{'chart-box':true,'chart-box-active':selectChart===index}">
|
<n-icon>
|
||||||
<NuxtImg v-tooltip="chart.description" :src="chart.image" draggable="false" @click="selectChart=index"/>
|
<ArrowRight />
|
||||||
</div>
|
</n-icon>
|
||||||
</div>
|
</template>
|
||||||
<div v-if="select===1" class="step2-box">
|
下一步
|
||||||
<div v-for="(chart,index) in ServerSelect" class="Select-box">
|
|
||||||
<p>数据槽 {{ index + 1 }}</p>
|
|
||||||
<n-select v-model:value="ServerSelect[index]" :options="ServerValues.map(serverId=>{})" />
|
|
||||||
<Icon :size="20" :stroke-width="0.7" name="X" @click="removeServerValue(index)"/>
|
|
||||||
</div>
|
|
||||||
<n-button type="info" @click="addServerValue">
|
|
||||||
添加一个数据槽
|
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
|
||||||
<div v-if="select===2" class="step3-box">
|
|
||||||
<div v-for="setting in CardSettings" class="setting-box">
|
|
||||||
<p>{{ setting.label }}</p>
|
|
||||||
<InputText v-if="setting.type==='text'" id="username" v-model="setting.value"/>
|
|
||||||
<ColorPicker v-if="setting.type==='color'" v-model="setting.value"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="select===3" class="step4-box">
|
|
||||||
<div class="card-layout">
|
|
||||||
<div class="card-title">
|
|
||||||
<div></div>
|
|
||||||
<h3>{{ CardSettings['name'].value }}</h3>
|
|
||||||
</div>
|
|
||||||
<component :is="charts[selectChart].component" :valueIds="ValueIds"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-action">
|
|
||||||
<button :style="{visibility:select>0?'visible':'hidden'}" @click="stepPrev">后退</button>
|
|
||||||
<button v-if="select<3" @click="stepNext">前进</button>
|
|
||||||
<button v-else @click="stepFinish">完成</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -215,267 +116,59 @@ onMounted(() => {
|
||||||
display: grid;
|
display: grid;
|
||||||
padding: $padding*2;
|
padding: $padding*2;
|
||||||
grid-template-rows: auto auto 1fr auto;
|
grid-template-rows: auto auto 1fr auto;
|
||||||
gap: $gap*4;
|
gap: $gap*5;
|
||||||
background: $light-bg-color;
|
background: $light-bg-color;
|
||||||
border-radius: $radius*2;
|
border-radius: $radius*2;
|
||||||
|
*{
|
||||||
|
@include SC_Font()
|
||||||
|
}
|
||||||
.dark-mode & {
|
.dark-mode & {
|
||||||
background: $dark-bg-color;
|
background: $dark-bg-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.setting-card-header{
|
||||||
.card-top {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
gap: $gap*2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-step-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: $gap;
|
|
||||||
|
|
||||||
div {
|
|
||||||
display: flex;
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
border-radius: 100px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #8D8D99;
|
|
||||||
background: #E1E1E6;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
color: #8D8D99;
|
|
||||||
font-size: 16px;
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 150%; /* 24px */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-step-item-active {
|
|
||||||
|
|
||||||
div {
|
|
||||||
color: #FFFFFF;
|
|
||||||
background: $primary-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
color: $light-text-color;
|
|
||||||
|
|
||||||
.dark-mode & {
|
|
||||||
color: $dark-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-step-item-activated {
|
|
||||||
div {
|
|
||||||
background: #1D8841;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
stroke: #FFF;
|
|
||||||
margin-top: 2.5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
color: $light-text-color;
|
|
||||||
|
|
||||||
.dark-mode & {
|
|
||||||
color: $dark-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-split {
|
|
||||||
width: 95%;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
height: 1px;
|
|
||||||
background: $unfocused-color;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.setting-card-content {
|
||||||
.card-container {
|
min-height: 400px;
|
||||||
min-height: 200px;
|
max-height: 800px;
|
||||||
height: 100%;
|
|
||||||
max-height: 400px;
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
width: 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.card-action {
|
|
||||||
height: 56px;
|
|
||||||
gap: $gap*4;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
button {
|
|
||||||
display: flex;
|
|
||||||
width: 158px;
|
|
||||||
padding: 16px 32px;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
font-size: 16px;
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 150%; /* 24px */
|
|
||||||
text-transform: uppercase;
|
|
||||||
border: unset;
|
|
||||||
outline: unset;
|
|
||||||
background: unset;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:first-of-type {
|
|
||||||
|
|
||||||
color: $primary-color;
|
|
||||||
|
|
||||||
border: 2px solid $primary-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:last-of-type {
|
|
||||||
background: $primary-color;
|
|
||||||
color: #FFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.step1-box{
|
.step1-box{
|
||||||
display: grid;
|
display: grid;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
|
||||||
gap: $gap*2;
|
gap: $gap*2;
|
||||||
grid-template-rows: repeat(auto-fit, auto);
|
grid-template-columns: repeat(3,1fr);
|
||||||
|
place-content: center;
|
||||||
|
place-items: center;
|
||||||
.chart-box{
|
.chart-box{
|
||||||
min-width: 120px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $gap;
|
gap: $gap;
|
||||||
border: 1px solid #E1E1E6;
|
font-size: 12px;
|
||||||
height: min-content;
|
font-weight: 900;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
background: rgba(238, 238, 238, 0.1);
|
||||||
|
border: $border;
|
||||||
|
height: 140px;
|
||||||
border-radius: $radius*2;
|
border-radius: $radius*2;
|
||||||
padding: $padding;
|
width: 140px;
|
||||||
background: #f4f4f4;
|
|
||||||
|
|
||||||
.dark-mode & {
|
|
||||||
background: $dark-bg-underline-color;
|
|
||||||
border-color: $unfocused-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-box-active{
|
.chart-box-active{
|
||||||
border: 2px solid $primary-color;
|
border-color: $primary-color;
|
||||||
|
background: rgba(238, 238, 238, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.setting-card-folder{
|
||||||
.step2-box {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
gap: $gap*2;
|
gap: $gap*2;
|
||||||
padding: 0 0 $padding*4 0;
|
button{
|
||||||
|
|
||||||
> button {
|
|
||||||
background: $primary-color;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Select-box {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: $gap;
|
|
||||||
|
|
||||||
.p-dropdown {
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
:deep(.n-cascader-menu .n-cascader-submenu.n-cascader-submenu--virtual){
|
||||||
|
width: auto;
|
||||||
.step3-box {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: $gap*2;
|
|
||||||
|
|
||||||
|
|
||||||
.setting-box {
|
|
||||||
display: flex;
|
|
||||||
gap: $gap;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.p-inputtext {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.p-inputtext) {
|
|
||||||
color: $light-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.step4-box {
|
|
||||||
background: $light-bg-underline-color;
|
|
||||||
padding: $padding;
|
|
||||||
height: 100%;
|
|
||||||
border-radius: $radius*2;
|
|
||||||
|
|
||||||
.dark-mode & {
|
|
||||||
background: $dark-bg-underline-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-layout {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
min-height: 250px;
|
|
||||||
background: $light-bg-color;
|
|
||||||
border-radius: $radius*2;
|
|
||||||
box-shadow: 0 10px 30px 0 rgba(17, 38, 146, 0.05);
|
|
||||||
padding: $padding*1.5;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: $gap*2;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
cursor: move;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark-mode & {
|
|
||||||
background: $dark-bg-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: $gap;
|
|
||||||
color: $light-text-color;
|
|
||||||
|
|
||||||
.dark-mode & {
|
|
||||||
color: $dark-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
width: 6px;
|
|
||||||
height: 20px;
|
|
||||||
border-radius: $radius;
|
|
||||||
background: $primary-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -1,11 +1,12 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
import {toggleDark} from "~/utils";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="BottomBar-Box">
|
<div class="BottomBar-Box">
|
||||||
<div class="Left-Text-Box">
|
<div class="Left-Text-Box">
|
||||||
<p @click="$colorMode.preference = $colorMode.value == 'dark' ? 'light' : 'dark'" style="cursor: pointer">{{$colorMode.value=='dark'?'深色':'浅色'}}</p>
|
<p @click="toggleDark" style="cursor: pointer">{{$colorMode.value=='dark'?'深色':'浅色'}}</p>
|
||||||
<p>隐私策略</p>
|
<p>隐私策略</p>
|
||||||
<p>关于我们</p>
|
<p>关于我们</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
30
web/utils.ts
30
web/utils.ts
|
@ -40,3 +40,33 @@ export function useBeep() {
|
||||||
|
|
||||||
return {playBeep};
|
return {playBeep};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function toggleDark(event: MouseEvent) {
|
||||||
|
const isAppearanceTransition = document.startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||||
|
|
||||||
|
if (!isAppearanceTransition) {
|
||||||
|
useColorMode().preference = useColorMode().value == 'dark' ? 'light' : 'dark'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const x = event.clientX
|
||||||
|
const y = event.clientY
|
||||||
|
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y),)
|
||||||
|
// @ts-expect-error: Transition API
|
||||||
|
const transition = document.startViewTransition(async () => {
|
||||||
|
useColorMode().preference = useColorMode().value == 'dark' ? 'light' : 'dark'
|
||||||
|
await nextTick()
|
||||||
|
})
|
||||||
|
transition.ready
|
||||||
|
.then(() => {
|
||||||
|
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`,]
|
||||||
|
document.documentElement.animate({
|
||||||
|
clipPath: useColorMode().value == 'dark' ? [...clipPath].reverse() : clipPath,
|
||||||
|
}, {
|
||||||
|
duration: 400,
|
||||||
|
easing: 'ease-out',
|
||||||
|
pseudoElement: useColorMode().value == 'dark' ? '::view-transition-old(root)' : '::view-transition-new(root)',
|
||||||
|
},)
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue