diff --git a/CLAUDE.md b/CLAUDE.md index 281b275..7d81a33 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -26,4 +26,8 @@ api/src/ Packages (packages/) packages/ ├── db/ Database package for schema management, migrations, client generation, and seed workflows. -├── shared/ Shared package space for cross-package utilities/types \ No newline at end of file +├── shared/ Shared package space for cross-package utilities/types + + +禁止使用 npm, pnpm npx, yarn +只能使用 bun \ No newline at end of file diff --git a/api/src/controllers/moods.controller.ts b/api/src/controllers/moods.controller.ts index 27c3572..7b059e5 100644 --- a/api/src/controllers/moods.controller.ts +++ b/api/src/controllers/moods.controller.ts @@ -31,29 +31,20 @@ export const moodsController = { return Response.json(entries); }, - // 传统的创建 mood 接口(兼容旧版) - async create(req: Request) { - const data = (await req.json()) as { - userId: string; - mood: string; - emotion?: string; - notes?: string; - recordedAt?: string; - }; + async listWithoutRedeemed(req: Request){ + const url = new URL(req.url); + const userId = url.searchParams.get("userId"); + const moodKind = url.searchParams.get("kind"); - if (!data.userId || !data.mood) { - return Response.json({ error: "userId and mood are required" }, { status: 400 }); + if (!userId) { + return Response.json({ error: "userId is required" }, { status: 400 }); } - const entry = await moods.create({ - userId: data.userId, - mood: data.mood, - emotion: data.emotion, - notes: data.notes, - recordedAt: data.recordedAt ? new Date(data.recordedAt) : undefined, + const entries = await moods.listWithoutRedeemed(userId, { + sentiment: moodKind || undefined }); - return Response.json(entry, { status: 201 }); + return Response.json(entries); }, // 新的 AI 情绪分析接口 @@ -158,28 +149,6 @@ export const moodsController = { return Response.json(entry); }, - async update(req: Request) { - const request = req as RequestWithParams<{ id: string }>; - const data = (await req.json()) as Partial<{ - mood: string; - emotion: string; - notes: string; - recordedAt: string; - }>; - - const entry = await moods.findById(request.params.id); - if (!entry) { - return Response.json({ error: "Mood not found" }, { status: 404 }); - } - - const updated = await moods.update(request.params.id, { - ...data, - recordedAt: data.recordedAt ? new Date(data.recordedAt) : undefined, - }); - - return Response.json(updated); - }, - async getTeamStats(req: Request) { const url = new URL(req.url); const userId = url.searchParams.get("userId"); @@ -276,15 +245,97 @@ export const moodsController = { } }, - async delete(req: Request) { - const request = req as RequestWithParams<{ id: string }>; + // 获取兑换资格 + async getRedemptionEligibility(req: Request) { + const url = new URL(req.url); + const userId = url.searchParams.get("userId"); - const entry = await moods.findById(request.params.id); - if (!entry) { - return Response.json({ error: "Mood not found" }, { status: 404 }); + if (!userId) { + return Response.json({ error: "userId is required" }, { status: 400 }); + } + + try { + const eligibility = await moods.getRedemptionEligibility(userId); + return Response.json(eligibility); + } catch (error) { + console.error("Get redemption eligibility error:", error); + return Response.json( + { error: "Failed to fetch redemption eligibility" }, + { status: 500 } + ); + } + }, + + // 执行情绪倾倒 + async dump(req: Request) { + const data = (await req.json()) as { + userId: string; + }; + + if (!data.userId) { + return Response.json({ error: "userId is required" }, { status: 400 }); } - await moods.delete(request.params.id); - return new Response(null, { status: 204 }); + try { + const result = await moods.redeem(data.userId, 'dump'); + return Response.json(result); + } catch (error) { + console.error("Dump moods error:", error); + if (error instanceof Error) { + return Response.json({ error: error.message }, { status: 400 }); + } + return Response.json( + { error: "Failed to dump moods" }, + { status: 500 } + ); + } + }, + + // 正向情绪兑换 + async reward(req: Request) { + const data = (await req.json()) as { + userId: string; + }; + + if (!data.userId) { + return Response.json({ error: "userId is required" }, { status: 400 }); + } + + try { + const result = await moods.redeem(data.userId, 'reward'); + return Response.json(result); + } catch (error) { + console.error("Reward moods error:", error); + if (error instanceof Error) { + return Response.json({ error: error.message }, { status: 400 }); + } + return Response.json( + { error: "Failed to reward moods" }, + { status: 500 } + ); + } + }, + + // 获取兑换历史 + async getRedemptionHistory(req: Request) { + const url = new URL(req.url); + const userId = url.searchParams.get("userId"); + const limit = parseInt(url.searchParams.get("limit") || "10", 10); + const offset = parseInt(url.searchParams.get("offset") || "0", 10); + + if (!userId) { + return Response.json({ error: "userId is required" }, { status: 400 }); + } + + try { + const history = await moods.getRedemptionHistory(userId, { limit, offset }); + return Response.json(history); + } catch (error) { + console.error("Get redemption history error:", error); + return Response.json( + { error: "Failed to fetch redemption history" }, + { status: 500 } + ); + } }, }; diff --git a/api/src/routes/moods.routes.ts b/api/src/routes/moods.routes.ts index ca1bf6b..32f83f7 100644 --- a/api/src/routes/moods.routes.ts +++ b/api/src/routes/moods.routes.ts @@ -3,7 +3,9 @@ import { moodsController } from "../controllers/index.js"; export const moodsRoutes = { "/api/moods": { GET: moodsController.list, - POST: moodsController.create, + }, + "/api/moods_without_redeemed": { + GET: moodsController.listWithoutRedeemed, }, "/api/moods/analyze": { POST: moodsController.analyze, @@ -29,9 +31,19 @@ export const moodsRoutes = { "/api/moods/team-insights": { GET: moodsController.getTeamInsights, }, + "/api/moods/redemption-eligibility": { + GET: moodsController.getRedemptionEligibility, + }, + "/api/moods/dump": { + POST: moodsController.dump, + }, + "/api/moods/redemption-history": { + GET: moodsController.getRedemptionHistory, + }, + "/api/moods/reward": { + POST: moodsController.reward, + }, "/api/moods/:id": { GET: moodsController.getById, - PUT: moodsController.update, - DELETE: moodsController.delete, }, }; diff --git a/api/src/services/moodAnalysis.service.ts b/api/src/services/moodAnalysis.service.ts index eb657ab..efc85ab 100644 --- a/api/src/services/moodAnalysis.service.ts +++ b/api/src/services/moodAnalysis.service.ts @@ -38,7 +38,7 @@ export const emotionSpectrum = { label: "快乐", color: "#F97316", // orange-500 bgGradient: "from-amber-400 to-orange-600", - icon: "restaurant", + icon: "sentiment_very_satisfied", container: "candy", }, achievement: { diff --git a/api/src/services/moods.service.ts b/api/src/services/moods.service.ts index 8d7365f..89876df 100644 --- a/api/src/services/moods.service.ts +++ b/api/src/services/moods.service.ts @@ -15,7 +15,7 @@ export interface TeamMoodStats { } export interface TeamMoodDistribution { - emotion: string; + mood: string; count: number; percentage: number; } @@ -58,7 +58,7 @@ export async function analyzeAndCreateMood( const analysis = await analyzeEmotion(input); // 保存到数据库 - const mood = await moods.create({ + const mood = await moods.createWithSummary({ userId, mood: analysis.spectrum, // 使用 spectrum 作为 mood 值 emotion: analysis.emotion, // 具体情绪描述 @@ -131,12 +131,12 @@ function getIconForSpectrum( boredom: "hourglass_empty", anxiety: "cloud", anger: "local_fire_department", - joy: "restaurant", + joy: "sentiment_very_satisfied", achievement: "star", warmth: "lightbulb", calm: "eco", }; - return iconMap[spectrum] || "sentiment_satisfied"; + return iconMap[spectrum] || "sentiment_very_satisfied"; } /** @@ -198,7 +198,7 @@ export async function getTeamStats( // 获取主要情绪 const emotionCounts = recentMoods.reduce((acc, m) => { - const emotion = m.emotion || m.mood; + const emotion = m.mood || m.emotion; acc[emotion] = (acc[emotion] || 0) + 1; return acc; }, {} as Record); @@ -240,14 +240,14 @@ export async function getTeamDistribution( const recentMoods = moodsList.filter(m => new Date(m.recordedAt) >= cutoffDate); const emotionCounts = recentMoods.reduce((acc, m) => { - const emotion = m.emotion || m.mood; - acc[emotion] = (acc[emotion] || 0) + 1; + const mood = m.mood || m.emotion; + acc[mood] = (acc[mood] || 0) + 1; return acc; }, {} as Record); const total = recentMoods.length; - const distribution = Object.entries(emotionCounts).map(([emotion, count]) => ({ - emotion, + const distribution = Object.entries(emotionCounts).map(([mood, count]) => ({ + mood, count, percentage: Math.round((count / total) * 100), })); @@ -405,4 +405,4 @@ function getMoodValue(mood: string): number { frustrated: 1, }; return moodMap[mood.toLowerCase()] || 3; -} +} \ No newline at end of file diff --git a/design/group_home.html b/design/group_home.html index cbadd3f..1696567 100644 --- a/design/group_home.html +++ b/design/group_home.html @@ -139,7 +139,7 @@

Mood Cor
-restaurant +sentiment_very_satisfied
Candy Jar

Store joy

diff --git a/design/my_mood.html b/design/my_mood.html new file mode 100644 index 0000000..6719edb --- /dev/null +++ b/design/my_mood.html @@ -0,0 +1,409 @@ + + + + + +Mood History - WIDEA + + + + + + + +
+ +
+
+
+ +
+
+ +
+ +
+User profile +
+
+
+
+
+
+ +
+

Your Mood Journey

+

Visualizing your emotional well-being over the last 30 days.

+
+ +
+
+
+local_fire_department +
+
+

Current Streak

+

12 Days

+
+
+
+
+calendar_month +
+
+

Total Recorded

+

128 Entries

+
+
+
+
+sentiment_very_satisfied +
+
+

Top Emotion

+

Joyful

+
+
+
+
+ +
+ +
+
+
+celebration +

Incredible Momentum!

+
+

+ You've been feeling great for 12 days straight! Your consistency is helping you build a deeper understanding of your well-being. +

+
+
+show_chart +
+
+ +
+
+
+

Emotional Accumulation

+

Complete 7 days of positive logs to unlock your reward.

+
+
+ 7/7 COMPLETE +
+
+
+ +
+
+
+sentiment_satisfied +
+
+sentiment_very_satisfied +
+
+mood +
+
+sunny +
+
+volunteer_activism +
+
+auto_awesome +
+
+workspace_premium +
+
+ +
+
+format_quote +

+ "Every step forward is progress. Keep going!" +

+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+

October 2023

+
+ + +
+
+
+
S
+
M
+
T
+
W
+
T
+
F
+
S
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
+
+
+ +Positive +
+
+ +Neutral +
+
+ +Negative +
+
+ +Missed Day +
+
+
+ +
+
+

Mood Trend

+ +
+
+
+AWESOME +GOOD +NEUTRAL +LOW +POOR +
+
+ + + + + + + + + + + + + +
+
+SEP 15 +SEP 22 +SEP 29 +OCT 06 +TODAY +
+
+
+ +
+
+lightbulb +
+
+

Weekly Mood Insight

+

+ You tend to feel more energized and positive on Wednesdays and Thursdays. This correlates with your consistent gym check-ins on those days. +

+ +
+
+
+
+
+ +
+ + + + + +
+
+ \ No newline at end of file diff --git a/design/my_mood_negative.html b/design/my_mood_negative.html new file mode 100644 index 0000000..e00e59b --- /dev/null +++ b/design/my_mood_negative.html @@ -0,0 +1,435 @@ + + + + + +Mood History - WIDEA + + + + + + + +
+ +
+
+
+ +
+
+ +
+ +
+User profile +
+
+
+
+
+
+ +
+

Your Mood Journey

+

Visualizing your emotional well-being over the last 30 days.

+
+ +
+
+
+local_fire_department +
+
+

Current Streak

+

12 Days

+
+
+
+
+calendar_month +
+
+

Total Recorded

+

128 Entries

+
+
+
+
+sentiment_very_satisfied +
+
+

Top Emotion

+

Joyful

+
+
+
+
+ +
+ +
+
+
+favorite +

It's Okay to Feel This Way

+
+

+ Some days are heavier than others. Take a deep breath—you are doing enough. You don't have to carry it all today. +

+
+
+self_improvement +
+
+ +
+
+
+

Release Your Worries

+

Feeling overwhelmed? Let's clear some mental space.

+
+
+
+ +
+
+
+

+ "Letting go isn't giving up, it's making room for better things." +

+
+
+
+ +
+
+ +
+ +
+
+
+
+
+ +
+Work stress +Overthinking +Deadline +Tiredness +Social anxiety +Poor sleep +Expectations +Finances +
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+

October 2023

+
+ + +
+
+
+
S
+
M
+
T
+
W
+
T
+
F
+
S
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
+
+
+ +Positive +
+
+ +Neutral +
+
+ +Negative +
+
+ +Missed Day +
+
+
+ +
+
+

Mood Trend

+ +
+
+
+AWESOME +GOOD +NEUTRAL +LOW +POOR +
+
+ + + + + + + + + + + + + +
+
+SEP 15 +SEP 22 +SEP 29 +OCT 06 +TODAY +
+
+
+ +
+
+lightbulb +
+
+

Weekly Mood Insight

+

+ You tend to feel more energized and positive on Wednesdays and Thursdays. This correlates with your consistent gym check-ins on those days. +

+ +
+
+
+
+
+ +
+ + + + + +
+
+ \ No newline at end of file diff --git a/design/personal_mood_history.html b/design/my_mood_negative_v1.html similarity index 72% rename from design/personal_mood_history.html rename to design/my_mood_negative_v1.html index 5efb02d..1d2d1af 100644 --- a/design/personal_mood_history.html +++ b/design/my_mood_negative_v1.html @@ -7,7 +7,6 @@ -