diff --git a/.workbuddy/memory/2026-07-15.md b/.workbuddy/memory/2026-07-15.md index e6f0b95..63fdf23 100644 --- a/.workbuddy/memory/2026-07-15.md +++ b/.workbuddy/memory/2026-07-15.md @@ -286,3 +286,47 @@ 1. 角标位置 `top-0 right-2` → `-top-1 -right-1`:让小红点紧贴 cell 右上角外缘,更像标准徽标 2. 角标尺寸 `text-xs` + 自由拉伸 → `min-w-[16px] h-4` + 10px/12px 字体:单数字也保持圆形,多位数字自动变椭圆 3. 0 判断 `item.count && item.count > 0` → `item.count && Number(item.count) > 0`:用 `Number()` 包一层,防止后端返回字符串 "0" 时 `> 0` 误判 + +## 抽取通用 Badge 组件(2026-07-15 23:10) +- 新文件:`src/components/common/Badge/index.tsx` +- 用途:替代项目里多处复制粘贴的内联角标 View(user.tsx / index/index.tsx / store/center/index.tsx 都有 `min-w-[16px] h-4 px-1 bg-red-500 rounded-full` 这种重复写法) +- API: + ```ts + interface BadgeProps { + count?: number | null // 0 / null / undefined / 负数 → 不渲染 + max?: number // 默认 99,超过显示 `${max}+` + className?: string // 外层定位 className,如 'absolute -top-1 -right-1' + color?: string // 默认 #ef4444(red-500) + fontSize?: number // 默认 10px + } + ``` +- user.tsx 已替换:内联 `{Number(item.count) > 0 && }` → `` +- 风格遵循项目 common 组件约定:函数式组件 + 默认导出 + Taro View/Text + Tailwind className +- 待办(未做):首页 `src/pages/index/index.tsx:248` 和门店中心 `src/pages/store/center/index.tsx:218` 也有相同内联角标写法,后续可统一替换为 Badge + +## 抽取通用 ArrowRight 组件(2026-07-15 23:13) +- 新文件:`src/components/common/ArrowRight/index.tsx` +- 用途:替代项目里到处可见的 `{'>'}` / `'>'` 文本箭头 +- 实现:CSS V 形(border-top + border-right + rotate(45deg)),颜色用 `currentColor` 跟父级 `text-*` 类走 +- API: + ```ts + interface ArrowRightProps { + className?: string // 颜色用 text-* 类(如 'text-gray-400'),间距用 ml-1 等 + size?: number // V 形边长 px,默认 6 + thickness?: number // 描边粗细 px,默认 1.5 + } + ``` +- user.tsx 已替换 3 处 `{'>'}`: + 1. 用户卡片头部箭头(白色 60% 透明)→ `` + 2. 「全部订单 >」→ 拆成 `全部订单` + 3. 菜单项末尾箭头(amber-700 / gray-300)→ `` +- 关键点:Tailwind 的 `text-opacity-60` 会通过 `--tw-text-opacity` 影响 color,currentColor 会继承这个带 opacity 的 color,所以 ArrowRight 的透明度也会跟随 +- 待办(未做):其它页面也有 `{'>'}` 文本箭头,后续可统一替换 + +## 统一替换 index/index.tsx 和 store/center 的内联角标为 Badge(2026-07-15 23:17) +- Badge 组件 API 扩展:新增 `size`(默认 16)和 `fontWeight`(默认 'normal')参数;padding 从 className 的 `px-1` 改为 inline style 根据 size 自动计算(16→2px,20→3px),避免与调用方 className 冲突 +- `src/pages/index/index.tsx:248`:数字角标(16x16/10px)→ `` + - 注意:保留了 `isClerk && newOrderCount > 0` 外层判断(虽然 Badge 内部 0 不渲染,但下面还有 `newOrderCount === 0` 的小红点逻辑,保留判断让语义更明确) +- `src/pages/store/center/index.tsx:218`:数字角标(20x20/11px/加粗)→ `` + - 简化了外层判断:`card.showBadge && getBadgeCount > 0` → `card.showBadge`(Badge 内部已处理 0 不渲染) +- 项目内联角标已全部统一为 Badge 组件,共 3 处(user.tsx / index/index.tsx / store/center/index.tsx) diff --git a/src/app.config.ts b/src/app.config.ts index c95e399..78a6cd0 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -160,10 +160,10 @@ export default { text: '分类', }, { - pagePath: 'pages/order/list', - iconPath: 'assets/tabbar/order.png', - selectedIconPath: 'assets/tabbar/order-active.png', - text: '订单', + pagePath: 'pages/shop/cart', + iconPath: 'assets/tabbar/cart.png', + selectedIconPath: 'assets/tabbar/cart-active.png', + text: '购物车', }, { pagePath: 'pages/user/user', diff --git a/src/assets/tabbar/cart-active.png b/src/assets/tabbar/cart-active.png new file mode 100644 index 0000000..bf31cf9 Binary files /dev/null and b/src/assets/tabbar/cart-active.png differ diff --git a/src/assets/tabbar/cart.png b/src/assets/tabbar/cart.png new file mode 100644 index 0000000..23d2b4e Binary files /dev/null and b/src/assets/tabbar/cart.png differ diff --git a/src/components/common/ArrowRight/index.tsx b/src/components/common/ArrowRight/index.tsx new file mode 100644 index 0000000..ffe6f50 --- /dev/null +++ b/src/components/common/ArrowRight/index.tsx @@ -0,0 +1,42 @@ +import React from 'react' +import { View } from '@tarojs/components' + +/** + * 右箭头图标(CSS V 形,颜色跟随 currentColor) + * + * 颜色通过 className 里的 text-* 类控制(如 'text-gray-400' / 'text-white'), + * 因为内部用 currentColor,会自动继承父元素 text color。 + * + * @example + * + * 全部订单 + * + * + */ +export interface ArrowRightProps { + /** 颜色/间距等 className(颜色用 text-* 类,跟随 currentColor) */ + className?: string + /** V 形边长 px,默认 6 */ + size?: number + /** 描边粗细 px,默认 1.5 */ + thickness?: number +} + +const ArrowRight: React.FC = ({ + className = '', + size = 6, + thickness = 1.5, +}) => ( + +) + +export default ArrowRight diff --git a/src/components/common/Badge/index.tsx b/src/components/common/Badge/index.tsx new file mode 100644 index 0000000..6af7fee --- /dev/null +++ b/src/components/common/Badge/index.tsx @@ -0,0 +1,72 @@ +import React from 'react' +import { View, Text } from '@tarojs/components' + +/** + * 数字角标 + * - count 为 0 / null / undefined 时不渲染 + * - count > max 时显示 `${max}+`(默认 99+) + * - 通过 className 控制定位(通常配合父元素 relative + absolute -top-1 -right-1) + * + * @example + * + * 📦 + * + * + * + * // 大尺寸 + 加粗(如门店中心卡片角标) + * + */ +export interface BadgeProps { + /** 数量;为 0 / null / undefined 时不渲染 */ + count?: number | null + /** 超过此值显示 `${max}+`,默认 99 */ + max?: number + /** 外层定位/样式 className(如 'absolute -top-1 -right-1') */ + className?: string + /** 背景色,默认红色 #ef4444 */ + color?: string + /** 字体大小 px,默认 10 */ + fontSize?: number + /** 角标尺寸 px(min-width 与 height 同步),默认 16 */ + size?: number + /** 字重,默认 'normal' */ + fontWeight?: 'normal' | 'medium' | 'bold' +} + +const Badge: React.FC = ({ + count, + max = 99, + className = '', + color = '#ef4444', + fontSize = 10, + size = 16, + fontWeight = 'normal', +}) => { + // 0 / null / undefined / 负数 都不渲染 + const n = Number(count) || 0 + if (n <= 0) return null + + const display = n > max ? `${max}+` : String(n) + // 横向 padding 跟随 size:16→2px,20→3px,避免多位数字挤压 + const padding = Math.max(2, Math.round(size / 8)) + + return ( + + {display} + + ) +} + +export default Badge diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx index 9f91764..4237714 100644 --- a/src/pages/index/index.tsx +++ b/src/pages/index/index.tsx @@ -15,6 +15,7 @@ import type { CmsAd } from '@/api/cms/cmsAd/model' import type { CmsArticle } from '@/api/cms/cmsArticle/model' import type { ShopGoods } from '@/api/shop/shopGoods/model' import Price from '@/components/common/Price' +import Badge from '@/components/common/Badge' import { getCompressedImageUrl } from '@/utils/image' definePageConfig({ @@ -245,11 +246,7 @@ const IndexPage: React.FC = () => { 🔔 {isClerk && newOrderCount > 0 && ( - - - {newOrderCount > 99 ? '99+' : newOrderCount} - - + )} {isClerk && newOrderCount === 0 && ( diff --git a/src/pages/store/center/index.tsx b/src/pages/store/center/index.tsx index 347fcdb..80ae31c 100644 --- a/src/pages/store/center/index.tsx +++ b/src/pages/store/center/index.tsx @@ -4,6 +4,7 @@ import Taro from '@tarojs/taro' import { getMyClerk } from '@/api/shop/shopStoreUser' import { listShopDealerApply } from '@/api/shop/shopDealerApply' import { pageShopOrder } from '@/api/shop/shopOrder' +import Badge from '@/components/common/Badge' definePageConfig({ navigationBarTitleText: '门店中心', @@ -214,12 +215,8 @@ export default function StoreCenterPage() { {/* 待处理角标 */} - {card.showBadge && getBadgeCount(card.key) > 0 && ( - - - {getBadgeCount(card.key) > 99 ? '99+' : getBadgeCount(card.key)} - - + {card.showBadge && ( + )} {/* 箭头 */} diff --git a/src/pages/user/user.tsx b/src/pages/user/user.tsx index b66ba80..db65da2 100644 --- a/src/pages/user/user.tsx +++ b/src/pages/user/user.tsx @@ -11,6 +11,8 @@ import type { UserRole } from '@/api/system/userRole/model' import { checkAndCacheVipStatus } from '@/utils/vip' import { requireLogin } from '@/utils/login-guard' import MemberBadge from '@/components/business/MemberBadge' +import Badge from '@/components/common/Badge' +import ArrowRight from '@/components/common/ArrowRight' const UserPage: React.FC = () => { const scrollHeight = useScrollHeight() @@ -215,7 +217,7 @@ const UserPage: React.FC = () => { ))} - {isLoggedIn && {'>'}} + {isLoggedIn && } {/* 数据概览 */} {isLoggedIn && ( @@ -258,9 +260,10 @@ const UserPage: React.FC = () => { 我的订单 - - 全部订单 {'>'} - + + 全部订单 + + {[ @@ -277,12 +280,8 @@ const UserPage: React.FC = () => { > {item.icon} {item.label} - {/* 数量角标:紧贴图标右上角;为 0 时不渲染 */} - {Number(item.count) > 0 && ( - - {Number(item.count) > 99 ? '99+' : item.count} - - )} + {/* 数量角标:count 为 0 时组件内部不渲染 */} + ))} @@ -313,7 +312,7 @@ const UserPage: React.FC = () => { )} - {'>'} + ))}