perf: 图表主题设置优化

This commit is contained in:
zxc 2025-03-14 22:31:37 +08:00
parent 296aa4c171
commit 96f9029b54
2 changed files with 166 additions and 95 deletions

View File

@ -0,0 +1,108 @@
<template>
<div class="theme-colors-setting">
<div class="title">图表主题配色</div>
<div class="list">
<div class="row" v-for="(item, index) in themeColors" :key="index">
<div class="label" style="width: 40%;">主题配色{{ index + 1 }}</div>
<Popover trigger="click" style="width: 60%;">
<template #content>
<ColorPicker
:modelValue="item"
@update:modelValue="(value: string) => themeColors[index] = value"
/>
</template>
<div class="color-btn-wrap" style="width: 100%;">
<ColorButton :color="item" />
<div class="delete-color-btn" v-tooltip="'删除'" @click.stop="deleteThemeColor(index)" v-if="index !== 0"><IconCloseSmall /></div>
</div>
</Popover>
</div>
<Button
style="width: 100%"
:disabled="themeColors.length >= 10"
@click="addThemeColor()"
>
<IconPlus class="btn-icon" /> 添加主题色
</Button>
</div>
<Button class="btn" type="primary" @click="setThemeColors()">确认</Button>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import Popover from '@/components/Popover.vue'
import ColorPicker from '@/components/ColorPicker/index.vue'
import ColorButton from '@/components/ColorButton.vue'
import Button from '@/components/Button.vue'
const props = defineProps<{
colors: string[]
}>()
const emit = defineEmits<{
(event: 'update', payload: string[]): void
}>()
const themeColors = ref<string[]>([])
onMounted(() => {
themeColors.value = [...props.colors]
})
const setThemeColors = () => {
emit('update', themeColors.value)
}
const addThemeColor = () => {
const colors = [...themeColors.value, '#00000000']
themeColors.value = colors
}
const deleteThemeColor = (index: number) => {
const colors = themeColors.value.filter((c, i) => i !== index)
themeColors.value = colors
}
</script>
<style lang="scss" scoped>
.theme-colors-setting {
display: flex;
flex-direction: column;
}
.title {
margin-bottom: 15px;
font-size: 17px;
font-weight: 700;
}
.row {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 10px;
}
.label {
font-size: 13px;
}
.btn {
width: 100%;
margin-top: 12px;
}
.color-btn-wrap {
position: relative;
}
.delete-color-btn {
position: absolute;
width: 30px;
right: 2px;
top: 2px;
bottom: 2px;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
cursor: pointer;
}
</style>

View File

@ -49,52 +49,40 @@
</Popover>
</div>
<Divider />
<div class="row" v-for="(color, index) in themeColors" :key="index">
<div style="width: 40%;">{{index === 0 ? '主题配色:' : ''}}</div>
<Popover trigger="click" style="width: 60%;">
<div class="row">
<div style="width: 40%;">主题配色</div>
<Popover trigger="click" v-model:value="themesVisible" style="width: 60%;">
<template #content>
<ColorPicker
:modelValue="color"
@update:modelValue="value => updateTheme(value, index)"
/>
</template>
<div class="color-btn-wrap" style="width: 100%;">
<ColorButton :color="color" />
<div class="delete-color-btn" v-tooltip="'删除'" @click.stop="deleteThemeColor(index)" v-if="index !== 0"><IconCloseSmall /></div>
</div>
</Popover>
</div>
<ButtonGroup class="row" passive>
<Popover trigger="click" v-model:open="presetThemesVisible" style="width: 40%;">
<template #content>
<div class="preset-themes">
<div class="preset-theme" v-for="(item, index) in CHART_PRESET_THEMES" :key="index">
<div
class="preset-theme-color"
:class="{ 'select': presetThemeColorHoverIndex[0] === index && itemIndex <= presetThemeColorHoverIndex[1] }"
v-for="(color, itemIndex) in item"
:key="color"
:style="{ backgroundColor: color }"
@click="applyPresetTheme(item, itemIndex)"
@mouseenter="presetThemeColorHoverIndex = [index, itemIndex]"
@mouseleave="presetThemeColorHoverIndex = [-1, -1]"
></div>
<div class="themes">
<div class="label">预置图表主题</div>
<div class="preset-themes">
<div class="preset-theme" v-for="(item, index) in CHART_PRESET_THEMES" :key="index" @click="setThemeColors(item)">
<div
class="preset-theme-color"
v-for="color in item"
:key="color"
:style="{ backgroundColor: color }"
></div>
</div>
</div>
<div class="label">幻灯片主题</div>
<div class="preset-themes" :style="{ marginBottom: '-10px' }">
<div class="preset-theme" @click="setThemeColors(theme.themeColors)">
<div
class="preset-theme-color"
v-for="color in theme.themeColors"
:key="color"
:style="{ backgroundColor: color }"
></div>
</div>
</div>
<Divider :margin="10" />
<Button class="full-width-btn" @click="themesVisible = false; themeColorsSettingVisible = true">自定义配色</Button>
</div>
</template>
<Button first style="width: 100%;">推荐主题</Button>
<ColorListButton :colors="themeColors" />
</Popover>
<Button
last
:disabled="themeColors.length >= 10"
style="width: 60%;"
@click="addThemeColor()"
>
<IconPlus class="btn-icon" /> 添加主题色
</Button>
</ButtonGroup>
</div>
<Divider />
@ -111,6 +99,14 @@
@save="value => updateData(value)"
/>
</Modal>
<Modal
v-model:visible="themeColorsSettingVisible"
:width="310"
@closed="themeColorsSettingVisible = false"
>
<ThemeColorsSetting :colors="themeColors" @update="colors => setThemeColors(colors)" />
</Modal>
</div>
</template>
@ -125,13 +121,14 @@ import { CHART_PRESET_THEMES } from '@/configs/chart'
import ElementOutline from '../../common/ElementOutline.vue'
import ChartDataEditor from './ChartDataEditor.vue'
import ThemeColorsSetting from './ThemeColorsSetting.vue'
import ColorButton from '@/components/ColorButton.vue'
import ColorListButton from '@/components/ColorListButton.vue'
import ColorPicker from '@/components/ColorPicker/index.vue'
import Modal from '@/components/Modal.vue'
import Divider from '@/components/Divider.vue'
import Checkbox from '@/components/Checkbox.vue'
import Button from '@/components/Button.vue'
import ButtonGroup from '@/components/ButtonGroup.vue'
import Popover from '@/components/Popover.vue'
const mainStore = useMainStore()
@ -142,8 +139,8 @@ const { theme } = storeToRefs(slidesStore)
const handleChartElement = handleElement as Ref<PPTChartElement>
const chartDataEditorVisible = ref(false)
const presetThemesVisible = ref(false)
const presetThemeColorHoverIndex = ref<[number, number]>([-1, -1])
const themesVisible = ref(false)
const themeColorsSettingVisible = ref(false)
const { addHistorySnapshot } = useHistorySnapshot()
@ -202,35 +199,11 @@ const updateOptions = (optionProps: ChartOptions) => {
updateElement({ options: newOptions })
}
//
const updateTheme = (color: string, index: number) => {
const props = {
themeColors: themeColors.value.map((c, i) => i === index ? color : c),
}
updateElement(props)
}
//
const addThemeColor = () => {
const props = {
themeColors: [...themeColors.value, theme.value.themeColors[0]],
}
updateElement(props)
}
// 使
const applyPresetTheme = (colors: string[], index: number) => {
const themeColors = colors.slice(0, index + 1)
updateElement({ themeColors })
presetThemesVisible.value = false
}
//
const deleteThemeColor = (index: number) => {
const props = {
themeColors: themeColors.value.filter((c, i) => i !== index),
}
updateElement(props)
const setThemeColors = (colors: string[]) => {
updateElement({ themeColors: colors })
themesVisible.value = false
themeColorsSettingVisible.value = false
}
//
@ -262,41 +235,31 @@ onUnmounted(() => {
.btn-icon {
margin-right: 3px;
}
.color-btn-wrap {
position: relative;
}
.delete-color-btn {
position: absolute;
width: 30px;
right: 2px;
top: 2px;
bottom: 2px;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
cursor: pointer;
.label {
font-size: 12px;
margin-bottom: 4px;
}
.preset-themes {
width: 250px;
display: flex;
margin-bottom: -10px;
@include flex-grid-layout();
}
.preset-theme {
display: flex;
cursor: pointer;
border: 1px solid #ccc;
padding: 2px;
border-radius: $borderRadius;
@include flex-grid-layout-children(2, 48%);
}
.preset-theme-color {
width: 20px;
height: 20px;
&.select {
transform: scale(1.2);
transition: transform $transitionDelayFast;
&:hover {
border-color: $themeColor;
transition: border-color $transitionDelayFast;
}
}
.preset-theme-color {
height: 20px;
flex: 1;
}
</style>