From 5cc918bcd95f224df5501c28e1e48bb5a86a1144 Mon Sep 17 00:00:00 2001 From: openclaw Date: Fri, 24 Jul 2026 00:00:12 +0800 Subject: [PATCH] Expand expense categories --- apps/web/src/data/categories.ts | 93 ++++++++++++++++++++++++++------- docs/分类体系.md | 22 ++++---- 2 files changed, 84 insertions(+), 31 deletions(-) diff --git a/apps/web/src/data/categories.ts b/apps/web/src/data/categories.ts index dbd34d2..d336423 100644 --- a/apps/web/src/data/categories.ts +++ b/apps/web/src/data/categories.ts @@ -1,9 +1,13 @@ import type { EntryType } from "@cents/domain"; import { + Ambulance, + Apple, Banknote, + BatteryCharging, Bike, BookOpen, BriefcaseBusiness, + Building2, BusFront, CarTaxiFront, ChartNoAxesCombined, @@ -11,17 +15,26 @@ import { Coffee, CookingPot, Cookie, + Crown, CupSoda, + Droplets, + Dumbbell, FileText, + Flame, Fuel, Gamepad2, + Gauge, Gift, GraduationCap, HandCoins, + Handshake, HeartPulse, + Hospital, + Hotel, House, Music2, ParkingCircle, + Pill, Plane, ReceiptText, RotateCcw, @@ -32,10 +45,15 @@ import { Shirt, Smartphone, Soup, + Sparkles, + Stethoscope, + Syringe, Ticket, TrainFront, Utensils, + WalletCards, Wifi, + Zap, type LucideIcon, } from "@lucide/vue"; @@ -75,6 +93,7 @@ export const categories: Record = { { id: "coffee", label: "咖啡", color: "#9b6a48", tint: "#f8eee6", icon: Coffee }, { id: "snacks", label: "零食", color: "#c98535", tint: "#fff4e5", icon: Cookie }, { id: "drinks", label: "饮品", color: "#2d8f9e", tint: "#eaf8fa", icon: CupSoda }, + { id: "fruit", label: "水果", color: "#df6345", tint: "#fff0eb", icon: Apple }, ], }, { @@ -85,23 +104,14 @@ export const categories: Record = { icon: BusFront, children: [ { id: "taxi", label: "打车", color: "#3478e5", tint: "#edf4ff", icon: CarTaxiFront }, - { id: "public-transit", label: "公交地铁", color: "#2563c7", tint: "#edf4ff", icon: Ticket }, + { id: "public-transit", label: "公交", color: "#2563c7", tint: "#edf4ff", icon: BusFront }, + { id: "subway", label: "地铁", color: "#5368bd", tint: "#eef1fb", icon: TrainFront }, { id: "train", label: "火车", color: "#4869b1", tint: "#eef2fb", icon: TrainFront }, { id: "cycling", label: "骑行", color: "#168c87", tint: "#e8f8f6", icon: Bike }, { id: "fuel", label: "加油", color: "#6f6b58", tint: "#f3f2ed", icon: Fuel }, + { id: "charging", label: "充电", color: "#2b8a74", tint: "#e8f7f2", icon: BatteryCharging }, { id: "parking", label: "停车", color: "#4f7190", tint: "#edf3f7", icon: ParkingCircle }, - ], - }, - { - id: "daily", - label: "日用", - color: "#1a9b62", - tint: "#eaf9f1", - icon: ShoppingBasket, - children: [ - { id: "groceries", label: "杂货", color: "#1a9b62", tint: "#eaf9f1", icon: ShoppingBasket }, - { id: "digital", label: "数码", color: "#52606f", tint: "#eff2f5", icon: Smartphone }, - { id: "home", label: "家居", color: "#2b8a74", tint: "#e8f7f2", icon: House }, + { id: "highway", label: "高速", color: "#697970", tint: "#f0f4f2", icon: Gauge }, ], }, { @@ -112,6 +122,9 @@ export const categories: Record = { icon: ShoppingBag, children: [ { id: "clothing", label: "服饰", color: "#b14e79", tint: "#faeef4", icon: Shirt }, + { id: "groceries", label: "杂货", color: "#1a9b62", tint: "#eaf9f1", icon: ShoppingBasket }, + { id: "digital", label: "数码", color: "#52606f", tint: "#eff2f5", icon: Smartphone }, + { id: "home", label: "家居", color: "#2b8a74", tint: "#e8f7f2", icon: House }, ], }, { @@ -124,9 +137,37 @@ export const categories: Record = { { id: "games", label: "游戏", color: "#7958b3", tint: "#f3effb", icon: Gamepad2 }, { id: "movies", label: "电影", color: "#a74d65", tint: "#faeef2", icon: Clapperboard }, { id: "music", label: "音乐", color: "#4f70aa", tint: "#edf2fa", icon: Music2 }, + { id: "massage", label: "按摩", color: "#9b678f", tint: "#f8eef5", icon: Sparkles }, + { id: "sports", label: "运动", color: "#2f8768", tint: "#eaf7f1", icon: Dumbbell }, + { id: "tickets", label: "门票", color: "#b57a0e", tint: "#fff7dd", icon: Ticket }, + { id: "hotel", label: "酒店", color: "#526a78", tint: "#edf2f4", icon: Hotel }, + ], + }, + { + id: "social", + label: "社交", + color: "#c35f76", + tint: "#faeef2", + icon: Handshake, + children: [ + { id: "red-packet", label: "红包", color: "#d94f45", tint: "#fff0ed", icon: WalletCards }, + { id: "gift", label: "礼物", color: "#b57a0e", tint: "#fff7dd", icon: Gift }, + ], + }, + { + id: "health", + label: "医疗", + color: "#df3f5f", + tint: "#fff0f2", + icon: HeartPulse, + children: [ + { id: "pharmacy", label: "药店", color: "#2f8768", tint: "#eaf7f1", icon: Pill }, + { id: "outpatient", label: "门诊", color: "#3478a5", tint: "#edf5f9", icon: Stethoscope }, + { id: "emergency", label: "急诊", color: "#d94f45", tint: "#fff0ed", icon: Ambulance }, + { id: "vaccine", label: "疫苗", color: "#7559d9", tint: "#f2efff", icon: Syringe }, + { id: "hospitalization", label: "住院", color: "#526a78", tint: "#edf2f4", icon: Hospital }, ], }, - { id: "health", label: "医疗", color: "#df3f5f", tint: "#fff0f2", icon: HeartPulse }, { id: "education", label: "教育", @@ -140,13 +181,19 @@ export const categories: Record = { }, { id: "bills", - label: "账单", + label: "缴费", color: "#526a78", tint: "#edf2f4", icon: FileText, children: [ { id: "mobile", label: "话费", color: "#526a78", tint: "#edf2f4", icon: Smartphone }, { id: "internet", label: "宽带网络", color: "#3478a5", tint: "#edf5f9", icon: Wifi }, + { id: "water", label: "水费", color: "#2d8f9e", tint: "#eaf8fa", icon: Droplets }, + { id: "electricity", label: "电费", color: "#b27a22", tint: "#fff7e7", icon: Zap }, + { id: "gas", label: "燃气", color: "#d76a35", tint: "#fff1e9", icon: Flame }, + { id: "property-fee", label: "物业", color: "#387b70", tint: "#eaf6f3", icon: Building2 }, + { id: "parking-fee", label: "车位费", color: "#4f7190", tint: "#edf3f7", icon: ParkingCircle }, + { id: "membership", label: "会员费", color: "#8559cf", tint: "#f4efff", icon: Crown }, { id: "insurance", label: "保险", color: "#477866", tint: "#edf6f2", icon: ShieldCheck }, ], }, @@ -162,13 +209,18 @@ export const categories: Record = { ], }; +const categoryAliases: Record = { + daily: "shopping", +}; + export function findCategory(categoryId: string): Category | EntryTypeOption | undefined { - const entryType = entryTypes.find((type) => type.id === categoryId); + const resolvedId = categoryAliases[categoryId] ?? categoryId; + const entryType = entryTypes.find((type) => type.id === resolvedId); if (entryType) return entryType; for (const group of Object.values(categories)) { for (const category of group) { - if (category.id === categoryId) return category; - const child = category.children?.find((item) => item.id === categoryId); + if (category.id === resolvedId) return category; + const child = category.children?.find((item) => item.id === resolvedId); if (child) return child; } } @@ -176,9 +228,10 @@ export function findCategory(categoryId: string): Category | EntryTypeOption | u } export function findCategoryPath(type: EntryType, categoryId: string): Category[] { + const resolvedId = categoryAliases[categoryId] ?? categoryId; for (const category of categories[type]) { - if (category.id === categoryId) return [category]; - const child = category.children?.find((item) => item.id === categoryId); + if (category.id === resolvedId) return [category]; + const child = category.children?.find((item) => item.id === resolvedId); if (child) return [category, child]; } return []; diff --git a/docs/分类体系.md b/docs/分类体系.md index 48cf0a8..71ad66c 100644 --- a/docs/分类体系.md +++ b/docs/分类体系.md @@ -21,12 +21,12 @@ | --- | --- | --- | | 1 | 餐饮 | `food` | | 2 | 交通 | `transport` | -| 3 | 日用 | `daily` | -| 4 | 购物 | `shopping` | -| 5 | 娱乐 | `entertainment` | +| 3 | 购物 | `shopping` | +| 4 | 娱乐 | `entertainment` | +| 5 | 社交 | `social` | | 6 | 医疗 | `health` | | 7 | 教育 | `education` | -| 8 | 账单 | `bills` | +| 8 | 缴费 | `bills` | | 9 | 旅行 | `travel` | ### 收入 @@ -50,14 +50,14 @@ | 二级分类 | 三级分类 | | --- | --- | -| 餐饮 | 外卖 `takeout`、堂食 `restaurant`、咖啡 `coffee`、零食 `snacks`、饮品 `drinks` | -| 交通 | 打车 `taxi`、公交地铁 `public-transit`、火车 `train`、骑行 `cycling`、加油 `fuel`、停车 `parking` | -| 日用 | 杂货 `groceries`、数码 `digital`、家居 `home` | -| 购物 | 服饰 `clothing` | -| 娱乐 | 游戏 `games`、电影 `movies`、音乐 `music` | -| 医疗 | 无 | +| 餐饮 | 外卖 `takeout`、堂食 `restaurant`、咖啡 `coffee`、零食 `snacks`、饮品 `drinks`、水果 `fruit` | +| 交通 | 打车 `taxi`、公交 `public-transit`、地铁 `subway`、火车 `train`、骑行 `cycling`、加油 `fuel`、充电 `charging`、停车 `parking`、高速 `highway` | +| 购物 | 服饰 `clothing`、杂货 `groceries`、数码 `digital`、家居 `home` | +| 娱乐 | 游戏 `games`、电影 `movies`、音乐 `music`、按摩 `massage`、运动 `sports`、门票 `tickets`、酒店 `hotel` | +| 社交 | 红包 `red-packet`、礼物 `gift` | +| 医疗 | 药店 `pharmacy`、门诊 `outpatient`、急诊 `emergency`、疫苗 `vaccine`、住院 `hospitalization` | | 教育 | 书籍 `books`、课程 `courses` | -| 账单 | 话费 `mobile`、宽带网络 `internet`、保险 `insurance` | +| 缴费 | 话费 `mobile`、宽带网络 `internet`、水费 `water`、电费 `electricity`、燃气 `gas`、物业 `property-fee`、车位费 `parking-fee`、会员费 `membership`、保险 `insurance` | | 旅行 | 无 | ### 收入