|
@@ -1,682 +0,0 @@
|
|
|
-import { Image } from 'expo-image';
|
|
|
|
|
-import { useRouter } from 'expo-router';
|
|
|
|
|
-import React, { useCallback, useEffect, useState } from 'react';
|
|
|
|
|
-import {
|
|
|
|
|
- Alert,
|
|
|
|
|
- ImageBackground,
|
|
|
|
|
- ScrollView,
|
|
|
|
|
- StatusBar,
|
|
|
|
|
- StyleSheet,
|
|
|
|
|
- Text,
|
|
|
|
|
- TouchableOpacity,
|
|
|
|
|
- View,
|
|
|
|
|
-} from 'react-native';
|
|
|
|
|
-import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
|
|
|
-
|
|
|
|
|
-import { Images } from '@/constants/images';
|
|
|
|
|
-import services from '@/services/api';
|
|
|
|
|
-
|
|
|
|
|
-interface DayInfo {
|
|
|
|
|
- text: string;
|
|
|
|
|
- date: string;
|
|
|
|
|
- isFutureDate: boolean;
|
|
|
|
|
- istoday: boolean;
|
|
|
|
|
- isSignIn: boolean;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-interface RecordItem {
|
|
|
|
|
- id: string;
|
|
|
|
|
- credit: number;
|
|
|
|
|
- createTime: string;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-export default function IntegralScreen() {
|
|
|
|
|
- const router = useRouter();
|
|
|
|
|
- const insets = useSafeAreaInsets();
|
|
|
|
|
-
|
|
|
|
|
- const [integral, setIntegral] = useState(0);
|
|
|
|
|
- const [daysIntegral, setDaysIntegral] = useState(0);
|
|
|
|
|
- const [istodaySignIn, setIstodaySignIn] = useState(false);
|
|
|
|
|
- const [record, setRecord] = useState<RecordItem[]>([]);
|
|
|
|
|
- const [dataInfo, setDataInfo] = useState<DayInfo[]>([]);
|
|
|
|
|
- const [todayIntegral, setTodayIntegral] = useState(1);
|
|
|
|
|
- const [tomorrowIntegral, setTomorrowIntegral] = useState(1);
|
|
|
|
|
- const [isTooltip, setIsTooltip] = useState(false);
|
|
|
|
|
-
|
|
|
|
|
- // 格式化数字为两位
|
|
|
|
|
- const padWithZeros = (number: number, length: number) => {
|
|
|
|
|
- return String(number).padStart(length, '0');
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // 设置日期数据
|
|
|
|
|
- const setDate = useCallback(() => {
|
|
|
|
|
- const now = new Date();
|
|
|
|
|
- const dataInfoArr: DayInfo[] = [];
|
|
|
|
|
-
|
|
|
|
|
- // 前4天
|
|
|
|
|
- for (let i = -4; i <= 0; i++) {
|
|
|
|
|
- const date = new Date(now);
|
|
|
|
|
- date.setDate(date.getDate() + i);
|
|
|
|
|
- const m = date.getMonth() + 1;
|
|
|
|
|
- const d = date.getDate();
|
|
|
|
|
- const y = date.getFullYear();
|
|
|
|
|
-
|
|
|
|
|
- dataInfoArr.push({
|
|
|
|
|
- text: `${m}.${d}`,
|
|
|
|
|
- date: `${y}-${padWithZeros(m, 2)}-${padWithZeros(d, 2)}`,
|
|
|
|
|
- isFutureDate: false,
|
|
|
|
|
- istoday: i === 0,
|
|
|
|
|
- isSignIn: false,
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 明天
|
|
|
|
|
- const tomorrow = new Date(now);
|
|
|
|
|
- tomorrow.setDate(tomorrow.getDate() + 1);
|
|
|
|
|
- const tm = tomorrow.getMonth() + 1;
|
|
|
|
|
- const td = tomorrow.getDate();
|
|
|
|
|
- const ty = tomorrow.getFullYear();
|
|
|
|
|
-
|
|
|
|
|
- dataInfoArr.push({
|
|
|
|
|
- text: `${tm}.${td}`,
|
|
|
|
|
- date: `${ty}-${padWithZeros(tm, 2)}-${padWithZeros(td, 2)}`,
|
|
|
|
|
- isFutureDate: true,
|
|
|
|
|
- istoday: false,
|
|
|
|
|
- isSignIn: false,
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- setDataInfo(dataInfoArr);
|
|
|
|
|
- return dataInfoArr;
|
|
|
|
|
- }, []);
|
|
|
|
|
-
|
|
|
|
|
- // 获取积分信息
|
|
|
|
|
- const getInfo = useCallback(async () => {
|
|
|
|
|
- try {
|
|
|
|
|
- // Use wallet service info instead of user service getWalletInfo
|
|
|
|
|
- const info = await services.wallet.info('USER_CREDIT');
|
|
|
|
|
- setIntegral(info?.balance || 0);
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('获取积分失败:', error);
|
|
|
|
|
- }
|
|
|
|
|
- }, []);
|
|
|
|
|
-
|
|
|
|
|
- // 获取积分规则
|
|
|
|
|
- const showRule = async () => {
|
|
|
|
|
- try {
|
|
|
|
|
- const res = await services.user.getParamConfig('credit_sign');
|
|
|
|
|
- if (res && res.data) {
|
|
|
|
|
- Alert.alert('积分规则', res.data.replace(/<[^>]+>/g, '')); // Strip HTML tags for Alert
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('获取规则失败:', error);
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // 获取签到记录
|
|
|
|
|
- const getData = useCallback(async (dateInfo: DayInfo[]) => {
|
|
|
|
|
- try {
|
|
|
|
|
- const fourDaysAgo = new Date();
|
|
|
|
|
- fourDaysAgo.setDate(fourDaysAgo.getDate() - 4);
|
|
|
|
|
- const m = fourDaysAgo.getMonth() + 1;
|
|
|
|
|
- const d = fourDaysAgo.getDate();
|
|
|
|
|
- const y = fourDaysAgo.getFullYear();
|
|
|
|
|
-
|
|
|
|
|
- const param = {
|
|
|
|
|
- createTime: `${y}-${padWithZeros(m, 2)}-${padWithZeros(d, 2)}`,
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const res = await services.user.getCreditRecord(param);
|
|
|
|
|
- const recordData = res?.data || [];
|
|
|
|
|
- setRecord(recordData);
|
|
|
|
|
-
|
|
|
|
|
- // 今天日期
|
|
|
|
|
- const now = new Date();
|
|
|
|
|
- const todayStr = `${now.getFullYear()}-${padWithZeros(now.getMonth() + 1, 2)}-${padWithZeros(now.getDate(), 2)}`;
|
|
|
|
|
-
|
|
|
|
|
- // 更新签到状态
|
|
|
|
|
- const updatedDataInfo = dateInfo.map(item => {
|
|
|
|
|
- const newItem = { ...item };
|
|
|
|
|
-
|
|
|
|
|
- // 检查是否已签到
|
|
|
|
|
- for (const rec of recordData) {
|
|
|
|
|
- const createTime = rec.createTime?.slice(0, 10);
|
|
|
|
|
- if (createTime === item.date) {
|
|
|
|
|
- newItem.isSignIn = true;
|
|
|
|
|
- if (item.date === todayStr) {
|
|
|
|
|
- setIstodaySignIn(true);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return newItem;
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- setDataInfo(updatedDataInfo);
|
|
|
|
|
-
|
|
|
|
|
- // 计算签到积分
|
|
|
|
|
- let total = 0;
|
|
|
|
|
- for (const rec of recordData) {
|
|
|
|
|
- if (rec.credit > 0) {
|
|
|
|
|
- total += rec.credit;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- setDaysIntegral(total);
|
|
|
|
|
-
|
|
|
|
|
- // 计算今天和明天的积分
|
|
|
|
|
- if (recordData.length > 0) {
|
|
|
|
|
- const lastCredit = recordData[0]?.credit || 1;
|
|
|
|
|
- const yesterday = new Date();
|
|
|
|
|
- yesterday.setDate(yesterday.getDate() - 1);
|
|
|
|
|
- const yesterdayStr = `${yesterday.getFullYear()}-${padWithZeros(yesterday.getMonth() + 1, 2)}-${padWithZeros(yesterday.getDate(), 2)}`;
|
|
|
|
|
- const lastRecordDate = recordData[0]?.createTime?.slice(0, 10);
|
|
|
|
|
-
|
|
|
|
|
- if (yesterdayStr === lastRecordDate) {
|
|
|
|
|
- setTodayIntegral(lastCredit + 1);
|
|
|
|
|
- setTomorrowIntegral(lastCredit + 2);
|
|
|
|
|
- } else {
|
|
|
|
|
- setTodayIntegral(lastCredit);
|
|
|
|
|
- setTomorrowIntegral(Math.min(lastCredit + 1, 7));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('获取签到记录失败:', error);
|
|
|
|
|
- }
|
|
|
|
|
- }, []);
|
|
|
|
|
-
|
|
|
|
|
- // 初始化
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- const dateInfo = setDate();
|
|
|
|
|
- getInfo();
|
|
|
|
|
- getData(dateInfo);
|
|
|
|
|
- }, [setDate, getInfo, getData]);
|
|
|
|
|
-
|
|
|
|
|
- // 签到
|
|
|
|
|
- const handleSignIn = async () => {
|
|
|
|
|
- if (istodaySignIn) {
|
|
|
|
|
- Alert.alert('提示', '今天已签到');
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const res = await services.user.signIn();
|
|
|
|
|
- if (res?.code === 0) {
|
|
|
|
|
- Alert.alert('提示', '签到成功');
|
|
|
|
|
- setIstodaySignIn(true);
|
|
|
|
|
-
|
|
|
|
|
- // Optimistic update for UI
|
|
|
|
|
- const optimisticDateInfo = dataInfo.map(item => {
|
|
|
|
|
- if (item.istoday) {
|
|
|
|
|
- return { ...item, isSignIn: true };
|
|
|
|
|
- }
|
|
|
|
|
- return item;
|
|
|
|
|
- });
|
|
|
|
|
- setDataInfo(optimisticDateInfo);
|
|
|
|
|
-
|
|
|
|
|
- // Delay fetch to ensure backend data consistency
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- const dateInfo = setDate();
|
|
|
|
|
- getInfo();
|
|
|
|
|
- getData(dateInfo);
|
|
|
|
|
- }, 500);
|
|
|
|
|
- } else {
|
|
|
|
|
- Alert.alert('提示', res?.msg || '签到失败');
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('签到失败:', error);
|
|
|
|
|
- Alert.alert('提示', '签到失败');
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const handleBack = () => {
|
|
|
|
|
- router.back();
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- return (
|
|
|
|
|
- <View style={styles.container}>
|
|
|
|
|
- <StatusBar barStyle="dark-content" />
|
|
|
|
|
-
|
|
|
|
|
- {/* 顶部导航 */}
|
|
|
|
|
- <View style={[styles.header, { paddingTop: insets.top }]}>
|
|
|
|
|
- <TouchableOpacity style={styles.backBtn} onPress={handleBack}>
|
|
|
|
|
- <Text style={styles.backIcon}>‹</Text>
|
|
|
|
|
- </TouchableOpacity>
|
|
|
|
|
- <Text style={styles.title}>我的积分</Text>
|
|
|
|
|
- <View style={styles.placeholder} />
|
|
|
|
|
- </View>
|
|
|
|
|
-
|
|
|
|
|
- <ScrollView style={styles.scrollView} showsVerticalScrollIndicator={false}>
|
|
|
|
|
- {/* 头部积分展示 */}
|
|
|
|
|
- <ImageBackground
|
|
|
|
|
- source={{ uri: Images.integral?.head || Images.common.commonBg }}
|
|
|
|
|
- style={styles.headerBg}
|
|
|
|
|
- resizeMode="cover"
|
|
|
|
|
- >
|
|
|
|
|
- <Text style={styles.integralNum}>{integral}</Text>
|
|
|
|
|
- <TouchableOpacity
|
|
|
|
|
- style={styles.allBox}
|
|
|
|
|
- onPress={() => setIsTooltip(!isTooltip)}
|
|
|
|
|
- >
|
|
|
|
|
- <Text style={styles.allText}>所有积分</Text>
|
|
|
|
|
- <Image
|
|
|
|
|
- source={{ uri: Images.integral?.greetings }}
|
|
|
|
|
- style={styles.infoIcon}
|
|
|
|
|
- contentFit="contain"
|
|
|
|
|
- />
|
|
|
|
|
- {isTooltip && (
|
|
|
|
|
- <ImageBackground
|
|
|
|
|
- source={{uri: Images.integral?.tooltip }}
|
|
|
|
|
- style={styles.tooltip}
|
|
|
|
|
- resizeMode="stretch"
|
|
|
|
|
- >
|
|
|
|
|
- <Text style={styles.tooltipText}>消费积分与签到积分总和</Text>
|
|
|
|
|
- </ImageBackground>
|
|
|
|
|
- )}
|
|
|
|
|
- </TouchableOpacity>
|
|
|
|
|
- <View style={styles.todayBox}>
|
|
|
|
|
- <Text style={styles.todayText}>
|
|
|
|
|
- 今日已获得<Text style={styles.todayNum}>{istodaySignIn ? todayIntegral : 0}</Text>积分
|
|
|
|
|
- </Text>
|
|
|
|
|
- </View>
|
|
|
|
|
-
|
|
|
|
|
- <TouchableOpacity style={styles.ruleBtn} onPress={showRule}>
|
|
|
|
|
- <Text style={styles.ruleText}>积分规则</Text>
|
|
|
|
|
- </TouchableOpacity>
|
|
|
|
|
- </ImageBackground>
|
|
|
|
|
-
|
|
|
|
|
- <View style={styles.content}>
|
|
|
|
|
- {/* 签到面板 */}
|
|
|
|
|
- <View style={styles.panel}>
|
|
|
|
|
- <View style={styles.panelTitle}>
|
|
|
|
|
- <View style={styles.panelTitleLeft}>
|
|
|
|
|
- <Image
|
|
|
|
|
- source={{ uri: Images.integral?.goldCoins }}
|
|
|
|
|
- style={styles.goldIcon}
|
|
|
|
|
- contentFit="contain"
|
|
|
|
|
- />
|
|
|
|
|
- <Text style={styles.panelTitleText}>签到领积分</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- <Text style={[styles.panelTitleRight, istodaySignIn && styles.signedText]}>
|
|
|
|
|
- {istodaySignIn ? '今日已签到' : '今日未签到'}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </View>
|
|
|
|
|
-
|
|
|
|
|
- <Text style={styles.explain}>
|
|
|
|
|
- 已签到{record.filter(r => r.credit > 0).length}天,共获得<Text style={styles.highlightText}>{daysIntegral}</Text>积分
|
|
|
|
|
- </Text>
|
|
|
|
|
-
|
|
|
|
|
- {/* 签到进度 */}
|
|
|
|
|
- <View style={styles.progressBox}>
|
|
|
|
|
- <View style={styles.lineBox}>
|
|
|
|
|
- {[1, 2, 3, 4, 5].map((_, index) => (
|
|
|
|
|
- <View key={index} style={styles.lineSection}>
|
|
|
|
|
- <View style={[styles.line, styles.lineOn]} />
|
|
|
|
|
- </View>
|
|
|
|
|
- ))}
|
|
|
|
|
- </View>
|
|
|
|
|
-
|
|
|
|
|
- <View style={styles.daysBox}>
|
|
|
|
|
- {dataInfo.map((item, index) => (
|
|
|
|
|
- <View key={index} style={styles.dayItem}>
|
|
|
|
|
- <TouchableOpacity
|
|
|
|
|
- style={styles.dayCircleBox}
|
|
|
|
|
- onPress={item.istoday && !istodaySignIn ? handleSignIn : undefined}
|
|
|
|
|
- activeOpacity={item.istoday && !istodaySignIn ? 0.7 : 1}
|
|
|
|
|
- >
|
|
|
|
|
- {item.istoday && !istodaySignIn ? (
|
|
|
|
|
- <ImageBackground
|
|
|
|
|
- source={{ uri: Images.integral?.basisBg }}
|
|
|
|
|
- style={styles.dayCircleBg}
|
|
|
|
|
- resizeMode="contain"
|
|
|
|
|
- >
|
|
|
|
|
- <View style={[styles.dayCircle, styles.todayCircle]}>
|
|
|
|
|
- <Text style={styles.todayCircleText}>+{todayIntegral}</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- </ImageBackground>
|
|
|
|
|
- ) : item.isFutureDate ? (
|
|
|
|
|
- <View style={[styles.dayCircle, styles.futureCircle]}>
|
|
|
|
|
- <Text style={styles.futureText}>+{tomorrowIntegral}</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- ) : item.isSignIn ? (
|
|
|
|
|
- <View style={[styles.dayCircle, styles.signedCircle]}>
|
|
|
|
|
- <Text style={styles.checkIcon}>✓</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <View style={[styles.dayCircle, styles.missedCircle]}>
|
|
|
|
|
- <Text style={styles.missedIcon}>✗</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- )}
|
|
|
|
|
- </TouchableOpacity>
|
|
|
|
|
- <Text style={[styles.dayText, item.istoday && styles.todayDayText]}>
|
|
|
|
|
- {item.istoday ? '今天' : item.text}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- ))}
|
|
|
|
|
- </View>
|
|
|
|
|
- </View>
|
|
|
|
|
- </View>
|
|
|
|
|
-
|
|
|
|
|
- {/* 积分明细 */}
|
|
|
|
|
- <View style={styles.listSection}>
|
|
|
|
|
- <Text style={styles.listTitle}>积分明细</Text>
|
|
|
|
|
- {record.map((item, index) => (
|
|
|
|
|
- <View key={item.id || index} style={styles.listItem}>
|
|
|
|
|
- <View style={styles.listItemLeft}>
|
|
|
|
|
- <Text style={styles.listItemTitle}>
|
|
|
|
|
- {item.credit > 0 ? '积分签到获得' : '大转盘消费'}
|
|
|
|
|
- </Text>
|
|
|
|
|
- <Text style={styles.listItemTime}>{item.createTime}</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- <Text style={[
|
|
|
|
|
- styles.listItemCredit,
|
|
|
|
|
- item.credit > 0 ? styles.creditPositive : styles.creditNegative
|
|
|
|
|
- ]}>
|
|
|
|
|
- {item.credit > 0 ? '+' : ''}{item.credit}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- ))}
|
|
|
|
|
- {record.length === 0 && (
|
|
|
|
|
- <View style={styles.emptyBox}>
|
|
|
|
|
- <Text style={styles.emptyText}>暂无积分记录</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- )}
|
|
|
|
|
- </View>
|
|
|
|
|
- </View>
|
|
|
|
|
- </ScrollView>
|
|
|
|
|
- </View>
|
|
|
|
|
- );
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const styles = StyleSheet.create({
|
|
|
|
|
- container: {
|
|
|
|
|
- flex: 1,
|
|
|
|
|
- backgroundColor: '#F8FAFB',
|
|
|
|
|
- },
|
|
|
|
|
- header: {
|
|
|
|
|
- flexDirection: 'row',
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- justifyContent: 'space-between',
|
|
|
|
|
- paddingHorizontal: 10,
|
|
|
|
|
- height: 80,
|
|
|
|
|
- backgroundColor: 'transparent',
|
|
|
|
|
- position: 'absolute',
|
|
|
|
|
- top: 0,
|
|
|
|
|
- left: 0,
|
|
|
|
|
- right: 0,
|
|
|
|
|
- zIndex: 100,
|
|
|
|
|
- },
|
|
|
|
|
- backBtn: {
|
|
|
|
|
- width: 40,
|
|
|
|
|
- height: 40,
|
|
|
|
|
- justifyContent: 'center',
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- },
|
|
|
|
|
- backIcon: {
|
|
|
|
|
- fontSize: 32,
|
|
|
|
|
- color: '#000',
|
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
|
- },
|
|
|
|
|
- title: {
|
|
|
|
|
- fontSize: 15,
|
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
|
- color: '#000',
|
|
|
|
|
- },
|
|
|
|
|
- placeholder: {
|
|
|
|
|
- width: 40,
|
|
|
|
|
- },
|
|
|
|
|
- scrollView: {
|
|
|
|
|
- flex: 1,
|
|
|
|
|
- },
|
|
|
|
|
- headerBg: {
|
|
|
|
|
- width: '100%',
|
|
|
|
|
- height: 283,
|
|
|
|
|
- paddingTop: 100,
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- position: 'relative',
|
|
|
|
|
- },
|
|
|
|
|
- integralNum: {
|
|
|
|
|
- fontSize: 48,
|
|
|
|
|
- fontWeight: '400',
|
|
|
|
|
- color: '#5B460F',
|
|
|
|
|
- textAlign: 'center',
|
|
|
|
|
- },
|
|
|
|
|
- allBox: {
|
|
|
|
|
- flexDirection: 'row',
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- marginTop: 7,
|
|
|
|
|
- marginBottom: 12,
|
|
|
|
|
- position: 'relative',
|
|
|
|
|
- },
|
|
|
|
|
- allText: {
|
|
|
|
|
- fontSize: 12,
|
|
|
|
|
- color: '#C8B177',
|
|
|
|
|
- },
|
|
|
|
|
- infoIcon: {
|
|
|
|
|
- width: 16,
|
|
|
|
|
- height: 16,
|
|
|
|
|
- marginLeft: 4,
|
|
|
|
|
- },
|
|
|
|
|
- tooltip: {
|
|
|
|
|
- position: 'absolute',
|
|
|
|
|
- width: 150,
|
|
|
|
|
- height: 27,
|
|
|
|
|
- top: 15,
|
|
|
|
|
- left: 30, // Adjust execution based on design
|
|
|
|
|
- justifyContent: 'center',
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- zIndex: 999,
|
|
|
|
|
- paddingHorizontal: 5,
|
|
|
|
|
- },
|
|
|
|
|
- tooltipText: {
|
|
|
|
|
- color: '#fff',
|
|
|
|
|
- fontSize: 10,
|
|
|
|
|
- },
|
|
|
|
|
- todayBox: {
|
|
|
|
|
- backgroundColor: 'rgba(0,0,0,0.08)',
|
|
|
|
|
- borderRadius: 217,
|
|
|
|
|
- paddingHorizontal: 15,
|
|
|
|
|
- paddingVertical: 5,
|
|
|
|
|
- },
|
|
|
|
|
- todayText: {
|
|
|
|
|
- fontSize: 12,
|
|
|
|
|
- color: '#8A794F',
|
|
|
|
|
- },
|
|
|
|
|
- todayNum: {
|
|
|
|
|
- fontWeight: '800',
|
|
|
|
|
- color: '#5B460F',
|
|
|
|
|
- },
|
|
|
|
|
- ruleBtn: {
|
|
|
|
|
- position: 'absolute',
|
|
|
|
|
- right: 0,
|
|
|
|
|
- top: 130, // Half of 260rpx approx
|
|
|
|
|
- backgroundColor: '#fff',
|
|
|
|
|
- borderTopLeftRadius: 20,
|
|
|
|
|
- borderBottomLeftRadius: 20,
|
|
|
|
|
- paddingHorizontal: 10,
|
|
|
|
|
- paddingVertical: 6,
|
|
|
|
|
- zIndex: 10,
|
|
|
|
|
- },
|
|
|
|
|
- ruleText: {
|
|
|
|
|
- fontSize: 12,
|
|
|
|
|
- color: '#333',
|
|
|
|
|
- },
|
|
|
|
|
- content: {
|
|
|
|
|
- paddingHorizontal: 10,
|
|
|
|
|
- marginTop: -50,
|
|
|
|
|
- },
|
|
|
|
|
- panel: {
|
|
|
|
|
- backgroundColor: '#fff',
|
|
|
|
|
- borderRadius: 15,
|
|
|
|
|
- padding: 12,
|
|
|
|
|
- },
|
|
|
|
|
- panelTitle: {
|
|
|
|
|
- flexDirection: 'row',
|
|
|
|
|
- justifyContent: 'space-between',
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- paddingHorizontal: 10,
|
|
|
|
|
- },
|
|
|
|
|
- panelTitleLeft: {
|
|
|
|
|
- flexDirection: 'row',
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- },
|
|
|
|
|
- goldIcon: {
|
|
|
|
|
- width: 24,
|
|
|
|
|
- height: 24,
|
|
|
|
|
- marginRight: 6,
|
|
|
|
|
- },
|
|
|
|
|
- panelTitleText: {
|
|
|
|
|
- fontSize: 16,
|
|
|
|
|
- fontWeight: '700',
|
|
|
|
|
- color: '#3D3D3D',
|
|
|
|
|
- },
|
|
|
|
|
- panelTitleRight: {
|
|
|
|
|
- fontSize: 12,
|
|
|
|
|
- color: '#FC7D2E',
|
|
|
|
|
- },
|
|
|
|
|
- signedText: {
|
|
|
|
|
- color: '#999',
|
|
|
|
|
- },
|
|
|
|
|
- explain: {
|
|
|
|
|
- fontSize: 12,
|
|
|
|
|
- color: '#999',
|
|
|
|
|
- paddingHorizontal: 10,
|
|
|
|
|
- marginTop: 7,
|
|
|
|
|
- marginBottom: 11,
|
|
|
|
|
- },
|
|
|
|
|
- highlightText: {
|
|
|
|
|
- color: '#FC7D2E',
|
|
|
|
|
- },
|
|
|
|
|
- progressBox: {
|
|
|
|
|
- paddingTop: 20,
|
|
|
|
|
- },
|
|
|
|
|
- lineBox: {
|
|
|
|
|
- flexDirection: 'row',
|
|
|
|
|
- paddingHorizontal: 10,
|
|
|
|
|
- },
|
|
|
|
|
- lineSection: {
|
|
|
|
|
- flex: 1,
|
|
|
|
|
- },
|
|
|
|
|
- line: {
|
|
|
|
|
- height: 1,
|
|
|
|
|
- backgroundColor: '#9E9E9E',
|
|
|
|
|
- },
|
|
|
|
|
- lineOn: {
|
|
|
|
|
- backgroundColor: '#FC7D2E',
|
|
|
|
|
- },
|
|
|
|
|
- daysBox: {
|
|
|
|
|
- flexDirection: 'row',
|
|
|
|
|
- marginTop: -25,
|
|
|
|
|
- },
|
|
|
|
|
- dayItem: {
|
|
|
|
|
- flex: 1,
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- },
|
|
|
|
|
- dayCircleBox: {
|
|
|
|
|
- width: 46,
|
|
|
|
|
- height: 46,
|
|
|
|
|
- justifyContent: 'center',
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- marginBottom: 3,
|
|
|
|
|
- },
|
|
|
|
|
- dayCircleBg: {
|
|
|
|
|
- width: 46,
|
|
|
|
|
- height: 46,
|
|
|
|
|
- justifyContent: 'center',
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- },
|
|
|
|
|
- dayCircle: {
|
|
|
|
|
- width: 32,
|
|
|
|
|
- height: 32,
|
|
|
|
|
- borderRadius: 16,
|
|
|
|
|
- justifyContent: 'center',
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- },
|
|
|
|
|
- todayCircle: {
|
|
|
|
|
- backgroundColor: '#FC7D2E',
|
|
|
|
|
- },
|
|
|
|
|
- todayCircleText: {
|
|
|
|
|
- color: '#fff',
|
|
|
|
|
- fontSize: 12,
|
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
|
- },
|
|
|
|
|
- futureCircle: {
|
|
|
|
|
- backgroundColor: '#F4F6F8',
|
|
|
|
|
- borderWidth: 1,
|
|
|
|
|
- borderColor: 'rgba(226,226,226,0.5)',
|
|
|
|
|
- },
|
|
|
|
|
- futureText: {
|
|
|
|
|
- color: '#505050',
|
|
|
|
|
- fontSize: 12,
|
|
|
|
|
- },
|
|
|
|
|
- signedCircle: {
|
|
|
|
|
- backgroundColor: '#FFE7C4',
|
|
|
|
|
- },
|
|
|
|
|
- checkIcon: {
|
|
|
|
|
- color: '#FC7D2E',
|
|
|
|
|
- fontSize: 16,
|
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
|
- },
|
|
|
|
|
- missedCircle: {
|
|
|
|
|
- backgroundColor: '#F4F6F8',
|
|
|
|
|
- },
|
|
|
|
|
- missedIcon: {
|
|
|
|
|
- color: '#999',
|
|
|
|
|
- fontSize: 16,
|
|
|
|
|
- },
|
|
|
|
|
- dayText: {
|
|
|
|
|
- fontSize: 12,
|
|
|
|
|
- color: '#9E9E9E',
|
|
|
|
|
- },
|
|
|
|
|
- todayDayText: {
|
|
|
|
|
- color: '#FC7D2E',
|
|
|
|
|
- },
|
|
|
|
|
- listSection: {
|
|
|
|
|
- backgroundColor: '#fff',
|
|
|
|
|
- borderRadius: 15,
|
|
|
|
|
- padding: 12,
|
|
|
|
|
- marginTop: 10,
|
|
|
|
|
- marginBottom: 30,
|
|
|
|
|
- },
|
|
|
|
|
- listTitle: {
|
|
|
|
|
- fontSize: 16,
|
|
|
|
|
- fontWeight: '700',
|
|
|
|
|
- color: '#3D3D3D',
|
|
|
|
|
- marginBottom: 10,
|
|
|
|
|
- },
|
|
|
|
|
- listItem: {
|
|
|
|
|
- flexDirection: 'row',
|
|
|
|
|
- justifyContent: 'space-between',
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- paddingVertical: 14,
|
|
|
|
|
- borderBottomWidth: 1,
|
|
|
|
|
- borderBottomColor: 'rgba(0,0,0,0.05)',
|
|
|
|
|
- },
|
|
|
|
|
- listItemLeft: {},
|
|
|
|
|
- listItemTitle: {
|
|
|
|
|
- fontSize: 14,
|
|
|
|
|
- color: '#333',
|
|
|
|
|
- marginBottom: 3,
|
|
|
|
|
- },
|
|
|
|
|
- listItemTime: {
|
|
|
|
|
- fontSize: 12,
|
|
|
|
|
- color: '#999',
|
|
|
|
|
- },
|
|
|
|
|
- listItemCredit: {
|
|
|
|
|
- fontSize: 18,
|
|
|
|
|
- fontWeight: '700',
|
|
|
|
|
- },
|
|
|
|
|
- creditPositive: {
|
|
|
|
|
- color: '#588CFF',
|
|
|
|
|
- },
|
|
|
|
|
- creditNegative: {
|
|
|
|
|
- color: '#FC7D2E',
|
|
|
|
|
- },
|
|
|
|
|
- emptyBox: {
|
|
|
|
|
- paddingVertical: 50,
|
|
|
|
|
- alignItems: 'center',
|
|
|
|
|
- },
|
|
|
|
|
- emptyText: {
|
|
|
|
|
- fontSize: 14,
|
|
|
|
|
- color: '#999',
|
|
|
|
|
- },
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|