feat(mp): 积分商城 V2 重设计 — design-handoff 全流程
- 新增 4 个 UI 组件: PointsCard/ProductCard/CheckinCalendar/CheckinModal - 商城首页 V2: 积分卡 + 快捷操作 + 分类标签 + 商品网格 - 商品详情 V2: 大图 + 信息卡 + 库存/余额状态 + 底部操作栏 - TabBar 新增商城入口(5 Tab: 首页/健康/商城/助手/我的) - 设计原型 docs/design/mp-05-mall-v2.html + SPEC.md 交付包 - CLAUDE.md 安全规范加固: 新增 §3.7 安全规范 6 条 + Feature DoD 安全清单扩展
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
@import '../../../styles/variables.scss';
|
||||
@import '../../../styles/mixins.scss';
|
||||
|
||||
.checkin-calendar {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
justify-content: center;
|
||||
padding: $sp-section $sp-lg $sp-md;
|
||||
|
||||
&__day {
|
||||
width: 36px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: $sp-xs;
|
||||
}
|
||||
|
||||
&__dot {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 18px;
|
||||
@include flex-center;
|
||||
|
||||
&--checked {
|
||||
background: $acc-l;
|
||||
}
|
||||
&--today {
|
||||
background: $pri;
|
||||
border: 2px solid $pri;
|
||||
box-shadow: 0 2px 8px rgba(196, 98, 58, 0.3);
|
||||
}
|
||||
&--empty {
|
||||
background: $surface-alt;
|
||||
}
|
||||
}
|
||||
|
||||
&__check {
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
color: $acc;
|
||||
|
||||
.checkin-calendar__dot--today & {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 11px;
|
||||
color: $tx3;
|
||||
font-weight: 400;
|
||||
|
||||
&--today {
|
||||
color: $tx;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
&__tip {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 10px 14px;
|
||||
background: $acc-l;
|
||||
border-radius: $r-sm;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $sp-xs;
|
||||
}
|
||||
|
||||
&__tip-text {
|
||||
font-size: 12px;
|
||||
color: $acc;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
// 长者模式
|
||||
.elder-mode & {
|
||||
&__dot {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
&__label {
|
||||
font-size: 13px;
|
||||
}
|
||||
&__tip-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
apps/miniprogram/src/components/ui/CheckinCalendar/index.tsx
Normal file
53
apps/miniprogram/src/components/ui/CheckinCalendar/index.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import React from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import './index.scss';
|
||||
|
||||
interface CheckinCalendarProps {
|
||||
consecutiveDays: number;
|
||||
earnedPoints?: number;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
const DAYS = ['一', '二', '三', '四', '五', '六', '日'];
|
||||
|
||||
const CheckinCalendar: React.FC<CheckinCalendarProps> = ({
|
||||
consecutiveDays,
|
||||
}) => {
|
||||
const daysUntilReward = 7 - consecutiveDays;
|
||||
|
||||
return (
|
||||
<View className='checkin-calendar'>
|
||||
{DAYS.map((d, i) => {
|
||||
const isChecked = i < consecutiveDays;
|
||||
const isToday = i === consecutiveDays - 1;
|
||||
return (
|
||||
<View key={i} className='checkin-calendar__day'>
|
||||
<View
|
||||
className={`checkin-calendar__dot ${
|
||||
isChecked
|
||||
? isToday
|
||||
? 'checkin-calendar__dot--today'
|
||||
: 'checkin-calendar__dot--checked'
|
||||
: 'checkin-calendar__dot--empty'
|
||||
}`}
|
||||
>
|
||||
{isChecked && <Text className='checkin-calendar__check'>✓</Text>}
|
||||
</View>
|
||||
<Text className={`checkin-calendar__label ${isToday ? 'checkin-calendar__label--today' : ''}`}>
|
||||
周{d}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
{daysUntilReward > 0 && (
|
||||
<View className='checkin-calendar__tip'>
|
||||
<Text className='checkin-calendar__tip-text'>
|
||||
再坚持 {daysUntilReward} 天,连续 7 天签到额外奖励 50 积分
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(CheckinCalendar);
|
||||
Reference in New Issue
Block a user