feat(theme): 实现主题切换系统并优化经销商相关页面
- 新增主题切换系统,支持智能主题和手动选择 - 更新经销商首页、团队、订单、提现等页面样式 - 添加主题相关的Hook和样式工具函数 - 优化部分组件样式以适配新主题
This commit is contained in:
@@ -43,7 +43,8 @@ export default defineAppConfig({
|
||||
"gift/index",
|
||||
"gift/redeem",
|
||||
"gift/detail",
|
||||
"store/verification"
|
||||
"store/verification",
|
||||
"theme/index"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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<CouponFilterProps> = ({
|
||||
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<CouponFilterProps> = ({
|
||||
<Popup
|
||||
visible={visible}
|
||||
position="right"
|
||||
style={{ width: '80%', height: '100%' }}
|
||||
style={{width: '80%', height: '100%'}}
|
||||
>
|
||||
<View className="h-full flex flex-col">
|
||||
{/* 头部 */}
|
||||
<View className="flex items-center justify-between p-4 border-b border-gray-100">
|
||||
<View className="flex items-center">
|
||||
<Filter size="20" className="text-gray-600 mr-2" />
|
||||
<Filter size="20" className="text-gray-600 mr-2"/>
|
||||
<Text className="text-lg font-semibold">筛选条件</Text>
|
||||
</View>
|
||||
<View onClick={onClose}>
|
||||
<Close size="20" className="text-gray-600" />
|
||||
<Close size="20" className="text-gray-600"/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -109,7 +109,7 @@ const CouponFilter: React.FC<CouponFilterProps> = ({
|
||||
</Text>
|
||||
<RadioGroup
|
||||
value={tempFilters.type?.[0]?.toString() || ''}
|
||||
onChange={(value) => {
|
||||
onChange={(value: any) => {
|
||||
updateTempFilters('type', value ? [parseInt(value)] : [])
|
||||
}}
|
||||
>
|
||||
@@ -121,7 +121,7 @@ const CouponFilter: React.FC<CouponFilterProps> = ({
|
||||
</RadioGroup>
|
||||
</View>
|
||||
|
||||
<Divider />
|
||||
<Divider/>
|
||||
|
||||
{/* 最低消费金额 */}
|
||||
<View className="mb-6">
|
||||
@@ -130,7 +130,7 @@ const CouponFilter: React.FC<CouponFilterProps> = ({
|
||||
</Text>
|
||||
<RadioGroup
|
||||
value={tempFilters.minAmount?.toString() || ''}
|
||||
onChange={(value) => {
|
||||
onChange={(value: any) => {
|
||||
updateTempFilters('minAmount', value ? parseInt(value) : undefined)
|
||||
}}
|
||||
>
|
||||
@@ -142,7 +142,7 @@ const CouponFilter: React.FC<CouponFilterProps> = ({
|
||||
</RadioGroup>
|
||||
</View>
|
||||
|
||||
<Divider />
|
||||
<Divider/>
|
||||
|
||||
{/* 排序方式 */}
|
||||
<View className="mb-6">
|
||||
@@ -161,7 +161,7 @@ const CouponFilter: React.FC<CouponFilterProps> = ({
|
||||
</RadioGroup>
|
||||
</View>
|
||||
|
||||
<Divider />
|
||||
<Divider/>
|
||||
|
||||
{/* 排序方向 */}
|
||||
<View className="mb-6">
|
||||
|
||||
@@ -77,9 +77,6 @@ const CouponList: React.FC<CouponListProps> = ({
|
||||
scrollX
|
||||
className="flex p-4 gap-2 overflow-x-auto"
|
||||
showScrollbar={false}
|
||||
style={{
|
||||
WebkitOverflowScrolling: 'touch'
|
||||
}}
|
||||
>
|
||||
{coupons.map((coupon, index) => (
|
||||
<View
|
||||
|
||||
@@ -7,9 +7,10 @@ interface FixedButtonProps {
|
||||
onClick?: () => 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) {
|
||||
<View
|
||||
className="fixed z-50 bottom-0 left-0 right-0 bg-white border-t border-gray-200 px-4 py-3 safe-area-bottom">
|
||||
<Button
|
||||
type="success"
|
||||
type="primary"
|
||||
style={{
|
||||
background
|
||||
}}
|
||||
size="large"
|
||||
block
|
||||
icon={icon}
|
||||
|
||||
@@ -46,7 +46,7 @@ const GradientThemeSelector: React.FC<GradientThemeSelectorProps> = ({
|
||||
}}
|
||||
>
|
||||
<View className="w-full h-full flex items-center justify-center">
|
||||
<Text className="text-white text-xs font-bold drop-shadow-sm">
|
||||
<Text className="text-white text-xs font-bold">
|
||||
预览
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
8
src/dealer/index.scss
Normal file
8
src/dealer/index.scss
Normal file
@@ -0,0 +1,8 @@
|
||||
/* 添加这段样式后,Primary Button 会变成绿色 */
|
||||
:root {
|
||||
--nutui-color-primary: green;
|
||||
--nutui-color-primary-stop1: green;
|
||||
--nutui-color-primary-stop2: green;
|
||||
// 间隔线/容错线,用于结构或信息分割
|
||||
--nutui-black-2: rgba(255, 0, 0, 0.08);
|
||||
}
|
||||
@@ -1,34 +1,28 @@
|
||||
import React from 'react'
|
||||
import {View, Text} from '@tarojs/components'
|
||||
import {Button, Cell, CellGroup, Tag, Grid, Avatar, Divider} from '@nutui/nutui-react-taro'
|
||||
import {ConfigProvider, Button, Grid, Avatar} from '@nutui/nutui-react-taro'
|
||||
import {
|
||||
User,
|
||||
Shopping,
|
||||
Dongdong,
|
||||
Share,
|
||||
Service,
|
||||
ArrowRight,
|
||||
Purse,
|
||||
People
|
||||
} from '@nutui/icons-react-taro'
|
||||
import {useDealerUser} from '@/hooks/useDealerUser'
|
||||
import { gradientUtils, businessGradients, cardGradients, textGradients } from '@/styles/gradients'
|
||||
import { useThemeStyles } from '@/hooks/useTheme'
|
||||
import {businessGradients, cardGradients, gradientUtils} from '@/styles/gradients'
|
||||
import Taro from '@tarojs/taro'
|
||||
|
||||
const DealerIndex: React.FC = () => {
|
||||
const {
|
||||
dealerUser,
|
||||
loading,
|
||||
error,
|
||||
refresh,
|
||||
} = useDealerUser()
|
||||
|
||||
// 跳转到申请页面
|
||||
const navigateToApply = () => {
|
||||
Taro.navigateTo({
|
||||
url: '/dealer/apply/add'
|
||||
})
|
||||
}
|
||||
// 使用主题样式
|
||||
const themeStyles = useThemeStyles()
|
||||
|
||||
// 导航到各个功能页面
|
||||
const navigateToPage = (url: string) => {
|
||||
@@ -59,6 +53,8 @@ const DealerIndex: React.FC = () => {
|
||||
return userTheme.background
|
||||
}
|
||||
|
||||
console.log(getGradientBackground(),'getGradientBackground()')
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<View className="p-4">
|
||||
@@ -77,46 +73,45 @@ const DealerIndex: React.FC = () => {
|
||||
<View>
|
||||
{/*头部信息*/}
|
||||
{dealerUser && (
|
||||
<View className="px-4 py-6 relative overflow-hidden" style={{
|
||||
background: getGradientBackground(dealerUser?.themeColor)
|
||||
}}>
|
||||
{/* 装饰性背景元素 */}
|
||||
<View className="absolute top-0 right-0 w-32 h-32 rounded-full opacity-10" style={{
|
||||
background: 'radial-gradient(circle, rgba(255, 255, 255, 0.3) 0%, rgba(255, 255, 255, 0.1) 100%)',
|
||||
transform: 'translate(50%, -50%)'
|
||||
<View className="px-4 py-6 relative overflow-hidden" style={themeStyles.primaryBackground}>
|
||||
{/* 装饰性背景元素 - 小程序兼容版本 */}
|
||||
<View className="absolute w-32 h-32 rounded-full" style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||
top: '-16px',
|
||||
right: '-16px'
|
||||
}}></View>
|
||||
<View className="absolute bottom-0 left-0 w-24 h-24 rounded-full opacity-10" style={{
|
||||
background: 'radial-gradient(circle, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.05) 100%)',
|
||||
transform: 'translate(-50%, 50%)'
|
||||
<View className="absolute w-24 h-24 rounded-full" style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.08)',
|
||||
bottom: '-12px',
|
||||
left: '-12px'
|
||||
}}></View>
|
||||
<View className="absolute top-1/2 left-1/2 w-16 h-16 rounded-full opacity-5" style={{
|
||||
background: 'radial-gradient(circle, rgba(255, 255, 255, 0.4) 0%, transparent 70%)',
|
||||
transform: 'translate(-50%, -50%)'
|
||||
<View className="absolute w-16 h-16 rounded-full" style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.05)',
|
||||
top: '60px',
|
||||
left: '120px'
|
||||
}}></View>
|
||||
<View className="flex items-center justify-between relative z-10">
|
||||
<View className="flex items-center justify-between relative z-10 mb-4">
|
||||
<Avatar
|
||||
size="50"
|
||||
src={dealerUser?.qrcode}
|
||||
icon={<User/>}
|
||||
className="mr-4"
|
||||
style={{
|
||||
border: '2px solid rgba(255, 255, 255, 0.3)',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)'
|
||||
border: '2px solid rgba(255, 255, 255, 0.3)'
|
||||
}}
|
||||
/>
|
||||
<View className="flex-1">
|
||||
<Text className="text-white text-lg font-bold mb-1" style={{
|
||||
textShadow: '0 1px 2px rgba(0, 0, 0, 0.1)'
|
||||
<View className="flex-1 flex-col">
|
||||
<View className="text-white text-lg font-bold mb-1" style={{
|
||||
}}>
|
||||
{dealerUser?.realName || '分销商'}
|
||||
</Text>
|
||||
<Text className="text-sm" style={{
|
||||
</View>
|
||||
<View className="text-sm" style={{
|
||||
color: 'rgba(255, 255, 255, 0.8)'
|
||||
}}>
|
||||
ID: {dealerUser.userId} | 推荐人: {dealerUser.refereeId || '无'}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View className="text-right">
|
||||
<View className="text-right hidden">
|
||||
<Text className="text-xs" style={{
|
||||
color: 'rgba(255, 255, 255, 0.9)'
|
||||
}}>加入时间</Text>
|
||||
@@ -133,34 +128,33 @@ const DealerIndex: React.FC = () => {
|
||||
{/* 佣金统计卡片 */}
|
||||
{dealerUser && (
|
||||
<View className="mx-4 -mt-6 rounded-xl p-4 relative z-10" style={cardGradients.elevated}>
|
||||
<Text className="font-semibold mb-4 text-gray-800">佣金统计</Text>
|
||||
<View className="mb-4">
|
||||
<Text className="font-semibold text-gray-800">佣金统计</Text>
|
||||
</View>
|
||||
<View className="grid grid-cols-3 gap-4">
|
||||
<View className="text-center p-3 rounded-lg" style={{
|
||||
background: businessGradients.money.available,
|
||||
backgroundImage: 'linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%)'
|
||||
background: businessGradients.money.available
|
||||
}}>
|
||||
<Text className="text-2xl font-bold mb-1 text-white drop-shadow-sm">
|
||||
<Text className="text-2xl font-bold mb-1 text-white">
|
||||
¥{formatMoney(dealerUser.money)}
|
||||
</Text>
|
||||
<Text className="text-xs text-white text-opacity-90">可提现</Text>
|
||||
<Text className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.9)' }}>可提现</Text>
|
||||
</View>
|
||||
<View className="text-center p-3 rounded-lg" style={{
|
||||
background: businessGradients.money.frozen,
|
||||
backgroundImage: 'linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%)'
|
||||
background: businessGradients.money.frozen
|
||||
}}>
|
||||
<Text className="text-2xl font-bold mb-1 text-white drop-shadow-sm">
|
||||
<Text className="text-2xl font-bold mb-1 text-white">
|
||||
¥{formatMoney(dealerUser.freezeMoney)}
|
||||
</Text>
|
||||
<Text className="text-xs text-white text-opacity-90">冻结中</Text>
|
||||
<Text className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.9)' }}>冻结中</Text>
|
||||
</View>
|
||||
<View className="text-center p-3 rounded-lg" style={{
|
||||
background: businessGradients.money.total,
|
||||
backgroundImage: 'linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%)'
|
||||
background: businessGradients.money.total
|
||||
}}>
|
||||
<Text className="text-2xl font-bold mb-1 text-white drop-shadow-sm">
|
||||
<Text className="text-2xl font-bold mb-1 text-white">
|
||||
¥{formatMoney(dealerUser.totalMoney)}
|
||||
</Text>
|
||||
<Text className="text-xs text-white text-opacity-90">累计收益</Text>
|
||||
<Text className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.9)' }}>累计收益</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
@@ -171,27 +165,28 @@ const DealerIndex: React.FC = () => {
|
||||
<View className="bg-white mx-4 mt-4 rounded-xl p-4">
|
||||
<View className="flex items-center justify-between mb-4">
|
||||
<Text className="font-semibold text-gray-800">我的团队</Text>
|
||||
<Text
|
||||
className="text-blue-500 text-sm"
|
||||
<View
|
||||
className="text-gray-400 text-sm flex items-center"
|
||||
onClick={() => navigateToPage('/dealer/team/index')}
|
||||
>
|
||||
查看详情 <ArrowRight size="12"/>
|
||||
</Text>
|
||||
<Text>查看详情</Text>
|
||||
<ArrowRight size="12"/>
|
||||
</View>
|
||||
</View>
|
||||
<View className="grid grid-cols-3 gap-4">
|
||||
<View className="text-center">
|
||||
<View className="text-center grid">
|
||||
<Text className="text-xl font-bold text-purple-500 mb-1">
|
||||
{dealerUser.firstNum || 0}
|
||||
</Text>
|
||||
<Text className="text-xs text-gray-500">一级成员</Text>
|
||||
</View>
|
||||
<View className="text-center">
|
||||
<View className="text-center grid">
|
||||
<Text className="text-xl font-bold text-indigo-500 mb-1">
|
||||
{dealerUser.secondNum || 0}
|
||||
</Text>
|
||||
<Text className="text-xs text-gray-500">二级成员</Text>
|
||||
</View>
|
||||
<View className="text-center">
|
||||
<View className="text-center grid">
|
||||
<Text className="text-xl font-bold text-pink-500 mb-1">
|
||||
{dealerUser.thirdNum || 0}
|
||||
</Text>
|
||||
@@ -203,44 +198,45 @@ const DealerIndex: React.FC = () => {
|
||||
|
||||
{/* 功能导航 */}
|
||||
<View className="bg-white mx-4 mt-4 rounded-xl p-4">
|
||||
<Text className="font-semibold mb-4 text-gray-800">分销工具</Text>
|
||||
<Grid columns={4} gap={16}>
|
||||
<Grid.Item onClick={() => navigateToPage('/dealer/orders/index')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-blue-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<Shopping color="#3b82f6" size="20"/>
|
||||
<View className="font-semibold mb-4 text-gray-800">分销工具</View>
|
||||
<ConfigProvider>
|
||||
<Grid columns={4}>
|
||||
<Grid.Item text="分销订单" onClick={() => navigateToPage('/dealer/orders/index')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-blue-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<Shopping color="#3b82f6" size="20"/>
|
||||
</View>
|
||||
</View>
|
||||
<Text className="text-xs text-gray-600">分销订单</Text>
|
||||
</View>
|
||||
</Grid.Item>
|
||||
</Grid.Item>
|
||||
|
||||
<Grid.Item onClick={() => navigateToPage('/dealer/withdraw/index')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-green-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<Purse color="#10b981" size="20"/>
|
||||
<Grid.Item onClick={() => navigateToPage('/dealer/withdraw/index')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-green-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<Purse color="#10b981" size="20"/>
|
||||
</View>
|
||||
<Text className="text-xs text-gray-600">提现申请</Text>
|
||||
</View>
|
||||
<Text className="text-xs text-gray-600">提现申请</Text>
|
||||
</View>
|
||||
</Grid.Item>
|
||||
</Grid.Item>
|
||||
|
||||
<Grid.Item onClick={() => navigateToPage('/dealer/team/index')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-purple-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<People color="#8b5cf6" size="20"/>
|
||||
<Grid.Item onClick={() => navigateToPage('/dealer/team/index')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-purple-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<People color="#8b5cf6" size="20"/>
|
||||
</View>
|
||||
<Text className="text-xs text-gray-600">我的团队</Text>
|
||||
</View>
|
||||
<Text className="text-xs text-gray-600">我的团队</Text>
|
||||
</View>
|
||||
</Grid.Item>
|
||||
</Grid.Item>
|
||||
|
||||
<Grid.Item onClick={() => navigateToPage('/dealer/qrcode/index')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-orange-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<Dongdong color="#f59e0b" size="20"/>
|
||||
<Grid.Item onClick={() => navigateToPage('/dealer/qrcode/index')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-orange-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<Dongdong color="#f59e0b" size="20"/>
|
||||
</View>
|
||||
<Text className="text-xs text-gray-600">推广二维码</Text>
|
||||
</View>
|
||||
<Text className="text-xs text-gray-600">推广二维码</Text>
|
||||
</View>
|
||||
</Grid.Item>
|
||||
</Grid>
|
||||
</Grid.Item>
|
||||
</Grid>
|
||||
</ConfigProvider>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ const DealerInfo: React.FC = () => {
|
||||
</CellGroup>
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<View className="mt-6 space-y-3">
|
||||
<View className="mt-6 gap-2">
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
@@ -104,7 +104,7 @@ const DealerInfo: React.FC = () => {
|
||||
{/* 经销商权益 */}
|
||||
<View className="bg-white mx-4 mt-4 rounded-lg p-4">
|
||||
<Text className="font-semibold mb-3">经销商权益</Text>
|
||||
<View className="space-y-2">
|
||||
<View className="gap-2">
|
||||
<Text className="text-sm text-gray-600">
|
||||
• 享受经销商专属价格
|
||||
</Text>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { useState } from 'react'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import { Cell, Empty, Tabs, Tag, Button, PullToRefresh } from '@nutui/nutui-react-taro'
|
||||
import { Empty, Tabs, Tag, PullToRefresh } from '@nutui/nutui-react-taro'
|
||||
|
||||
const DealerOrders: React.FC = () => {
|
||||
const [activeTab, setActiveTab] = useState('0')
|
||||
const [refreshing, setRefreshing] = useState(false)
|
||||
const [activeTab, setActiveTab] = useState<string>('0')
|
||||
const [refreshing, setRefreshing] = useState<boolean>(false)
|
||||
|
||||
// 模拟订单数据
|
||||
const mockOrders = [
|
||||
@@ -65,7 +65,7 @@ const DealerOrders: React.FC = () => {
|
||||
客户:{order.customerName}
|
||||
</Text>
|
||||
</View>
|
||||
<Tag type={getStatusColor(order.status)} size="small">
|
||||
<Tag type={getStatusColor(order.status)}>
|
||||
{getStatusText(order.status)}
|
||||
</Tag>
|
||||
</View>
|
||||
@@ -107,9 +107,10 @@ const DealerOrders: React.FC = () => {
|
||||
</View>
|
||||
|
||||
{/* 订单列表 */}
|
||||
<Tabs value={activeTab} onChange={setActiveTab}>
|
||||
<Tabs value={activeTab} onChange={() => setActiveTab}>
|
||||
<Tabs.TabPane title="全部" value="0">
|
||||
<PullToRefresh
|
||||
// @ts-ignore
|
||||
loading={refreshing}
|
||||
onRefresh={handleRefresh}
|
||||
>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import React, { useState } from 'react'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import { Empty, Tabs, Avatar, Tag, Cell, Progress } from '@nutui/nutui-react-taro'
|
||||
import { User, Crown, Star } from '@nutui/icons-react-taro'
|
||||
import { businessGradients, cardGradients } from '@/styles/gradients'
|
||||
import { Empty, Tabs, Avatar, Tag, Progress } from '@nutui/nutui-react-taro'
|
||||
import { User, Star, StarFill } from '@nutui/icons-react-taro'
|
||||
|
||||
const DealerTeam: React.FC = () => {
|
||||
const [activeTab, setActiveTab] = useState('0')
|
||||
@@ -63,7 +62,7 @@ const DealerTeam: React.FC = () => {
|
||||
|
||||
const getLevelIcon = (level: number) => {
|
||||
switch (level) {
|
||||
case 1: return <Crown color={getLevelColor(level)} size="16" />
|
||||
case 1: return <StarFill color={getLevelColor(level)} size="16" />
|
||||
case 2: return <Star color={getLevelColor(level)} size="16" />
|
||||
case 3: return <User color={getLevelColor(level)} size="16" />
|
||||
default: return <User color={getLevelColor(level)} size="16" />
|
||||
@@ -96,7 +95,6 @@ const DealerTeam: React.FC = () => {
|
||||
<View className="text-right">
|
||||
<Tag
|
||||
type={member.status === 'active' ? 'success' : 'default'}
|
||||
size="small"
|
||||
>
|
||||
{member.status === 'active' ? '活跃' : '沉默'}
|
||||
</Tag>
|
||||
@@ -132,26 +130,28 @@ const DealerTeam: React.FC = () => {
|
||||
<View className="rounded-xl p-6 mb-6 text-white relative overflow-hidden" style={{
|
||||
background: 'linear-gradient(135deg, #8b5cf6 0%, #ec4899 100%)'
|
||||
}}>
|
||||
{/* 装饰背景 */}
|
||||
<View className="absolute top-0 right-0 w-32 h-32 rounded-full opacity-10" style={{
|
||||
background: 'radial-gradient(circle, rgba(255, 255, 255, 0.3) 0%, transparent 70%)',
|
||||
transform: 'translate(50%, -50%)'
|
||||
{/* 装饰背景 - 小程序兼容版本 */}
|
||||
<View className="absolute w-32 h-32 rounded-full" style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||
top: '-16px',
|
||||
right: '-16px'
|
||||
}}></View>
|
||||
<View className="absolute bottom-0 left-0 w-20 h-20 rounded-full opacity-5" style={{
|
||||
background: 'radial-gradient(circle, rgba(255, 255, 255, 0.4) 0%, transparent 70%)',
|
||||
transform: 'translate(-50%, 50%)'
|
||||
<View className="absolute w-20 h-20 rounded-full" style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.05)',
|
||||
bottom: '-10px',
|
||||
left: '-10px'
|
||||
}}></View>
|
||||
|
||||
<View className="relative z-10">
|
||||
<Text className="text-lg font-bold mb-4 text-white drop-shadow-sm">团队总览</Text>
|
||||
<Text className="text-lg font-bold mb-4 text-white">团队总览</Text>
|
||||
<View className="grid grid-cols-2 gap-4">
|
||||
<View>
|
||||
<Text className="text-2xl font-bold mb-1 text-white drop-shadow-sm">{teamStats.total}</Text>
|
||||
<Text className="text-white text-opacity-80 text-sm">团队总人数</Text>
|
||||
<Text className="text-2xl font-bold mb-1 text-white">{teamStats.total}</Text>
|
||||
<Text className="text-sm" style={{ color: 'rgba(255, 255, 255, 0.8)' }}>团队总人数</Text>
|
||||
</View>
|
||||
<View>
|
||||
<Text className="text-2xl font-bold mb-1 text-white drop-shadow-sm">¥{teamStats.monthlyCommission}</Text>
|
||||
<Text className="text-white text-opacity-80 text-sm">本月团队佣金</Text>
|
||||
<Text className="text-2xl font-bold mb-1 text-white">¥{teamStats.monthlyCommission}</Text>
|
||||
<Text className="text-sm" style={{ color: 'rgba(255, 255, 255, 0.8)' }}>本月团队佣金</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
@@ -160,18 +160,18 @@ const DealerTeam: React.FC = () => {
|
||||
{/* 层级分布 */}
|
||||
<View className="bg-white rounded-xl p-4 mb-4">
|
||||
<Text className="font-semibold mb-4 text-gray-800">层级分布</Text>
|
||||
<View className="space-y-3">
|
||||
<View className="gap-2">
|
||||
<View className="flex items-center justify-between">
|
||||
<View className="flex items-center">
|
||||
<Crown color="#f59e0b" size="16" className="mr-2" />
|
||||
<StarFill color="#f59e0b" size="16" className="mr-2" />
|
||||
<Text className="text-sm">一级成员</Text>
|
||||
</View>
|
||||
<View className="flex items-center">
|
||||
<Text className="text-sm font-semibold mr-2">{teamStats.firstLevel}</Text>
|
||||
<Progress
|
||||
percentage={(teamStats.firstLevel / teamStats.total) * 100}
|
||||
percent={(teamStats.firstLevel / teamStats.total) * 100}
|
||||
strokeWidth="6"
|
||||
strokeColor="#f59e0b"
|
||||
background="#f59e0b"
|
||||
className="w-20"
|
||||
/>
|
||||
</View>
|
||||
@@ -185,9 +185,9 @@ const DealerTeam: React.FC = () => {
|
||||
<View className="flex items-center">
|
||||
<Text className="text-sm font-semibold mr-2">{teamStats.secondLevel}</Text>
|
||||
<Progress
|
||||
percentage={(teamStats.secondLevel / teamStats.total) * 100}
|
||||
percent={(teamStats.secondLevel / teamStats.total) * 100}
|
||||
strokeWidth="6"
|
||||
strokeColor="#8b5cf6"
|
||||
background="#8b5cf6"
|
||||
className="w-20"
|
||||
/>
|
||||
</View>
|
||||
@@ -201,9 +201,9 @@ const DealerTeam: React.FC = () => {
|
||||
<View className="flex items-center">
|
||||
<Text className="text-sm font-semibold mr-2">{teamStats.thirdLevel}</Text>
|
||||
<Progress
|
||||
percentage={(teamStats.thirdLevel / teamStats.total) * 100}
|
||||
percent={(teamStats.thirdLevel / teamStats.total) * 100}
|
||||
strokeWidth="6"
|
||||
strokeColor="#ec4899"
|
||||
background="#ec4899"
|
||||
className="w-20"
|
||||
/>
|
||||
</View>
|
||||
@@ -233,7 +233,7 @@ const DealerTeam: React.FC = () => {
|
||||
|
||||
return (
|
||||
<View className="bg-gray-50 min-h-screen">
|
||||
<Tabs value={activeTab} onChange={setActiveTab}>
|
||||
<Tabs value={activeTab} onChange={() => setActiveTab}>
|
||||
<Tabs.TabPane title="团队总览" value="0">
|
||||
{renderOverview()}
|
||||
</Tabs.TabPane>
|
||||
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
Tag,
|
||||
Empty
|
||||
} from '@nutui/nutui-react-taro'
|
||||
import { Money, ArrowRight } from '@nutui/icons-react-taro'
|
||||
import { businessGradients, cardGradients } from '@/styles/gradients'
|
||||
import { Wallet } from '@nutui/icons-react-taro'
|
||||
import { businessGradients } from '@/styles/gradients'
|
||||
import Taro from '@tarojs/taro'
|
||||
|
||||
const DealerWithdraw: React.FC = () => {
|
||||
@@ -84,21 +84,22 @@ const DealerWithdraw: React.FC = () => {
|
||||
<View className="rounded-xl p-6 mb-6 text-white relative overflow-hidden" style={{
|
||||
background: businessGradients.dealer.header
|
||||
}}>
|
||||
{/* 装饰背景 */}
|
||||
<View className="absolute top-0 right-0 w-24 h-24 rounded-full opacity-10" style={{
|
||||
background: 'radial-gradient(circle, rgba(255, 255, 255, 0.3) 0%, transparent 70%)',
|
||||
transform: 'translate(50%, -50%)'
|
||||
{/* 装饰背景 - 小程序兼容版本 */}
|
||||
<View className="absolute top-0 right-0 w-24 h-24 rounded-full" style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||
right: '-12px',
|
||||
top: '-12px'
|
||||
}}></View>
|
||||
|
||||
<View className="flex items-center justify-between relative z-10">
|
||||
<View>
|
||||
<Text className="text-white text-opacity-80 text-sm mb-1">可提现余额</Text>
|
||||
<Text className="text-2xl font-bold text-white drop-shadow-sm">¥{availableAmount}</Text>
|
||||
<Text className="text-2xl font-bold text-white">¥{availableAmount}</Text>
|
||||
</View>
|
||||
<View className="p-3 rounded-full" style={{
|
||||
background: 'rgba(255, 255, 255, 0.2)'
|
||||
}}>
|
||||
<Money color="white" size="32" />
|
||||
<Wallet color="white" size="32" />
|
||||
</View>
|
||||
</View>
|
||||
<View className="mt-4 pt-4 relative z-10" style={{
|
||||
@@ -149,7 +150,7 @@ const DealerWithdraw: React.FC = () => {
|
||||
</View>
|
||||
|
||||
<Form.Item name="accountType" label="提现方式" required>
|
||||
<Radio.Group value={selectedAccount} onChange={setSelectedAccount}>
|
||||
<Radio.Group value={selectedAccount} onChange={() => setSelectedAccount}>
|
||||
<Cell.Group>
|
||||
<Cell>
|
||||
<Radio value="wechat">微信钱包</Radio>
|
||||
@@ -200,7 +201,7 @@ const DealerWithdraw: React.FC = () => {
|
||||
提现账户:{record.account}
|
||||
</Text>
|
||||
</View>
|
||||
<Tag type={getStatusColor(record.status)} size="small">
|
||||
<Tag type={getStatusColor(record.status)}>
|
||||
{getStatusText(record.status)}
|
||||
</Tag>
|
||||
</View>
|
||||
@@ -223,7 +224,7 @@ const DealerWithdraw: React.FC = () => {
|
||||
|
||||
return (
|
||||
<View className="bg-gray-50 min-h-screen">
|
||||
<Tabs value={activeTab} onChange={setActiveTab}>
|
||||
<Tabs value={activeTab} onChange={() => setActiveTab}>
|
||||
<Tabs.TabPane title="申请提现" value="0">
|
||||
{renderWithdrawForm()}
|
||||
</Tabs.TabPane>
|
||||
|
||||
95
src/hooks/useTheme.ts
Normal file
95
src/hooks/useTheme.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { gradientThemes, GradientTheme, gradientUtils } from '@/styles/gradients'
|
||||
import Taro from '@tarojs/taro'
|
||||
|
||||
export interface UseThemeReturn {
|
||||
currentTheme: GradientTheme
|
||||
setTheme: (themeName: string) => void
|
||||
isAutoTheme: boolean
|
||||
refreshTheme: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* 主题管理Hook
|
||||
* 提供主题切换和状态管理功能
|
||||
*/
|
||||
export const useTheme = (): UseThemeReturn => {
|
||||
const [currentTheme, setCurrentTheme] = useState<GradientTheme>(gradientThemes[0])
|
||||
const [isAutoTheme, setIsAutoTheme] = useState<boolean>(true)
|
||||
|
||||
// 获取当前主题
|
||||
const getCurrentTheme = (): GradientTheme => {
|
||||
const savedTheme = Taro.getStorageSync('user_theme') || 'auto'
|
||||
|
||||
if (savedTheme === 'auto') {
|
||||
// 自动主题:根据用户ID生成
|
||||
const userId = Taro.getStorageSync('userId') || '1'
|
||||
return gradientUtils.getThemeByUserId(userId)
|
||||
} else {
|
||||
// 手动选择的主题
|
||||
return gradientThemes.find(t => t.name === savedTheme) || gradientThemes[0]
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化主题
|
||||
useEffect(() => {
|
||||
const savedTheme = Taro.getStorageSync('user_theme') || 'auto'
|
||||
setIsAutoTheme(savedTheme === 'auto')
|
||||
setCurrentTheme(getCurrentTheme())
|
||||
}, [])
|
||||
|
||||
// 设置主题
|
||||
const setTheme = (themeName: string) => {
|
||||
try {
|
||||
Taro.setStorageSync('user_theme', themeName)
|
||||
setIsAutoTheme(themeName === 'auto')
|
||||
setCurrentTheme(getCurrentTheme())
|
||||
} catch (error) {
|
||||
console.error('保存主题失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新主题(用于自动主题模式下用户信息变更时)
|
||||
const refreshTheme = () => {
|
||||
setCurrentTheme(getCurrentTheme())
|
||||
}
|
||||
|
||||
return {
|
||||
currentTheme,
|
||||
setTheme,
|
||||
isAutoTheme,
|
||||
refreshTheme
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前主题的样式对象
|
||||
* 用于直接应用到组件样式中
|
||||
*/
|
||||
export const useThemeStyles = () => {
|
||||
const { currentTheme } = useTheme()
|
||||
|
||||
return {
|
||||
// 主要背景样式
|
||||
primaryBackground: {
|
||||
background: currentTheme.background,
|
||||
color: currentTheme.textColor
|
||||
},
|
||||
|
||||
// 按钮样式
|
||||
primaryButton: {
|
||||
background: currentTheme.background,
|
||||
border: 'none',
|
||||
color: currentTheme.textColor
|
||||
},
|
||||
|
||||
// 强调色
|
||||
accentColor: currentTheme.primary,
|
||||
|
||||
// 文字颜色
|
||||
textColor: currentTheme.textColor,
|
||||
|
||||
// 完整主题对象
|
||||
theme: currentTheme
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
Divider,
|
||||
ConfigProvider
|
||||
} from '@nutui/nutui-react-taro';
|
||||
import {ArrowLeft, Del, Shopping} from '@nutui/icons-react-taro';
|
||||
import {ArrowLeft, Del} from '@nutui/icons-react-taro';
|
||||
import {View} from '@tarojs/components';
|
||||
import {CartItem, useCart} from "@/hooks/useCart";
|
||||
import './cart.scss';
|
||||
@@ -48,11 +48,11 @@ function Cart() {
|
||||
useShareAppMessage(() => {
|
||||
return {
|
||||
title: '购物车 - 网宿小店',
|
||||
success: function (res) {
|
||||
console.log('分享成功', res);
|
||||
success: function () {
|
||||
console.log('分享成功');
|
||||
},
|
||||
fail: function (res) {
|
||||
console.log('分享失败', res);
|
||||
fail: function () {
|
||||
console.log('分享失败');
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -203,15 +203,25 @@ function Cart() {
|
||||
>
|
||||
<span className="text-lg">购物车({cartCount})</span>
|
||||
</NavBar>
|
||||
<Empty
|
||||
description="购物车空空如也"
|
||||
actions={[{ text: '去逛逛' }]}
|
||||
|
||||
{/* 垂直居中的空状态容器 */}
|
||||
<View
|
||||
className="flex items-center justify-center"
|
||||
style={{
|
||||
marginTop: `${statusBarHeight + 50}px`,
|
||||
height: `calc(100vh - ${statusBarHeight + 150}px)`,
|
||||
paddingTop: `${statusBarHeight + 50}px`,
|
||||
backgroundColor: 'transparent'
|
||||
}}
|
||||
onClick={() => Taro.switchTab({ url: '/pages/index/index' })}
|
||||
/>
|
||||
>
|
||||
<Empty
|
||||
description="购物车空空如也"
|
||||
actions={[{ text: '去逛逛' }]}
|
||||
style={{
|
||||
backgroundColor: 'transparent'
|
||||
}}
|
||||
onClick={() => Taro.switchTab({ url: '/pages/index/index' })}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -251,33 +261,8 @@ function Cart() {
|
||||
</NavBar>
|
||||
|
||||
{/* 购物车内容 */}
|
||||
<View
|
||||
className="pt-24"
|
||||
style={{ backgroundColor: cartItems.length === 0 ? 'transparent' : undefined }}
|
||||
>
|
||||
{cartItems.length === 0 ? (
|
||||
// 空购物车
|
||||
<View
|
||||
className="cart-empty-container flex flex-col items-center justify-center h-96"
|
||||
style={{ backgroundColor: 'transparent' }}
|
||||
>
|
||||
<Empty
|
||||
image={<Shopping size={80}/>}
|
||||
description="购物车空空如也"
|
||||
style={{ backgroundColor: 'transparent' }}
|
||||
>
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
onClick={() => Taro.switchTab({url: '/pages/index/index'})}
|
||||
>
|
||||
去逛逛
|
||||
</Button>
|
||||
</Empty>
|
||||
</View>
|
||||
) : (
|
||||
<>
|
||||
{/* 商品列表 */}
|
||||
<View className="pt-24">
|
||||
{/* 商品列表 */}
|
||||
<View className="bg-white">
|
||||
{cartItems.map((item: CartItem, index: number) => (
|
||||
<View key={item.goodsId}>
|
||||
@@ -361,10 +346,8 @@ function Cart() {
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 底部安全区域占位 */}
|
||||
<View className="h-20"></View>
|
||||
</>
|
||||
)}
|
||||
{/* 底部安全区域占位 */}
|
||||
<View className="h-20"></View>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -27,12 +27,13 @@ const UserCell = () => {
|
||||
backgroundImage: 'linear-gradient(to right bottom, #e53e3e, #c53030)',
|
||||
}}
|
||||
title={
|
||||
<View style={{display: 'inline-flex', alignItems: 'center'}} onClick={() => navTo('/admin/index', true)}>
|
||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||
<Setting className={'text-white '} size={16}/>
|
||||
<Text style={{fontSize: '16px'}} className={'pl-3 text-white font-medium'}>管理中心</Text>
|
||||
</View>
|
||||
}
|
||||
extra={<ArrowRight color="#ffffff" size={18}/>}
|
||||
onClick={() => navTo('/admin/index', true)}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
@@ -52,7 +53,7 @@ const UserCell = () => {
|
||||
backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)',
|
||||
}}
|
||||
title={
|
||||
<View style={{display: 'inline-flex', alignItems: 'center'}} onClick={() => navTo('/dealer/index', true)}>
|
||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||
<Reward className={'text-orange-100 '} size={16}/>
|
||||
<Text style={{fontSize: '16px'}}
|
||||
className={'pl-3 text-orange-100 font-medium'}>分销中心</Text>
|
||||
@@ -60,6 +61,7 @@ const UserCell = () => {
|
||||
</View>
|
||||
}
|
||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||
onClick={() => navTo('/dealer/index', true)}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
|
||||
@@ -122,6 +122,13 @@ const UserCell = () => {
|
||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||
onClick={() => navTo('/user/profile/profile', true)}
|
||||
/>
|
||||
<Cell
|
||||
className="nutui-cell-clickable"
|
||||
title="切换主题"
|
||||
align="center"
|
||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||
onClick={() => navTo('/user/theme/index', true)}
|
||||
/>
|
||||
<Cell
|
||||
className="nutui-cell-clickable"
|
||||
title="退出登录"
|
||||
|
||||
@@ -582,9 +582,7 @@ const OrderConfirm = () => {
|
||||
|
||||
<Gap height={50}/>
|
||||
|
||||
<div className={'fixed z-50 bg-white w-full bottom-0 left-0 pt-4 pb-10'} style={{
|
||||
boxShadow: '0 -2px 4px 0 rgba(0,0,0,0.10)'
|
||||
}}>
|
||||
<div className={'fixed z-50 bg-white w-full bottom-0 left-0 pt-4 pb-10 border-t border-gray-200'}>
|
||||
<View className={'btn-bar flex justify-between items-center'}>
|
||||
<div className={'flex flex-col justify-center items-start mx-4'}>
|
||||
<View className={'flex items-center gap-2'}>
|
||||
|
||||
@@ -195,9 +195,7 @@ const OrderConfirm = () => {
|
||||
|
||||
<Gap height={50} />
|
||||
|
||||
<div className={'fixed z-50 bg-white w-full bottom-0 left-0 pt-4 pb-10'} style={{
|
||||
boxShadow: '0 -2px 4px 0 rgba(0,0,0,0.10)'
|
||||
}}>
|
||||
<div className={'fixed z-50 bg-white w-full bottom-0 left-0 pt-4 pb-10 border-t border-gray-200'}>
|
||||
<View className={'btn-bar flex justify-between items-center'}>
|
||||
<div className={'flex justify-center items-center mx-4'}>
|
||||
<span className={'total-price text-sm text-gray-500'}>实付金额:</span>
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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 && (
|
||||
<>
|
||||
<View className="text-sm text-gray-600 mb-2" style={{
|
||||
display: '-webkit-box',
|
||||
WebkitLineClamp: 2,
|
||||
WebkitBoxOrient: 'vertical',
|
||||
overflow: 'hidden'
|
||||
// 注意:小程序不支持 WebKit 文本截断属性
|
||||
}}>
|
||||
{giftInfo.description}
|
||||
</View>
|
||||
|
||||
4
src/user/theme/index.config.ts
Normal file
4
src/user/theme/index.config.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '主题设置',
|
||||
navigationBarTextStyle: 'black'
|
||||
})
|
||||
179
src/user/theme/index.tsx
Normal file
179
src/user/theme/index.tsx
Normal file
@@ -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<string>('')
|
||||
const [currentTheme, setCurrentTheme] = useState<GradientTheme | null>(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 (
|
||||
<View className="min-h-screen bg-gray-50">
|
||||
{/* 当前主题预览 */}
|
||||
{currentTheme && (
|
||||
<View
|
||||
className="mx-4 mt-4 rounded-xl p-6 text-center"
|
||||
style={{
|
||||
background: currentTheme.background,
|
||||
color: currentTheme.textColor
|
||||
}}
|
||||
>
|
||||
<Text className="text-lg font-bold mb-2">当前主题预览</Text>
|
||||
<Text className="text-sm opacity-90 px-2">{currentTheme.description}</Text>
|
||||
<View className="mt-4 flex justify-center space-x-4">
|
||||
<View
|
||||
className="w-8 h-8 rounded-full"
|
||||
style={{ backgroundColor: currentTheme.primary }}
|
||||
></View>
|
||||
{currentTheme.secondary && (
|
||||
<View
|
||||
className="w-8 h-8 rounded-full"
|
||||
style={{ backgroundColor: currentTheme.secondary }}
|
||||
></View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 主题选择 */}
|
||||
<View className="mt-4">
|
||||
<CellGroup>
|
||||
<Cell
|
||||
className="px-4 py-2"
|
||||
title={
|
||||
<View className="flex items-center justify-between w-full">
|
||||
<View>
|
||||
<Text className="font-medium">智能主题</Text>
|
||||
<Text className="text-sm text-gray-500 mt-1">
|
||||
根据您的用户ID自动选择个性化主题
|
||||
</Text>
|
||||
</View>
|
||||
<Radio
|
||||
checked={selectedTheme === 'auto'}
|
||||
onChange={() => {
|
||||
setSelectedTheme('auto')
|
||||
previewTheme('auto')
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
onClick={() => {
|
||||
setSelectedTheme('auto')
|
||||
previewTheme('auto')
|
||||
}}
|
||||
/>
|
||||
</CellGroup>
|
||||
|
||||
<View className="mt-4">
|
||||
<Text className="text-sm text-gray-600 px-4 mb-2">手动选择主题</Text>
|
||||
<CellGroup>
|
||||
{gradientThemes.map((theme) => (
|
||||
<Cell
|
||||
key={theme.name}
|
||||
className="px-4 py-3"
|
||||
title={
|
||||
<View className="flex items-center justify-between w-full">
|
||||
<View className="flex items-center">
|
||||
<View
|
||||
className="w-6 h-6 rounded-full mr-3"
|
||||
style={{ background: theme.background }}
|
||||
></View>
|
||||
<View>
|
||||
<Text className="font-medium">{theme.description.split(' - ')[0]}</Text>
|
||||
<Text className="text-sm text-gray-500 mt-1">
|
||||
{theme.description.split(' - ')[1]}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Radio
|
||||
checked={selectedTheme === theme.name}
|
||||
onChange={() => {
|
||||
setSelectedTheme(theme.name)
|
||||
previewTheme(theme.name)
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
onClick={() => {
|
||||
setSelectedTheme(theme.name)
|
||||
previewTheme(theme.name)
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</CellGroup>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 保存按钮 */}
|
||||
<FixedButton text={'保存主题设置'} background={currentTheme?.background || '#1890ff'} onClick={() => saveTheme(selectedTheme)} />
|
||||
|
||||
{/* 底部安全区域 */}
|
||||
<View className="h-20"></View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThemeSelector
|
||||
Reference in New Issue
Block a user