feat: 用自定义侧边栏替换聊天室 Conversations 组件,提取公共 SidebarGroup 和 date-group
This commit is contained in:
28
src/web/shared/components/SidebarGroup/index.tsx
Normal file
28
src/web/shared/components/SidebarGroup/index.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { CaretDownOutlined, CaretRightOutlined } from "@ant-design/icons";
|
||||
import { Typography } from "antd";
|
||||
import { type ReactNode, useState } from "react";
|
||||
|
||||
interface SidebarGroupProps {
|
||||
children: ReactNode;
|
||||
count: number;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export function SidebarGroup({ children, count, label }: SidebarGroupProps) {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="app-sidebar-group">
|
||||
<div className="app-sidebar-group-header" onClick={() => setCollapsed(!collapsed)}>
|
||||
<span className="app-sidebar-group-arrow">{collapsed ? <CaretRightOutlined /> : <CaretDownOutlined />}</span>
|
||||
<Typography.Text className="app-sidebar-group-label" type="secondary">
|
||||
{label}
|
||||
</Typography.Text>
|
||||
<Typography.Text className="app-sidebar-group-count" type="secondary">
|
||||
({count})
|
||||
</Typography.Text>
|
||||
</div>
|
||||
{!collapsed && <div className="app-sidebar-group-content">{children}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export async function fetchConversation(projectId: string, conversationId: strin
|
||||
}
|
||||
|
||||
export async function fetchConversations(projectId: string): Promise<ConversationListResponse> {
|
||||
const response = await fetch(`/api/projects/${projectId}/conversations?pageSize=100`);
|
||||
const response = await fetch(`/api/projects/${projectId}/conversations?pageSize=200`);
|
||||
return handleResponse(response, (data) => data as ConversationListResponse);
|
||||
}
|
||||
|
||||
|
||||
52
src/web/shared/utils/date-group.ts
Normal file
52
src/web/shared/utils/date-group.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
export type DateGroup = "earlier" | "thisMonth" | "thisWeek" | "today" | "yesterday";
|
||||
|
||||
export const GROUP_LABELS: Record<DateGroup, string> = {
|
||||
earlier: "更早",
|
||||
thisMonth: "本月",
|
||||
thisWeek: "本周",
|
||||
today: "今天",
|
||||
yesterday: "昨天",
|
||||
};
|
||||
|
||||
export const GROUP_ORDER: readonly DateGroup[] = ["today", "yesterday", "thisWeek", "thisMonth", "earlier"];
|
||||
|
||||
export interface DateGroupData<T> {
|
||||
items: T[];
|
||||
key: DateGroup;
|
||||
}
|
||||
|
||||
export function getDateGroup(dateStr: string, now: Date): DateGroup {
|
||||
const date = new Date(dateStr);
|
||||
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||||
const yesterday = new Date(today.getTime() - 86_400_000);
|
||||
const dateDay = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
|
||||
if (dateDay.getTime() >= today.getTime()) return "today";
|
||||
if (dateDay.getTime() >= yesterday.getTime()) return "yesterday";
|
||||
|
||||
const dayOfWeek = today.getDay();
|
||||
const mondayOffset = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
|
||||
const monday = new Date(today.getTime() - mondayOffset * 86_400_000);
|
||||
if (dateDay.getTime() >= monday.getTime()) return "thisWeek";
|
||||
|
||||
if (dateDay.getFullYear() === today.getFullYear() && dateDay.getMonth() === today.getMonth()) {
|
||||
return "thisMonth";
|
||||
}
|
||||
|
||||
return "earlier";
|
||||
}
|
||||
|
||||
export function groupByDate<T>(items: readonly T[], dateField: keyof T & string): Array<DateGroupData<T>> {
|
||||
const now = new Date();
|
||||
const groups = new Map<DateGroup, T[]>();
|
||||
|
||||
for (const item of items) {
|
||||
const dateValue = item[dateField];
|
||||
if (typeof dateValue !== "string") continue;
|
||||
const group = getDateGroup(dateValue, now);
|
||||
if (!groups.has(group)) groups.set(group, []);
|
||||
groups.get(group)!.push(item);
|
||||
}
|
||||
|
||||
return GROUP_ORDER.map((key) => ({ items: groups.get(key) ?? [], key }));
|
||||
}
|
||||
Reference in New Issue
Block a user