Files
youlai-app/src/pages/mine/settings/theme/index.vue
Ray.Hao 4dd142bb5a chore: 升级 wot-ui 至 2.2.0 并适配暗黑模式主题色
- ConfigProvider 全局配置 button 默认类型、tag 默认变体
- 清理模板中重复的 type=primary 和 variant=plain
- 静态资源 logo.png 迁至 src/static/images/
- 暗黑模式 --wot-filled-oppo 统一组件背景色
2026-07-23 23:13:21 +08:00

292 lines
7.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="page page--padding">
<!-- 暗黑模式设置 -->
<wd-cell-group title="外观模式" border>
<wd-cell title="暗黑模式" :value="isDarkMode ? '已开启' : '已关闭'">
<wd-switch :model-value="isDarkMode" @change="handleToggleDarkMode" />
</wd-cell>
</wd-cell-group>
<!-- 主题色设置 -->
<wd-cell-group title="主题色彩" border custom-class="mt-24rpx">
<!-- 预设颜色选择 -->
<wd-cell title="预设主题色">
<template #default>
<view class="flex flex-wrap gap-12rpx">
<view
v-for="(color, index) in themeColorOptions"
:key="index"
class="color-option"
:class="{ 'color-option--active': currentThemeColor === color.primary }"
:style="{ backgroundColor: color.primary }"
@click="handleSelectColor(color)"
>
<wd-icon
v-if="currentThemeColor === color.primary"
name="check"
size="14"
color="var(--color-text-inverse)"
/>
</view>
</view>
</template>
</wd-cell>
<!-- 当前主题色 -->
<wd-cell title="当前主题色">
<template #default>
<view class="flex items-center gap-12rpx">
<view class="color-dot" :style="{ backgroundColor: currentThemeColor }" />
<text class="text-24rpx color-text-secondary">{{ currentThemeColor }}</text>
</view>
</template>
</wd-cell>
<!-- 自定义颜色 -->
<wd-cell title="自定义颜色" is-link @click="showCustomInput">
<template #icon>
<wd-icon name="edit" size="16" class="mr-12rpx" />
</template>
</wd-cell>
</wd-cell-group>
<!-- 效果预览 -->
<wd-cell-group title="效果预览" border custom-class="mt-24rpx">
<wd-cell>
<template #default>
<view class="flex items-center justify-center gap-24rpx py-12rpx">
<wd-button size="small">主要按钮</wd-button>
<text class="text-28rpx font-500" :style="{ color: currentThemeColor }">
主题色文本
</text>
<wd-tag type="primary" size="small" variant="filled">标签</wd-tag>
</view>
</template>
</wd-cell>
</wd-cell-group>
<!-- 操作按钮 -->
<view class="mt-32rpx">
<wd-button plain size="large" block @click="handleResetTheme">
重置为默认主题
</wd-button>
</view>
<!-- 自定义颜色输入弹窗 -->
<wd-popup v-model="showCustomColorInput" position="bottom" custom-class="popup-bottom">
<view class="popup-content">
<view class="popup-header">
<text class="popup-title">自定义主题色</text>
<view
class="w-64rpx h-64rpx flex-center rounded-full"
hover-class="bg-[var(--color-text-placeholder)]/16"
@click="showCustomColorInput = false"
>
<wd-icon name="close" size="18" class="color-text-secondary" />
</view>
</view>
<view class="p-4">
<text class="text-28rpx color-text-secondary">请输入十六进制颜色值</text>
<view class="flex items-center gap-16rpx mt-16rpx">
<view class="color-dot-lg" :style="{ backgroundColor: customColor || '#FF4757' }" />
<wd-input
v-model="customColor"
placeholder="例如: #FF4757"
:maxlength="7"
custom-class="theme-input"
/>
</view>
<text class="text-24rpx color-text-placeholder mt-12rpx">支持格式#RGB #RRGGBB</text>
</view>
<view class="popup-actions">
<wd-button type="info" plain @click="showCustomColorInput = false">取消</wd-button>
<wd-button @click="applyCustomColor">应用</wd-button>
</view>
</view>
</wd-popup>
</view>
</template>
<script lang="ts" setup>
import { useTheme } from "@/composables/useTheme";
import { useToast, useDialog } from "@wot-ui/ui";
definePage({
name: "theme",
style: { navigationBarTitleText: "主题设置" },
});
// 使用主题组合函数
const { isDark, themeColorOptions, toggleTheme, setThemeColor } = useTheme();
const toast = useToast();
const { confirm } = useDialog();
// 创建响应式的计算属性
const isDarkMode = computed(() => isDark.value);
// 自定义颜色输入
const customColor = ref("");
const showCustomColorInput = ref(false);
// 当前选中的主题色
const currentThemeColor = computed(() => {
return themeColorOptions[0].primary;
});
// 选择预设颜色
const handleSelectColor = (color: (typeof themeColorOptions)[0]) => {
setThemeColor(color);
customColor.value = color.primary;
// 提示
uni.showToast({
title: "主题色已更新",
icon: "success",
duration: 1500,
});
};
// 显示自定义颜色输入
const showCustomInput = () => {
showCustomColorInput.value = true;
customColor.value = currentThemeColor.value;
};
// 应用自定义颜色
const applyCustomColor = () => {
// 验证颜色格式
const colorRegex = /^#([0-9A-F]{6}|[0-9A-F]{3})$/i;
if (!colorRegex.test(customColor.value)) {
uni.showToast({
title: "请输入有效的颜色值",
icon: "none",
duration: 2000,
});
return;
}
// 转换3位颜色值为6位
let color = customColor.value;
if (color.length === 4) {
color = "#" + color[1] + color[1] + color[2] + color[2] + color[3] + color[3];
}
// 创建自定义主题色选项
const customColorOption = {
name: "自定义",
value: "custom",
primary: color,
};
setThemeColor(customColorOption);
showCustomColorInput.value = false;
// 提示
uni.showToast({
title: "自定义主题色已应用",
icon: "success",
duration: 1500,
});
};
// 重置为默认主题
const handleResetTheme = async () => {
try {
await confirm({ title: "确认重置", msg: "确定要重置为默认主题吗?", headerImage: "warning" });
setThemeColor(themeColorOptions[0]);
customColor.value = themeColorOptions[0].primary;
toast.success("已重置为默认主题");
} catch {
// 用户取消
}
};
// 切换暗黑模式
const handleToggleDarkMode = () => {
toggleTheme();
nextTick(() => {
uni.showToast({
title: `已切换到${isDarkMode.value ? "暗黑" : "浅色"}模式`,
icon: "success",
duration: 1500,
});
});
};
onLoad(() => {
customColor.value = currentThemeColor.value;
});
onMounted(() => {
customColor.value = currentThemeColor.value;
});
// 页面显示时确保主题色同步
onShow(() => {
customColor.value = currentThemeColor.value;
});
</script>
<style lang="scss" scoped>
.color-option {
display: flex;
align-items: center;
justify-content: center;
width: 48rpx;
height: 48rpx;
cursor: pointer;
border-radius: 50%;
&--active {
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.2);
transform: scale(1.1);
}
}
.color-dot {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
}
.color-dot-lg {
flex-shrink: 0;
width: 48rpx;
height: 48rpx;
border-radius: 8rpx;
}
.popup-content {
padding-bottom: env(safe-area-inset-bottom);
}
.popup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 32rpx;
border-bottom: 1rpx solid var(--color-border);
}
.popup-title {
font-size: 32rpx;
font-weight: 600;
color: var(--color-text);
}
.popup-actions {
display: flex;
gap: 24rpx;
padding: 24rpx 32rpx;
border-top: 1rpx solid var(--color-border);
}
:deep(.theme-input) {
color: var(--color-text) !important;
background-color: var(--color-bg-secondary) !important;
}
</style>