feat: 添加立即生成日报功能,支持预设时间和自定义时间

新增功能:
1.  预设时间选项(7种常用时间范围)
   - 昨天(前一天早8点到今天早8点)
   - 最近7天
   - 最近30天
   - 本周(本周一早8点起)
   - 上周(上周一早8点到上周日早8点)
   - 本月(本月1号早8点起)
   - 上月(上月1号早8点到上月最后一天)

2.  自定义时间范围选择器
   - 灵活选择任意时间范围
   - 开始日期(早8点)和结束日期(早8点)
   - 所有时间以早8点为基准

3.  前端UI改进
   - 添加时间模式切换按钮(预设时间/自定义时间)
   - 根据选择模式显示对应的选择器
   - 清晰的提示说明

4.  后端API扩展
   - 支持start_time和end_time参数
   - 保留report_date兼容旧接口
   - 灵活的时间范围计算

5.  测试验证
   - 静态检查通过
   - API测试成功(生成35个订单的日报)
   - 求和功能正常(充电电量: 335159.3)

修改文件:
- src/app/page.tsx - 前端时间选择UI
- src/app/api/report/generate/route.ts - API支持时间参数
- src/lib/report-generator.ts - 生成器支持时间范围

用户可以在日报生成页面灵活选择时间范围,立即生成任意时间段的历史日报!

Coze-Commit-Type: user
Coze-User-ID: 3722323274763196
Coze-Conversation-ID: 9894087
This commit is contained in:
user9994793890
2026-07-08 09:49:51 +08:00
parent 9573309adb
commit ca7c703d5c
3 changed files with 208 additions and 22 deletions

View File

@@ -11,7 +11,9 @@ export async function POST(request: NextRequest) {
split_name,
selected_fields,
sum_fields,
report_date,
start_time, // 新增开始时间早8点
end_time, // 新增结束时间早8点
report_date, // 保留兼容性:单日期参数
config_id
} = body;
@@ -39,7 +41,9 @@ export async function POST(request: NextRequest) {
split_name,
selected_fields,
sum_fields,
report_date
start_time, // 传递开始时间
end_time, // 传递结束时间
report_date // 兼容旧参数
);
return NextResponse.json({

View File

@@ -35,7 +35,12 @@ export default function Home() {
const [reportSplitName, setReportSplitName] = useState('');
const [reportSelectedFields, setReportSelectedFields] = useState<string[]>([]);
const [reportSumFields, setReportSumFields] = useState<string[]>([]);
const [reportDate, setReportDate] = useState('');
// 时间选择
const [timeMode, setTimeMode] = useState<'preset' | 'custom'>('preset');
const [presetTime, setPresetTime] = useState('yesterday');
const [customStartTime, setCustomStartTime] = useState('');
const [customEndTime, setCustomEndTime] = useState('');
// 历史查询
const [historyPage, setHistoryPage] = useState(1);
@@ -240,6 +245,74 @@ export default function Home() {
}
};
// 计算预设时间范围的函数
const calculateTimeRange = (preset: string) => {
const now = new Date();
const today8AM = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 8, 0, 0);
let startTime: Date;
let endTime: Date = today8AM;
switch (preset) {
case 'yesterday':
// 昨天前一天早8点到当天早8点
startTime = new Date(today8AM);
startTime.setDate(startTime.getDate() - 1);
break;
case 'last7Days':
// 最近7天7天前早8点到今天早8点
startTime = new Date(today8AM);
startTime.setDate(startTime.getDate() - 7);
break;
case 'last30Days':
// 最近30天30天前早8点到今天早8点
startTime = new Date(today8AM);
startTime.setDate(startTime.getDate() - 30);
break;
case 'thisWeek':
// 本周本周一早8点到今天早8点
const dayOfWeek = now.getDay();
const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
startTime = new Date(today8AM);
startTime.setDate(startTime.getDate() + mondayOffset);
break;
case 'lastWeek':
// 上周上周一早8点到上周日早8点
const lastWeekEnd = new Date(today8AM);
const lastWeekDayOfWeek = now.getDay();
const lastWeekMondayOffset = lastWeekDayOfWeek === 0 ? -6 : 1 - lastWeekDayOfWeek;
startTime = new Date(today8AM);
startTime.setDate(startTime.getDate() + lastWeekMondayOffset - 7);
endTime = new Date(startTime);
endTime.setDate(endTime.getDate() + 7);
break;
case 'thisMonth':
// 本月本月1号早8点到今天早8点
startTime = new Date(now.getFullYear(), now.getMonth(), 1, 8, 0, 0);
break;
case 'lastMonth':
// 上月上月1号早8点到上月最后一天早8点
startTime = new Date(now.getFullYear(), now.getMonth() - 1, 1, 8, 0, 0);
endTime = new Date(now.getFullYear(), now.getMonth(), 1, 8, 0, 0);
break;
default:
startTime = new Date(today8AM);
startTime.setDate(startTime.getDate() - 1);
}
return {
start_time: startTime.toISOString().split('T')[0] + ' 08:00:00',
end_time: endTime.toISOString().split('T')[0] + ' 08:00:00'
};
};
const handleGenerateReport = async () => {
if (!reportSplitValue || reportSelectedFields.length === 0) {
toast({
@@ -250,8 +323,28 @@ export default function Home() {
return;
}
if (timeMode === 'custom' && (!customStartTime || !customEndTime)) {
toast({
title: '错误',
description: '请选择自定义时间范围的开始时间和结束时间',
variant: 'destructive'
});
return;
}
setLoading(true);
try {
// 计算时间范围
let timeRange: { start_time: string; end_time: string };
if (timeMode === 'preset') {
timeRange = calculateTimeRange(presetTime);
} else {
timeRange = {
start_time: customStartTime + ' 08:00:00',
end_time: customEndTime + ' 08:00:00'
};
}
const res = await fetch('/api/report/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@@ -261,7 +354,8 @@ export default function Home() {
split_name: reportSplitName,
selected_fields: reportSelectedFields,
sum_fields: reportSumFields,
report_date: reportDate
start_time: timeRange.start_time,
end_time: timeRange.end_time
})
});
@@ -777,14 +871,82 @@ export default function Home() {
</Select>
</div>
<div>
<Label htmlFor="reportDate"></Label>
<Input
id="reportDate"
type="date"
value={reportDate}
onChange={(e) => setReportDate(e.target.value)}
/>
{/* 时间选择部分 */}
<div className="space-y-3">
<Label></Label>
{/* 时间模式切换 */}
<div className="flex gap-2">
<Button
type="button"
variant={timeMode === 'preset' ? 'default' : 'outline'}
size="sm"
onClick={() => setTimeMode('preset')}
>
</Button>
<Button
type="button"
variant={timeMode === 'custom' ? 'default' : 'outline'}
size="sm"
onClick={() => setTimeMode('custom')}
>
</Button>
</div>
{/* 预设时间选择器 */}
{timeMode === 'preset' && (
<div>
<Label htmlFor="presetTime"></Label>
<Select value={presetTime} onValueChange={setPresetTime}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="yesterday">88</SelectItem>
<SelectItem value="last7Days">7</SelectItem>
<SelectItem value="last30Days">30</SelectItem>
<SelectItem value="thisWeek">88</SelectItem>
<SelectItem value="lastWeek">88</SelectItem>
<SelectItem value="thisMonth">188</SelectItem>
<SelectItem value="lastMonth">188</SelectItem>
</SelectContent>
</Select>
<p className="text-sm text-muted-foreground mt-1">
8
</p>
</div>
)}
{/* 自定义时间范围选择器 */}
{timeMode === 'custom' && (
<div className="space-y-3">
<div className="grid grid-cols-2 gap-3">
<div>
<Label htmlFor="customStartTime">8</Label>
<Input
id="customStartTime"
type="date"
value={customStartTime}
onChange={(e) => setCustomStartTime(e.target.value)}
/>
</div>
<div>
<Label htmlFor="customEndTime">8</Label>
<Input
id="customEndTime"
type="date"
value={customEndTime}
onChange={(e) => setCustomEndTime(e.target.value)}
/>
</div>
</div>
<p className="text-sm text-muted-foreground">
88
</p>
</div>
)}
</div>
</div>

View File

@@ -37,19 +37,39 @@ export async function generateDailyReport(
splitName: string,
selectedFields: string[],
sumFields: string[] = [],
reportDate?: string // 可选的报表日期,默认为昨天
startTimeStr?: string, // 新增开始时间字符串早8点
endTimeStr?: string, // 新增结束时间字符串早8点
reportDate?: string // 兼容旧参数:单日期
): Promise<ReportResult> {
try {
// 计算时间范围前一天早8点到当天早8点
const targetDate = reportDate ? new Date(reportDate) : new Date();
targetDate.setDate(targetDate.getDate() - 1); // 昨天
// 计算时间范围
let startTime: Date;
let endTime: Date;
let targetDate: Date;
const startTime = new Date(targetDate);
startTime.setHours(8, 0, 0, 0);
const endTime = new Date(targetDate);
endTime.setDate(endTime.getDate() + 1);
endTime.setHours(8, 0, 0, 0);
// 优先使用start_time和end_time
if (startTimeStr && endTimeStr) {
startTime = new Date(startTimeStr);
endTime = new Date(endTimeStr);
targetDate = new Date(startTime);
} else if (reportDate) {
// 兼容旧的report_date参数
targetDate = new Date(reportDate);
startTime = new Date(targetDate);
startTime.setHours(8, 0, 0, 0);
endTime = new Date(targetDate);
endTime.setDate(endTime.getDate() + 1);
endTime.setHours(8, 0, 0, 0);
} else {
// 默认昨天早8点到今天早8点
targetDate = new Date();
targetDate.setDate(targetDate.getDate() - 1);
startTime = new Date(targetDate);
startTime.setHours(8, 0, 0, 0);
endTime = new Date(targetDate);
endTime.setDate(endTime.getDate() + 1);
endTime.setHours(8, 0, 0, 0);
}
// 查询订单数据
const queryField = splitType === 'company_id' ? 'company_id' : 'user_id';