From 9d9762ef177b6b313dd3438b30396e791a26df98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 19 Aug 2025 00:08:26 +0800 Subject: [PATCH] =?UTF-8?q?feat(theme):=20=E5=AE=9E=E7=8E=B0=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E5=88=87=E6=8D=A2=E7=B3=BB=E7=BB=9F=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=BB=8F=E9=94=80=E5=95=86=E7=9B=B8=E5=85=B3=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增主题切换系统,支持智能主题和手动选择 - 更新经销商首页、团队、订单、提现等页面样式 - 添加主题相关的Hook和样式工具函数 - 优化部分组件样式以适配新主题 --- docs/THEME_SYSTEM_GUIDE.md | 191 +++++++++++++++++++++++ src/app.config.ts | 3 +- src/components/CouponFilter.tsx | 62 ++++---- src/components/CouponList.tsx | 3 - src/components/FixedButton.tsx | 8 +- src/components/GradientThemeSelector.tsx | 2 +- src/dealer/index.scss | 8 + src/dealer/index.tsx | 172 ++++++++++---------- src/dealer/info.tsx | 4 +- src/dealer/orders/index.tsx | 11 +- src/dealer/team/index.tsx | 52 +++--- src/dealer/withdraw/index.tsx | 23 +-- src/hooks/useTheme.ts | 95 +++++++++++ src/pages/cart/cart.tsx | 67 +++----- src/pages/user/components/IsDealer.tsx | 6 +- src/pages/user/components/UserCell.tsx | 7 + src/shop/orderConfirm/index.tsx | 4 +- src/shop/orderConfirmCart/index.tsx | 4 +- src/styles/gradients.ts | 60 ++++--- src/user/order/components/OrderList.tsx | 8 +- src/user/store/verification.tsx | 36 +++-- src/user/theme/index.config.ts | 4 + src/user/theme/index.tsx | 179 +++++++++++++++++++++ 23 files changed, 742 insertions(+), 267 deletions(-) create mode 100644 docs/THEME_SYSTEM_GUIDE.md create mode 100644 src/dealer/index.scss create mode 100644 src/hooks/useTheme.ts create mode 100644 src/user/theme/index.config.ts create mode 100644 src/user/theme/index.tsx diff --git a/docs/THEME_SYSTEM_GUIDE.md b/docs/THEME_SYSTEM_GUIDE.md new file mode 100644 index 0000000..7188a5f --- /dev/null +++ b/docs/THEME_SYSTEM_GUIDE.md @@ -0,0 +1,191 @@ +# 🎨 主题切换系统使用指南 + +## 📖 功能概述 + +我们为你的小程序实现了一套完整的主题切换系统,用户可以选择不同的渐变主题来个性化界面。 + +## 🎯 功能特点 + +### ✨ 智能主题 +- **自动选择**:根据用户ID自动分配个性化主题 +- **8种精美主题**:海洋蓝紫、日落橙红、清新蓝绿、自然绿青、温暖橙黄、梦幻紫粉、经典蓝白、优雅灰黑 +- **持久化存储**:用户选择会自动保存 + +### 🎨 手动选择 +- **实时预览**:选择主题时立即看到效果 +- **一键保存**:保存后自动返回上级页面 +- **全局应用**:主题会应用到所有支持的页面 + +## 🚀 如何使用 + +### 1. 访问主题设置页面 + +用户可以通过以下方式进入主题设置: + +```javascript +// 在任何页面中跳转到主题设置 +Taro.navigateTo({ + url: '/user/theme/index' +}) +``` + +### 2. 在用户中心添加入口 + +你可以在用户中心页面添加"主题设置"入口: + +```jsx + Taro.navigateTo({ url: '/user/theme/index' })} +/> +``` + +### 3. 在组件中使用主题 + +#### 使用 useThemeStyles Hook + +```jsx +import { useThemeStyles } from '@/hooks/useTheme' + +const MyComponent = () => { + const themeStyles = useThemeStyles() + + return ( + + + 这里会应用当前主题的样式 + + + + ) +} +``` + +#### 使用 useTheme Hook + +```jsx +import { useTheme } from '@/hooks/useTheme' + +const MyComponent = () => { + const { currentTheme, setTheme, isAutoTheme } = useTheme() + + return ( + + + 当前主题:{currentTheme.description} + + {isAutoTheme && 使用智能主题} + + ) +} +``` + +## 🎨 可用主题列表 + +| 主题名称 | 主色调 | 描述 | 适用场景 | +|---------|--------|------|----------| +| ocean | 蓝紫色 | 海洋蓝紫 - 科技感与专业感 | 商务、科技类应用 | +| sunset | 橙红色 | 日落橙红 - 活力与热情 | 社交、娱乐类应用 | +| fresh | 蓝绿色 | 清新蓝绿 - 清新与活力 | 健康、运动类应用 | +| nature | 绿青色 | 自然绿青 - 生机与成长 | 环保、教育类应用 | +| warm | 橙黄色 | 温暖橙黄 - 温馨与舒适 | 生活、家居类应用 | +| dream | 紫粉色 | 梦幻紫粉 - 浪漫与梦幻 | 时尚、美妆类应用 | +| classic | 蓝白色 | 经典蓝白 - 简约与专业 | 办公、工具类应用 | +| elegant | 灰黑色 | 优雅灰黑 - 高端与品质 | 奢侈品、艺术类应用 | + +## 🔧 开发者指南 + +### 添加新主题 + +在 `src/styles/gradients.ts` 中添加新主题: + +```typescript +export const gradientThemes: GradientTheme[] = [ + // 现有主题... + { + name: 'custom', + primary: '#your-primary-color', + secondary: '#your-secondary-color', + background: 'linear-gradient(135deg, #color1 0%, #color2 100%)', + textColor: '#ffffff', + description: '自定义主题 - 你的描述' + } +] +``` + +### 在新页面中应用主题 + +```jsx +import { useThemeStyles } from '@/hooks/useTheme' + +const NewPage = () => { + const themeStyles = useThemeStyles() + + return ( + + {/* 使用主题背景的头部 */} + + + 页面标题 + + + + {/* 其他内容 */} + + + + + ) +} +``` + +## 📱 用户体验 + +### 智能主题算法 + +系统会根据用户ID生成一个稳定的主题选择: + +```typescript +// 用户ID为 "12345" 的用户总是会得到相同的主题 +const theme = gradientUtils.getThemeByUserId("12345") +``` + +### 主题持久化 + +- 用户选择会保存在本地存储中 +- 重新打开应用时会自动应用上次选择的主题 +- 支持"智能主题"和"手动选择"两种模式 + +## 🎉 效果展示 + +### 智能主题模式 +- 每个用户都有独特的个性化主题 +- 基于用户ID算法分配,确保稳定性 +- 提升用户归属感和个性化体验 + +### 手动选择模式 +- 用户可以自由选择喜欢的主题 +- 实时预览效果 +- 一键保存并应用 + +## 🔄 更新日志 + +### v1.0.0 (2025-01-18) +- ✅ 实现8种精美渐变主题 +- ✅ 智能主题自动分配算法 +- ✅ 主题切换页面UI +- ✅ useTheme 和 useThemeStyles Hooks +- ✅ 主题持久化存储 +- ✅ 小程序兼容性优化 + +--- + +**现在你的用户可以享受个性化的主题体验了!** 🎨✨ diff --git a/src/app.config.ts b/src/app.config.ts index 6fbba22..a1be3ab 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -43,7 +43,8 @@ export default defineAppConfig({ "gift/index", "gift/redeem", "gift/detail", - "store/verification" + "store/verification", + "theme/index" ] }, { diff --git a/src/components/CouponFilter.tsx b/src/components/CouponFilter.tsx index 64e4dca..a16c5d1 100644 --- a/src/components/CouponFilter.tsx +++ b/src/components/CouponFilter.tsx @@ -1,7 +1,7 @@ -import React, { useState } from 'react' -import { View, Text } from '@tarojs/components' -import { Button, Popup, Radio, RadioGroup, Divider } from '@nutui/nutui-react-taro' -import { Filter, Close } from '@nutui/icons-react-taro' +import React, {useState} from 'react' +import {View, Text} from '@tarojs/components' +import {Button, Popup, Radio, RadioGroup, Divider} from '@nutui/nutui-react-taro' +import {Filter, Close} from '@nutui/icons-react-taro' export interface CouponFilterProps { /** 是否显示筛选器 */ @@ -20,41 +20,41 @@ export interface CouponFilterProps { } const CouponFilter: React.FC = ({ - visible, - filters, - onFiltersChange, - onClose -}) => { + visible, + filters, + onFiltersChange, + onClose + }) => { const [tempFilters, setTempFilters] = useState(filters) // 优惠券类型选项 const typeOptions = [ - { label: '全部类型', value: '' }, - { label: '满减券', value: '10' }, - { label: '折扣券', value: '20' }, - { label: '免费券', value: '30' } + {label: '全部类型', value: ''}, + {label: '满减券', value: '10'}, + {label: '折扣券', value: '20'}, + {label: '免费券', value: '30'} ] // 最低金额选项 const minAmountOptions = [ - { label: '不限', value: '' }, - { label: '10元以上', value: '10' }, - { label: '50元以上', value: '50' }, - { label: '100元以上', value: '100' }, - { label: '200元以上', value: '200' } + {label: '不限', value: ''}, + {label: '10元以上', value: '10'}, + {label: '50元以上', value: '50'}, + {label: '100元以上', value: '100'}, + {label: '200元以上', value: '200'} ] // 排序选项 const sortOptions = [ - { label: '创建时间', value: 'createTime' }, - { label: '优惠金额', value: 'amount' }, - { label: '到期时间', value: 'expireTime' } + {label: '创建时间', value: 'createTime'}, + {label: '优惠金额', value: 'amount'}, + {label: '到期时间', value: 'expireTime'} ] // 排序方向选项 const sortOrderOptions = [ - { label: '升序', value: 'asc' }, - { label: '降序', value: 'desc' } + {label: '升序', value: 'asc'}, + {label: '降序', value: 'desc'} ] // 重置筛选条件 @@ -86,17 +86,17 @@ const CouponFilter: React.FC = ({ {/* 头部 */} - + 筛选条件 - + @@ -109,7 +109,7 @@ const CouponFilter: React.FC = ({ { + onChange={(value: any) => { updateTempFilters('type', value ? [parseInt(value)] : []) }} > @@ -121,7 +121,7 @@ const CouponFilter: React.FC = ({ - + {/* 最低消费金额 */} @@ -130,7 +130,7 @@ const CouponFilter: React.FC = ({ { + onChange={(value: any) => { updateTempFilters('minAmount', value ? parseInt(value) : undefined) }} > @@ -142,7 +142,7 @@ const CouponFilter: React.FC = ({ - + {/* 排序方式 */} @@ -161,7 +161,7 @@ const CouponFilter: React.FC = ({ - + {/* 排序方向 */} diff --git a/src/components/CouponList.tsx b/src/components/CouponList.tsx index 1837586..f833aba 100644 --- a/src/components/CouponList.tsx +++ b/src/components/CouponList.tsx @@ -77,9 +77,6 @@ const CouponList: React.FC = ({ scrollX className="flex p-4 gap-2 overflow-x-auto" showScrollbar={false} - style={{ - WebkitOverflowScrolling: 'touch' - }} > {coupons.map((coupon, index) => ( void; icon?: React.ReactNode; disabled?: boolean; + background?: string; } -function FixedButton({text, onClick, icon, disabled}: FixedButtonProps) { +function FixedButton({text, onClick, icon, disabled, background}: FixedButtonProps) { return ( <> {/* 底部安全区域占位 */} @@ -17,7 +18,10 @@ function FixedButton({text, onClick, icon, disabled}: FixedButtonProps) { - - - ) : ( - <> - {/* 商品列表 */} + + {/* 商品列表 */} {cartItems.map((item: CartItem, index: number) => ( @@ -361,10 +346,8 @@ function Cart() { - {/* 底部安全区域占位 */} - - - )} + {/* 底部安全区域占位 */} + ); diff --git a/src/pages/user/components/IsDealer.tsx b/src/pages/user/components/IsDealer.tsx index 2019988..f8315aa 100644 --- a/src/pages/user/components/IsDealer.tsx +++ b/src/pages/user/components/IsDealer.tsx @@ -27,12 +27,13 @@ const UserCell = () => { backgroundImage: 'linear-gradient(to right bottom, #e53e3e, #c53030)', }} title={ - navTo('/admin/index', true)}> + 管理中心 } extra={} + onClick={() => navTo('/admin/index', true)} /> @@ -52,7 +53,7 @@ const UserCell = () => { backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)', }} title={ - navTo('/dealer/index', true)}> + 分销中心 @@ -60,6 +61,7 @@ const UserCell = () => { } extra={} + onClick={() => navTo('/dealer/index', true)} /> diff --git a/src/pages/user/components/UserCell.tsx b/src/pages/user/components/UserCell.tsx index 412edb8..7aa218d 100644 --- a/src/pages/user/components/UserCell.tsx +++ b/src/pages/user/components/UserCell.tsx @@ -122,6 +122,13 @@ const UserCell = () => { extra={} onClick={() => navTo('/user/profile/profile', true)} /> + } + onClick={() => navTo('/user/theme/index', true)} + /> { -
+
diff --git a/src/shop/orderConfirmCart/index.tsx b/src/shop/orderConfirmCart/index.tsx index 9a24361..d6aed1d 100644 --- a/src/shop/orderConfirmCart/index.tsx +++ b/src/shop/orderConfirmCart/index.tsx @@ -195,9 +195,7 @@ const OrderConfirm = () => { -
+
实付金额: diff --git a/src/styles/gradients.ts b/src/styles/gradients.ts index ff522b9..fd973fd 100644 --- a/src/styles/gradients.ts +++ b/src/styles/gradients.ts @@ -91,7 +91,7 @@ export const businessGradients = { danger: 'linear-gradient(135deg, #ef4444 0%, #f87171 100%)', info: 'linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%)' }, - + // 订单相关 order: { pending: 'linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%)', @@ -99,7 +99,7 @@ export const businessGradients = { cancelled: 'linear-gradient(135deg, #ef4444 0%, #dc2626 100%)', processing: 'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)' }, - + // 金额相关 money: { available: 'linear-gradient(135deg, #10b981 0%, #059669 100%)', @@ -108,51 +108,47 @@ export const businessGradients = { } } -// 卡片渐变样式 +// 卡片渐变样式(小程序兼容版本) export const cardGradients = { glass: { background: 'linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%)', - border: '1px solid rgba(255, 255, 255, 0.2)', - backdropFilter: 'blur(10px)' + border: '1px solid rgba(255, 255, 255, 0.2)' + // 注意:小程序不支持 backdropFilter }, - + subtle: { background: 'linear-gradient(135deg, #ffffff 0%, #f8fafc 100%)', - border: '1px solid rgba(255, 255, 255, 0.8)', - boxShadow: '0 10px 25px rgba(0, 0, 0, 0.1), 0 4px 10px rgba(0, 0, 0, 0.05)' + border: '1px solid rgba(255, 255, 255, 0.8)' + // 注意:小程序不支持 boxShadow,使用边框和背景替代 }, - + elevated: { background: 'linear-gradient(135deg, #ffffff 0%, #f1f5f9 100%)', - border: '1px solid rgba(255, 255, 255, 0.9)', - boxShadow: '0 20px 40px rgba(0, 0, 0, 0.1), 0 8px 16px rgba(0, 0, 0, 0.06)' + border: '1px solid rgba(255, 255, 255, 0.9)' + // 注意:小程序不支持 boxShadow,使用边框和背景替代 } } -// 文字渐变样式 +// 文字渐变样式(小程序兼容版本 - 使用纯色替代) export const textGradients = { primary: { - background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', - WebkitBackgroundClip: 'text', - WebkitTextFillColor: 'transparent' + color: '#667eea' + // 注意:小程序不支持 WebkitBackgroundClip 和 WebkitTextFillColor,使用纯色替代 }, - + success: { - background: 'linear-gradient(135deg, #10b981 0%, #059669 100%)', - WebkitBackgroundClip: 'text', - WebkitTextFillColor: 'transparent' + color: '#10b981' + // 注意:小程序不支持文字渐变,使用纯色替代 }, - + warning: { - background: 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)', - WebkitBackgroundClip: 'text', - WebkitTextFillColor: 'transparent' + color: '#f59e0b' + // 注意:小程序不支持文字渐变,使用纯色替代 }, - + danger: { - background: 'linear-gradient(135deg, #ef4444 0%, #dc2626 100%)', - WebkitBackgroundClip: 'text', - WebkitTextFillColor: 'transparent' + color: '#ef4444' + // 注意:小程序不支持文字渐变,使用纯色替代 } } @@ -164,12 +160,12 @@ export const gradientUtils = { const index = userId % gradientThemes.length return gradientThemes[index] }, - + // 根据主题名获取主题 getThemeByName: (name: string): GradientTheme | undefined => { return gradientThemes.find(theme => theme.name === name) }, - + // 调整颜色亮度 adjustColorBrightness: (color: string, percent: number): string => { const num = parseInt(color.replace("#", ""), 16) @@ -181,12 +177,12 @@ export const gradientUtils = { (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1) }, - + // 生成自定义渐变 createGradient: (color1: string, color2: string, direction = '135deg'): string => { return `linear-gradient(${direction}, ${color1} 0%, ${color2} 100%)` }, - + // 获取渐变的主色调 getPrimaryColor: (gradient: string): string => { const match = gradient.match(/#[a-fA-F0-9]{6}/) @@ -201,7 +197,7 @@ export const animatedGradients = { backgroundSize: '400% 400%', animation: 'gradientFlow 15s ease infinite' }, - + pulse: { background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', animation: 'gradientPulse 3s ease-in-out infinite' diff --git a/src/user/order/components/OrderList.tsx b/src/user/order/components/OrderList.tsx index 954b466..2c81f9e 100644 --- a/src/user/order/components/OrderList.tsx +++ b/src/user/order/components/OrderList.tsx @@ -16,8 +16,8 @@ const getInfiniteUlStyle = (showSearch: boolean = false): CSSProperties => ({ width: '100%', padding: '0', overflowY: 'auto', - overflowX: 'hidden', - boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)', + overflowX: 'hidden' + // 注意:小程序不支持 boxShadow }) // 统一的订单状态标签配置,与后端 statusFilter 保持一致 @@ -362,8 +362,8 @@ function OrderList(props: OrderListProps) { borderBottom: '1px solid #e5e5e5' }} tabStyle={{ - backgroundColor: '#ffffff', - boxShadow: '0 2px 4px rgba(0,0,0,0.1)' + backgroundColor: '#ffffff' + // 注意:小程序不支持 boxShadow }} value={tapIndex} onChange={(paneKey) => { diff --git a/src/user/store/verification.tsx b/src/user/store/verification.tsx index e26ef74..cb2cdb6 100644 --- a/src/user/store/verification.tsx +++ b/src/user/store/verification.tsx @@ -31,6 +31,7 @@ const StoreVerification: React.FC = () => { const json = JSON.parse(res.result) console.log(json, 'json') if (json.businessType === 'gift') { + // 调用解密接口 handleDecryptAndVerify(json.token, json.data).then() } } @@ -48,20 +49,35 @@ const StoreVerification: React.FC = () => { // 调用解密接口 const handleDecryptAndVerify = async (token: string, encryptedData: string) => { - const decryptedData = await decryptQrData({token, encryptedData}) - console.log('解密成功:', decryptedData) - setScanResult(`${decryptedData}`) - setVerificationCode(`${decryptedData}`) - await handleVerification(`${decryptedData}`) - setLoading(false) + decryptQrData({token, encryptedData}).then(res => { + const decryptedData = res; + console.log('解密结果:', decryptedData) + console.log('解密成功:', decryptedData) + setScanResult(`${decryptedData}`) + setVerificationCode(`${decryptedData}`) + handleVerification(`${decryptedData}`) + }).catch(() => { + console.error('解密失败:') + Taro.showToast({ + title: `token失效,请刷新二维码重试`, + icon: 'none' + }) + }).finally(() => { + setLoading(false) + }) } // 验证商品信息 const handleVerification = async (code?: string) => { + setGiftInfo(null) + setVerificationCode(`${code}`) // 这里应该调用后端API验证核销码 const gift = await getShopGiftByCode(`${code}`) - // 设置礼品信息用于显示 - setGiftInfo(gift) + if(gift){ + // 设置礼品信息用于显示 + setGiftInfo(gift) + } + } // 手动输入核销码验证 @@ -264,10 +280,8 @@ const StoreVerification: React.FC = () => { {giftInfo.description && ( <> {giftInfo.description} diff --git a/src/user/theme/index.config.ts b/src/user/theme/index.config.ts new file mode 100644 index 0000000..01ca5b5 --- /dev/null +++ b/src/user/theme/index.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '主题设置', + navigationBarTextStyle: 'black' +}) diff --git a/src/user/theme/index.tsx b/src/user/theme/index.tsx new file mode 100644 index 0000000..ec41396 --- /dev/null +++ b/src/user/theme/index.tsx @@ -0,0 +1,179 @@ +import React, { useState, useEffect } from 'react' +import { View, Text } from '@tarojs/components' +import { Cell, CellGroup, Radio } from '@nutui/nutui-react-taro' +import { gradientThemes, GradientTheme, gradientUtils } from '@/styles/gradients' +import Taro from '@tarojs/taro' +import FixedButton from "@/components/FixedButton"; + +const ThemeSelector: React.FC = () => { + const [selectedTheme, setSelectedTheme] = useState('') + const [currentTheme, setCurrentTheme] = useState(null) + + // 获取当前主题 + useEffect(() => { + const savedTheme = Taro.getStorageSync('user_theme') || 'auto' + setSelectedTheme(savedTheme) + + if (savedTheme === 'auto') { + // 自动主题:根据用户ID生成 + const userId = Taro.getStorageSync('userId') || '1' + const theme = gradientUtils.getThemeByUserId(userId) + setCurrentTheme(theme) + } else { + // 手动选择的主题 + const theme = gradientThemes.find(t => t.name === savedTheme) + setCurrentTheme(theme || gradientThemes[0]) + } + }, []) + + // 保存主题设置 + const saveTheme = (themeName: string) => { + try { + Taro.setStorageSync('user_theme', themeName) + setSelectedTheme(themeName) + + if (themeName === 'auto') { + const userId = Taro.getStorageSync('userId') || '1' + const theme = gradientUtils.getThemeByUserId(userId) + setCurrentTheme(theme) + } else { + const theme = gradientThemes.find(t => t.name === themeName) + setCurrentTheme(theme || gradientThemes[0]) + } + + Taro.showToast({ + title: '主题已保存', + icon: 'success', + }) + + // 延迟返回,让用户看到效果 + setTimeout(() => { + Taro.navigateBack() + }, 1000) + } catch (error) { + Taro.showToast({ + title: '保存失败', + icon: 'error', + }) + } + } + + // 预览主题 + const previewTheme = (themeName: string) => { + if (themeName === 'auto') { + const userId = Taro.getStorageSync('userId') || '1' + const theme = gradientUtils.getThemeByUserId(userId) + setCurrentTheme(theme) + } else { + const theme = gradientThemes.find(t => t.name === themeName) + setCurrentTheme(theme || gradientThemes[0]) + } + } + + return ( + + {/* 当前主题预览 */} + {currentTheme && ( + + 当前主题预览 + {currentTheme.description} + + + {currentTheme.secondary && ( + + )} + + + )} + + {/* 主题选择 */} + + + + + 智能主题 + + 根据您的用户ID自动选择个性化主题 + + + { + setSelectedTheme('auto') + previewTheme('auto') + }} + /> + + } + onClick={() => { + setSelectedTheme('auto') + previewTheme('auto') + }} + /> + + + + 手动选择主题 + + {gradientThemes.map((theme) => ( + + + + + {theme.description.split(' - ')[0]} + + {theme.description.split(' - ')[1]} + + + + { + setSelectedTheme(theme.name) + previewTheme(theme.name) + }} + /> + + } + onClick={() => { + setSelectedTheme(theme.name) + previewTheme(theme.name) + }} + /> + ))} + + + + + {/* 保存按钮 */} + saveTheme(selectedTheme)} /> + + {/* 底部安全区域 */} + + + ) +} + +export default ThemeSelector